feat: PN code в импорте BOM, объединённый список LOT (world ∪ estimate)

Колонка «PN code» в таблице импорта BOM: HPE-спецификации хранят партномер
в двух столбцах, канонический вид — P52534-B21#B19. Склейка попадает
в vendor_partnumber и сравнивается с книгой партномеров как есть; при
загрузке разбирается обратно на две колонки. Схему БД менять не пришлось.

Список допустимых LOT собирается из world ∪ estimate (componentUniverse),
а не только из estimate. Прежняя область видимости молча теряла
lot_mappings: резолвер сопоставлял PN по книге, которая про прайслисты
не знает, а фронт отбрасывал LOT, которого нет в estimate — при этом
в корзину он всё равно попадал. World-only позиции отдают price_quality 0.

Кнопка «Пересопоставить» — перерешать BOM по актуальной книге, так как
при открытии конфигурации сопоставления остаются замороженными.

Итоги на вкладке «Ценообразование»: звёздочки убраны (переносились
на новую строку), все три суммы красные, при наведении — попап с долей
цен из прайслиста WORLD. Колонка «PN вендора» больше не переносится.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-07-24 17:01:31 +03:00
co-authored by Claude Opus 4.8
parent 0fa7b0b1b6
commit 905f9a4952
7 changed files with 547 additions and 119 deletions
+27
View File
@@ -25,6 +25,33 @@ Rules:
- QuoteForge does not use legacy BOM tables;
- apply flow rebuilds cart rows from `lot_mappings[]`.
## Split partnumbers (HPE option codes)
HPE specs carry the partnumber in two columns: base PN plus an option code
(`P52534-B21` + `B19`). The canonical partnumber is the concatenation
`P52534-B21#B19`, and it is what gets compared against the partnumber book.
Rules:
- the import grid has a `PN code` column type in addition to `P/N`; it is optional
and at most one column may carry it;
- an empty code cell keeps the bare PN — no trailing `#`;
- the composed value is stored in `vendor_partnumber`. There is **no separate
`pn_code` field**: no DDL and no new JSON key, and the stored string is exactly
the string the resolver looks up;
- the column layout of the import grid is not persisted. On load the grid is
re-derived from `vendor_spec`, and the `PN code` column reappears only when at
least one stored partnumber contains `#`, split on the first `#`.
## Re-resolving an existing BOM
Opening a configuration does **not** re-resolve its BOM: `loadVendorSpec` renders the
`lot_mappings[]` frozen at save time, so a configuration keeps the mapping it was
saved with even after the partnumber book changes.
Book entries added later are picked up only through the `Пересопоставить` button,
which calls the resolve endpoint for every row. Book matches win over the stored
mapping (resolver step 1 beats step 2); rows the book does not know keep theirs.
## Partnumber books
Partnumber books are pull-only snapshots from PriceForge.