fix: DDP-экспорт с проекта игнорировал свой аплифт каждой конфигурации
ProjectPricingExportOptions.SaleMarkup всегда был 0 при экспорте с проекта, поэтому применялся единый дефолт 1,3 вместо сохранённого в Notes конфигурации значения. buildPricingExportBlock теперь берёт аплифт из настроек каждой конфигурации — экспорт с проекта идёт по тому же конвейеру, что и экспорт с конкретной конфигурации. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
619967c954
commit
c83e4ec9f9
@@ -0,0 +1,51 @@
|
||||
# Decision: project-level DDP export uses each configuration's own sale uplift
|
||||
|
||||
**Date:** 2026-08-12
|
||||
**Status:** active
|
||||
|
||||
## Context
|
||||
|
||||
Two code paths produce the same "Ценообразование" (pricing) CSV: exporting a single
|
||||
configuration from `index.html` (`exportPricingCSV`), and exporting an entire project
|
||||
from `project_detail.html` (`exportProject` → `POST /api/projects/:uuid/export` →
|
||||
`ExportProjectPricingCSV`). Both end up in `ExportService.buildPricingExportBlock`.
|
||||
|
||||
Each configuration's "Аплифт к estimate" (`#pricing-uplift-sale` in the pricing tab) is
|
||||
saved per configuration, piggybacked into `Configuration.Notes` as
|
||||
`{"pricing_ui":{"sale_uplift":...}}` (see `serializeConfigNotes`/
|
||||
`restorePricingStateFromNotes` in `index.html`). The single-config export sends this value
|
||||
explicitly as `sale_markup` in the request, so it always applies the right uplift.
|
||||
|
||||
The project-level export modal never had an uplift input and never sent `sale_markup`, so
|
||||
`ProjectPricingExportOptions.SaleMarkup` was always `0`. `buildPricingExportBlock` used to
|
||||
fall back to a single hardcoded `defaultSaleMarkup` (1.3) for every configuration in the
|
||||
project, silently ignoring each configuration's own saved uplift — a bulk DDP export did
|
||||
not match what exporting those same configurations individually would produce.
|
||||
|
||||
## Decision
|
||||
|
||||
`buildPricingExportBlock` resolves the DDP estimate factor per configuration via
|
||||
`ProjectPricingExportOptions.effectiveSaleMarkupFactor(cfg)`:
|
||||
|
||||
- an explicit `opts.SaleMarkup` (only ever sent by the single-config pricing tab, which
|
||||
knows the live-edited value that may not be saved yet) always wins;
|
||||
- otherwise it reads that configuration's own saved uplift from `Notes`
|
||||
(`configSavedSaleUplift`);
|
||||
- otherwise it falls back to `defaultSaleMarkup` (1.3), same as before, for configurations
|
||||
that never had an uplift saved.
|
||||
|
||||
Both `applyDDPMarkup` call sites in `buildPricingExportBlock` (the BOM-driven branch and
|
||||
the plain-items fallback) use this per-configuration factor. Stock/Competitor keep using
|
||||
the fixed `stockCompetitorMarkupFactor` (1.3) — only the Estimate uplift is configurable.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Project-level DDP export now goes through the same "pipeline" as single-config export:
|
||||
each row's Estimate is scaled by that configuration's own saved uplift, not a
|
||||
project-wide constant.
|
||||
- If a future caller needs to force one uplift across an entire project export regardless
|
||||
of individual configs' saved settings, it must do so explicitly via `sale_markup` in the
|
||||
request — do not reintroduce a silent global default that overrides saved per-config
|
||||
values.
|
||||
- `configSavedSaleUplift` only reads `Notes`; it does not fail loudly on malformed/foreign
|
||||
JSON in that field — it just returns 0 and lets the 1.3 fallback apply.
|
||||
Reference in New Issue
Block a user