@dainamite/cpq 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/MIGRATION.md +74 -0
- package/dist/modules/cpq/acl.js +1 -0
- package/dist/modules/cpq/acl.js.map +2 -2
- package/dist/modules/cpq/api/_helpers/adjustmentCommandRoute.js +45 -0
- package/dist/modules/cpq/api/_helpers/adjustmentCommandRoute.js.map +7 -0
- package/dist/modules/cpq/api/_helpers/quoteMutationGuard.js +23 -0
- package/dist/modules/cpq/api/_helpers/quoteMutationGuard.js.map +7 -0
- package/dist/modules/cpq/api/_helpers/quoteRouteOpenApi.js +19 -0
- package/dist/modules/cpq/api/_helpers/quoteRouteOpenApi.js.map +7 -0
- package/dist/modules/cpq/api/orders/[orderId]/route.js +17 -1
- package/dist/modules/cpq/api/orders/[orderId]/route.js.map +2 -2
- package/dist/modules/cpq/api/orders/route.js +47 -2
- package/dist/modules/cpq/api/orders/route.js.map +2 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/restore/route.js +54 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/restore/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js +42 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js.map +2 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js +27 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js.map +2 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/[adjustmentId]/route.js +47 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/[adjustmentId]/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/preview/route.js +30 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/preview/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/route.js +47 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/route.js.map +7 -0
- package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js +32 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js.map +2 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js +33 -2
- package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js.map +2 -2
- package/dist/modules/cpq/api/quotes/price/route.js +43 -3
- package/dist/modules/cpq/api/quotes/price/route.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +3 -9
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +21 -25
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +48 -47
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +3 -3
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js +37 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +174 -184
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +168 -143
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/page.js +36 -34
- package/dist/modules/cpq/backend/cpq/offerings/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +140 -280
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/page.js +6 -6
- package/dist/modules/cpq/backend/cpq/orders/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/orders/page.meta.js.map +1 -1
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +41 -36
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +76 -72
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/page.js +18 -15
- package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +23 -21
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +22 -50
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +74 -52
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +20 -17
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/pricing/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +115 -123
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js +208 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentsPanel.js +79 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentsPanel.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/arcLineRemoval.js +53 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/arcLineRemoval.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/priceAdjustmentContext.js +107 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/priceAdjustmentContext.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/usePriceAdjustments.js +130 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/usePriceAdjustments.js.map +7 -0
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +269 -311
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +3 -3
- package/dist/modules/cpq/backend/cpq/quotes/page.js +23 -19
- package/dist/modules/cpq/backend/cpq/quotes/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/quotes/page.meta.js.map +1 -1
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +19 -15
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +171 -178
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +60 -50
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +22 -18
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/wizards/page.js.map +2 -2
- package/dist/modules/cpq/ce.js +8 -0
- package/dist/modules/cpq/ce.js.map +2 -2
- package/dist/modules/cpq/cli.js +34 -1
- package/dist/modules/cpq/cli.js.map +2 -2
- package/dist/modules/cpq/commands/price-adjustments.js +107 -0
- package/dist/modules/cpq/commands/price-adjustments.js.map +7 -0
- package/dist/modules/cpq/components/ArcLineDiff.js +53 -0
- package/dist/modules/cpq/components/ArcLineDiff.js.map +7 -0
- package/dist/modules/cpq/components/ChargeBreakdownTable.js +148 -0
- package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +7 -0
- package/dist/modules/cpq/components/PriceWaterfall.js +68 -0
- package/dist/modules/cpq/components/PriceWaterfall.js.map +7 -0
- package/dist/modules/cpq/components/PricingSummaryCard.js +112 -0
- package/dist/modules/cpq/components/PricingSummaryCard.js.map +7 -0
- package/dist/modules/cpq/components/StatusPath.js +5 -3
- package/dist/modules/cpq/components/StatusPath.js.map +2 -2
- package/dist/modules/cpq/components/useCpqRowActions.js +10 -22
- package/dist/modules/cpq/components/useCpqRowActions.js.map +2 -2
- package/dist/modules/cpq/components/useGrantedFeatures.js +27 -0
- package/dist/modules/cpq/components/useGrantedFeatures.js.map +7 -0
- package/dist/modules/cpq/data/entities.js +97 -0
- package/dist/modules/cpq/data/entities.js.map +2 -2
- package/dist/modules/cpq/data/price-adjustments.js +70 -0
- package/dist/modules/cpq/data/price-adjustments.js.map +7 -0
- package/dist/modules/cpq/data/validators.js +4 -0
- package/dist/modules/cpq/data/validators.js.map +2 -2
- package/dist/modules/cpq/di.js +6 -0
- package/dist/modules/cpq/di.js.map +2 -2
- package/dist/modules/cpq/events.js +47 -0
- package/dist/modules/cpq/events.js.map +2 -2
- package/dist/modules/cpq/i18n/de.json +1220 -0
- package/dist/modules/cpq/i18n/en.json +1220 -0
- package/dist/modules/cpq/i18n/es.json +1220 -0
- package/dist/modules/cpq/i18n/pl.json +1220 -0
- package/dist/modules/cpq/index.js +1 -1
- package/dist/modules/cpq/index.js.map +2 -2
- package/dist/modules/cpq/lib/auditActor.js +10 -0
- package/dist/modules/cpq/lib/auditActor.js.map +7 -0
- package/dist/modules/cpq/lib/formatMoney.js +7 -0
- package/dist/modules/cpq/lib/formatMoney.js.map +7 -0
- package/dist/modules/cpq/lib/priceAdjustmentDefaults.js +60 -0
- package/dist/modules/cpq/lib/priceAdjustmentDefaults.js.map +7 -0
- package/dist/modules/cpq/lib/priceAdjustmentView.js +169 -0
- package/dist/modules/cpq/lib/priceAdjustmentView.js.map +7 -0
- package/dist/modules/cpq/lib/quotePermissions.js +13 -0
- package/dist/modules/cpq/lib/quotePermissions.js.map +7 -0
- package/dist/modules/cpq/lib/quoteSummaryView.js +28 -0
- package/dist/modules/cpq/lib/quoteSummaryView.js.map +7 -0
- package/dist/modules/cpq/migrations/Migration20261110213052.js +22 -0
- package/dist/modules/cpq/migrations/Migration20261110213052.js.map +7 -0
- package/dist/modules/cpq/services/arcLineRemoval.js +53 -0
- package/dist/modules/cpq/services/arcLineRemoval.js.map +7 -0
- package/dist/modules/cpq/services/arcPriceFreeze.js +79 -0
- package/dist/modules/cpq/services/arcPriceFreeze.js.map +7 -0
- package/dist/modules/cpq/services/cpqOrderService.js +25 -28
- package/dist/modules/cpq/services/cpqOrderService.js.map +2 -2
- package/dist/modules/cpq/services/cpqPricingService.js +7 -0
- package/dist/modules/cpq/services/cpqPricingService.js.map +2 -2
- package/dist/modules/cpq/services/cpqQuotingService.js +330 -109
- package/dist/modules/cpq/services/cpqQuotingService.js.map +2 -2
- package/dist/modules/cpq/services/orderPricingSummary.js +26 -0
- package/dist/modules/cpq/services/orderPricingSummary.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/adjustmentService.js +264 -0
- package/dist/modules/cpq/services/priceAdjustments/adjustmentService.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/chargeWaterfall.js +25 -0
- package/dist/modules/cpq/services/priceAdjustments/chargeWaterfall.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/loadQuoteAdjustments.js +38 -0
- package/dist/modules/cpq/services/priceAdjustments/loadQuoteAdjustments.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/pricingSnapshot.js +104 -0
- package/dist/modules/cpq/services/priceAdjustments/pricingSnapshot.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/quoteAdjustmentLifecycle.js +102 -0
- package/dist/modules/cpq/services/priceAdjustments/quoteAdjustmentLifecycle.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/quotePricingEvents.js +52 -0
- package/dist/modules/cpq/services/priceAdjustments/quotePricingEvents.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/quotePricingWrite.js +37 -0
- package/dist/modules/cpq/services/priceAdjustments/quotePricingWrite.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/resolveManualAdjustments.js +107 -0
- package/dist/modules/cpq/services/priceAdjustments/resolveManualAdjustments.js.map +7 -0
- package/dist/modules/cpq/services/priceAdjustments/storedAdjustmentFailure.js +30 -0
- package/dist/modules/cpq/services/priceAdjustments/storedAdjustmentFailure.js.map +7 -0
- package/dist/modules/cpq/services/types.js.map +2 -2
- package/dist/modules/cpq/setup.js +6 -0
- package/dist/modules/cpq/setup.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +39 -31
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +13 -5
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +41 -21
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection-table.js +2 -2
- package/dist/modules/cpq/widgets/injection-table.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardRunner.js +10 -8
- package/dist/modules/cpq/workflows/WizardRunner.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardTrigger.js +15 -9
- package/dist/modules/cpq/workflows/WizardTrigger.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +9 -7
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +9 -4
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ItemListStep.js +16 -19
- package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +19 -32
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +8 -6
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ReviewStep.js +32 -30
- package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/index.js +12 -0
- package/dist/modules/cpq/workflows/steps/index.js.map +2 -2
- package/package.json +1 -1
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-012.spec.ts +134 -0
- package/src/modules/cpq/__tests__/i18n/dictionaries.test.ts +62 -0
- package/src/modules/cpq/__tests__/i18n/hardcodedStrings.test.ts +35 -0
- package/src/modules/cpq/__tests__/i18n/sourceScan.ts +109 -0
- package/src/modules/cpq/acl.ts +1 -0
- package/src/modules/cpq/api/__tests__/adjustmentRoutes.test.ts +79 -0
- package/src/modules/cpq/api/__tests__/quoteWriteGuards.test.ts +100 -0
- package/src/modules/cpq/api/_helpers/__tests__/quoteMutationGuard.test.ts +48 -0
- package/src/modules/cpq/api/_helpers/adjustmentCommandRoute.ts +45 -0
- package/src/modules/cpq/api/_helpers/quoteMutationGuard.ts +38 -0
- package/src/modules/cpq/api/_helpers/quoteRouteOpenApi.ts +19 -0
- package/src/modules/cpq/api/orders/[orderId]/route.ts +18 -0
- package/src/modules/cpq/api/orders/route.ts +51 -1
- package/src/modules/cpq/api/quotes/[quoteId]/items/[lineId]/restore/route.ts +56 -0
- package/src/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.ts +48 -1
- package/src/modules/cpq/api/quotes/[quoteId]/items/route.ts +31 -1
- package/src/modules/cpq/api/quotes/[quoteId]/price-adjustments/[adjustmentId]/route.ts +39 -0
- package/src/modules/cpq/api/quotes/[quoteId]/price-adjustments/preview/route.ts +24 -0
- package/src/modules/cpq/api/quotes/[quoteId]/price-adjustments/route.ts +40 -0
- package/src/modules/cpq/api/quotes/[quoteId]/recalculate/__tests__/route.test.ts +95 -0
- package/src/modules/cpq/api/quotes/[quoteId]/recalculate/route.ts +40 -1
- package/src/modules/cpq/api/quotes/[quoteId]/status/__tests__/route.test.ts +74 -0
- package/src/modules/cpq/api/quotes/[quoteId]/status/route.ts +37 -1
- package/src/modules/cpq/api/quotes/price/__tests__/route.test.ts +37 -0
- package/src/modules/cpq/api/quotes/price/route.ts +28 -2
- package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +3 -9
- package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +22 -26
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +43 -46
- package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +3 -3
- package/src/modules/cpq/backend/cpq/inventory/shared.tsx +37 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +164 -120
- package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +169 -130
- package/src/modules/cpq/backend/cpq/offerings/page.tsx +34 -24
- package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +122 -308
- package/src/modules/cpq/backend/cpq/orders/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/orders/page.tsx +6 -6
- package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +48 -34
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +76 -70
- package/src/modules/cpq/backend/cpq/price-rules/page.tsx +25 -16
- package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -18
- package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +29 -19
- package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +95 -47
- package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +23 -15
- package/src/modules/cpq/backend/cpq/pricing/page.tsx +1 -1
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +111 -88
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.tsx +260 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentsPanel.tsx +124 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/__tests__/PriceAdjustmentsPanel.test.tsx +76 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/arcLineRemoval.tsx +76 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/priceAdjustmentContext.tsx +133 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/usePriceAdjustments.tsx +165 -0
- package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +304 -348
- package/src/modules/cpq/backend/cpq/quotes/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/quotes/page.tsx +29 -21
- package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +19 -15
- package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +171 -171
- package/src/modules/cpq/backend/cpq/specifications/page.tsx +2 -2
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +51 -41
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +17 -13
- package/src/modules/cpq/backend/cpq/wizards/page.tsx +1 -1
- package/src/modules/cpq/ce.ts +8 -0
- package/src/modules/cpq/cli.ts +48 -1
- package/src/modules/cpq/commands/__tests__/price-adjustments.test.ts +54 -0
- package/src/modules/cpq/commands/price-adjustments.ts +90 -0
- package/src/modules/cpq/components/ArcLineDiff.tsx +87 -0
- package/src/modules/cpq/components/ChargeBreakdownTable.tsx +203 -0
- package/src/modules/cpq/components/PriceWaterfall.tsx +96 -0
- package/src/modules/cpq/components/PricingSummaryCard.tsx +128 -0
- package/src/modules/cpq/components/StatusPath.tsx +7 -4
- package/src/modules/cpq/components/__tests__/PriceWaterfall.test.tsx +38 -0
- package/src/modules/cpq/components/useCpqRowActions.tsx +17 -25
- package/src/modules/cpq/components/useGrantedFeatures.ts +35 -0
- package/src/modules/cpq/data/__tests__/price-adjustment-migration.test.ts +11 -0
- package/src/modules/cpq/data/__tests__/price-adjustments.test.ts +26 -0
- package/src/modules/cpq/data/entities.ts +83 -0
- package/src/modules/cpq/data/price-adjustments.ts +67 -0
- package/src/modules/cpq/data/validators.ts +3 -0
- package/src/modules/cpq/di.ts +6 -0
- package/src/modules/cpq/events.ts +53 -2
- package/src/modules/cpq/i18n/de.json +1220 -0
- package/src/modules/cpq/i18n/en.json +1220 -0
- package/src/modules/cpq/i18n/es.json +1220 -0
- package/src/modules/cpq/i18n/pl.json +1220 -0
- package/src/modules/cpq/index.ts +1 -1
- package/src/modules/cpq/lib/__tests__/auditActor.test.ts +12 -0
- package/src/modules/cpq/lib/__tests__/priceAdjustmentDefaults.test.ts +37 -0
- package/src/modules/cpq/lib/__tests__/priceAdjustmentView.test.ts +152 -0
- package/src/modules/cpq/lib/__tests__/quotePermissions.test.ts +30 -0
- package/src/modules/cpq/lib/__tests__/quoteSummaryView.test.ts +56 -0
- package/src/modules/cpq/lib/auditActor.ts +13 -0
- package/src/modules/cpq/lib/formatMoney.ts +4 -0
- package/src/modules/cpq/lib/priceAdjustmentDefaults.ts +36 -0
- package/src/modules/cpq/lib/priceAdjustmentView.ts +259 -0
- package/src/modules/cpq/lib/quotePermissions.ts +22 -0
- package/src/modules/cpq/lib/quoteSummaryView.ts +51 -0
- package/src/modules/cpq/migrations/.snapshot-open-mercato.json +3298 -2423
- package/src/modules/cpq/migrations/Migration20261110213052.ts +22 -0
- package/src/modules/cpq/services/__tests__/_helpers/mockEm.ts +9 -2
- package/src/modules/cpq/services/__tests__/adjustmentService.test.ts +183 -0
- package/src/modules/cpq/services/__tests__/arcLineRemoval.test.ts +109 -0
- package/src/modules/cpq/services/__tests__/arcPriceFreeze.test.ts +141 -0
- package/src/modules/cpq/services/__tests__/chargeWaterfall.test.ts +28 -0
- package/src/modules/cpq/services/__tests__/cpqOrderService.test.ts +35 -2
- package/src/modules/cpq/services/__tests__/cpqPricingService.test.ts +57 -0
- package/src/modules/cpq/services/__tests__/cpqQuotingService.arc.test.ts +237 -0
- package/src/modules/cpq/services/__tests__/cpqQuotingService.test.ts +58 -3
- package/src/modules/cpq/services/__tests__/orderPricingSummary.test.ts +50 -0
- package/src/modules/cpq/services/__tests__/pricingSnapshot.test.ts +62 -0
- package/src/modules/cpq/services/__tests__/quoteAdjustmentLifecycle.test.ts +35 -0
- package/src/modules/cpq/services/__tests__/quoteAdjustmentPricing.test.ts +65 -0
- package/src/modules/cpq/services/__tests__/quoteCloneAdjustments.test.ts +45 -0
- package/src/modules/cpq/services/__tests__/quoteDetachTargetAdjustments.test.ts +54 -0
- package/src/modules/cpq/services/__tests__/quoteEventsService.test.ts +72 -0
- package/src/modules/cpq/services/__tests__/quotePricingEvents.test.ts +126 -0
- package/src/modules/cpq/services/__tests__/quotePricingIsolation.test.ts +52 -0
- package/src/modules/cpq/services/__tests__/quotePricingWrite.test.ts +74 -0
- package/src/modules/cpq/services/__tests__/resolveManualAdjustments.test.ts +90 -0
- package/src/modules/cpq/services/__tests__/storedAdjustmentFailure.test.ts +9 -0
- package/src/modules/cpq/services/arcLineRemoval.ts +87 -0
- package/src/modules/cpq/services/arcPriceFreeze.ts +165 -0
- package/src/modules/cpq/services/cpqOrderService.ts +22 -28
- package/src/modules/cpq/services/cpqPricingService.ts +8 -0
- package/src/modules/cpq/services/cpqQuotingService.ts +374 -125
- package/src/modules/cpq/services/orderPricingSummary.ts +47 -0
- package/src/modules/cpq/services/priceAdjustments/adjustmentService.ts +249 -0
- package/src/modules/cpq/services/priceAdjustments/chargeWaterfall.ts +28 -0
- package/src/modules/cpq/services/priceAdjustments/loadQuoteAdjustments.ts +25 -0
- package/src/modules/cpq/services/priceAdjustments/pricingSnapshot.ts +86 -0
- package/src/modules/cpq/services/priceAdjustments/quoteAdjustmentLifecycle.ts +68 -0
- package/src/modules/cpq/services/priceAdjustments/quotePricingEvents.ts +94 -0
- package/src/modules/cpq/services/priceAdjustments/quotePricingWrite.ts +51 -0
- package/src/modules/cpq/services/priceAdjustments/resolveManualAdjustments.ts +116 -0
- package/src/modules/cpq/services/priceAdjustments/storedAdjustmentFailure.ts +31 -0
- package/src/modules/cpq/services/types.ts +34 -1
- package/src/modules/cpq/setup.ts +7 -1
- package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +38 -31
- package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +7 -5
- package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +36 -21
- package/src/modules/cpq/widgets/injection-table.ts +8 -2
- package/src/modules/cpq/workflows/WizardRunner.tsx +8 -5
- package/src/modules/cpq/workflows/WizardTrigger.tsx +15 -9
- package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +11 -7
- package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +9 -5
- package/src/modules/cpq/workflows/steps/ItemListStep.tsx +18 -12
- package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +20 -16
- package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +8 -6
- package/src/modules/cpq/workflows/steps/ReviewStep.tsx +33 -18
- package/src/modules/cpq/workflows/steps/index.ts +12 -0
- package/src/modules/cpq/workflows/types.ts +4 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/cpq/backend/cpq/offerings/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { NumberInput } from '../../../../components/NumberInput'\nimport { normalizeChargePricing } from '../../../../data/charge-pricing'\nimport {\n chargeTypeMap,\n formatStatusLabel,\n lifecycleStatusMap,\n type ChargeType,\n type LifecycleStatus,\n} from '../../../../components/statusMaps'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype OfferingComponent = {\n id: string\n slotId: string\n slot: { id: string; componentGroup: string; name: string; cardinalityMin: number; cardinalityMax: number | null } | null\n childOfferingId: string\n childOffering: { id: string; code: string; name: string; offeringType: string; specId: string } | null\n isDefault: boolean\n sortOrder: number\n isActive: boolean\n}\n\ntype BundleSlot = {\n id: string\n componentGroup: string\n name: string\n targetSpecId: string\n targetSpec: { id: string; code: string; name: string; specType: string } | null\n cardinalityMin: number\n cardinalityMax: number | null\n sortOrder: number\n}\n\ntype Offering = {\n id: string\n specId: string\n catalogOfferId: string | null\n code: string\n name: string\n description: string | null\n offeringType: string\n designTimeValues: Record<string, unknown>\n lifecycleStatus: string\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: Record<string, unknown> | null\n isActive: boolean\n specification: { id: string; code: string; name: string; productId: string; specType?: string } | null\n charges: Charge[]\n components?: OfferingComponent[]\n}\n\ntype Charge = {\n id: string\n code: string\n name: string\n description: string | null\n chargeType: string\n chargeModel: string | null\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\ntype Attribute = {\n id: string\n code: string\n name: string\n attributeType: string\n resolutionTime: string\n options: Array<{ value: string; label: string }> | null\n constraints: Record<string, unknown> | null\n defaultValue: unknown | null\n helpText: string | null\n sortOrder: number\n isRequired: boolean\n isActive: boolean\n}\n\ntype Specification = {\n id: string\n code: string\n name: string\n productId: string\n}\n\ntype PricingTableRef = { id: string; code: string; name: string; dimensions: Array<{ key: string; label: string }>; priceColumns: Array<{ key: string; label: string }> }\n\n// Shared by the eager mount-load and the lazy editor dropdown. Returns [] on\n// failure so a transient error degrades gracefully instead of blanking the page.\nasync function fetchPricingTables(): Promise<PricingTableRef[]> {\n try {\n const { ok, result } = await apiCall<{ items?: PricingTableRef[] }>('/api/cpq/pricing-tables?pageSize=100')\n if (!ok) {\n console.warn('[cpq] Failed to load pricing tables for the charges list')\n return []\n }\n return result?.items ?? []\n } catch (err) {\n console.warn('[cpq] Failed to load pricing tables for the charges list:', err)\n return []\n }\n}\n\ntype EditingCharge = Omit<Charge, 'id'> & { id?: string }\n\n// \u2500\u2500\u2500 Defaults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst EMPTY_FORM = {\n code: '',\n name: '',\n description: '',\n offeringType: 'simple' as string,\n lifecycleStatus: 'draft',\n effectiveFrom: null as string | null,\n effectiveTo: null as string | null,\n isActive: true,\n specId: '',\n}\n\nconst EMPTY_CHARGE: EditingCharge = {\n code: '',\n name: '',\n description: null,\n chargeType: 'mrc',\n chargeModel: 'flat',\n pricingMethod: 'fixed',\n pricingTableId: null,\n priceColumnKey: null,\n fixedPrice: null,\n currencyCode: 'USD',\n quantityAttributeCode: null,\n applicabilityCondition: null,\n sortOrder: 0,\n isActive: true,\n}\n\n\n// XD-297: the charge \"shape\" is two axes \u2014 Charge Model (how quantity drives\n// the charge) and Pricing Method (where the unit price comes from).\nconst CHARGE_MODEL_LABELS: Record<string, string> = {\n flat: 'Flat Fee',\n per_unit: 'Per Unit',\n volume: 'Volume-based',\n tiered: 'Tiered',\n}\n\nconst PRICING_SOURCE_LABELS: Record<string, string> = {\n fixed: 'Fixed Price',\n table: 'Table Lookup',\n}\n\n// V-CHG-1 in `validators.ts`: mirror the (chargeModel \u00D7 pricingMethod) rules in\n// the UI so users see what's missing without round-tripping to the server.\ntype ChargeShape = {\n chargeModel: string | null\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n}\n\nfunction isChargeComplete(charge: ChargeShape): boolean {\n return chargeMissingFields(charge).length === 0\n}\n\nfunction chargeMissingFields(charge: ChargeShape): string[] {\n const { model, source } = normalizeChargePricing(charge)\n const missing: string[] = []\n if (source === 'fixed') {\n if (!charge.fixedPrice) missing.push('Fixed Price')\n if (!charge.currencyCode) missing.push('Currency')\n if (model === 'per_unit' && !charge.quantityAttributeCode) missing.push('Quantity Attribute')\n } else {\n if (!charge.pricingTableId) missing.push('Pricing Table')\n if (!charge.priceColumnKey) missing.push('Price Column')\n if (model !== 'flat' && !charge.quantityAttributeCode) missing.push('Quantity Attribute')\n }\n return missing\n}\n\n// \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function OfferingDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const offeringId = (props.params?.id ?? urlParams?.id) as string\n const isNew = offeringId === 'new'\n\n // \u2500\u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const [tab, setTab] = React.useState<'general' | 'charges' | 'components'>('general')\n const [form, setForm] = React.useState(EMPTY_FORM)\n const [designTimeValues, setDesignTimeValues] = React.useState<Record<string, unknown>>({})\n const [charges, setCharges] = React.useState<Charge[]>([])\n const [attributes, setAttributes] = React.useState<Attribute[]>([])\n const [specs, setSpecs] = React.useState<Specification[]>([])\n const [specDetail, setSpecDetail] = React.useState<{ id: string; code: string; name: string; specType?: string } | null>(null)\n const [pricingTables, setPricingTables] = React.useState<PricingTableRef[]>([])\n const [components, setComponents] = React.useState<OfferingComponent[]>([])\n const [bundleSlots, setBundleSlots] = React.useState<BundleSlot[]>([])\n const [addingComponent, setAddingComponent] = React.useState<{ slotId: string; childOfferingId: string; isDefault: boolean } | null>(null)\n const [slotOfferings, setSlotOfferings] = React.useState<Record<string, Array<{ id: string; code: string; name: string; offeringType: string }>>>({})\n\n const [loading, setLoading] = React.useState(!isNew)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editingCharge, setEditingCharge] = React.useState<EditingCharge | null>(null)\n\n // OM-standard detail page: existing offerings open read-only and require\n // an explicit Edit click to allow changes. New offerings skip view mode.\n const [generalMode, setGeneralMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [formSnapshot, setFormSnapshot] = React.useState<typeof EMPTY_FORM | null>(null)\n const [designTimeSnapshot, setDesignTimeSnapshot] = React.useState<Record<string, unknown> | null>(null)\n\n // \u2500\u2500\u2500 Load data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n React.useEffect(() => {\n let cancelled = false\n\n async function load() {\n try {\n // Load specs for dropdown (needed for new + showing spec name)\n const specsRes = await fetch('/api/cpq/product-specifications?pageSize=200')\n if (specsRes.ok) {\n const d = await specsRes.json()\n if (!cancelled) setSpecs(d.items ?? [])\n }\n\n if (isNew) return\n\n // Load offering detail\n const res = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (!res.ok) {\n if (!cancelled) setError('Failed to load offering')\n return\n }\n\n const data: Offering = await res.json()\n if (!cancelled) {\n setForm({\n code: data.code,\n name: data.name,\n description: data.description ?? '',\n offeringType: data.offeringType ?? 'simple',\n lifecycleStatus: data.lifecycleStatus,\n effectiveFrom: data.effectiveFrom,\n effectiveTo: data.effectiveTo,\n isActive: data.isActive,\n specId: data.specId,\n })\n setDesignTimeValues(data.designTimeValues ?? {})\n setCharges(data.charges ?? [])\n setSpecDetail(data.specification ?? null)\n setComponents(data.components ?? [])\n\n // Charges reference pricing tables by id; load the tables up front so\n // the list renders their names instead of \"missing\". The charge editor\n // also lazy-loads them, but the read view needs them on mount/refresh.\n if ((data.charges ?? []).some((c) => c.pricingTableId)) {\n const tables = await fetchPricingTables()\n if (!cancelled) setPricingTables(tables)\n }\n\n // Load attributes for the spec\n if (data.specId) {\n const attrRes = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(data.specId)}&pageSize=200`)\n if (attrRes.ok) {\n const attrData = await attrRes.json()\n if (!cancelled) setAttributes(attrData.items ?? [])\n }\n }\n\n // Load bundle slots if this is a bundle offering\n if (data.offeringType === 'bundle' && data.specId) {\n const slotsRes = await fetch(`/api/cpq/bundle-slots?specId=${encodeURIComponent(data.specId)}`)\n if (slotsRes.ok) {\n const slotsData = await slotsRes.json()\n if (!cancelled) setBundleSlots(slotsData.items ?? [])\n }\n }\n }\n } catch (err) {\n console.error('Failed to load', err)\n if (!cancelled) setError('Failed to load')\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n\n load()\n return () => { cancelled = true }\n }, [offeringId, isNew])\n\n // Load attributes when spec changes (for new offering)\n const loadSpecAttributes = async (specId: string) => {\n if (!specId) { setAttributes([]); return }\n try {\n const res = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(specId)}&pageSize=200`)\n if (res.ok) {\n const data = await res.json()\n setAttributes(data.items ?? [])\n }\n } catch {\n console.error('Failed to load spec attributes')\n }\n }\n\n // \u2500\u2500\u2500 Save offering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const saveOffering = async () => {\n setSaving(true)\n setError(null)\n try {\n const payload = isNew\n ? { ...form, description: form.description || null, designTimeValues, specId: form.specId }\n : { id: offeringId, ...form, description: form.description || null, designTimeValues }\n\n const res = await fetch('/api/cpq/product-offerings', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save')\n return\n }\n\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/offerings/${saved.id}`)\n } else {\n setForm({\n code: saved.code,\n name: saved.name,\n description: saved.description ?? '',\n offeringType: saved.offeringType ?? form.offeringType,\n lifecycleStatus: saved.lifecycleStatus,\n effectiveFrom: saved.effectiveFrom,\n effectiveTo: saved.effectiveTo,\n isActive: saved.isActive,\n specId: saved.specId,\n })\n setDesignTimeValues(saved.designTimeValues ?? {})\n // Save succeeded \u2014 drop snapshots and flip back to read-only.\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }\n } catch {\n setError('Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteOffering = async () => {\n if (!confirm(t('cpq.offerings.confirmDelete', 'Delete this offering and all its charges?'))) return\n try {\n const res = await fetch('/api/cpq/product-offerings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: offeringId }),\n })\n if (res.ok) {\n router.push('/backend/cpq/offerings')\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to delete')\n }\n } catch {\n setError('Failed to delete')\n }\n }\n\n // \u2500\u2500\u2500 Charge CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const loadPricingTables = async () => {\n if (pricingTables.length > 0) return\n setPricingTables(await fetchPricingTables())\n }\n\n const startEditCharge = (charge?: Charge) => {\n if (charge) {\n // Normalise legacy rows (chargeModel null, combined pricingMethod) into\n // the split shape the form's two dropdowns expect.\n const { model, source } = normalizeChargePricing(charge)\n setEditingCharge({ ...charge, chargeModel: model, pricingMethod: source })\n } else {\n setEditingCharge({ ...EMPTY_CHARGE })\n }\n loadPricingTables()\n }\n\n const saveCharge = async () => {\n if (!editingCharge) return\n setSaving(true)\n setError(null)\n try {\n const isEdit = !!editingCharge.id\n const payload = {\n ...editingCharge,\n offeringId,\n }\n const res = await fetch('/api/cpq/product-charges', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save charge')\n return\n }\n // Reload offering to get updated charges\n const offeringRes = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (offeringRes.ok) {\n const data = await offeringRes.json()\n setCharges(data.charges ?? [])\n }\n setEditingCharge(null)\n } catch {\n setError('Failed to save charge')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteCharge = async (chargeId: string) => {\n if (!confirm('Delete this charge?')) return\n try {\n const res = await fetch('/api/cpq/product-charges', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: chargeId }),\n })\n if (res.ok) setCharges((prev) => prev.filter((c) => c.id !== chargeId))\n } catch {\n setError('Failed to delete charge')\n }\n }\n\n const selectedPricingTable = editingCharge?.pricingTableId\n ? pricingTables.find((pt) => pt.id === editingCharge.pricingTableId)\n : null\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const designTimeAttrs = attributes.filter((a) => a.resolutionTime === 'design_time')\n\n // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('common.loading', 'Loading...')}</div>\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/offerings')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.offerings.new', 'New Offering') : form.name}\n </h1>\n {!isNew && (\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n )}\n {specDetail && (\n <span className=\"text-sm text-muted-foreground\">\n Spec: <button onClick={() => router.push(`/backend/cpq/specifications/${specDetail.id}`)} className=\"text-primary hover:underline\">{specDetail.name}</button>\n </span>\n )}\n </div>\n {!isNew && (\n <div className=\"flex items-center gap-2\">\n {generalMode === 'view' && tab === 'general' && (\n <Button\n type=\"button\"\n onClick={() => {\n setFormSnapshot(form)\n setDesignTimeSnapshot(designTimeValues)\n setGeneralMode('edit')\n }}\n >\n {t('common.edit', 'Edit')}\n </Button>\n )}\n <Button type=\"button\" variant=\"destructive\" onClick={deleteOffering}>\n {t('common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && (\n <Alert variant=\"destructive\">{error}</Alert>\n )}\n\n {/* Tabs */}\n {!isNew && (\n <div className=\"flex gap-1 border-b\">\n {([\n 'general',\n 'charges',\n ...(form.offeringType === 'bundle' ? ['components' as const] : []),\n ] as const).map((t_) => (\n <button\n key={t_}\n onClick={() => setTab(t_ as typeof tab)}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n tab === t_ ? 'border-primary text-primary' : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {t_ === 'general' && 'General'}\n {t_ === 'charges' && `Charges (${charges.length})`}\n {t_ === 'components' && `Components (${components.length})`}\n </button>\n ))}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 General Tab / New Form \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {(isNew || tab === 'general') && (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n {isNew && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">Specification</label>\n <select\n value={form.specId}\n onChange={(e) => {\n setForm({ ...form, specId: e.target.value })\n loadSpecAttributes(e.target.value)\n setDesignTimeValues({})\n }}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">Select a specification...</option>\n {specs.map((s) => (\n <option key={s.id} value={s.id}>{s.name} ({s.code})</option>\n ))}\n </select>\n </div>\n )}\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.code', 'Code')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm font-mono py-2\">{form.code || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.code}\n onChange={(e) => setForm({ ...form, code: e.target.value })}\n placeholder=\"e.g. gix-cloud-connect-aws\"\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.name', 'Name')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm py-2\">{form.name || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.lifecycleStatus', 'Lifecycle Status')}</label>\n {generalMode === 'view' && !isNew ? (\n <div className=\"py-2\">\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n </div>\n ) : (\n <select\n value={form.lifecycleStatus}\n onChange={(e) => setForm({ ...form, lifecycleStatus: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"draft\">Draft</option>\n <option value=\"active\">Active</option>\n <option value=\"deprecated\">Deprecated</option>\n </select>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.isActive', 'Is Active?')}</label>\n <div className=\"flex items-center h-[38px]\">\n {generalMode === 'view' && !isNew ? (\n <Tag variant={form.isActive ? 'success' : 'neutral'} dot>\n {form.isActive ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n )}\n </div>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.description', 'Description')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm text-muted-foreground py-2 whitespace-pre-wrap\">{form.description || '\u2014'}</p>\n ) : (\n <textarea\n value={form.description ?? ''}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={3}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n\n {/* Design-time values */}\n {designTimeAttrs.length > 0 && (\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium\">Design-Time Values</label>\n <div className=\"grid grid-cols-2 gap-3\">\n {designTimeAttrs.map((attr) => {\n const value = designTimeValues[attr.code]\n const isViewing = generalMode === 'view' && !isNew\n // Lookup the human label for select-type values so the\n // read-only view doesn't show raw codes.\n const optionLabel =\n (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options\n ? attr.options.find((o) => o.value === value)?.label\n : undefined\n return (\n <div key={attr.code}>\n <label className=\"block text-xs font-medium mb-1\">\n {attr.name}\n {attr.isRequired && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {isViewing ? (\n <p className=\"text-sm py-2\">\n {value == null || value === '' ? (\n <span className=\"text-muted-foreground\">\u2014</span>\n ) : attr.attributeType === 'boolean' ? (\n <Tag variant={value ? 'success' : 'neutral'} dot>\n {value ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n optionLabel ?? String(value)\n )}\n </p>\n ) : (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options ? (\n <select\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"\">Select {attr.name}...</option>\n {attr.options.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n ) : attr.attributeType === 'number' ? (\n <NumberInput\n value={typeof value === 'number' ? (value as number) : null}\n onChange={(n) => setDesignTimeValues({ ...designTimeValues, [attr.code]: n })}\n />\n ) : attr.attributeType === 'boolean' ? (\n <div className=\"pt-1\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.checked })}\n className=\"rounded border\"\n />\n {attr.name}\n </label>\n </div>\n ) : (\n <input\n type=\"text\"\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n placeholder={attr.helpText ?? undefined}\n />\n )}\n {attr.helpText && <p className=\"text-xs text-muted-foreground mt-0.5\">{attr.helpText}</p>}\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {/* In view mode the Edit button lives in the page header next to\n Delete (OM standard). Here we only render the Save/Cancel\n pair when actually editing. */}\n {!(generalMode === 'view' && !isNew) && (\n <div className=\"flex gap-3\">\n <Button\n type=\"button\"\n onClick={saveOffering}\n disabled={saving || !form.code || !form.name || (isNew && !form.specId)}\n >\n {saving ? t('common.saving', 'Saving...') : t('common.save', 'Save')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n if (isNew) {\n router.push('/backend/cpq/offerings')\n return\n }\n if (formSnapshot) setForm(formSnapshot)\n if (designTimeSnapshot) setDesignTimeValues(designTimeSnapshot)\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }}\n >\n {t('common.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Charges Tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'charges' && !isNew && (\n <div className=\"space-y-4\">\n <div className=\"flex justify-end\">\n <button\n onClick={() => startEditCharge()}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.offerings.addCharge', 'Add Charge')}\n </button>\n </div>\n\n {/* Charge edit form */}\n {editingCharge && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <h3 className=\"font-medium text-sm\">\n {editingCharge.id ? 'Edit Charge' : 'New Charge'}\n </h3>\n <div className=\"grid grid-cols-3 gap-3\">\n <div>\n <label className=\"block text-xs font-medium mb-1\">Code</label>\n <input type=\"text\" value={editingCharge.code} onChange={(e) => setEditingCharge({ ...editingCharge, code: e.target.value })} placeholder=\"e.g. mrc-monthly\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Name</label>\n <input type=\"text\" value={editingCharge.name} onChange={(e) => setEditingCharge({ ...editingCharge, name: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Charge Type</label>\n <select value={editingCharge.chargeType} onChange={(e) => setEditingCharge({ ...editingCharge, chargeType: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"mrc\">MRC (Monthly Recurring)</option>\n <option value=\"nrc\">NRC (Non-Recurring)</option>\n <option value=\"usage\">Usage</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Charge Model</label>\n <select\n value={editingCharge.chargeModel ?? 'flat'}\n onChange={(e) => {\n const model = e.target.value\n const next = { ...editingCharge, chargeModel: model }\n // Volume / tiered are graduated over table ranges \u2014 they can't use a fixed price.\n if ((model === 'volume' || model === 'tiered') && editingCharge.pricingMethod !== 'table') {\n next.pricingMethod = 'table'\n next.fixedPrice = null\n }\n // Flat never takes a quantity attribute.\n if (model === 'flat') next.quantityAttributeCode = null\n setEditingCharge(next)\n }}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"flat\">Flat Fee</option>\n <option value=\"per_unit\">Per Unit</option>\n <option value=\"volume\">Volume-based</option>\n <option value=\"tiered\">Tiered</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Method</label>\n <select\n value={editingCharge.pricingMethod}\n onChange={(e) => {\n const source = e.target.value\n if (source === 'fixed') {\n // Only per_unit keeps the quantity attribute under a fixed\n // price; flat must drop it (V-CHG-1 forbids it).\n const keepQty = editingCharge.chargeModel === 'per_unit'\n setEditingCharge({ ...editingCharge, pricingMethod: source, pricingTableId: null, priceColumnKey: null, ...(keepQty ? {} : { quantityAttributeCode: null }) })\n } else {\n setEditingCharge({ ...editingCharge, pricingMethod: source, fixedPrice: null })\n }\n }}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n {/* Volume / tiered are graduated over table ranges \u2014 a fixed price isn't applicable. */}\n {editingCharge.chargeModel !== 'volume' && editingCharge.chargeModel !== 'tiered' && (\n <option value=\"fixed\">Fixed Price</option>\n )}\n <option value=\"table\">Table Lookup</option>\n </select>\n </div>\n {editingCharge.pricingMethod === 'fixed' ? (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Fixed Price <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.fixedPrice ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, fixedPrice: e.target.value || null })} placeholder=\"0.00\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Currency <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.currencyCode ?? 'USD'} onChange={(e) => setEditingCharge({ ...editingCharge, currencyCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n </>\n ) : (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Table <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.pricingTableId ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, pricingTableId: e.target.value || null, priceColumnKey: null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select table...</option>\n {pricingTables.map((pt) => (\n <option key={pt.id} value={pt.id}>{pt.name} ({pt.code})</option>\n ))}\n </select>\n {pricingTables.length === 0 && (\n <p className=\"text-xs text-warning mt-0.5\">\n No pricing tables yet \u2014{' '}\n <a href=\"/backend/cpq/pricing-tables\" className=\"text-primary hover:underline\">create one</a>{' '}\n before using Table Lookup pricing.\n </p>\n )}\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Price Column <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.priceColumnKey ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, priceColumnKey: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" disabled={!selectedPricingTable}>\n <option value=\"\">Select column...</option>\n {selectedPricingTable?.priceColumns.map((col) => (\n <option key={col.key} value={col.key}>{col.label}</option>\n ))}\n </select>\n </div>\n </>\n )}\n {/* Quantity attribute drives the unit count \u2014 needed for per-unit\n (any source) and for volume / tiered table lookups. */}\n {((editingCharge.pricingMethod === 'table' && editingCharge.chargeModel !== 'flat') ||\n (editingCharge.pricingMethod === 'fixed' && editingCharge.chargeModel === 'per_unit')) && (\n <div>\n <label className=\"block text-xs font-medium mb-1\">Quantity Attribute <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.quantityAttributeCode ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, quantityAttributeCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select attribute...</option>\n {attributes.filter((a) => a.attributeType === 'number').map((a) => (\n <option key={a.code} value={a.code}>{a.name} ({a.code})</option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground mt-0.5\">Attribute whose value drives the quantity for pricing</p>\n {attributes.filter((a) => a.attributeType === 'number').length === 0 && form.specId && (\n <p className=\"text-xs text-warning mt-0.5\">\n Spec has no number attributes \u2014{' '}\n <a href={`/backend/cpq/specifications/${form.specId}`} className=\"text-primary hover:underline\">\n add one to the spec\n </a>{' '}\n first.\n </p>\n )}\n </div>\n )}\n <div>\n <label className=\"block text-xs font-medium mb-1\">Sort Order</label>\n <NumberInput\n integer\n value={editingCharge.sortOrder}\n onChange={(n) => setEditingCharge({ ...editingCharge, sortOrder: n ?? 0 })}\n />\n </div>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Description</label>\n <input type=\"text\" value={editingCharge.description ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, description: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div className=\"flex items-end gap-4\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input type=\"checkbox\" checked={editingCharge.isActive} onChange={(e) => setEditingCharge({ ...editingCharge, isActive: e.target.checked })} className=\"rounded border\" />\n Active\n </label>\n </div>\n {(() => {\n const missing = chargeMissingFields(editingCharge)\n const blocked = saving || !editingCharge.code || !editingCharge.name || missing.length > 0\n return (\n <>\n {missing.length > 0 && (\n <Alert variant=\"destructive\">\n Missing required field{missing.length > 1 ? 's' : ''} for {editingCharge.pricingMethod} pricing: {missing.join(', ')}\n </Alert>\n )}\n <div className=\"flex gap-2\">\n <button onClick={saveCharge} disabled={blocked} className=\"inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\">\n {saving ? 'Saving...' : 'Save'}\n </button>\n <button onClick={() => setEditingCharge(null)} className=\"inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted\">Cancel</button>\n </div>\n </>\n )\n })()}\n </div>\n )}\n\n {/* Charges table */}\n {charges.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No charges defined. Add recurring, non-recurring, or usage charges to this offering.\n </div>\n ) : (\n <div className=\"rounded-lg border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium\">Code</th>\n <th className=\"px-4 py-3 text-left font-medium\">Name</th>\n <th className=\"px-4 py-3 text-left font-medium\">Type</th>\n <th className=\"px-4 py-3 text-left font-medium\">Pricing</th>\n <th className=\"px-4 py-3 text-left font-medium\">Price</th>\n <th className=\"px-4 py-3 text-left font-medium\">Active</th>\n <th className=\"px-4 py-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {charges.map((charge) => {\n const incomplete = !isChargeComplete(charge)\n const tableRef = charge.pricingTableId\n ? pricingTables.find((pt) => pt.id === charge.pricingTableId)\n : null\n const qtyAttr = charge.quantityAttributeCode\n ? attributes.find((a) => a.code === charge.quantityAttributeCode)\n : null\n const { model, source } = normalizeChargePricing(charge)\n return (\n <tr key={charge.id} className=\"border-b\">\n <td className=\"px-4 py-3 font-mono text-xs\">{charge.code}</td>\n <td className=\"px-4 py-3\">\n {charge.name}\n {incomplete && (\n <Tag variant=\"error\" className=\"ml-2 px-2 text-[10px]\" dot>Incomplete</Tag>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <Tag variant={chargeTypeMap[charge.chargeType as ChargeType] ?? 'neutral'} className=\"px-2 text-xs\">\n {charge.chargeType.toUpperCase()}\n </Tag>\n </td>\n <td className=\"px-4 py-3 text-xs\">\n {CHARGE_MODEL_LABELS[model] ?? model}\n <span className=\"text-muted-foreground\"> \u00B7 {PRICING_SOURCE_LABELS[source] ?? source}</span>\n </td>\n <td className=\"px-4 py-3 text-xs\">\n {source === 'fixed' ? (\n <div className=\"flex flex-col gap-0.5\">\n {charge.fixedPrice != null\n ? <span>{`${charge.currencyCode ?? 'USD'} ${charge.fixedPrice}`}</span>\n : <span className=\"text-muted-foreground\">\u2014</span>}\n {model === 'per_unit' && (\n <span>\n <span className=\"text-muted-foreground\">\u00D7 Qty:</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">missing</span>}\n </span>\n )}\n </div>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n <span>\n <span className=\"text-muted-foreground\">Table:</span>{' '}\n {tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? '?'}` : <span className=\"text-destructive\">missing</span>}\n </span>\n {model !== 'flat' && (\n <span>\n <span className=\"text-muted-foreground\">\u00D7 Qty:</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">missing</span>}\n </span>\n )}\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">{charge.isActive ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-3 text-right\">\n <button onClick={() => startEditCharge(charge)} className=\"text-xs text-primary hover:underline mr-2\">Edit</button>\n <button onClick={() => deleteCharge(charge.id)} className=\"text-xs text-destructive hover:underline\">Delete</button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Components Tab (bundle offerings) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'components' && !isNew && form.offeringType === 'bundle' && (\n <div className=\"space-y-4\">\n {bundleSlots.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No bundle slots defined on this specification. Add slots on the specification first.\n </div>\n ) : (\n <>\n {/* Group components by slot */}\n {bundleSlots.map((slot) => {\n const slotComponents = components.filter((c) => c.slotId === slot.id)\n return (\n <div key={slot.id} className=\"rounded-lg border bg-card overflow-hidden\">\n <div className=\"bg-muted/50 px-4 py-3 border-b flex items-center justify-between\">\n <div>\n <span className=\"font-medium text-sm\">{slot.name}</span>\n <Tag variant=\"info\" className=\"ml-2 px-2 text-[10px]\">\n {slot.componentGroup}\n </Tag>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {slot.cardinalityMin}..{slot.cardinalityMax ?? '\u221E'}\n </span>\n {slot.targetSpec && (\n <span className=\"ml-2 text-xs text-muted-foreground\">\u2192 {slot.targetSpec.name}</span>\n )}\n </div>\n <button\n onClick={async () => {\n setAddingComponent({ slotId: slot.id, childOfferingId: '', isDefault: false })\n if (!slotOfferings[slot.targetSpecId]) {\n const res = await fetch(`/api/cpq/product-offerings?specId=${encodeURIComponent(slot.targetSpecId)}&pageSize=100`)\n if (res.ok) {\n const d = await res.json()\n setSlotOfferings((prev) => ({ ...prev, [slot.targetSpecId]: d.items ?? [] }))\n }\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90\"\n >\n + Add Component\n </button>\n </div>\n\n {addingComponent?.slotId === slot.id && (\n <div className=\"p-4 border-b bg-muted/20 space-y-3\">\n <div className=\"grid grid-cols-3 gap-3\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium mb-1\">Component Offering</label>\n <select\n value={addingComponent.childOfferingId}\n onChange={(e) => setAddingComponent({ ...addingComponent, childOfferingId: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">\u2014 Select offering \u2014</option>\n {(slotOfferings[slot.targetSpecId] ?? []).map((o) => (\n <option key={o.id} value={o.id}>{o.name} ({o.code}){o.offeringType === 'bundle' ? ' [bundle]' : ''}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Default?</label>\n <div className=\"flex items-center h-[38px]\">\n <input\n type=\"checkbox\"\n checked={addingComponent.isDefault}\n onChange={(e) => setAddingComponent({ ...addingComponent, isDefault: e.target.checked })}\n className=\"rounded border\"\n />\n <span className=\"ml-2 text-xs text-muted-foreground\">Pre-selected in quote</span>\n </div>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n disabled={saving || !addingComponent.childOfferingId}\n onClick={async () => {\n setSaving(true)\n setError(null)\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n offeringId,\n slotId: addingComponent.slotId,\n childOfferingId: addingComponent.childOfferingId,\n isDefault: addingComponent.isDefault,\n }),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to add component')\n return\n }\n setAddingComponent(null)\n const compRes = await fetch(`/api/cpq/offering-components?offeringId=${offeringId}`)\n if (compRes.ok) {\n const d = await compRes.json()\n setComponents(d.items ?? [])\n }\n } catch {\n setError('Failed to add component')\n } finally {\n setSaving(false)\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {saving ? 'Adding...' : 'Add'}\n </button>\n <button\n onClick={() => setAddingComponent(null)}\n className=\"inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n\n {slotComponents.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-muted-foreground\">\n No components assigned to this slot\n {slot.cardinalityMin > 0 && (\n <span className=\"ml-1 text-status-warning-text font-medium\">(required: min {slot.cardinalityMin})</span>\n )}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30\">\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Offering</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Code</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Type</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Default</th>\n <th className=\"px-4 py-2 text-right text-xs font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {slotComponents.map((comp) => (\n <tr key={comp.id} className=\"border-b last:border-0\">\n <td className=\"px-4 py-2.5 font-medium\">{comp.childOffering?.name ?? 'Unknown'}</td>\n <td className=\"px-4 py-2.5 text-muted-foreground text-xs\">{comp.childOffering?.code ?? '\u2014'}</td>\n <td className=\"px-4 py-2.5\">\n {comp.childOffering?.offeringType === 'bundle' ? (\n <Tag variant=\"brand\" className=\"px-2 text-[10px]\">bundle</Tag>\n ) : (\n <Tag variant=\"neutral\" className=\"px-2 text-[10px]\">simple</Tag>\n )}\n </td>\n <td className=\"px-4 py-2.5\">\n <button\n onClick={async () => {\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id, isDefault: !comp.isDefault }),\n })\n if (res.ok) {\n setComponents((prev) => prev.map((c) => c.id === comp.id ? { ...c, isDefault: !c.isDefault } : c))\n }\n } catch { /* ignore */ }\n }}\n className=\"cursor-pointer\"\n >\n <Tag variant={comp.isDefault ? 'success' : 'neutral'} className=\"px-2 text-[10px]\">\n {comp.isDefault ? 'Yes' : 'No'}\n </Tag>\n </button>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <button\n onClick={async () => {\n if (!confirm('Remove this component from the bundle?')) return\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id }),\n })\n if (res.ok) {\n setComponents((prev) => prev.filter((c) => c.id !== comp.id))\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to remove')\n }\n } catch {\n setError('Failed to remove component')\n }\n }}\n className=\"text-xs text-destructive hover:underline\"\n >\n Remove\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n )\n })}\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { NumberInput } from '../../../../components/NumberInput'\nimport { normalizeChargePricing } from '../../../../data/charge-pricing'\nimport {\n chargeTypeMap,\n formatStatusLabel,\n lifecycleStatusMap,\n type ChargeType,\n type LifecycleStatus,\n} from '../../../../components/statusMaps'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype OfferingComponent = {\n id: string\n slotId: string\n slot: { id: string; componentGroup: string; name: string; cardinalityMin: number; cardinalityMax: number | null } | null\n childOfferingId: string\n childOffering: { id: string; code: string; name: string; offeringType: string; specId: string } | null\n isDefault: boolean\n sortOrder: number\n isActive: boolean\n}\n\ntype BundleSlot = {\n id: string\n componentGroup: string\n name: string\n targetSpecId: string\n targetSpec: { id: string; code: string; name: string; specType: string } | null\n cardinalityMin: number\n cardinalityMax: number | null\n sortOrder: number\n}\n\ntype Offering = {\n id: string\n specId: string\n catalogOfferId: string | null\n code: string\n name: string\n description: string | null\n offeringType: string\n designTimeValues: Record<string, unknown>\n lifecycleStatus: string\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: Record<string, unknown> | null\n isActive: boolean\n specification: { id: string; code: string; name: string; productId: string; specType?: string } | null\n charges: Charge[]\n components?: OfferingComponent[]\n}\n\ntype Charge = {\n id: string\n code: string\n name: string\n description: string | null\n chargeType: string\n chargeModel: string | null\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\ntype Attribute = {\n id: string\n code: string\n name: string\n attributeType: string\n resolutionTime: string\n options: Array<{ value: string; label: string }> | null\n constraints: Record<string, unknown> | null\n defaultValue: unknown | null\n helpText: string | null\n sortOrder: number\n isRequired: boolean\n isActive: boolean\n}\n\ntype Specification = {\n id: string\n code: string\n name: string\n productId: string\n}\n\ntype PricingTableRef = { id: string; code: string; name: string; dimensions: Array<{ key: string; label: string }>; priceColumns: Array<{ key: string; label: string }> }\n\n// Shared by the eager mount-load and the lazy editor dropdown. Returns [] on\n// failure so a transient error degrades gracefully instead of blanking the page.\nasync function fetchPricingTables(): Promise<PricingTableRef[]> {\n try {\n const { ok, result } = await apiCall<{ items?: PricingTableRef[] }>('/api/cpq/pricing-tables?pageSize=100')\n if (!ok) {\n console.warn('[cpq] Failed to load pricing tables for the charges list')\n return []\n }\n return result?.items ?? []\n } catch (err) {\n console.warn('[cpq] Failed to load pricing tables for the charges list:', err)\n return []\n }\n}\n\ntype EditingCharge = Omit<Charge, 'id'> & { id?: string }\n\n// \u2500\u2500\u2500 Defaults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst EMPTY_FORM = {\n code: '',\n name: '',\n description: '',\n offeringType: 'simple' as string,\n lifecycleStatus: 'draft',\n effectiveFrom: null as string | null,\n effectiveTo: null as string | null,\n isActive: true,\n specId: '',\n}\n\nconst EMPTY_CHARGE: EditingCharge = {\n code: '',\n name: '',\n description: null,\n chargeType: 'mrc',\n chargeModel: 'flat',\n pricingMethod: 'fixed',\n pricingTableId: null,\n priceColumnKey: null,\n fixedPrice: null,\n currencyCode: 'USD',\n quantityAttributeCode: null,\n applicabilityCondition: null,\n sortOrder: 0,\n isActive: true,\n}\n\n\n// XD-297: the charge \"shape\" is two axes \u2014 Charge Model (how quantity drives\n// the charge) and Pricing Method (where the unit price comes from).\nfunction chargeModelLabel(t: TranslateFn, model: string): string {\n switch (model) {\n case 'flat':\n return t('cpq.offerings.chargeModel.flat', 'Flat Fee')\n case 'per_unit':\n return t('cpq.offerings.chargeModel.perUnit', 'Per Unit')\n case 'volume':\n return t('cpq.offerings.chargeModel.volume', 'Volume-based')\n case 'tiered':\n return t('cpq.offerings.chargeModel.tiered', 'Tiered')\n default:\n return model\n }\n}\n\nfunction pricingSourceLabel(t: TranslateFn, source: string): string {\n switch (source) {\n case 'fixed':\n return t('cpq.offerings.pricingMethod.fixed', 'Fixed Price')\n case 'table':\n return t('cpq.offerings.pricingMethod.table', 'Table Lookup')\n default:\n return source\n }\n}\n\ntype ChargeMissingField = 'fixedPrice' | 'currency' | 'quantityAttribute' | 'pricingTable' | 'priceColumn'\n\nfunction chargeMissingFieldLabel(t: TranslateFn, field: ChargeMissingField): string {\n switch (field) {\n case 'fixedPrice':\n return t('cpq.offerings.charge.fields.fixedPrice', 'Fixed Price')\n case 'currency':\n return t('cpq.offerings.charge.fields.currency', 'Currency')\n case 'quantityAttribute':\n return t('cpq.offerings.charge.fields.quantityAttribute', 'Quantity Attribute')\n case 'pricingTable':\n return t('cpq.offerings.charge.fields.pricingTable', 'Pricing Table')\n case 'priceColumn':\n return t('cpq.offerings.charge.fields.priceColumn', 'Price Column')\n }\n}\n\n// V-CHG-1 in `validators.ts`: mirror the (chargeModel \u00D7 pricingMethod) rules in\n// the UI so users see what's missing without round-tripping to the server.\ntype ChargeShape = {\n chargeModel: string | null\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n}\n\nfunction isChargeComplete(charge: ChargeShape): boolean {\n return chargeMissingFields(charge).length === 0\n}\n\nfunction chargeMissingFields(charge: ChargeShape): ChargeMissingField[] {\n const { model, source } = normalizeChargePricing(charge)\n const missing: ChargeMissingField[] = []\n if (source === 'fixed') {\n if (!charge.fixedPrice) missing.push('fixedPrice')\n if (!charge.currencyCode) missing.push('currency')\n if (model === 'per_unit' && !charge.quantityAttributeCode) missing.push('quantityAttribute')\n } else {\n if (!charge.pricingTableId) missing.push('pricingTable')\n if (!charge.priceColumnKey) missing.push('priceColumn')\n if (model !== 'flat' && !charge.quantityAttributeCode) missing.push('quantityAttribute')\n }\n return missing\n}\n\n// \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function OfferingDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const offeringId = (props.params?.id ?? urlParams?.id) as string\n const isNew = offeringId === 'new'\n\n // \u2500\u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const [tab, setTab] = React.useState<'general' | 'charges' | 'components'>('general')\n const [form, setForm] = React.useState(EMPTY_FORM)\n const [designTimeValues, setDesignTimeValues] = React.useState<Record<string, unknown>>({})\n const [charges, setCharges] = React.useState<Charge[]>([])\n const [attributes, setAttributes] = React.useState<Attribute[]>([])\n const [specs, setSpecs] = React.useState<Specification[]>([])\n const [specDetail, setSpecDetail] = React.useState<{ id: string; code: string; name: string; specType?: string } | null>(null)\n const [pricingTables, setPricingTables] = React.useState<PricingTableRef[]>([])\n const [components, setComponents] = React.useState<OfferingComponent[]>([])\n const [bundleSlots, setBundleSlots] = React.useState<BundleSlot[]>([])\n const [addingComponent, setAddingComponent] = React.useState<{ slotId: string; childOfferingId: string; isDefault: boolean } | null>(null)\n const [slotOfferings, setSlotOfferings] = React.useState<Record<string, Array<{ id: string; code: string; name: string; offeringType: string }>>>({})\n\n const [loading, setLoading] = React.useState(!isNew)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editingCharge, setEditingCharge] = React.useState<EditingCharge | null>(null)\n\n // OM-standard detail page: existing offerings open read-only and require\n // an explicit Edit click to allow changes. New offerings skip view mode.\n const [generalMode, setGeneralMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [formSnapshot, setFormSnapshot] = React.useState<typeof EMPTY_FORM | null>(null)\n const [designTimeSnapshot, setDesignTimeSnapshot] = React.useState<Record<string, unknown> | null>(null)\n\n // \u2500\u2500\u2500 Load data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n React.useEffect(() => {\n let cancelled = false\n\n async function load() {\n try {\n // Load specs for dropdown (needed for new + showing spec name)\n const specsRes = await fetch('/api/cpq/product-specifications?pageSize=200')\n if (specsRes.ok) {\n const d = await specsRes.json()\n if (!cancelled) setSpecs(d.items ?? [])\n }\n\n if (isNew) return\n\n // Load offering detail\n const res = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (!res.ok) {\n if (!cancelled) setError(t('cpq.offerings.detail.error.load', 'Failed to load offering'))\n return\n }\n\n const data: Offering = await res.json()\n if (!cancelled) {\n setForm({\n code: data.code,\n name: data.name,\n description: data.description ?? '',\n offeringType: data.offeringType ?? 'simple',\n lifecycleStatus: data.lifecycleStatus,\n effectiveFrom: data.effectiveFrom,\n effectiveTo: data.effectiveTo,\n isActive: data.isActive,\n specId: data.specId,\n })\n setDesignTimeValues(data.designTimeValues ?? {})\n setCharges(data.charges ?? [])\n setSpecDetail(data.specification ?? null)\n setComponents(data.components ?? [])\n\n // Charges reference pricing tables by id; load the tables up front so\n // the list renders their names instead of \"missing\". The charge editor\n // also lazy-loads them, but the read view needs them on mount/refresh.\n if ((data.charges ?? []).some((c) => c.pricingTableId)) {\n const tables = await fetchPricingTables()\n if (!cancelled) setPricingTables(tables)\n }\n\n // Load attributes for the spec\n if (data.specId) {\n const attrRes = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(data.specId)}&pageSize=200`)\n if (attrRes.ok) {\n const attrData = await attrRes.json()\n if (!cancelled) setAttributes(attrData.items ?? [])\n }\n }\n\n // Load bundle slots if this is a bundle offering\n if (data.offeringType === 'bundle' && data.specId) {\n const slotsRes = await fetch(`/api/cpq/bundle-slots?specId=${encodeURIComponent(data.specId)}`)\n if (slotsRes.ok) {\n const slotsData = await slotsRes.json()\n if (!cancelled) setBundleSlots(slotsData.items ?? [])\n }\n }\n }\n } catch (err) {\n console.error('Failed to load', err)\n if (!cancelled) setError(t('cpq.offerings.detail.error.loadGeneric', 'Failed to load'))\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n\n load()\n return () => { cancelled = true }\n }, [offeringId, isNew])\n\n // Load attributes when spec changes (for new offering)\n const loadSpecAttributes = async (specId: string) => {\n if (!specId) { setAttributes([]); return }\n try {\n const res = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(specId)}&pageSize=200`)\n if (res.ok) {\n const data = await res.json()\n setAttributes(data.items ?? [])\n }\n } catch {\n console.error('Failed to load spec attributes')\n }\n }\n\n // \u2500\u2500\u2500 Save offering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const saveOffering = async () => {\n setSaving(true)\n setError(null)\n try {\n const payload = isNew\n ? { ...form, description: form.description || null, designTimeValues, specId: form.specId }\n : { id: offeringId, ...form, description: form.description || null, designTimeValues }\n\n const res = await fetch('/api/cpq/product-offerings', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? t('cpq.offerings.detail.error.save', 'Failed to save'))\n return\n }\n\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/offerings/${saved.id}`)\n } else {\n setForm({\n code: saved.code,\n name: saved.name,\n description: saved.description ?? '',\n offeringType: saved.offeringType ?? form.offeringType,\n lifecycleStatus: saved.lifecycleStatus,\n effectiveFrom: saved.effectiveFrom,\n effectiveTo: saved.effectiveTo,\n isActive: saved.isActive,\n specId: saved.specId,\n })\n setDesignTimeValues(saved.designTimeValues ?? {})\n // Save succeeded \u2014 drop snapshots and flip back to read-only.\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }\n } catch {\n setError(t('cpq.offerings.detail.error.save', 'Failed to save'))\n } finally {\n setSaving(false)\n }\n }\n\n const deleteOffering = async () => {\n if (!confirm(t('cpq.offerings.confirmDelete', 'Delete this offering and all its charges?'))) return\n try {\n const res = await fetch('/api/cpq/product-offerings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: offeringId }),\n })\n if (res.ok) {\n router.push('/backend/cpq/offerings')\n } else {\n const d = await res.json()\n setError(d.error ?? t('cpq.offerings.detail.error.delete', 'Failed to delete'))\n }\n } catch {\n setError(t('cpq.offerings.detail.error.delete', 'Failed to delete'))\n }\n }\n\n // \u2500\u2500\u2500 Charge CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const loadPricingTables = async () => {\n if (pricingTables.length > 0) return\n setPricingTables(await fetchPricingTables())\n }\n\n const startEditCharge = (charge?: Charge) => {\n if (charge) {\n // Normalise legacy rows (chargeModel null, combined pricingMethod) into\n // the split shape the form's two dropdowns expect.\n const { model, source } = normalizeChargePricing(charge)\n setEditingCharge({ ...charge, chargeModel: model, pricingMethod: source })\n } else {\n setEditingCharge({ ...EMPTY_CHARGE })\n }\n loadPricingTables()\n }\n\n const saveCharge = async () => {\n if (!editingCharge) return\n setSaving(true)\n setError(null)\n try {\n const isEdit = !!editingCharge.id\n const payload = {\n ...editingCharge,\n offeringId,\n }\n const res = await fetch('/api/cpq/product-charges', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? t('cpq.offerings.detail.error.saveCharge', 'Failed to save charge'))\n return\n }\n // Reload offering to get updated charges\n const offeringRes = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (offeringRes.ok) {\n const data = await offeringRes.json()\n setCharges(data.charges ?? [])\n }\n setEditingCharge(null)\n } catch {\n setError(t('cpq.offerings.detail.error.saveCharge', 'Failed to save charge'))\n } finally {\n setSaving(false)\n }\n }\n\n const deleteCharge = async (chargeId: string) => {\n if (!confirm(t('cpq.offerings.detail.confirmDeleteCharge', 'Delete this charge?'))) return\n try {\n const res = await fetch('/api/cpq/product-charges', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: chargeId }),\n })\n if (res.ok) setCharges((prev) => prev.filter((c) => c.id !== chargeId))\n } catch {\n setError(t('cpq.offerings.detail.error.deleteCharge', 'Failed to delete charge'))\n }\n }\n\n const selectedPricingTable = editingCharge?.pricingTableId\n ? pricingTables.find((pt) => pt.id === editingCharge.pricingTableId)\n : null\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const designTimeAttrs = attributes.filter((a) => a.resolutionTime === 'design_time')\n\n // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('cpq.common.loading', 'Loading...')}</div>\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/offerings')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('cpq.common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.offerings.new', 'New Offering') : form.name}\n </h1>\n {!isNew && (\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n )}\n {specDetail && (\n <span className=\"text-sm text-muted-foreground\">\n {t('cpq.offerings.detail.specLabel', 'Spec:')} <button onClick={() => router.push(`/backend/cpq/specifications/${specDetail.id}`)} className=\"text-primary hover:underline\">{specDetail.name}</button>\n </span>\n )}\n </div>\n {!isNew && (\n <div className=\"flex items-center gap-2\">\n {generalMode === 'view' && tab === 'general' && (\n <Button\n type=\"button\"\n onClick={() => {\n setFormSnapshot(form)\n setDesignTimeSnapshot(designTimeValues)\n setGeneralMode('edit')\n }}\n >\n {t('cpq.common.edit', 'Edit')}\n </Button>\n )}\n <Button type=\"button\" variant=\"destructive\" onClick={deleteOffering}>\n {t('cpq.common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && (\n <Alert variant=\"destructive\">{error}</Alert>\n )}\n\n {/* Tabs */}\n {!isNew && (\n <div className=\"flex gap-1 border-b\">\n {([\n 'general',\n 'charges',\n ...(form.offeringType === 'bundle' ? ['components' as const] : []),\n ] as const).map((t_) => (\n <button\n key={t_}\n onClick={() => setTab(t_ as typeof tab)}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n tab === t_ ? 'border-primary text-primary' : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {t_ === 'general' && t('cpq.offerings.detail.tabs.general', 'General')}\n {t_ === 'charges' && t('cpq.offerings.detail.tabs.charges', 'Charges ({count})', { count: charges.length })}\n {t_ === 'components' && t('cpq.offerings.detail.tabs.components', 'Components ({count})', { count: components.length })}\n </button>\n ))}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 General Tab / New Form \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {(isNew || tab === 'general') && (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n {isNew && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.detail.specification', 'Specification')}</label>\n <select\n value={form.specId}\n onChange={(e) => {\n setForm({ ...form, specId: e.target.value })\n loadSpecAttributes(e.target.value)\n setDesignTimeValues({})\n }}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">{t('cpq.offerings.detail.selectSpecification', 'Select a specification...')}</option>\n {specs.map((s) => (\n <option key={s.id} value={s.id}>{s.name} ({s.code})</option>\n ))}\n </select>\n </div>\n )}\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.code', 'Code')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm font-mono py-2\">{form.code || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.code}\n onChange={(e) => setForm({ ...form, code: e.target.value })}\n placeholder={t('cpq.offerings.detail.codePlaceholder', 'e.g. gix-cloud-connect-aws')}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.name', 'Name')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm py-2\">{form.name || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.lifecycleStatus', 'Lifecycle Status')}</label>\n {generalMode === 'view' && !isNew ? (\n <div className=\"py-2\">\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n </div>\n ) : (\n <select\n value={form.lifecycleStatus}\n onChange={(e) => setForm({ ...form, lifecycleStatus: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"draft\">{t('cpq.offerings.lifecycle.draft', 'Draft')}</option>\n <option value=\"active\">{t('cpq.offerings.lifecycle.active', 'Active')}</option>\n <option value=\"deprecated\">{t('cpq.offerings.lifecycle.deprecated', 'Deprecated')}</option>\n </select>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.isActive', 'Is Active?')}</label>\n <div className=\"flex items-center h-[38px]\">\n {generalMode === 'view' && !isNew ? (\n <Tag variant={form.isActive ? 'success' : 'neutral'} dot>\n {form.isActive ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}\n </Tag>\n ) : (\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n )}\n </div>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.description', 'Description')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm text-muted-foreground py-2 whitespace-pre-wrap\">{form.description || '\u2014'}</p>\n ) : (\n <textarea\n value={form.description ?? ''}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={3}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n\n {/* Design-time values */}\n {designTimeAttrs.length > 0 && (\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium\">{t('cpq.offerings.detail.designTimeValues', 'Design-Time Values')}</label>\n <div className=\"grid grid-cols-2 gap-3\">\n {designTimeAttrs.map((attr) => {\n const value = designTimeValues[attr.code]\n const isViewing = generalMode === 'view' && !isNew\n // Lookup the human label for select-type values so the\n // read-only view doesn't show raw codes.\n const optionLabel =\n (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options\n ? attr.options.find((o) => o.value === value)?.label\n : undefined\n return (\n <div key={attr.code}>\n <label className=\"block text-xs font-medium mb-1\">\n {attr.name}\n {attr.isRequired && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {isViewing ? (\n <p className=\"text-sm py-2\">\n {value == null || value === '' ? (\n <span className=\"text-muted-foreground\">\u2014</span>\n ) : attr.attributeType === 'boolean' ? (\n <Tag variant={value ? 'success' : 'neutral'} dot>\n {value ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}\n </Tag>\n ) : (\n optionLabel ?? String(value)\n )}\n </p>\n ) : (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options ? (\n <select\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"\">{t('cpq.offerings.detail.selectAttribute', 'Select {name}...', { name: attr.name })}</option>\n {attr.options.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n ) : attr.attributeType === 'number' ? (\n <NumberInput\n value={typeof value === 'number' ? (value as number) : null}\n onChange={(n) => setDesignTimeValues({ ...designTimeValues, [attr.code]: n })}\n />\n ) : attr.attributeType === 'boolean' ? (\n <div className=\"pt-1\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.checked })}\n className=\"rounded border\"\n />\n {attr.name}\n </label>\n </div>\n ) : (\n <input\n type=\"text\"\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n placeholder={attr.helpText ?? undefined}\n />\n )}\n {attr.helpText && <p className=\"text-xs text-muted-foreground mt-0.5\">{attr.helpText}</p>}\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {/* In view mode the Edit button lives in the page header next to\n Delete (OM standard). Here we only render the Save/Cancel\n pair when actually editing. */}\n {!(generalMode === 'view' && !isNew) && (\n <div className=\"flex gap-3\">\n <Button\n type=\"button\"\n onClick={saveOffering}\n disabled={saving || !form.code || !form.name || (isNew && !form.specId)}\n >\n {saving ? t('cpq.common.saving', 'Saving...') : t('cpq.common.save', 'Save')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n if (isNew) {\n router.push('/backend/cpq/offerings')\n return\n }\n if (formSnapshot) setForm(formSnapshot)\n if (designTimeSnapshot) setDesignTimeValues(designTimeSnapshot)\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }}\n >\n {t('cpq.common.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Charges Tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'charges' && !isNew && (\n <div className=\"space-y-4\">\n <div className=\"flex justify-end\">\n <button\n onClick={() => startEditCharge()}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.offerings.addCharge', 'Add Charge')}\n </button>\n </div>\n\n {/* Charge edit form */}\n {editingCharge && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <h3 className=\"font-medium text-sm\">\n {editingCharge.id ? t('cpq.offerings.charge.form.editTitle', 'Edit Charge') : t('cpq.offerings.charge.form.newTitle', 'New Charge')}\n </h3>\n <div className=\"grid grid-cols-3 gap-3\">\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.code', 'Code')}</label>\n <input type=\"text\" value={editingCharge.code} onChange={(e) => setEditingCharge({ ...editingCharge, code: e.target.value })} placeholder={t('cpq.offerings.charge.fields.codePlaceholder', 'e.g. mrc-monthly')} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.name', 'Name')}</label>\n <input type=\"text\" value={editingCharge.name} onChange={(e) => setEditingCharge({ ...editingCharge, name: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.chargeType', 'Charge Type')}</label>\n <select value={editingCharge.chargeType} onChange={(e) => setEditingCharge({ ...editingCharge, chargeType: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"mrc\">{t('cpq.offerings.chargeType.mrc', 'MRC (Monthly Recurring)')}</option>\n <option value=\"nrc\">{t('cpq.offerings.chargeType.nrc', 'NRC (Non-Recurring)')}</option>\n <option value=\"usage\">{t('cpq.offerings.chargeType.usage', 'Usage')}</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.chargeModel', 'Charge Model')}</label>\n <select\n value={editingCharge.chargeModel ?? 'flat'}\n onChange={(e) => {\n const model = e.target.value\n const next = { ...editingCharge, chargeModel: model }\n // Volume / tiered are graduated over table ranges \u2014 they can't use a fixed price.\n if ((model === 'volume' || model === 'tiered') && editingCharge.pricingMethod !== 'table') {\n next.pricingMethod = 'table'\n next.fixedPrice = null\n }\n // Flat never takes a quantity attribute.\n if (model === 'flat') next.quantityAttributeCode = null\n setEditingCharge(next)\n }}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"flat\">{chargeModelLabel(t, 'flat')}</option>\n <option value=\"per_unit\">{chargeModelLabel(t, 'per_unit')}</option>\n <option value=\"volume\">{chargeModelLabel(t, 'volume')}</option>\n <option value=\"tiered\">{chargeModelLabel(t, 'tiered')}</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.pricingMethod', 'Pricing Method')}</label>\n <select\n value={editingCharge.pricingMethod}\n onChange={(e) => {\n const source = e.target.value\n if (source === 'fixed') {\n // Only per_unit keeps the quantity attribute under a fixed\n // price; flat must drop it (V-CHG-1 forbids it).\n const keepQty = editingCharge.chargeModel === 'per_unit'\n setEditingCharge({ ...editingCharge, pricingMethod: source, pricingTableId: null, priceColumnKey: null, ...(keepQty ? {} : { quantityAttributeCode: null }) })\n } else {\n setEditingCharge({ ...editingCharge, pricingMethod: source, fixedPrice: null })\n }\n }}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n {/* Volume / tiered are graduated over table ranges \u2014 a fixed price isn't applicable. */}\n {editingCharge.chargeModel !== 'volume' && editingCharge.chargeModel !== 'tiered' && (\n <option value=\"fixed\">{pricingSourceLabel(t, 'fixed')}</option>\n )}\n <option value=\"table\">{pricingSourceLabel(t, 'table')}</option>\n </select>\n </div>\n {editingCharge.pricingMethod === 'fixed' ? (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{chargeMissingFieldLabel(t, 'fixedPrice')} <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.fixedPrice ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, fixedPrice: e.target.value || null })} placeholder=\"0.00\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{chargeMissingFieldLabel(t, 'currency')} <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.currencyCode ?? 'USD'} onChange={(e) => setEditingCharge({ ...editingCharge, currencyCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n </>\n ) : (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{chargeMissingFieldLabel(t, 'pricingTable')} <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.pricingTableId ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, pricingTableId: e.target.value || null, priceColumnKey: null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">{t('cpq.offerings.charge.fields.selectTable', 'Select table...')}</option>\n {pricingTables.map((pt) => (\n <option key={pt.id} value={pt.id}>{pt.name} ({pt.code})</option>\n ))}\n </select>\n {pricingTables.length === 0 && (\n <p className=\"text-xs text-warning mt-0.5\">\n {t('cpq.offerings.charge.noPricingTables.prefix', 'No pricing tables yet \u2014')}{' '}\n <a href=\"/backend/cpq/pricing-tables\" className=\"text-primary hover:underline\">{t('cpq.offerings.charge.noPricingTables.link', 'create one')}</a>{' '}\n {t('cpq.offerings.charge.noPricingTables.suffix', 'before using Table Lookup pricing.')}\n </p>\n )}\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{chargeMissingFieldLabel(t, 'priceColumn')} <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.priceColumnKey ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, priceColumnKey: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" disabled={!selectedPricingTable}>\n <option value=\"\">{t('cpq.offerings.charge.fields.selectColumn', 'Select column...')}</option>\n {selectedPricingTable?.priceColumns.map((col) => (\n <option key={col.key} value={col.key}>{col.label}</option>\n ))}\n </select>\n </div>\n </>\n )}\n {/* Quantity attribute drives the unit count \u2014 needed for per-unit\n (any source) and for volume / tiered table lookups. */}\n {((editingCharge.pricingMethod === 'table' && editingCharge.chargeModel !== 'flat') ||\n (editingCharge.pricingMethod === 'fixed' && editingCharge.chargeModel === 'per_unit')) && (\n <div>\n <label className=\"block text-xs font-medium mb-1\">{chargeMissingFieldLabel(t, 'quantityAttribute')} <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.quantityAttributeCode ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, quantityAttributeCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">{t('cpq.offerings.charge.fields.selectAttribute', 'Select attribute...')}</option>\n {attributes.filter((a) => a.attributeType === 'number').map((a) => (\n <option key={a.code} value={a.code}>{a.name} ({a.code})</option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground mt-0.5\">{t('cpq.offerings.charge.fields.quantityAttributeHelp', 'Attribute whose value drives the quantity for pricing')}</p>\n {attributes.filter((a) => a.attributeType === 'number').length === 0 && form.specId && (\n <p className=\"text-xs text-warning mt-0.5\">\n {t('cpq.offerings.charge.noNumberAttributes.prefix', 'Spec has no number attributes \u2014')}{' '}\n <a href={`/backend/cpq/specifications/${form.specId}`} className=\"text-primary hover:underline\">\n {t('cpq.offerings.charge.noNumberAttributes.link', 'add one to the spec')}\n </a>{' '}\n {t('cpq.offerings.charge.noNumberAttributes.suffix', 'first.')}\n </p>\n )}\n </div>\n )}\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.sortOrder', 'Sort Order')}</label>\n <NumberInput\n integer\n value={editingCharge.sortOrder}\n onChange={(n) => setEditingCharge({ ...editingCharge, sortOrder: n ?? 0 })}\n />\n </div>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.charge.fields.description', 'Description')}</label>\n <input type=\"text\" value={editingCharge.description ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, description: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div className=\"flex items-end gap-4\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input type=\"checkbox\" checked={editingCharge.isActive} onChange={(e) => setEditingCharge({ ...editingCharge, isActive: e.target.checked })} className=\"rounded border\" />\n {t('cpq.common.active', 'Active')}\n </label>\n </div>\n {(() => {\n const missing = chargeMissingFields(editingCharge)\n const blocked = saving || !editingCharge.code || !editingCharge.name || missing.length > 0\n return (\n <>\n {missing.length > 0 && (\n <Alert variant=\"destructive\">\n {missing.length > 1\n ? t('cpq.offerings.charge.missingFieldsPlural', 'Missing required fields for {method} pricing: {fields}', {\n method: editingCharge.pricingMethod,\n fields: missing.map((field) => chargeMissingFieldLabel(t, field)).join(', '),\n })\n : t('cpq.offerings.charge.missingFieldsSingular', 'Missing required field for {method} pricing: {fields}', {\n method: editingCharge.pricingMethod,\n fields: missing.map((field) => chargeMissingFieldLabel(t, field)).join(', '),\n })}\n </Alert>\n )}\n <div className=\"flex gap-2\">\n <button onClick={saveCharge} disabled={blocked} className=\"inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\">\n {saving ? t('cpq.common.saving', 'Saving...') : t('cpq.common.save', 'Save')}\n </button>\n <button onClick={() => setEditingCharge(null)} className=\"inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted\">{t('cpq.common.cancel', 'Cancel')}</button>\n </div>\n </>\n )\n })()}\n </div>\n )}\n\n {/* Charges table */}\n {charges.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t('cpq.offerings.charges.empty', 'No charges defined. Add recurring, non-recurring, or usage charges to this offering.')}\n </div>\n ) : (\n <div className=\"rounded-lg border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium\">{t('cpq.offerings.charges.columns.code', 'Code')}</th>\n <th className=\"px-4 py-3 text-left font-medium\">{t('cpq.offerings.charges.columns.name', 'Name')}</th>\n <th className=\"px-4 py-3 text-left font-medium\">{t('cpq.offerings.charges.columns.type', 'Type')}</th>\n <th className=\"px-4 py-3 text-left font-medium\">{t('cpq.offerings.charges.columns.pricing', 'Pricing')}</th>\n <th className=\"px-4 py-3 text-left font-medium\">{t('cpq.offerings.charges.columns.price', 'Price')}</th>\n <th className=\"px-4 py-3 text-left font-medium\">{t('cpq.offerings.charges.columns.active', 'Active')}</th>\n <th className=\"px-4 py-3 text-right font-medium\">{t('cpq.offerings.charges.columns.actions', 'Actions')}</th>\n </tr>\n </thead>\n <tbody>\n {charges.map((charge) => {\n const incomplete = !isChargeComplete(charge)\n const tableRef = charge.pricingTableId\n ? pricingTables.find((pt) => pt.id === charge.pricingTableId)\n : null\n const qtyAttr = charge.quantityAttributeCode\n ? attributes.find((a) => a.code === charge.quantityAttributeCode)\n : null\n const { model, source } = normalizeChargePricing(charge)\n return (\n <tr key={charge.id} className=\"border-b\">\n <td className=\"px-4 py-3 font-mono text-xs\">{charge.code}</td>\n <td className=\"px-4 py-3\">\n {charge.name}\n {incomplete && (\n <Tag variant=\"error\" className=\"ml-2 px-2 text-[10px]\" dot>{t('cpq.offerings.charges.incomplete', 'Incomplete')}</Tag>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <Tag variant={chargeTypeMap[charge.chargeType as ChargeType] ?? 'neutral'} className=\"px-2 text-xs\">\n {charge.chargeType.toUpperCase()}\n </Tag>\n </td>\n <td className=\"px-4 py-3 text-xs\">\n {chargeModelLabel(t, model)}\n <span className=\"text-muted-foreground\"> \u00B7 {pricingSourceLabel(t, source)}</span>\n </td>\n <td className=\"px-4 py-3 text-xs\">\n {source === 'fixed' ? (\n <div className=\"flex flex-col gap-0.5\">\n {charge.fixedPrice != null\n ? <span>{`${charge.currencyCode ?? 'USD'} ${charge.fixedPrice}`}</span>\n : <span className=\"text-muted-foreground\">\u2014</span>}\n {model === 'per_unit' && (\n <span>\n <span className=\"text-muted-foreground\">{t('cpq.offerings.charges.qtyLabel', '\u00D7 Qty:')}</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">{t('cpq.offerings.charges.missing', 'missing')}</span>}\n </span>\n )}\n </div>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n <span>\n <span className=\"text-muted-foreground\">{t('cpq.offerings.charges.tableLabel', 'Table:')}</span>{' '}\n {tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? '?'}` : <span className=\"text-destructive\">{t('cpq.offerings.charges.missing', 'missing')}</span>}\n </span>\n {model !== 'flat' && (\n <span>\n <span className=\"text-muted-foreground\">{t('cpq.offerings.charges.qtyLabel', '\u00D7 Qty:')}</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">{t('cpq.offerings.charges.missing', 'missing')}</span>}\n </span>\n )}\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">{charge.isActive ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}</td>\n <td className=\"px-4 py-3 text-right\">\n <button onClick={() => startEditCharge(charge)} className=\"text-xs text-primary hover:underline mr-2\">{t('cpq.common.edit', 'Edit')}</button>\n <button onClick={() => deleteCharge(charge.id)} className=\"text-xs text-destructive hover:underline\">{t('cpq.common.delete', 'Delete')}</button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Components Tab (bundle offerings) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'components' && !isNew && form.offeringType === 'bundle' && (\n <div className=\"space-y-4\">\n {bundleSlots.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t('cpq.offerings.components.noSlots', 'No bundle slots defined on this specification. Add slots on the specification first.')}\n </div>\n ) : (\n <>\n {/* Group components by slot */}\n {bundleSlots.map((slot) => {\n const slotComponents = components.filter((c) => c.slotId === slot.id)\n return (\n <div key={slot.id} className=\"rounded-lg border bg-card overflow-hidden\">\n <div className=\"bg-muted/50 px-4 py-3 border-b flex items-center justify-between\">\n <div>\n <span className=\"font-medium text-sm\">{slot.name}</span>\n <Tag variant=\"info\" className=\"ml-2 px-2 text-[10px]\">\n {slot.componentGroup}\n </Tag>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {slot.cardinalityMin}..{slot.cardinalityMax ?? '\u221E'}\n </span>\n {slot.targetSpec && (\n <span className=\"ml-2 text-xs text-muted-foreground\">\u2192 {slot.targetSpec.name}</span>\n )}\n </div>\n <button\n onClick={async () => {\n setAddingComponent({ slotId: slot.id, childOfferingId: '', isDefault: false })\n if (!slotOfferings[slot.targetSpecId]) {\n const res = await fetch(`/api/cpq/product-offerings?specId=${encodeURIComponent(slot.targetSpecId)}&pageSize=100`)\n if (res.ok) {\n const d = await res.json()\n setSlotOfferings((prev) => ({ ...prev, [slot.targetSpecId]: d.items ?? [] }))\n }\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.offerings.components.add', '+ Add Component')}\n </button>\n </div>\n\n {addingComponent?.slotId === slot.id && (\n <div className=\"p-4 border-b bg-muted/20 space-y-3\">\n <div className=\"grid grid-cols-3 gap-3\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.components.fields.componentOffering', 'Component Offering')}</label>\n <select\n value={addingComponent.childOfferingId}\n onChange={(e) => setAddingComponent({ ...addingComponent, childOfferingId: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">{t('cpq.offerings.components.fields.selectOffering', '\u2014 Select offering \u2014')}</option>\n {(slotOfferings[slot.targetSpecId] ?? []).map((o) => (\n <option key={o.id} value={o.id}>{o.name} ({o.code}){o.offeringType === 'bundle' ? t('cpq.offerings.components.bundleSuffix', ' [bundle]') : ''}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">{t('cpq.offerings.components.fields.isDefault', 'Default?')}</label>\n <div className=\"flex items-center h-[38px]\">\n <input\n type=\"checkbox\"\n checked={addingComponent.isDefault}\n onChange={(e) => setAddingComponent({ ...addingComponent, isDefault: e.target.checked })}\n className=\"rounded border\"\n />\n <span className=\"ml-2 text-xs text-muted-foreground\">{t('cpq.offerings.components.fields.isDefaultHelp', 'Pre-selected in quote')}</span>\n </div>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n disabled={saving || !addingComponent.childOfferingId}\n onClick={async () => {\n setSaving(true)\n setError(null)\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n offeringId,\n slotId: addingComponent.slotId,\n childOfferingId: addingComponent.childOfferingId,\n isDefault: addingComponent.isDefault,\n }),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? t('cpq.offerings.components.error.add', 'Failed to add component'))\n return\n }\n setAddingComponent(null)\n const compRes = await fetch(`/api/cpq/offering-components?offeringId=${offeringId}`)\n if (compRes.ok) {\n const d = await compRes.json()\n setComponents(d.items ?? [])\n }\n } catch {\n setError(t('cpq.offerings.components.error.add', 'Failed to add component'))\n } finally {\n setSaving(false)\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {saving ? t('cpq.offerings.components.adding', 'Adding...') : t('cpq.offerings.components.addSubmit', 'Add')}\n </button>\n <button\n onClick={() => setAddingComponent(null)}\n className=\"inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n {t('cpq.common.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n )}\n\n {slotComponents.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-muted-foreground\">\n {t('cpq.offerings.components.emptySlot', 'No components assigned to this slot')}\n {slot.cardinalityMin > 0 && (\n <span className=\"ml-1 text-status-warning-text font-medium\">{t('cpq.offerings.components.requiredMin', '(required: min {min})', { min: slot.cardinalityMin })}</span>\n )}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30\">\n <th className=\"px-4 py-2 text-left text-xs font-medium\">{t('cpq.offerings.components.columns.offering', 'Offering')}</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">{t('cpq.offerings.components.columns.code', 'Code')}</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">{t('cpq.offerings.components.columns.type', 'Type')}</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">{t('cpq.offerings.components.columns.default', 'Default')}</th>\n <th className=\"px-4 py-2 text-right text-xs font-medium\">{t('cpq.offerings.components.columns.actions', 'Actions')}</th>\n </tr>\n </thead>\n <tbody>\n {slotComponents.map((comp) => (\n <tr key={comp.id} className=\"border-b last:border-0\">\n <td className=\"px-4 py-2.5 font-medium\">{comp.childOffering?.name ?? t('cpq.offerings.components.unknown', 'Unknown')}</td>\n <td className=\"px-4 py-2.5 text-muted-foreground text-xs\">{comp.childOffering?.code ?? '\u2014'}</td>\n <td className=\"px-4 py-2.5\">\n {comp.childOffering?.offeringType === 'bundle' ? (\n <Tag variant=\"brand\" className=\"px-2 text-[10px]\">{t('cpq.offerings.components.tag.bundle', 'bundle')}</Tag>\n ) : (\n <Tag variant=\"neutral\" className=\"px-2 text-[10px]\">{t('cpq.offerings.components.tag.simple', 'simple')}</Tag>\n )}\n </td>\n <td className=\"px-4 py-2.5\">\n <button\n onClick={async () => {\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id, isDefault: !comp.isDefault }),\n })\n if (res.ok) {\n setComponents((prev) => prev.map((c) => c.id === comp.id ? { ...c, isDefault: !c.isDefault } : c))\n }\n } catch { /* ignore */ }\n }}\n className=\"cursor-pointer\"\n >\n <Tag variant={comp.isDefault ? 'success' : 'neutral'} className=\"px-2 text-[10px]\">\n {comp.isDefault ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}\n </Tag>\n </button>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <button\n onClick={async () => {\n if (!confirm(t('cpq.offerings.components.confirmRemove', 'Remove this component from the bundle?'))) return\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id }),\n })\n if (res.ok) {\n setComponents((prev) => prev.filter((c) => c.id !== comp.id))\n } else {\n const d = await res.json()\n setError(d.error ?? t('cpq.offerings.components.error.remove', 'Failed to remove'))\n }\n } catch {\n setError(t('cpq.offerings.components.error.removeComponent', 'Failed to remove component'))\n }\n }}\n className=\"text-xs text-destructive hover:underline\"\n >\n {t('cpq.offerings.components.remove', 'Remove')}\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n )\n })}\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|