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
@@ -3,6 +3,7 @@ package services
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -68,13 +69,41 @@ type ProjectPricingExportOptions struct {
|
||||
// other API callers that omit sale_markup.
|
||||
const defaultSaleMarkup = 1.3
|
||||
|
||||
func (o ProjectPricingExportOptions) saleMarkupFactor() float64 {
|
||||
// effectiveSaleMarkupFactor resolves the DDP estimate uplift for one configuration.
|
||||
// An explicit opts.SaleMarkup (sent by the single-config pricing tab, which knows the
|
||||
// live-edited value) always wins. Otherwise each configuration's own saved uplift
|
||||
// (persisted in Notes by the "Ценообразование" tab, see index.html buildPricingState/
|
||||
// restorePricingStateFromNotes) is used, so bulk project export matches what exporting
|
||||
// that same configuration individually would produce — one pipeline, not a single
|
||||
// project-wide constant.
|
||||
func (o ProjectPricingExportOptions) effectiveSaleMarkupFactor(cfg *models.Configuration) float64 {
|
||||
if o.SaleMarkup > 0 {
|
||||
return o.SaleMarkup
|
||||
}
|
||||
if v := configSavedSaleUplift(cfg); v > 0 {
|
||||
return v
|
||||
}
|
||||
return defaultSaleMarkup
|
||||
}
|
||||
|
||||
// configSavedSaleUplift reads the per-configuration DDP estimate uplift persisted by the
|
||||
// pricing tab. Notes stores {"pricing_ui":{"sale_uplift":...}} as JSON — see
|
||||
// serializeConfigNotes/restorePricingStateFromNotes in index.html.
|
||||
func configSavedSaleUplift(cfg *models.Configuration) float64 {
|
||||
if cfg == nil || strings.TrimSpace(cfg.Notes) == "" {
|
||||
return 0
|
||||
}
|
||||
var parsed struct {
|
||||
PricingUI struct {
|
||||
SaleUplift float64 `json:"sale_uplift"`
|
||||
} `json:"pricing_ui"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(cfg.Notes), &parsed); err != nil {
|
||||
return 0
|
||||
}
|
||||
return parsed.PricingUI.SaleUplift
|
||||
}
|
||||
|
||||
func (o ProjectPricingExportOptions) isDDP() bool {
|
||||
return strings.EqualFold(strings.TrimSpace(o.Basis), "ddp")
|
||||
}
|
||||
@@ -457,7 +486,7 @@ func (s *ExportService) buildPricingExportBlock(cfg *models.Configuration, opts
|
||||
})
|
||||
}
|
||||
if opts.isDDP() {
|
||||
applyDDPMarkup(block.Rows, opts.saleMarkupFactor())
|
||||
applyDDPMarkup(block.Rows, opts.effectiveSaleMarkupFactor(cfg))
|
||||
}
|
||||
if opts.ManualPrice != nil && *opts.ManualPrice > 0 {
|
||||
distributeManualPrice(block.Rows, *opts.ManualPrice)
|
||||
@@ -494,7 +523,7 @@ func (s *ExportService) buildPricingExportBlock(cfg *models.Configuration, opts
|
||||
}
|
||||
|
||||
if opts.isDDP() {
|
||||
applyDDPMarkup(block.Rows, opts.saleMarkupFactor())
|
||||
applyDDPMarkup(block.Rows, opts.effectiveSaleMarkupFactor(cfg))
|
||||
}
|
||||
if opts.ManualPrice != nil && *opts.ManualPrice > 0 {
|
||||
distributeManualPrice(block.Rows, *opts.ManualPrice)
|
||||
|
||||
Reference in New Issue
Block a user