fix: текстовый BOM работает в пасте конфигуратора через единый серверный парсер

Паста BOM на странице конфигурирования теперь распознаёт текстовый и
Inspur-форматы: вместо дублирования парсера на JS добавлен stateless
эндпоинт POST /api/vendor-spec/parse-text, который использует те же
детекторы и парсеры, что и импорт файла (KISS — один парсер на оба
входа). JS-копии _parseInspurBOMText/_isInspurBOMText удалены.

Заголовок конфигурации определяется по маркеру ", в составе:" с любым
префиксом ("Сервер X3" и "Вычислительный GPU сервер X3" → модель X3);
строки тримятся, пробел в начале не попадает в P/N; запятые и дефисы
внутри описания сохраняются (RAID0,1,10; 8-GPU-2304GB).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-06-16 09:16:55 +03:00
parent 6f2c261350
commit 24c34eb0e1
6 changed files with 235 additions and 58 deletions

View File

@@ -85,14 +85,14 @@ Rules:
The same endpoint `POST /api/projects/:uuid/vendor-import` also accepts a human-readable Russian text BOM.
Format: an optional header line `Сервер <model>, в составе:` followed by one component per line as
Format: an optional header line ending with `, в составе:` followed by one component per line as
`<description> - <quantity> шт.`. The separator may be a hyphen, en-dash, or em-dash; the space before
`шт` is optional; a trailing `.` after `шт` is optional. Quantities are anchored to the end of the line,
so hyphens and digits inside the description (e.g. `8-GPU-2304GB`) are preserved.
so hyphens, commas, and digits inside the description (e.g. `8-GPU-2304GB`, `RAID0,1,10`) are preserved.
Example:
```
Сервер KR9288X3, в составе:
Вычислительный GPU сервер G5500V7, в составе:
GPU-NVIDIA HGX B300 8-GPU-2304GB HBM3E - 1 шт.
CPU Intel 6760P Xeon 2.2GHz 64C 320M 330W - 2 шт.
Mem 128G DDR5-6400MHz ECC-RDIMM - 16 шт.
@@ -101,10 +101,25 @@ NVIDIA twin port transceiver, 800Gbps, OSFP - 8шт.
Rules:
- the entire file becomes a single configuration (`server_count = 1`);
- the `Сервер <model>, в составе:` header supplies the configuration `name` and `server_model`;
- the header (any line ending with `, в составе:`) supplies `server_model` and `name`; the model is the
last whitespace-separated token before the comma (so both `Сервер X3` and `Вычислительный GPU сервер X3`
resolve to `X3`);
- without a header, `name` falls back to the uploaded filename (without extension) and `server_model` is empty;
- each line is trimmed, so leading/trailing whitespace never enters `vendor_partnumber`;
- the format carries no partnumbers — each line's description is stored as both `vendor_partnumber` and
`description`, so rows resolve through the active partnumber book when matched and otherwise stay
unresolved and editable in the UI;
- lines that do not match `<description> - <quantity> шт.` are skipped;
- no price data is present in the format; `unit_price` and `total_price` are left nil.
## Pasted BOM text parsing
`POST /api/vendor-spec/parse-text` is a stateless endpoint that parses pasted single-column text BOM
(Inspur and Russian text BOM) into rows. Request body: `{"text": "..."}`. Response:
`{"rows": [{vendor_partnumber, quantity, description}], "format": "Inspur"|"Text"|""}`.
This shares the exact detectors and parsers used by the file-import path
(`ParsePastedBOMText``IsInspurBOM`/`parseInspurBOM`, `IsTextBOM`/`parseTextBOM`), so paste and upload
behave identically — there is no second parser in the frontend. The configurator's BOM paste box calls
this endpoint; an empty `rows` result (or any payload containing tabs, i.e. a real spreadsheet table)
falls back to the manual column-mapping grid.