From c6385f6cf15dbb733ae819aa77a0eeb93e9180be Mon Sep 17 00:00:00 2001 From: Mikhail Chusavitin Date: Wed, 17 Jun 2026 07:53:37 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20CSV=20=D1=8D=D0=BA=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82=20=E2=80=94=20bundle=20(1=20PN=20=E2=86=92=20N=20L?= =?UTF-8?q?OT)=20=D1=80=D0=B0=D0=B7=D0=B2=D0=BE=D1=80=D0=B0=D1=87=D0=B8?= =?UTF-8?q?=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BE=D1=82?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit buildPricingExportBlock теперь создаёт одну строку на каждый LOT mapping, а не одну строку на BOM-строку. BOM-цена ставится только в первую подстроку (как vendorOrig в фронтенде). Добавлен computeSingleLotTotal, удалён неиспользуемый formatLotDisplay. Co-Authored-By: Claude Sonnet 4.6 --- internal/services/export.go | 58 ++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/internal/services/export.go b/internal/services/export.go index 7bef03f..1db4025 100644 --- a/internal/services/export.go +++ b/internal/services/export.go @@ -388,17 +388,37 @@ func (s *ExportService) buildPricingExportBlock(cfg *models.Configuration, opts description = componentDescriptions[rowMappings[0].LotName] } - pricingRow := ProjectPricingExportRow{ - LotDisplay: formatLotDisplay(rowMappings), - VendorPN: row.VendorPartnumber, - Description: description, - Quantity: exportPositiveInt(row.Quantity, 1), - BOMTotal: vendorRowTotal(row), - Estimate: computeMappingTotal(priceMap, rowMappings, row.Quantity, func(p pricingLevels) *float64 { return p.Estimate }), - Stock: computeMappingTotal(priceMap, rowMappings, row.Quantity, func(p pricingLevels) *float64 { return p.Stock }), - Competitor: computeMappingTotal(priceMap, rowMappings, row.Quantity, func(p pricingLevels) *float64 { return p.Competitor }), + if len(rowMappings) == 0 { + block.Rows = append(block.Rows, ProjectPricingExportRow{ + LotDisplay: "н/д", + VendorPN: row.VendorPartnumber, + Description: description, + Quantity: exportPositiveInt(row.Quantity, 1), + BOMTotal: vendorRowTotal(row), + }) + continue + } + + // One export row per LOT mapping so that bundles (1 PN → N LOTs) appear + // as separate lines, matching the frontend pricing table layout. + pnQty := exportPositiveInt(row.Quantity, 1) + for i, mapping := range rowMappings { + lotQty := pnQty * mapping.QuantityPerPN + var bomTotal *float64 + if i == 0 { + bomTotal = vendorRowTotal(row) + } + block.Rows = append(block.Rows, ProjectPricingExportRow{ + LotDisplay: mapping.LotName, + VendorPN: row.VendorPartnumber, + Description: description, + Quantity: lotQty, + BOMTotal: bomTotal, + Estimate: computeSingleLotTotal(priceMap, mapping.LotName, lotQty, func(p pricingLevels) *float64 { return p.Estimate }), + Stock: computeSingleLotTotal(priceMap, mapping.LotName, lotQty, func(p pricingLevels) *float64 { return p.Stock }), + Competitor: computeSingleLotTotal(priceMap, mapping.LotName, lotQty, func(p pricingLevels) *float64 { return p.Competitor }), + }) } - block.Rows = append(block.Rows, pricingRow) } for _, item := range cfg.Items { @@ -696,6 +716,14 @@ func computeMappingTotal(priceMap map[string]pricingLevels, mappings []localdb.V return floatPtr(total) } +func computeSingleLotTotal(priceMap map[string]pricingLevels, lotName string, qty int, selector func(pricingLevels) *float64) *float64 { + price := selector(priceMap[lotName]) + if price == nil || *price <= 0 { + return nil + } + return floatPtr(*price * float64(qty)) +} + func totalForUnitPrice(unitPrice *float64, quantity int) *float64 { if unitPrice == nil || *unitPrice <= 0 { return nil @@ -789,16 +817,6 @@ func pricingConfigSummaryRow(cfg ProjectPricingExportConfig, opts ProjectPricing return record } -func formatLotDisplay(mappings []localdb.VendorSpecLotMapping) string { - switch len(mappings) { - case 0: - return "н/д" - case 1: - return mappings[0].LotName - default: - return fmt.Sprintf("%s +%d", mappings[0].LotName, len(mappings)-1) - } -} func formatMoneyValue(value *float64) string { if value == nil {