- Created bible/ with hierarchical documentation (architecture, pricelists, vendor mapping, background tasks, data rules, patterns, API, operations, history) - CLAUDE.md reduced to one instruction: read and follow the bible - README.md reduced to quick start only - Removed MEMORY.md and csv_export.md (content consolidated into bible/) - Fixed stale facts found during audit: weighted_avg (not weighted_median), correct API route names (/export-csv, /recalculate-all) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
3.3 KiB
Markdown
86 lines
3.3 KiB
Markdown
# Vendor Mapping (Сопоставление partnumber → LOT)
|
||
|
||
> Решение зафиксировано: 2026-02-18
|
||
|
||
## Концепция
|
||
|
||
`lot_partnumbers` — канонический контракт сопоставления для внешнего конфигуратора.
|
||
|
||
Маппинг строго 1:1 по ключу `(vendor, partnumber)` → `lot_name`.
|
||
|
||
---
|
||
|
||
## Правила
|
||
|
||
### 1. Единственная запись на ключ
|
||
|
||
Запрещено создавать несколько строк для одного ключа `(vendor, partnumber)`.
|
||
|
||
### 2. Порядок резолвинга (фиксированный)
|
||
|
||
```
|
||
1. Точное совпадение: vendor + partnumber → lot_name
|
||
2. Fallback: vendor='' + partnumber → lot_name
|
||
```
|
||
|
||
Резолвер: `internal/lotmatch/matcher.go`
|
||
|
||
### 3. Составные маппинги — через бандлы
|
||
|
||
Если один внешний partnumber соответствует нескольким LOT — использовать внутренние бандл-таблицы:
|
||
|
||
```
|
||
lot_partnumbers: (vendor, partnumber) → bundle_lot_name
|
||
qt_lot_bundles: bundle_lot_name → [item1, item2, ...]
|
||
qt_lot_bundle_items: bundle_lot_name, lot_name, qty
|
||
```
|
||
|
||
- Bundle LOT — внутренний, скрыт в обычном UI LOT по умолчанию.
|
||
- Bundle expansion (разворачивание) происходит только внутри PriceForge при расчёте warehouse-прайслиста.
|
||
|
||
### 4. Ignore-логика
|
||
|
||
- **Не использовать** `stock_ignore_rules` для новой логики.
|
||
- Использовать `qt_vendor_partnumber_seen.is_ignored` (cross-source флаг).
|
||
|
||
### 5. Клиентская совместимость
|
||
|
||
- Клиент потребляет LOT-based прайслисты (как обычно).
|
||
- Bundle expansion/allocation происходит только внутри PriceForge.
|
||
|
||
---
|
||
|
||
## Allocation при отсутствии estimate
|
||
|
||
Если у bundle-компонента нет estimate-цены:
|
||
1. Fallback: взять из предыдущего активного warehouse-прайслиста.
|
||
2. Если нет предыдущего — цена `0`.
|
||
|
||
---
|
||
|
||
## Таблицы БД
|
||
|
||
| Таблица | Назначение |
|
||
|---------|------------|
|
||
| `lot_partnumbers` | Канонические маппинги `(vendor, partnumber)` → `lot_name` |
|
||
| `qt_lot_bundles` | Определения бандлов (bundle LOT → описание) |
|
||
| `qt_lot_bundle_items` | Состав бандла: `(bundle_lot_name, lot_name, qty)` |
|
||
| `qt_vendor_partnumber_seen` | Реестр seen-записей + флаг `is_ignored` |
|
||
|
||
Миграция: `migrations/023_vendor_partnumber_global_mapping.sql`
|
||
|
||
---
|
||
|
||
## Связанные модули
|
||
|
||
| Роль | Файл |
|
||
|------|------|
|
||
| Миграция | `migrations/023_vendor_partnumber_global_mapping.sql` |
|
||
| Резолвер | `internal/lotmatch/matcher.go` |
|
||
| Сервис | `internal/services/vendor_mapping.go` |
|
||
| API | `internal/handlers/pricing.go` |
|
||
| Warehouse calc | `internal/warehouse/snapshot.go` |
|
||
| Stock import seen/ignore | `internal/services/stock_import.go` |
|
||
| Модели | `internal/models/lot.go`, `internal/models/configuration.go` |
|
||
| Роутинг | `cmd/pfs/main.go` |
|