Files
QuoteForge/bible-local/decisions/2026-07-10-world-pricelist-fallback.md
T
Mikhail ChusavitinandClaude Opus 4.8 bc17c18943 docs: записать решения по итогам ценообразования и индексу decisions
Смысл красной подсветки итогов сменился с «цены есть не для всех
позиций» на «часть суммы посчитана по ценам-заглушкам world» —
оформлено отдельной записью в decision log. Журнал решений добавлен
в оглавление bible-local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:16:36 +03:00

50 lines
2.8 KiB
Markdown

# Decision: `world` pricelist as a fallback stub for missing prices
**Date:** 2026-07-10
**Status:** active
## Context
Four pricelist `source` values sync from the server: `estimate`, `warehouse`, `competitor`,
`world`. Only the first three were ever read — `world` synced into `local_pricelists` /
`local_pricelist_items` but nothing consumed it, so LOTs with no warehouse/competitor price
showed as "—" in the "Ценообразование" tab, which also broke the "Итого" coverage (red "*").
## Decision
`world` is a fallback stub, applied per-column, only when the native price for that column
is missing or ≤ 0:
- Resolution order per column: native source price → `world` price → still missing.
- Applies to all three Buy columns (Estimate, Склад, Конкуренты), the Sale table (same
unit prices, multiplied by the existing sale coefficients), and CSV export.
- A world-fallback price counts toward "Итого" like a native price (closes the red "*" gap).
- UI marks only the specific cell that used a fallback, with `bg-amber-50 text-amber-700`
(amber was chosen because `applyCustomPrice()` strips `gray/green/red/blue` text-color
classes via regex on vendor-price cells — amber survives that).
- CSV keeps price values untouched (no suffixes) and adds one trailing comment column,
"Заглушка (world)", listing which columns used the fallback per row (e.g.
`world: Stock, Конкуренты`), always present regardless of export options so column counts
stay aligned across header/rows/summary.
- `world` is resolved independently in each call site (`quote.go` `CalculatePriceLevels`,
`export.go` `resolvePricingTotals`) via "explicit ID → latest active → latest local", same
pattern as the other three sources. It is intentionally NOT added to `levelBySource` /
`ResolvedPricelistIDs` as a fourth on-screen level.
- `NormalizePricelistSource("world")` returns `PricelistSourceWorld`, not `estimate` — it must
not collapse into the estimate source.
## Consequences
- `PriceLevelsItem` (API `POST /api/quote/price-levels`) carries three new bools:
`estimate_from_world`, `warehouse_from_world`, `competitor_from_world`.
- `price_missing` on that endpoint only lists a source when BOTH the native and the
`world` price are unavailable.
- No new config-level column (e.g. `world_pricelist_id`) — world always resolves to
"latest active `world` pricelist," not a per-configuration pin.
- If no `world` pricelist exists locally, behavior is unchanged (missing prices stay "—",
no error).
- How the footer totals surface this fallback is decided separately in
[2026-07-24-pricing-total-world-share.md](2026-07-24-pricing-total-world-share.md);
membership of world LOTs in the configurator's LOT set is decided in
[2026-07-24-component-universe-world-union.md](2026-07-24-component-universe-world-union.md).