@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/price-rules/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter, useParams } from 'next/navigation'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { NumberInput } from '../../../../components/NumberInput'\n\nconst RULE_TYPE_LABELS: Record<string, string> = {\n discount_percent: 'Discount %',\n discount_absolute: 'Discount $',\n surcharge_percent: 'Surcharge %',\n surcharge_absolute: 'Surcharge $',\n price_override: 'Override',\n}\n\ntype PriceRule = {\n id: string\n code: string\n name: string\n description: string | null\n productOfferingId: string | null\n ruleType: string\n value: number\n chargeCodeFilter: string | null\n chargeTypeFilter: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n createdAt: string\n updatedAt: string\n}\n\ntype ProductOffering = { id: string; code: string; name: string }\n\ntype FormData = {\n name: string\n description: string\n productOfferingId: string\n ruleType: string\n value: string\n chargeCodeFilter: string\n chargeTypeFilter: string\n conditionAttribute: string\n conditionOperator: string\n conditionValue: string\n sortOrder: string\n isActive: boolean\n}\n\nfunction ruleToForm(rule: PriceRule): FormData {\n const cond = rule.applicabilityCondition as { attribute?: string; operator?: string; value?: string } | null\n return {\n name: rule.name,\n description: rule.description ?? '',\n productOfferingId: rule.productOfferingId ?? '',\n ruleType: rule.ruleType,\n value: String(rule.value),\n chargeCodeFilter: rule.chargeCodeFilter ?? '',\n chargeTypeFilter: rule.chargeTypeFilter ?? '',\n conditionAttribute: cond?.attribute ?? '',\n conditionOperator: cond?.operator ?? 'eq',\n conditionValue: cond?.value ?? '',\n sortOrder: String(rule.sortOrder),\n isActive: rule.isActive,\n }\n}\n\nexport default function PriceRuleDetailPage(props: { params?: { id?: string } }) {\n const router = useRouter()\n const urlParams = useParams()\n const ruleId = (props.params?.id ?? urlParams?.id) as string\n\n const [rule, setRule] = React.useState<PriceRule | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editing, setEditing] = React.useState(false)\n const [form, setForm] = React.useState<FormData | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [saveError, setSaveError] = React.useState<string | null>(null)\n\n const [deleting, setDeleting] = React.useState(false)\n const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false)\n\n const [offerings, setOfferings] = React.useState<ProductOffering[]>([])\n\n React.useEffect(() => {\n fetch('/api/cpq/product-offerings?pageSize=100')\n .then((r) => r.json())\n .then((data) => setOfferings(data.items ?? []))\n .catch(() => {})\n }, [])\n\n const offeringLookup = React.useMemo(() => {\n const map = new Map<string, ProductOffering>()\n for (const o of offerings) map.set(o.id, o)\n return map\n }, [offerings])\n\n const loadRule = React.useCallback(() => {\n setLoading(true)\n setError(null)\n fetch(`/api/cpq/price-rules?id=${ruleId}`)\n .then(async (r) => {\n if (!r.ok) throw new Error('Not found')\n return r.json()\n })\n .then((data: PriceRule) => {\n setRule(data)\n })\n .catch((err) => setError(err.message))\n .finally(() => setLoading(false))\n }, [ruleId])\n\n React.useEffect(() => { loadRule() }, [loadRule])\n\n function startEdit() {\n if (!rule) return\n setForm(ruleToForm(rule))\n setSaveError(null)\n setEditing(true)\n }\n\n function cancelEdit() {\n setEditing(false)\n setForm(null)\n setSaveError(null)\n }\n\n async function handleSave() {\n if (!form || !rule) return\n setSaving(true)\n setSaveError(null)\n try {\n const payload: Record<string, unknown> = {\n id: rule.id,\n name: form.name,\n ruleType: form.ruleType,\n value: Number(form.value),\n sortOrder: Number(form.sortOrder),\n isActive: form.isActive,\n productOfferingId: form.productOfferingId || null,\n }\n if (form.description) payload.description = form.description\n else payload.description = null\n if (form.chargeCodeFilter) payload.chargeCodeFilter = form.chargeCodeFilter\n else payload.chargeCodeFilter = null\n if (form.chargeTypeFilter) payload.chargeTypeFilter = form.chargeTypeFilter\n else payload.chargeTypeFilter = null\n if (form.conditionAttribute) {\n payload.applicabilityCondition = {\n attribute: form.conditionAttribute,\n operator: form.conditionOperator || 'eq',\n value: form.conditionValue,\n }\n } else {\n payload.applicabilityCondition = null\n }\n\n const res = await fetch('/api/cpq/price-rules', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const err = await res.json()\n throw new Error(err.error ?? 'Failed to update')\n }\n const updated = await res.json()\n setRule(updated)\n setEditing(false)\n setForm(null)\n } catch (err: unknown) {\n setSaveError(err instanceof Error ? err.message : 'Unknown error')\n } finally {\n setSaving(false)\n }\n }\n\n async function handleDelete() {\n setDeleting(true)\n try {\n await fetch('/api/cpq/price-rules', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: ruleId }),\n })\n router.push('/backend/cpq/price-rules')\n } catch {\n setDeleting(false)\n }\n }\n\n async function handleToggleActive() {\n if (!rule) return\n const res = await fetch('/api/cpq/price-rules', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: rule.id, isActive: !rule.isActive }),\n })\n if (res.ok) {\n const updated = await res.json()\n setRule(updated)\n }\n }\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground py-12 text-center\">Loading...</div>\n }\n\n if (error || !rule) {\n return (\n <div className=\"space-y-4 py-12 text-center\">\n <div className=\"text-sm text-destructive\">{error ?? 'Rule not found'}</div>\n <button\n onClick={() => router.push('/backend/cpq/price-rules')}\n className=\"text-sm text-primary hover:underline\"\n >\n ← Back to Price Rules\n </button>\n </div>\n )\n }\n\n const cond = rule.applicabilityCondition as { attribute?: string; operator?: string; value?: string } | null\n const offering = rule.productOfferingId ? offeringLookup.get(rule.productOfferingId) : null\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/price-rules')}\n className=\"text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n ← Back\n </button>\n <h1 className=\"text-2xl font-bold\">{rule.name}</h1>\n <Tag variant={rule.isActive ? 'success' : 'neutral'} dot>\n {rule.isActive ? 'Active' : 'Inactive'}\n </Tag>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={handleToggleActive}>\n {rule.isActive ? 'Deactivate' : 'Activate'}\n </Button>\n {!editing && (\n <button\n onClick={startEdit}\n className=\"rounded-md bg-primary px-4 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n Edit\n </button>\n )}\n <button\n onClick={() => setShowDeleteConfirm(true)}\n className=\"rounded-md border border-destructive/30 px-3 py-1.5 text-sm font-medium text-destructive hover:bg-destructive/10 transition-colors\"\n >\n Delete\n </button>\n </div>\n </div>\n\n {/* Delete confirmation */}\n {showDeleteConfirm && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 p-4 flex items-center justify-between\">\n <span className=\"text-sm\">Are you sure you want to delete <strong>{rule.name}</strong>?</span>\n <div className=\"flex gap-2\">\n <button\n onClick={handleDelete}\n disabled={deleting}\n className=\"rounded-md bg-destructive px-3 py-1.5 text-sm font-medium text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50\"\n >\n {deleting ? 'Deleting...' : 'Yes, Delete'}\n </button>\n <button\n onClick={() => setShowDeleteConfirm(false)}\n className=\"rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted/50\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n\n {/* Edit mode */}\n {editing && form ? (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold\">Edit Rule</h2>\n {saveError && <div className=\"rounded-md bg-destructive/10 p-3 text-sm text-destructive\">{saveError}</div>}\n <div className=\"grid grid-cols-2 gap-4\">\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Code</span>\n <input className=\"w-full rounded-md border bg-muted/30 px-3 py-2 text-sm\" value={rule.code} disabled />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Name</span>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Rule Type</span>\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.ruleType} onChange={(e) => setForm({ ...form, ruleType: e.target.value })}>\n {Object.entries(RULE_TYPE_LABELS).map(([k, v]) => <option key={k} value={k}>{v}</option>)}\n </select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Value</span>\n <NumberInput\n value={form.value === '' ? null : Number(form.value)}\n onChange={(n) => setForm({ ...form, value: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Sort Order</span>\n <NumberInput\n integer\n value={form.sortOrder === '' ? null : Number(form.sortOrder)}\n onChange={(n) => setForm({ ...form, sortOrder: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Description</span>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder=\"Optional\" value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Charge Type Filter</span>\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.chargeTypeFilter} onChange={(e) => setForm({ ...form, chargeTypeFilter: e.target.value })}>\n <option value=\"\">All charge types</option>\n <option value=\"nrc\">NRC only</option>\n <option value=\"mrc\">MRC only</option>\n <option value=\"usage\">Usage only</option>\n </select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Charge Code Filter</span>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder=\"e.g. setup_fee (leave empty for all)\" value={form.chargeCodeFilter} onChange={(e) => setForm({ ...form, chargeCodeFilter: e.target.value })} />\n </label>\n <label className=\"space-y-1 col-span-2\">\n <span className=\"text-sm font-medium\">Product Offering</span>\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.productOfferingId} onChange={(e) => setForm({ ...form, productOfferingId: e.target.value })}>\n <option value=\"\">Global (all products)</option>\n {offerings.map((o) => <option key={o.id} value={o.id}>{o.name} ({o.code})</option>)}\n </select>\n </label>\n <div className=\"col-span-2 space-y-1\">\n <span className=\"text-sm font-medium\">Applicability Condition</span>\n <span className=\"ml-2 text-xs text-muted-foreground\">(optional)</span>\n <div className=\"grid grid-cols-3 gap-2\">\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder=\"Attribute (e.g. port_size)\" value={form.conditionAttribute} onChange={(e) => setForm({ ...form, conditionAttribute: e.target.value })} />\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.conditionOperator} onChange={(e) => setForm({ ...form, conditionOperator: e.target.value })}>\n <option value=\"eq\">equals (=)</option>\n <option value=\"neq\">not equals (≠)</option>\n </select>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder=\"Value\" value={form.conditionValue} onChange={(e) => setForm({ ...form, conditionValue: e.target.value })} />\n </div>\n </div>\n </div>\n <label className=\"flex items-center gap-2 text-sm\">\n <input type=\"checkbox\" checked={form.isActive} onChange={(e) => setForm({ ...form, isActive: e.target.checked })} />\n Active\n </label>\n <div className=\"flex gap-2\">\n <button onClick={handleSave} disabled={saving} className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\">\n {saving ? 'Saving...' : 'Save Changes'}\n </button>\n <button onClick={cancelEdit} className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted/50\">\n Cancel\n </button>\n </div>\n </div>\n ) : (\n /* Read-only view */\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Main info */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-sm font-semibold text-muted-foreground uppercase tracking-wider\">Rule Configuration</h2>\n <dl className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-muted-foreground\">Code</dt>\n <dd className=\"text-sm font-mono\">{rule.code}</dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">Rule Type</dt>\n <dd className=\"text-sm font-medium\">{RULE_TYPE_LABELS[rule.ruleType] ?? rule.ruleType}</dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">Value</dt>\n <dd className=\"text-sm font-mono font-medium\">\n {rule.ruleType.includes('percent') ? `${rule.value}%` : rule.ruleType === 'price_override' ? `= $${rule.value}` : `$${rule.value}`}\n </dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">Sort Order</dt>\n <dd className=\"text-sm font-mono\">{rule.sortOrder}</dd>\n </div>\n {rule.description && (\n <div className=\"border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground mb-1\">Description</dt>\n <dd className=\"text-sm\">{rule.description}</dd>\n </div>\n )}\n </dl>\n </div>\n\n {/* Scope & Filters */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-sm font-semibold text-muted-foreground uppercase tracking-wider\">Scope & Filters</h2>\n <dl className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-muted-foreground\">Scope</dt>\n <dd className=\"text-sm\">\n {offering ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"inline-block w-2 h-2 rounded-full bg-status-info-icon\" />\n {offering.name}\n <span className=\"text-muted-foreground font-mono text-xs\">({offering.code})</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"inline-block w-2 h-2 rounded-full bg-muted-foreground\" />\n Global (all offerings)\n </span>\n )}\n </dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">Charge Type</dt>\n <dd className=\"text-sm\">{rule.chargeTypeFilter ? rule.chargeTypeFilter.toUpperCase() : 'All types'}</dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">Charge Code</dt>\n <dd className=\"text-sm font-mono\">{rule.chargeCodeFilter ?? 'All charges'}</dd>\n </div>\n <div className=\"border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground mb-1\">Applicability Condition</dt>\n <dd className=\"text-sm\">\n {cond?.attribute ? (\n <code className=\"rounded bg-muted px-2 py-0.5 text-xs\">\n {cond.attribute} {cond.operator === 'neq' ? '\u2260' : '='} {cond.value ?? '\"\"'}\n </code>\n ) : (\n <span className=\"text-muted-foreground\">No condition (always applies)</span>\n )}\n </dd>\n </div>\n </dl>\n </div>\n\n {/* Metadata */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4 lg:col-span-2\">\n <h2 className=\"text-sm font-semibold text-muted-foreground uppercase tracking-wider\">Metadata</h2>\n <dl className=\"flex gap-8 text-sm\">\n <div>\n <dt className=\"text-muted-foreground\">Created</dt>\n <dd>{new Date(rule.createdAt).toLocaleString()}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">Updated</dt>\n <dd>{new Date(rule.updatedAt).toLocaleString()}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">ID</dt>\n <dd className=\"font-mono text-xs\">{rule.id}</dd>\n </div>\n </dl>\n </div>\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter, useParams } from 'next/navigation'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { NumberInput } from '../../../../components/NumberInput'\nimport { buildRuleTypeLabels } from '../PriceRuleForm'\n\ntype PriceRule = {\n id: string\n code: string\n name: string\n description: string | null\n productOfferingId: string | null\n ruleType: string\n value: number\n chargeCodeFilter: string | null\n chargeTypeFilter: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n createdAt: string\n updatedAt: string\n}\n\ntype ProductOffering = { id: string; code: string; name: string }\n\ntype FormData = {\n name: string\n description: string\n productOfferingId: string\n ruleType: string\n value: string\n chargeCodeFilter: string\n chargeTypeFilter: string\n conditionAttribute: string\n conditionOperator: string\n conditionValue: string\n sortOrder: string\n isActive: boolean\n}\n\nfunction ruleToForm(rule: PriceRule): FormData {\n const cond = rule.applicabilityCondition as { attribute?: string; operator?: string; value?: string } | null\n return {\n name: rule.name,\n description: rule.description ?? '',\n productOfferingId: rule.productOfferingId ?? '',\n ruleType: rule.ruleType,\n value: String(rule.value),\n chargeCodeFilter: rule.chargeCodeFilter ?? '',\n chargeTypeFilter: rule.chargeTypeFilter ?? '',\n conditionAttribute: cond?.attribute ?? '',\n conditionOperator: cond?.operator ?? 'eq',\n conditionValue: cond?.value ?? '',\n sortOrder: String(rule.sortOrder),\n isActive: rule.isActive,\n }\n}\n\nexport default function PriceRuleDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const ruleTypeLabels = React.useMemo(() => buildRuleTypeLabels(t), [t])\n const router = useRouter()\n const urlParams = useParams()\n const ruleId = (props.params?.id ?? urlParams?.id) as string\n\n const [rule, setRule] = React.useState<PriceRule | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editing, setEditing] = React.useState(false)\n const [form, setForm] = React.useState<FormData | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [saveError, setSaveError] = React.useState<string | null>(null)\n\n const [deleting, setDeleting] = React.useState(false)\n const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false)\n\n const [offerings, setOfferings] = React.useState<ProductOffering[]>([])\n\n React.useEffect(() => {\n fetch('/api/cpq/product-offerings?pageSize=100')\n .then((r) => r.json())\n .then((data) => setOfferings(data.items ?? []))\n .catch(() => {})\n }, [])\n\n const offeringLookup = React.useMemo(() => {\n const map = new Map<string, ProductOffering>()\n for (const o of offerings) map.set(o.id, o)\n return map\n }, [offerings])\n\n const loadRule = React.useCallback(() => {\n setLoading(true)\n setError(null)\n fetch(`/api/cpq/price-rules?id=${ruleId}`)\n .then(async (r) => {\n if (!r.ok) throw new Error(t('cpq.priceRules.detail.notFound', 'Not found'))\n return r.json()\n })\n .then((data: PriceRule) => {\n setRule(data)\n })\n .catch((err) => setError(err.message))\n .finally(() => setLoading(false))\n }, [ruleId, t])\n\n React.useEffect(() => { loadRule() }, [loadRule])\n\n function startEdit() {\n if (!rule) return\n setForm(ruleToForm(rule))\n setSaveError(null)\n setEditing(true)\n }\n\n function cancelEdit() {\n setEditing(false)\n setForm(null)\n setSaveError(null)\n }\n\n async function handleSave() {\n if (!form || !rule) return\n setSaving(true)\n setSaveError(null)\n try {\n const payload: Record<string, unknown> = {\n id: rule.id,\n name: form.name,\n ruleType: form.ruleType,\n value: Number(form.value),\n sortOrder: Number(form.sortOrder),\n isActive: form.isActive,\n productOfferingId: form.productOfferingId || null,\n }\n if (form.description) payload.description = form.description\n else payload.description = null\n if (form.chargeCodeFilter) payload.chargeCodeFilter = form.chargeCodeFilter\n else payload.chargeCodeFilter = null\n if (form.chargeTypeFilter) payload.chargeTypeFilter = form.chargeTypeFilter\n else payload.chargeTypeFilter = null\n if (form.conditionAttribute) {\n payload.applicabilityCondition = {\n attribute: form.conditionAttribute,\n operator: form.conditionOperator || 'eq',\n value: form.conditionValue,\n }\n } else {\n payload.applicabilityCondition = null\n }\n\n const res = await fetch('/api/cpq/price-rules', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const err = await res.json()\n throw new Error(err.error ?? t('cpq.priceRules.errors.updateFailed', 'Failed to update'))\n }\n const updated = await res.json()\n setRule(updated)\n setEditing(false)\n setForm(null)\n } catch (err: unknown) {\n setSaveError(err instanceof Error ? err.message : t('cpq.priceRules.errors.unknown', 'Unknown error'))\n } finally {\n setSaving(false)\n }\n }\n\n async function handleDelete() {\n setDeleting(true)\n try {\n await fetch('/api/cpq/price-rules', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: ruleId }),\n })\n router.push('/backend/cpq/price-rules')\n } catch {\n setDeleting(false)\n }\n }\n\n async function handleToggleActive() {\n if (!rule) return\n const res = await fetch('/api/cpq/price-rules', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: rule.id, isActive: !rule.isActive }),\n })\n if (res.ok) {\n const updated = await res.json()\n setRule(updated)\n }\n }\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground py-12 text-center\">{t('cpq.common.loading', 'Loading...')}</div>\n }\n\n if (error || !rule) {\n return (\n <div className=\"space-y-4 py-12 text-center\">\n <div className=\"text-sm text-destructive\">{error ?? t('cpq.priceRules.detail.ruleNotFound', 'Rule not found')}</div>\n <button\n onClick={() => router.push('/backend/cpq/price-rules')}\n className=\"text-sm text-primary hover:underline\"\n >\n \u2190 {t('cpq.priceRules.detail.backToList', 'Back to Price Rules')}\n </button>\n </div>\n )\n }\n\n const cond = rule.applicabilityCondition as { attribute?: string; operator?: string; value?: string } | null\n const offering = rule.productOfferingId ? offeringLookup.get(rule.productOfferingId) : null\n // `{name}` is left unresolved so the rule name can be rendered in <strong>.\n const deleteConfirmParts = t('cpq.priceRules.detail.deleteConfirm', 'Are you sure you want to delete {name}?').split('{name}')\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/price-rules')}\n className=\"text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n \u2190 {t('cpq.common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">{rule.name}</h1>\n <Tag variant={rule.isActive ? 'success' : 'neutral'} dot>\n {rule.isActive ? t('cpq.common.active', 'Active') : t('cpq.common.inactive', 'Inactive')}\n </Tag>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={handleToggleActive}>\n {rule.isActive\n ? t('cpq.priceRules.detail.deactivate', 'Deactivate')\n : t('cpq.priceRules.detail.activate', 'Activate')}\n </Button>\n {!editing && (\n <button\n onClick={startEdit}\n className=\"rounded-md bg-primary px-4 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.common.edit', 'Edit')}\n </button>\n )}\n <button\n onClick={() => setShowDeleteConfirm(true)}\n className=\"rounded-md border border-destructive/30 px-3 py-1.5 text-sm font-medium text-destructive hover:bg-destructive/10 transition-colors\"\n >\n {t('cpq.common.delete', 'Delete')}\n </button>\n </div>\n </div>\n\n {/* Delete confirmation */}\n {showDeleteConfirm && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 p-4 flex items-center justify-between\">\n <span className=\"text-sm\">\n {deleteConfirmParts[0]}\n <strong>{rule.name}</strong>\n {deleteConfirmParts[1]}\n </span>\n <div className=\"flex gap-2\">\n <button\n onClick={handleDelete}\n disabled={deleting}\n className=\"rounded-md bg-destructive px-3 py-1.5 text-sm font-medium text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50\"\n >\n {deleting\n ? t('cpq.priceRules.detail.deleting', 'Deleting...')\n : t('cpq.priceRules.detail.confirmDelete', 'Yes, Delete')}\n </button>\n <button\n onClick={() => setShowDeleteConfirm(false)}\n className=\"rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted/50\"\n >\n {t('cpq.common.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n )}\n\n {/* Edit mode */}\n {editing && form ? (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold\">{t('cpq.priceRules.form.editTitle', 'Edit Rule')}</h2>\n {saveError && <div className=\"rounded-md bg-destructive/10 p-3 text-sm text-destructive\">{saveError}</div>}\n <div className=\"grid grid-cols-2 gap-4\">\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.code', 'Code')}</span>\n <input className=\"w-full rounded-md border bg-muted/30 px-3 py-2 text-sm\" value={rule.code} disabled />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.name', 'Name')}</span>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.ruleType', 'Rule Type')}</span>\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.ruleType} onChange={(e) => setForm({ ...form, ruleType: e.target.value })}>\n {Object.entries(ruleTypeLabels).map(([k, v]) => <option key={k} value={k}>{v}</option>)}\n </select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.value', 'Value')}</span>\n <NumberInput\n value={form.value === '' ? null : Number(form.value)}\n onChange={(n) => setForm({ ...form, value: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.sortOrder', 'Sort Order')}</span>\n <NumberInput\n integer\n value={form.sortOrder === '' ? null : Number(form.sortOrder)}\n onChange={(n) => setForm({ ...form, sortOrder: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.description', 'Description')}</span>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder={t('cpq.priceRules.form.descriptionPlaceholder', 'Optional')} value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.chargeTypeFilter', 'Charge Type Filter')}</span>\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.chargeTypeFilter} onChange={(e) => setForm({ ...form, chargeTypeFilter: e.target.value })}>\n <option value=\"\">{t('cpq.priceRules.form.allChargeTypes', 'All charge types')}</option>\n <option value=\"nrc\">{t('cpq.priceRules.form.nrcOnly', 'NRC only')}</option>\n <option value=\"mrc\">{t('cpq.priceRules.form.mrcOnly', 'MRC only')}</option>\n <option value=\"usage\">{t('cpq.priceRules.form.usageOnly', 'Usage only')}</option>\n </select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.chargeCodeFilter', 'Charge Code Filter')}</span>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder={t('cpq.priceRules.form.chargeCodeFilterPlaceholder', 'e.g. setup_fee (leave empty for all)')} value={form.chargeCodeFilter} onChange={(e) => setForm({ ...form, chargeCodeFilter: e.target.value })} />\n </label>\n <label className=\"space-y-1 col-span-2\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.productOffering', 'Product Offering')}</span>\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.productOfferingId} onChange={(e) => setForm({ ...form, productOfferingId: e.target.value })}>\n <option value=\"\">{t('cpq.priceRules.form.globalAllProducts', 'Global (all products)')}</option>\n {offerings.map((o) => <option key={o.id} value={o.id}>{o.name} ({o.code})</option>)}\n </select>\n </label>\n <div className=\"col-span-2 space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.applicabilityCondition', 'Applicability Condition')}</span>\n <span className=\"ml-2 text-xs text-muted-foreground\">{t('cpq.priceRules.form.optionalHint', '(optional)')}</span>\n <div className=\"grid grid-cols-3 gap-2\">\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder={t('cpq.priceRules.form.conditionAttributePlaceholder', 'Attribute (e.g. port_size)')} value={form.conditionAttribute} onChange={(e) => setForm({ ...form, conditionAttribute: e.target.value })} />\n <select className=\"w-full rounded-md border px-3 py-2 text-sm\" value={form.conditionOperator} onChange={(e) => setForm({ ...form, conditionOperator: e.target.value })}>\n <option value=\"eq\">{t('cpq.priceRules.form.operatorEq', 'equals (=)')}</option>\n <option value=\"neq\">{t('cpq.priceRules.form.operatorNeq', 'not equals (\u2260)')}</option>\n </select>\n <input className=\"w-full rounded-md border px-3 py-2 text-sm\" placeholder={t('cpq.priceRules.form.conditionValuePlaceholderShort', 'Value')} value={form.conditionValue} onChange={(e) => setForm({ ...form, conditionValue: e.target.value })} />\n </div>\n </div>\n </div>\n <label className=\"flex items-center gap-2 text-sm\">\n <input type=\"checkbox\" checked={form.isActive} onChange={(e) => setForm({ ...form, isActive: e.target.checked })} />\n {t('cpq.common.active', 'Active')}\n </label>\n <div className=\"flex gap-2\">\n <button onClick={handleSave} disabled={saving} className=\"rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\">\n {saving ? t('cpq.common.saving', 'Saving...') : t('cpq.priceRules.detail.saveChanges', 'Save Changes')}\n </button>\n <button onClick={cancelEdit} className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted/50\">\n {t('cpq.common.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n ) : (\n /* Read-only view */\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Main info */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-sm font-semibold text-muted-foreground uppercase tracking-wider\">{t('cpq.priceRules.detail.ruleConfiguration', 'Rule Configuration')}</h2>\n <dl className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.code', 'Code')}</dt>\n <dd className=\"text-sm font-mono\">{rule.code}</dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.ruleType', 'Rule Type')}</dt>\n <dd className=\"text-sm font-medium\">{ruleTypeLabels[rule.ruleType] ?? rule.ruleType}</dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.value', 'Value')}</dt>\n <dd className=\"text-sm font-mono font-medium\">\n {rule.ruleType.includes('percent') ? `${rule.value}%` : rule.ruleType === 'price_override' ? `= $${rule.value}` : `$${rule.value}`}\n </dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.sortOrder', 'Sort Order')}</dt>\n <dd className=\"text-sm font-mono\">{rule.sortOrder}</dd>\n </div>\n {rule.description && (\n <div className=\"border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground mb-1\">{t('cpq.priceRules.detail.description', 'Description')}</dt>\n <dd className=\"text-sm\">{rule.description}</dd>\n </div>\n )}\n </dl>\n </div>\n\n {/* Scope & Filters */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-sm font-semibold text-muted-foreground uppercase tracking-wider\">{t('cpq.priceRules.detail.scopeAndFilters', 'Scope & Filters')}</h2>\n <dl className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.scope', 'Scope')}</dt>\n <dd className=\"text-sm\">\n {offering ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"inline-block w-2 h-2 rounded-full bg-status-info-icon\" />\n {offering.name}\n <span className=\"text-muted-foreground font-mono text-xs\">({offering.code})</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"inline-block w-2 h-2 rounded-full bg-muted-foreground\" />\n {t('cpq.priceRules.detail.globalAllOfferings', 'Global (all offerings)')}\n </span>\n )}\n </dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.chargeType', 'Charge Type')}</dt>\n <dd className=\"text-sm\">{rule.chargeTypeFilter ? rule.chargeTypeFilter.toUpperCase() : t('cpq.priceRules.detail.allTypes', 'All types')}</dd>\n </div>\n <div className=\"flex justify-between border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground\">{t('cpq.priceRules.detail.chargeCode', 'Charge Code')}</dt>\n <dd className=\"text-sm font-mono\">{rule.chargeCodeFilter ?? t('cpq.priceRules.detail.allCharges', 'All charges')}</dd>\n </div>\n <div className=\"border-t pt-3\">\n <dt className=\"text-sm text-muted-foreground mb-1\">{t('cpq.priceRules.detail.applicabilityCondition', 'Applicability Condition')}</dt>\n <dd className=\"text-sm\">\n {cond?.attribute ? (\n <code className=\"rounded bg-muted px-2 py-0.5 text-xs\">\n {cond.attribute} {cond.operator === 'neq' ? '\u2260' : '='} {cond.value ?? '\"\"'}\n </code>\n ) : (\n <span className=\"text-muted-foreground\">{t('cpq.priceRules.detail.noCondition', 'No condition (always applies)')}</span>\n )}\n </dd>\n </div>\n </dl>\n </div>\n\n {/* Metadata */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4 lg:col-span-2\">\n <h2 className=\"text-sm font-semibold text-muted-foreground uppercase tracking-wider\">{t('cpq.priceRules.detail.metadata', 'Metadata')}</h2>\n <dl className=\"flex gap-8 text-sm\">\n <div>\n <dt className=\"text-muted-foreground\">{t('cpq.priceRules.detail.created', 'Created')}</dt>\n <dd>{new Date(rule.createdAt).toLocaleString()}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">{t('cpq.priceRules.detail.updated', 'Updated')}</dt>\n <dd>{new Date(rule.updatedAt).toLocaleString()}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">{t('cpq.priceRules.detail.id', 'ID')}</dt>\n <dd className=\"font-mono text-xs\">{rule.id}</dd>\n </div>\n </dl>\n </div>\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,7 @@ const metadata = {
|
|
|
4
4
|
navHidden: true,
|
|
5
5
|
breadcrumb: [
|
|
6
6
|
{ label: "Price Rules", labelKey: "cpq.priceRules.list.title", href: "/backend/cpq/price-rules" },
|
|
7
|
-
{ label: "Rule Detail" }
|
|
7
|
+
{ label: "Rule Detail", labelKey: "cpq.priceRules.detail.breadcrumb" }
|
|
8
8
|
]
|
|
9
9
|
};
|
|
10
10
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/cpq/backend/cpq/price-rules/%5Bid%5D/page.meta.ts"],
|
|
4
|
-
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['cpq.pricing.view'],\n navHidden: true,\n breadcrumb: [\n { label: 'Price Rules', labelKey: 'cpq.priceRules.list.title', href: '/backend/cpq/price-rules' },\n { label: 'Rule Detail' },\n ],\n} as const\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,kBAAkB;AAAA,EACpC,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,eAAe,UAAU,6BAA6B,MAAM,2BAA2B;AAAA,IAChG,EAAE,OAAO,
|
|
4
|
+
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['cpq.pricing.view'],\n navHidden: true,\n breadcrumb: [\n { label: 'Price Rules', labelKey: 'cpq.priceRules.list.title', href: '/backend/cpq/price-rules' },\n { label: 'Rule Detail', labelKey: 'cpq.priceRules.detail.breadcrumb' },\n ],\n} as const\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,kBAAkB;AAAA,EACpC,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,eAAe,UAAU,6BAA6B,MAAM,2BAA2B;AAAA,IAChG,EAAE,OAAO,eAAe,UAAU,mCAAmC;AAAA,EACvE;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,7 +8,7 @@ import { Tag } from "@open-mercato/ui/primitives/tag";
|
|
|
8
8
|
import { CpqListView, useCpqListData } from "../../../components/CpqListView.js";
|
|
9
9
|
import {
|
|
10
10
|
PriceRuleForm,
|
|
11
|
-
|
|
11
|
+
buildRuleTypeLabels,
|
|
12
12
|
emptyPriceRuleForm,
|
|
13
13
|
priceRuleFormToPayload
|
|
14
14
|
} from "./PriceRuleForm.js";
|
|
@@ -48,17 +48,18 @@ function PriceRulesPage() {
|
|
|
48
48
|
fetch("/api/cpq/product-offerings?pageSize=100").then((r) => r.json()).then((d) => setOfferings(d.items ?? [])).catch(() => {
|
|
49
49
|
});
|
|
50
50
|
}, []);
|
|
51
|
+
const ruleTypeLabels = React.useMemo(() => buildRuleTypeLabels(t), [t]);
|
|
51
52
|
const ruleTypeOptions = React.useMemo(
|
|
52
|
-
() => Object.entries(
|
|
53
|
-
[]
|
|
53
|
+
() => Object.entries(ruleTypeLabels).map(([value, label]) => ({ value, label })),
|
|
54
|
+
[ruleTypeLabels]
|
|
54
55
|
);
|
|
55
56
|
const chargeTypeOptions = React.useMemo(
|
|
56
57
|
() => [
|
|
57
|
-
{ value: "nrc", label: "NRC" },
|
|
58
|
-
{ value: "mrc", label: "MRC" },
|
|
59
|
-
{ value: "usage", label: "Usage" }
|
|
58
|
+
{ value: "nrc", label: t("cpq.priceRules.chargeTypes.nrc", "NRC") },
|
|
59
|
+
{ value: "mrc", label: t("cpq.priceRules.chargeTypes.mrc", "MRC") },
|
|
60
|
+
{ value: "usage", label: t("cpq.priceRules.chargeTypes.usage", "Usage") }
|
|
60
61
|
],
|
|
61
|
-
[]
|
|
62
|
+
[t]
|
|
62
63
|
);
|
|
63
64
|
const filters = React.useMemo(
|
|
64
65
|
() => [
|
|
@@ -104,16 +105,18 @@ function PriceRulesPage() {
|
|
|
104
105
|
});
|
|
105
106
|
if (!res.ok) {
|
|
106
107
|
const err = await res.json();
|
|
107
|
-
throw new Error(
|
|
108
|
+
throw new Error(
|
|
109
|
+
err.details ? JSON.stringify(err.details) : err.error ?? t("cpq.priceRules.errors.createFailed", "Failed to create")
|
|
110
|
+
);
|
|
108
111
|
}
|
|
109
112
|
setShowForm(false);
|
|
110
113
|
data.reload();
|
|
111
114
|
} catch (err) {
|
|
112
|
-
setError(err instanceof Error ? err.message : "Unknown error");
|
|
115
|
+
setError(err instanceof Error ? err.message : t("cpq.priceRules.errors.unknown", "Unknown error"));
|
|
113
116
|
} finally {
|
|
114
117
|
setSaving(false);
|
|
115
118
|
}
|
|
116
|
-
}, [data, form]);
|
|
119
|
+
}, [data, form, t]);
|
|
117
120
|
const columns = React.useMemo(
|
|
118
121
|
() => [
|
|
119
122
|
{
|
|
@@ -134,7 +137,7 @@ function PriceRulesPage() {
|
|
|
134
137
|
{
|
|
135
138
|
accessorKey: "ruleType",
|
|
136
139
|
header: t("cpq.priceRules.table.type", "Type"),
|
|
137
|
-
cell: ({ row }) => /* @__PURE__ */ jsx("span", { children:
|
|
140
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("span", { children: ruleTypeLabels[row.original.ruleType] ?? row.original.ruleType })
|
|
138
141
|
},
|
|
139
142
|
{
|
|
140
143
|
id: "value",
|
|
@@ -144,7 +147,7 @@ function PriceRulesPage() {
|
|
|
144
147
|
{
|
|
145
148
|
id: "scope",
|
|
146
149
|
header: t("cpq.priceRules.table.scope", "Scope"),
|
|
147
|
-
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-xs", children: row.original.productOfferingId ? row.original.productOfferingName ?? "Product-scoped" : "Global" })
|
|
150
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-xs", children: row.original.productOfferingId ? row.original.productOfferingName ?? t("cpq.priceRules.scope.productScoped", "Product-scoped") : t("cpq.priceRules.scope.global", "Global") })
|
|
148
151
|
},
|
|
149
152
|
{
|
|
150
153
|
id: "filter",
|
|
@@ -166,10 +169,10 @@ function PriceRulesPage() {
|
|
|
166
169
|
{
|
|
167
170
|
accessorKey: "isActive",
|
|
168
171
|
header: t("cpq.priceRules.table.status", "Status"),
|
|
169
|
-
cell: ({ row }) => /* @__PURE__ */ jsx(Tag, { variant: row.original.isActive ? "success" : "neutral", dot: true, children: row.original.isActive ? "Active" : "Inactive" })
|
|
172
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(Tag, { variant: row.original.isActive ? "success" : "neutral", dot: true, children: row.original.isActive ? t("cpq.common.active", "Active") : t("cpq.common.inactive", "Inactive") })
|
|
170
173
|
}
|
|
171
174
|
],
|
|
172
|
-
[t]
|
|
175
|
+
[ruleTypeLabels, t]
|
|
173
176
|
);
|
|
174
177
|
return /* @__PURE__ */ jsx(
|
|
175
178
|
CpqListView,
|
|
@@ -201,7 +204,7 @@ function PriceRulesPage() {
|
|
|
201
204
|
onCancel: () => setShowForm(false)
|
|
202
205
|
}
|
|
203
206
|
) : null,
|
|
204
|
-
emptyState: /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: 'No price rules found. Click "Create Rule" to add one.' })
|
|
207
|
+
emptyState: /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("cpq.priceRules.empty", 'No price rules found. Click "Create Rule" to add one.') })
|
|
205
208
|
}
|
|
206
209
|
);
|
|
207
210
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/cpq/backend/cpq/price-rules/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { CpqListView, useCpqListData } from '../../../components/CpqListView'\nimport {\n PriceRuleForm,\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { CpqListView, useCpqListData } from '../../../components/CpqListView'\nimport {\n PriceRuleForm,\n buildRuleTypeLabels,\n emptyPriceRuleForm,\n priceRuleFormToPayload,\n type PriceRule,\n type PriceRuleFormData,\n type ProductOffering,\n} from './PriceRuleForm'\n\nconst PAGE_SIZE = 50\n\nfunction buildFilterParams(values: FilterValues, params: URLSearchParams) {\n if (typeof values.ruleType === 'string' && values.ruleType) {\n params.set('ruleType', values.ruleType)\n }\n if (typeof values.chargeTypeFilter === 'string' && values.chargeTypeFilter) {\n params.set('chargeTypeFilter', values.chargeTypeFilter)\n }\n if (values.globalOnly === true) params.set('globalOnly', 'true')\n if (values.isActive === true) params.set('isActive', 'true')\n if (values.isActive === false) params.set('isActive', 'false')\n}\n\nfunction formatValue(rule: PriceRule) {\n if (rule.ruleType.includes('percent')) return `${rule.value}%`\n if (rule.ruleType === 'price_override') return `= ${rule.value}`\n return `${rule.value}`\n}\n\nexport default function PriceRulesPage() {\n const t = useT()\n const router = useRouter()\n\n const data = useCpqListData<PriceRule>({\n endpoint: '/api/cpq/price-rules',\n pageSize: PAGE_SIZE,\n initialSorting: [{ id: 'sortOrder', desc: false }],\n buildFilterParams,\n loadErrorMessage: t('cpq.priceRules.list.error.load', 'Failed to load price rules'),\n })\n\n const [showForm, setShowForm] = React.useState(false)\n const [form, setForm] = React.useState<PriceRuleFormData>(emptyPriceRuleForm)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [offerings, setOfferings] = React.useState<ProductOffering[]>([])\n\n React.useEffect(() => {\n fetch('/api/cpq/product-offerings?pageSize=100')\n .then((r) => r.json())\n .then((d) => setOfferings(d.items ?? []))\n .catch(() => {})\n }, [])\n\n const ruleTypeLabels = React.useMemo(() => buildRuleTypeLabels(t), [t])\n\n const ruleTypeOptions = React.useMemo(\n () => Object.entries(ruleTypeLabels).map(([value, label]) => ({ value, label })),\n [ruleTypeLabels],\n )\n\n const chargeTypeOptions = React.useMemo(\n () => [\n { value: 'nrc', label: t('cpq.priceRules.chargeTypes.nrc', 'NRC') },\n { value: 'mrc', label: t('cpq.priceRules.chargeTypes.mrc', 'MRC') },\n { value: 'usage', label: t('cpq.priceRules.chargeTypes.usage', 'Usage') },\n ],\n [t],\n )\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'ruleType',\n label: t('cpq.priceRules.filters.ruleType', 'Rule Type'),\n type: 'select',\n options: ruleTypeOptions,\n },\n {\n id: 'chargeTypeFilter',\n label: t('cpq.priceRules.filters.chargeType', 'Charge Type'),\n type: 'select',\n options: chargeTypeOptions,\n },\n {\n id: 'globalOnly',\n label: t('cpq.priceRules.filters.globalOnly', 'Global only'),\n type: 'checkbox',\n },\n {\n id: 'isActive',\n label: t('cpq.priceRules.filters.isActive', 'Active'),\n type: 'checkbox',\n },\n ],\n [chargeTypeOptions, ruleTypeOptions, t],\n )\n\n const openCreate = React.useCallback(() => {\n setForm(emptyPriceRuleForm)\n setError(null)\n setShowForm(true)\n }, [])\n\n const handleSave = React.useCallback(async () => {\n setSaving(true)\n setError(null)\n try {\n const payload = priceRuleFormToPayload(form)\n const res = await fetch('/api/cpq/price-rules', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const err = await res.json()\n throw new Error(\n err.details\n ? JSON.stringify(err.details)\n : err.error ?? t('cpq.priceRules.errors.createFailed', 'Failed to create'),\n )\n }\n setShowForm(false)\n data.reload()\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : t('cpq.priceRules.errors.unknown', 'Unknown error'))\n } finally {\n setSaving(false)\n }\n }, [data, form, t])\n\n const columns = React.useMemo<ColumnDef<PriceRule>[]>(\n () => [\n {\n accessorKey: 'sortOrder',\n header: t('cpq.priceRules.table.order', 'Order'),\n cell: ({ row }) => <span className=\"text-muted-foreground\">{row.original.sortOrder}</span>,\n },\n {\n accessorKey: 'name',\n header: t('cpq.priceRules.table.name', 'Name'),\n cell: ({ row }) => <span className=\"font-medium\">{row.original.name}</span>,\n },\n {\n accessorKey: 'code',\n header: t('cpq.priceRules.table.code', 'Code'),\n cell: ({ row }) => <span className=\"font-mono text-xs\">{row.original.code}</span>,\n },\n {\n accessorKey: 'ruleType',\n header: t('cpq.priceRules.table.type', 'Type'),\n cell: ({ row }) => (\n <span>{ruleTypeLabels[row.original.ruleType] ?? row.original.ruleType}</span>\n ),\n },\n {\n id: 'value',\n header: t('cpq.priceRules.table.value', 'Value'),\n cell: ({ row }) => <span className=\"font-mono\">{formatValue(row.original)}</span>,\n },\n {\n id: 'scope',\n header: t('cpq.priceRules.table.scope', 'Scope'),\n cell: ({ row }) => (\n <span className=\"text-xs\">\n {row.original.productOfferingId\n ? row.original.productOfferingName ??\n t('cpq.priceRules.scope.productScoped', 'Product-scoped')\n : t('cpq.priceRules.scope.global', 'Global')}\n </span>\n ),\n },\n {\n id: 'filter',\n header: t('cpq.priceRules.table.filter', 'Filter'),\n cell: ({ row }) => {\n const rule = row.original\n const parts: string[] = []\n if (rule.chargeTypeFilter) parts.push(rule.chargeTypeFilter)\n if (rule.chargeCodeFilter) parts.push(rule.chargeCodeFilter)\n const cond = rule.applicabilityCondition as\n | { attribute?: string; operator?: string; value?: string }\n | null\n if (cond?.attribute) {\n const op = cond.operator === 'neq' ? '\u2260' : '='\n parts.push(`${cond.attribute} ${op} ${cond.value ?? '\"\"'}`)\n }\n return (\n <span className=\"text-xs text-muted-foreground\">\n {parts.length > 0 ? parts.join(' / ') : '\u2014'}\n </span>\n )\n },\n meta: { truncate: true, maxWidth: 240 },\n },\n {\n accessorKey: 'isActive',\n header: t('cpq.priceRules.table.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={row.original.isActive ? 'success' : 'neutral'} dot>\n {row.original.isActive\n ? t('cpq.common.active', 'Active')\n : t('cpq.common.inactive', 'Inactive')}\n </Tag>\n ),\n },\n ],\n [ruleTypeLabels, t],\n )\n\n return (\n <CpqListView<PriceRule>\n title={t('cpq.priceRules.list.title', 'Price Rules')}\n tableId=\"cpq.price-rules.list\"\n data={data}\n columns={columns}\n filters={filters}\n pageSize={PAGE_SIZE}\n searchPlaceholder={t('cpq.priceRules.search.placeholder', 'Search price rules...')}\n actions={\n <Button type=\"button\" onClick={openCreate}>\n {t('cpq.priceRules.create', 'Create Rule')}\n </Button>\n }\n crud={{\n endpoint: '/api/cpq/price-rules',\n entityName: t('cpq.priceRules.entityName', 'price rule'),\n editHref: (row) => `/backend/cpq/price-rules/${row.id}`,\n }}\n onRowClick={(row) => router.push(`/backend/cpq/price-rules/${row.id}`)}\n toolbarContent={\n showForm ? (\n <PriceRuleForm\n editingId={null}\n form={form}\n onFormChange={setForm}\n offerings={offerings}\n saving={saving}\n error={error}\n onSave={handleSave}\n onCancel={() => setShowForm(false)}\n />\n ) : null\n }\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t('cpq.priceRules.empty', 'No price rules found. Click \"Create Rule\" to add one.')}\n </div>\n }\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -12,11 +12,13 @@ import {
|
|
|
12
12
|
SelectValue
|
|
13
13
|
} from "@open-mercato/ui/primitives/select";
|
|
14
14
|
import { Trash2 } from "lucide-react";
|
|
15
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
15
16
|
function EntriesEditor({
|
|
16
17
|
table,
|
|
17
18
|
initialEntries,
|
|
18
19
|
onSaved
|
|
19
20
|
}) {
|
|
21
|
+
const t = useT();
|
|
20
22
|
const [drafts, setDrafts] = React.useState(
|
|
21
23
|
() => initialEntries.map((e) => ({ ...e, _state: null, _localId: e.id }))
|
|
22
24
|
);
|
|
@@ -87,7 +89,7 @@ function EntriesEditor({
|
|
|
87
89
|
});
|
|
88
90
|
if (!res.ok) {
|
|
89
91
|
const body = await res.json().catch(() => ({}));
|
|
90
|
-
return { ok: false, error: body.error ?? "Failed to create entries" };
|
|
92
|
+
return { ok: false, error: body.error ?? t("cpq.pricing.entries.errors.createFailed", "Failed to create entries") };
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
const mods = drafts.filter((d) => d._state === "modified");
|
|
@@ -107,7 +109,7 @@ function EntriesEditor({
|
|
|
107
109
|
});
|
|
108
110
|
if (!res.ok) {
|
|
109
111
|
const body = await res.json().catch(() => ({}));
|
|
110
|
-
return { ok: false, error: body.error ??
|
|
112
|
+
return { ok: false, error: body.error ?? t("cpq.pricing.entries.errors.updateFailed", "Failed to update entry {id}", { id: d.id }) };
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
const dels = drafts.filter((d) => d._state === "deleted");
|
|
@@ -119,12 +121,12 @@ function EntriesEditor({
|
|
|
119
121
|
});
|
|
120
122
|
if (!res.ok) {
|
|
121
123
|
const body = await res.json().catch(() => ({}));
|
|
122
|
-
return { ok: false, error: body.error ??
|
|
124
|
+
return { ok: false, error: body.error ?? t("cpq.pricing.entries.errors.deleteFailed", "Failed to delete entry {id}", { id: d.id }) };
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
127
|
return { ok: true };
|
|
126
128
|
} catch (err) {
|
|
127
|
-
return { ok: false, error: err instanceof Error ? err.message : "Failed to save entries" };
|
|
129
|
+
return { ok: false, error: err instanceof Error ? err.message : t("cpq.pricing.entries.errors.saveFailed", "Failed to save entries") };
|
|
128
130
|
} finally {
|
|
129
131
|
setSaving(false);
|
|
130
132
|
}
|
|
@@ -140,30 +142,29 @@ function EntriesEditor({
|
|
|
140
142
|
};
|
|
141
143
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
142
144
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
143
|
-
/* @__PURE__ */
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
")"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => addRow(false), children: "+ Add Row" }),
|
|
150
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => addRow(true), children: "+ Add Tier" }),
|
|
151
|
-
/* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: handleSave, disabled: saving || !dirty, children: saving ? "Saving..." : "Save" }),
|
|
152
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: cancelEdit, disabled: saving, children: "Cancel" })
|
|
145
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: t("cpq.pricing.entries.title", "Entries ({count})", { count: visibleDrafts.length }) }),
|
|
146
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: mode === "view" ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setMode("edit"), children: t("cpq.pricing.entries.edit", "Edit Entries") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
147
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => addRow(false), children: t("cpq.pricing.entries.addRow", "+ Add Row") }),
|
|
148
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => addRow(true), children: t("cpq.pricing.entries.addTier", "+ Add Tier") }),
|
|
149
|
+
/* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: handleSave, disabled: saving || !dirty, children: saving ? t("cpq.common.saving", "Saving...") : t("cpq.common.save", "Save") }),
|
|
150
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: cancelEdit, disabled: saving, children: t("cpq.common.cancel", "Cancel") })
|
|
153
151
|
] }) })
|
|
154
152
|
] }),
|
|
155
153
|
error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: error }),
|
|
156
|
-
visibleDrafts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: mode === "edit" ?
|
|
154
|
+
visibleDrafts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: mode === "edit" ? t(
|
|
155
|
+
"cpq.pricing.entries.emptyEditing",
|
|
156
|
+
'No entries yet \u2014 use "+ Add Row" (dimensions lookup) or "+ Add Tier" (range lookup).'
|
|
157
|
+
) : t("cpq.pricing.entries.empty", "No entries in this pricing table.") }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
157
158
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/50", children: [
|
|
158
159
|
table.dimensions.map((dim) => /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: dim.label }, dim.key)),
|
|
159
160
|
hasTieredEntries && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
160
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: "Tier #" }),
|
|
161
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: "Range From" }),
|
|
162
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: "Range To" })
|
|
161
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: t("cpq.pricing.entries.tierNumber", "Tier #") }),
|
|
162
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: t("cpq.pricing.entries.rangeFrom", "Range From") }),
|
|
163
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: t("cpq.pricing.entries.rangeTo", "Range To") })
|
|
163
164
|
] }),
|
|
164
165
|
table.priceColumns.map((col) => /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-right font-medium whitespace-nowrap", children: col.label }, col.key)),
|
|
165
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium", children: "Currency" }),
|
|
166
|
-
mode === "edit" && /* @__PURE__ */ jsx("th", { className: "px-3 py-3 w-8", "aria-label": "Actions" })
|
|
166
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium", children: t("cpq.pricing.entries.currency", "Currency") }),
|
|
167
|
+
mode === "edit" && /* @__PURE__ */ jsx("th", { className: "px-3 py-3 w-8", "aria-label": t("cpq.pricing.entries.actions", "Actions") })
|
|
167
168
|
] }) }),
|
|
168
169
|
/* @__PURE__ */ jsx("tbody", { children: visibleDrafts.map((entry) => /* @__PURE__ */ jsx(
|
|
169
170
|
EntryRow,
|
|
@@ -188,6 +189,7 @@ function EntryRow({
|
|
|
188
189
|
onChange,
|
|
189
190
|
onDelete
|
|
190
191
|
}) {
|
|
192
|
+
const t = useT();
|
|
191
193
|
const readOnly = mode === "view";
|
|
192
194
|
const rowBg = entry._state === "new" ? "bg-success/5" : entry._state === "modified" ? "bg-warning/5" : "";
|
|
193
195
|
return /* @__PURE__ */ jsxs("tr", { className: `border-b hover:bg-muted/30 ${rowBg}`, children: [
|
|
@@ -263,7 +265,7 @@ function EntryRow({
|
|
|
263
265
|
type: "button",
|
|
264
266
|
onClick: onDelete,
|
|
265
267
|
className: "text-destructive hover:bg-destructive/10 rounded p-1",
|
|
266
|
-
"aria-label": "Delete row",
|
|
268
|
+
"aria-label": t("cpq.pricing.entries.deleteRow", "Delete row"),
|
|
267
269
|
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
268
270
|
}
|
|
269
271
|
) })
|