@dainamite/cpq 0.5.0 → 0.6.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 +48 -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/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +22 -8
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +89 -232
- package/dist/modules/cpq/backend/cpq/orders/[id]/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/quotes/[id]/_components/PriceAdjustmentDialog.js +205 -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 +144 -221
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +3 -3
- 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/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 +154 -0
- package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +7 -0
- package/dist/modules/cpq/components/PriceWaterfall.js +66 -0
- package/dist/modules/cpq/components/PriceWaterfall.js.map +7 -0
- package/dist/modules/cpq/components/PricingSummaryCard.js +117 -0
- package/dist/modules/cpq/components/PricingSummaryCard.js.map +7 -0
- 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/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/package.json +1 -1
- package/src/modules/cpq/__integration__/TC-CPQ-ARC-012.spec.ts +134 -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/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +32 -10
- package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +60 -269
- package/src/modules/cpq/backend/cpq/orders/page.meta.ts +1 -1
- 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 +174 -263
- package/src/modules/cpq/backend/cpq/quotes/page.meta.ts +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 +201 -0
- package/src/modules/cpq/components/PriceWaterfall.tsx +94 -0
- package/src/modules/cpq/components/PricingSummaryCard.tsx +128 -0
- package/src/modules/cpq/components/__tests__/PriceWaterfall.test.tsx +38 -0
- 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/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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/cpq/backend/cpq/orders/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter, useParams } from 'next/navigation'\nimport { ArrowRight, ExternalLink, Play, X } from 'lucide-react'\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 { FormHeader } from '@open-mercato/ui/backend/forms'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../../components/statusMaps'\nimport { StatusPath } from '../../../../components/StatusPath'\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\u2500\n\ntype ArcLineSource = {\n subscriptionItemId: string\n name: string\n mrcAmount: number\n nrcAmount: number\n quantity: number\n}\n\ntype TierBreakdownEntry = { tier: number; from: number; to: number; pricePerUnit: number; quantity: number; subtotal: number }\ntype RuleAdjustment = { ruleCode: string; ruleName: string; ruleType: string; value: number; unitPriceBefore: number; unitPriceAfter: number; delta: number }\n\ntype ResolvedCharge = {\n chargeName?: string\n chargeType?: string\n pricingMethod?: 'flat' | 'tiered' | 'per_unit'\n unitPrice?: number\n quantity?: number | null\n totalPrice?: number | null\n note?: string | null\n breakdown?: { tiers: TierBreakdownEntry[] } | null\n adjustments?: RuleAdjustment[] | null\n}\n\ntype OrderLineResult = {\n lineId: string\n offeringId: string | null\n offeringName: string\n offeringType: string | null\n productId: string | null\n specId: string | null\n action: string\n parentLineId: string | null\n quantity: number\n configuration: Record<string, unknown>\n startDate: string | null\n termMonths: number | null\n endDate: string | null\n nrcTotal: number\n mrcTotal: number\n charges: ResolvedCharge[]\n sourceQuoteLineId: string | null\n arcSource: ArcLineSource | null\n}\n\ntype OrderResult = {\n id: string\n orderId: string\n orderNumber: string\n customerId: string\n cpqStatus: string\n sourceQuoteId: string | null\n quoteType: string\n currencyCode: string\n pricingSummary: {\n nrcTotal: number\n mrcTotal: number\n currencyCode: string\n }\n activatedAt: string | null\n createdAt: string\n lines: OrderLineResult[]\n}\n\nconst ARC_BADGE_VARIANTS: Record<string, 'brand' | 'success' | 'error'> = {\n amend: 'brand',\n renew: 'success',\n cancel: 'error',\n}\n\nconst RULE_TYPE_LABELS: Record<string, string> = {\n discount_percent: '% discount',\n discount_absolute: 'fixed discount',\n surcharge_percent: '% surcharge',\n surcharge_absolute: 'fixed surcharge',\n price_override: 'override',\n}\n\nfunction fmtRuleValue(adj: RuleAdjustment, currency?: string): string {\n if (adj.ruleType === 'discount_percent' || adj.ruleType === 'surcharge_percent') return `${adj.value}%`\n if (currency) return fmt(adj.value, currency)\n return String(adj.value)\n}\n\n// \u2500\u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nfunction fmt(amount: number, currency: string): string {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nasync function apiJson<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await fetch(url, init)\n const json = await res.json()\n if (!res.ok) throw new Error(json?.error ?? `Request failed (${res.status})`)\n return json as T\n}\n\n// \u2500\u2500\u2500 Main Page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 CpqOrderDetailPage(props: { params?: { id?: string } }) {\n const router = useRouter()\n const urlParams = useParams()\n const cpqOrderId = (props.params?.id ?? urlParams?.id) as string\n\n const [order, setOrder] = React.useState<OrderResult | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [activating, setActivating] = React.useState(false)\n const [expandedLines, setExpandedLines] = React.useState<Set<string>>(new Set())\n const [pricingDetail, setPricingDetail] = React.useState<{ lineIdx: number; chargeIdx: number } | null>(null)\n const [customerName, setCustomerName] = React.useState<string | null>(null)\n const [linkedSubscriptions, setLinkedSubscriptions] = React.useState<Array<{\n id: string\n name: string\n code: string\n status: string\n }>>([])\n\n // Find every subscription this order touches. NEW orders write\n // `sourceOrderId` on the freshly-created subscription, so a\n // `?sourceOrderId=\u2026` filter is enough there. ARC orders (amend /\n // renew / cancel) mutate existing subscriptions in place \u2014 the\n // subscription's `sourceOrderId` stays pinned to the original\n // order, so we also resolve targets via the source quote.\n const fetchLinkedSubscriptions = React.useCallback(\n async (orderConfigId: string, sourceQuoteId: string | null) => {\n const byOrderId = fetch(\n `/api/cpq/inventory/subscriptions?sourceOrderId=${orderConfigId}&pageSize=10`,\n )\n .then((r) => (r.ok ? r.json() : null))\n .then((d) => (d?.items ?? (Array.isArray(d) ? d : [])) as Array<{ id: string; name: string; code: string; status: string }>)\n .catch(() => [])\n\n const byTargets = sourceQuoteId\n ? fetch(`/api/cpq/quotes/${sourceQuoteId}/target-subscriptions`)\n .then((r) => (r.ok ? r.json() : null))\n .then(async (d) => {\n const targets: Array<{ subscriptionId: string }> = d?.items ?? []\n const fetched = await Promise.all(\n targets.map((t) =>\n fetch(`/api/cpq/inventory/subscriptions?id=${t.subscriptionId}`)\n .then((r) => (r.ok ? r.json() : null))\n .catch(() => null),\n ),\n )\n return fetched.filter(Boolean) as Array<{ id: string; name: string; code: string; status: string }>\n })\n .catch(() => [] as Array<{ id: string; name: string; code: string; status: string }>)\n : Promise.resolve([] as Array<{ id: string; name: string; code: string; status: string }>)\n\n const [a, b] = await Promise.all([byOrderId, byTargets])\n // Dedupe by id \u2014 a single subscription may appear in both lists\n // (e.g. a NEW order that was later amended into the same sub).\n const seen = new Set<string>()\n const merged: Array<{ id: string; name: string; code: string; status: string }> = []\n for (const sub of [...a, ...b]) {\n if (!sub || seen.has(sub.id)) continue\n seen.add(sub.id)\n merged.push({ id: sub.id, name: sub.name, code: sub.code, status: sub.status })\n }\n setLinkedSubscriptions(merged)\n },\n [],\n )\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n try {\n const result = await apiJson<OrderResult>(`/api/cpq/orders/${cpqOrderId}`)\n if (!cancelled) {\n setOrder(result)\n fetch(`/api/customers/companies?id=${result.customerId}&pageSize=1`)\n .then((r) => r.json())\n .then((data) => {\n const items = data.items ?? data ?? []\n const c = items[0]\n if (c && !cancelled) setCustomerName(c.display_name || c.displayName || c.name || null)\n })\n .catch(() => {})\n if (result.cpqStatus === 'active' || result.cpqStatus === 'fulfilled') {\n void fetchLinkedSubscriptions(result.id, result.sourceQuoteId)\n }\n }\n } catch (err) {\n if (!cancelled) setError((err as Error).message)\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [cpqOrderId, fetchLinkedSubscriptions])\n\n const activateOrder = async () => {\n if (!order) return\n try {\n setActivating(true)\n setError(null)\n const result = await apiJson<OrderResult>(`/api/cpq/orders/${order.id}/activate`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n setOrder(result)\n void fetchLinkedSubscriptions(result.id, result.sourceQuoteId)\n } catch (err) {\n setError((err as Error).message)\n } finally {\n setActivating(false)\n }\n }\n\n const cancelOrder = async () => {\n if (!order) return\n try {\n setError(null)\n const result = await apiJson<OrderResult>(`/api/cpq/orders/${order.id}/status`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ targetStatus: 'cancelled' }),\n })\n setOrder(result)\n } catch (err) {\n setError((err as Error).message)\n }\n }\n\n const toggleLine = (id: string) => {\n setExpandedLines((prev) => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n })\n }\n\n // \u2500\u2500\u2500 Render: loading / error \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 (\n <div className=\"flex items-center gap-2 py-12 justify-center text-sm text-muted-foreground\">\n <Spinner /> Loading\u2026\n </div>\n )\n }\n\n if (!order) {\n return (\n <div className=\"space-y-4\">\n <button onClick={() => router.push('/backend/cpq/orders')} className=\"text-sm text-muted-foreground hover:text-foreground\">\u2190 Back to Orders</button>\n {error && <ErrorBanner message={error} />}\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">Order not found.</div>\n </div>\n )\n }\n\n // \u2500\u2500\u2500 Render: detail \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 canActivate = order.cpqStatus === 'draft' || order.cpqStatus === 'pending_activation'\n const canCancel = order.cpqStatus === 'draft' || order.cpqStatus === 'pending_activation' || order.cpqStatus === 'active'\n const currency = order.currencyCode\n\n const togglePricingDetail = (lineIdx: number, chargeIdx: number) => {\n setPricingDetail((prev) =>\n prev?.lineIdx === lineIdx && prev?.chargeIdx === chargeIdx ? null : { lineIdx, chargeIdx },\n )\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header \u2014 standard FormHeader detail mode, mirrors the CPQ quote\n layout so order \u2194 quote stays consistent. Title is just the order\n number; status / ARC / converted tags sit underneath; primary\n actions (Activate, then Cancel) live on the right next to the\n View Sales Order / Source Quote utility links. */}\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/cpq/orders\"\n backLabel=\"Back to CPQ Orders\"\n entityTypeLabel=\"CPQ Order\"\n title={order.orderNumber || order.orderId.slice(0, 8)}\n statusBadge={\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n <Tag variant={orderCpqStatusMap[order.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(order.cpqStatus)}\n </Tag>\n {order.quoteType && order.quoteType !== 'new' && (\n <Tag variant={ARC_BADGE_VARIANTS[order.quoteType] ?? 'neutral'} className=\"uppercase\">\n {order.quoteType}\n </Tag>\n )}\n </div>\n }\n actionsContent={\n <>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(`/backend/sales/orders/${order.orderId}`)}\n >\n <ExternalLink className=\"h-3.5 w-3.5\" />\n View Sales Order\n </Button>\n {order.sourceQuoteId && (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(`/backend/cpq/quotes/${order.sourceQuoteId}`)}\n >\n Source Quote\n </Button>\n )}\n {canActivate && (\n <Button type=\"button\" onClick={activateOrder} disabled={activating}>\n {activating ? <Spinner /> : <Play className=\"h-4 w-4\" />}\n Activate\n </Button>\n )}\n {canCancel && (\n <Button type=\"button\" variant=\"destructive-outline\" onClick={cancelOrder}>\n <X className=\"h-4 w-4\" />\n Cancel\n </Button>\n )}\n </>\n }\n />\n\n {/* Status path \u2014 visual progress only. Orders advance via the\n dedicated Activate / Cancel buttons because activation has\n backend side effects (subscription / asset creation). */}\n <div className=\"flex items-center gap-3 flex-wrap\">\n <StatusPath\n // Order path is read-only \u2014 activation has backend side effects\n // (subscription / asset creation) so transitions go through the\n // dedicated Activate / Cancel buttons.\n current={order.cpqStatus}\n path={['draft', 'pending_activation', 'active', 'fulfilled']}\n terminals={['cancelled']}\n statusMap={orderCpqStatusMap}\n ariaLabel=\"Order status path\"\n />\n </div>\n\n {error && <ErrorBanner message={error} onDismiss={() => setError(null)} />}\n\n {/* Linked subscriptions \u2014 one card per subscription this order\n touches. NEW orders write one fresh subscription; ARC orders\n (amend / renew / cancel) reach one or more existing\n subscriptions through the source quote's target list. */}\n {linkedSubscriptions.length > 0 && (\n <div className=\"space-y-2\">\n {linkedSubscriptions.map((sub) => (\n <div\n key={sub.id}\n className=\"rounded-lg border bg-card p-4 flex items-center gap-4\"\n >\n <div className=\"flex-1 min-w-0 space-y-1\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n Linked Subscription\n </span>\n <Tag\n variant={sub.status === 'active' ? 'success' : 'info'}\n dot\n className=\"text-[10px] px-1.5\"\n >\n {sub.status}\n </Tag>\n </div>\n <div className=\"text-sm font-medium\">\n {sub.name}{' '}\n <span className=\"text-muted-foreground font-mono text-xs\">({sub.code})</span>\n </div>\n {order.activatedAt && (\n <div className=\"text-xs text-muted-foreground\">\n Activated on {new Date(order.activatedAt).toLocaleString()}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(`/backend/cpq/inventory/subscriptions/${sub.id}`)}\n >\n <ArrowRight className=\"h-3.5 w-3.5\" />\n Open\n </Button>\n </div>\n ))}\n </div>\n )}\n\n {/* Meta cards \u2014 secondary reference info, matches the quote layout. */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n <MetaCard label=\"Customer\">\n {customerName ? (\n <span className=\"font-medium\">{customerName}</span>\n ) : (\n <span className=\"font-mono text-xs text-muted-foreground\">\n {order.customerId.slice(0, 8)}\u2026\n </span>\n )}\n </MetaCard>\n <MetaCard label=\"Created\">\n <span className=\"font-medium\">{new Date(order.createdAt).toLocaleDateString()}</span>\n </MetaCard>\n <MetaCard label=\"Currency\">\n <span className=\"font-medium\">{currency}</span>\n </MetaCard>\n </div>\n\n {/* Pricing Summary Card */}\n <div className=\"rounded-lg border bg-card p-4\">\n <h3 className=\"text-sm font-medium mb-3\">Pricing Summary</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-xs text-muted-foreground\">Non-Recurring (NRC)</p>\n <p className=\"text-lg font-semibold font-mono\">{fmt(order.pricingSummary.nrcTotal, currency)}</p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">Monthly Recurring (MRC)</p>\n <p className=\"text-lg font-semibold font-mono\">{fmt(order.pricingSummary.mrcTotal, currency)}</p>\n </div>\n </div>\n </div>\n\n {/* Order Lines */}\n <OrderLineTree\n lines={order.lines}\n currency={currency}\n expandedLines={expandedLines}\n pricingDetail={pricingDetail}\n onToggleLine={toggleLine}\n onTogglePricingDetail={togglePricingDetail}\n />\n </div>\n )\n}\n\nfunction MetaCard({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {label}\n </div>\n <div className=\"mt-1 text-sm\">{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Sub-components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nfunction OrderLineTree({\n lines,\n currency,\n expandedLines,\n pricingDetail,\n onToggleLine,\n onTogglePricingDetail,\n}: {\n lines: OrderLineResult[]\n currency: string\n expandedLines: Set<string>\n pricingDetail: { lineIdx: number; chargeIdx: number } | null\n onToggleLine: (id: string) => void\n onTogglePricingDetail: (lineIdx: number, chargeIdx: number) => void\n}) {\n const rootLines = lines.filter((l) => !l.parentLineId)\n const childrenByParent = new Map<string, OrderLineResult[]>()\n for (const line of lines) {\n if (line.parentLineId) {\n const arr = childrenByParent.get(line.parentLineId) ?? []\n arr.push(line)\n childrenByParent.set(line.parentLineId, arr)\n }\n }\n\n // Stable index per visible line so the pricing-detail toggle can be\n // keyed by (lineIdx, chargeIdx) the same way the quote page does.\n const indexOf = new Map<string, number>()\n lines.forEach((l, i) => indexOf.set(l.lineId, i))\n\n return (\n <div>\n <h3 className=\"text-sm font-medium mb-2 px-1\">Line Items ({lines.length})</h3>\n {lines.length === 0 ? (\n <div className=\"rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground\">\n No line items.\n </div>\n ) : (\n <div className=\"rounded-lg border bg-card divide-y\">\n {rootLines.map((line) => {\n const isBundle = line.offeringType === 'bundle'\n const children = childrenByParent.get(line.lineId) ?? []\n const isExpanded = expandedLines.has(line.lineId)\n const lineIdx = indexOf.get(line.lineId) ?? 0\n return (\n <div key={line.lineId}>\n <OrderLineRow\n line={line}\n lineIdx={lineIdx}\n currency={currency}\n isExpanded={isExpanded}\n isBundle={isBundle}\n childCount={children.length}\n indent={0}\n pricingDetail={pricingDetail}\n onToggle={() => onToggleLine(line.lineId)}\n onTogglePricingDetail={onTogglePricingDetail}\n />\n {isBundle && isExpanded && children.length > 0 && (\n <div className=\"border-t border-dashed border-brand-violet/30 bg-brand-violet/5\">\n <div className=\"px-6 py-1.5\">\n <span className=\"text-[10px] font-medium text-brand-violet uppercase tracking-wider\">Bundle Components ({children.length})</span>\n </div>\n {children.map((child) => {\n const childIdx = indexOf.get(child.lineId) ?? 0\n return (\n <OrderLineRow\n key={child.lineId}\n line={child}\n lineIdx={childIdx}\n currency={currency}\n isExpanded={expandedLines.has(child.lineId)}\n isBundle={false}\n childCount={0}\n indent={1}\n pricingDetail={pricingDetail}\n onToggle={() => onToggleLine(child.lineId)}\n onTogglePricingDetail={onTogglePricingDetail}\n />\n )\n })}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nfunction OrderLineRow({ line, lineIdx, currency, isExpanded, isBundle, childCount, indent, pricingDetail, onToggle, onTogglePricingDetail }: {\n line: OrderLineResult; lineIdx: number; currency: string; isExpanded: boolean; isBundle: boolean; childCount: number; indent: number\n pricingDetail: { lineIdx: number; chargeIdx: number } | null\n onToggle: () => void\n onTogglePricingDetail: (lineIdx: number, chargeIdx: number) => void\n}) {\n const paddingLeft = indent > 0 ? `${indent * 2 + 1}rem` : undefined\n\n return (\n <div>\n <div\n className=\"flex items-center gap-3 px-4 py-3 hover:bg-muted/30 transition-colors cursor-pointer\"\n style={paddingLeft ? { paddingLeft } : undefined}\n onClick={onToggle}\n >\n <button className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground\">\n <svg className={`h-4 w-4 transition-transform ${isExpanded ? 'rotate-90' : ''}`} fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth=\"2\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n {indent > 0 && <span className=\"text-muted-foreground text-xs\">\u2514</span>}\n {isBundle && (\n <Tag variant=\"brand\" className=\"px-1.5 text-xs\">bundle</Tag>\n )}\n <span className=\"font-medium text-sm\">{line.offeringName}</span>\n {line.quantity > 1 && <span className=\"rounded bg-muted px-1.5 py-0.5 text-xs font-medium\">\u00D7{line.quantity}</span>}\n <Tag variant=\"info\" className=\"px-1.5 text-xs\">{line.action}</Tag>\n {isBundle && <span className=\"text-xs text-muted-foreground\">{childCount} component{childCount !== 1 ? 's' : ''}</span>}\n </div>\n </div>\n\n <div className=\"shrink-0 text-right text-xs space-y-0.5\">\n {line.nrcTotal > 0 && <div><span className=\"text-muted-foreground\">NRC </span><span className=\"font-mono font-medium\">{fmt(line.nrcTotal, currency)}</span></div>}\n {line.mrcTotal > 0 && <div><span className=\"text-muted-foreground\">MRC </span><span className=\"font-mono font-medium\">{fmt(line.mrcTotal, currency)}</span></div>}\n </div>\n </div>\n\n {isExpanded && (() => {\n const internalKeys = new Set(['_arcMirroredName', '_arcMirroredFromItemId', 'offeringName'])\n const visibleConfigEntries = Object.entries(line.configuration).filter(\n ([key]) => !internalKeys.has(key),\n )\n const hasConfig = visibleConfigEntries.length > 0\n const hasCharges = line.charges.length > 0\n const hasTerm = !!(line.startDate || line.termMonths || line.endDate)\n const hasArcDiff = !!line.arcSource\n const mirroredFromItemId = (line.configuration?._arcMirroredFromItemId as string | undefined) ?? null\n const isEmpty = !hasConfig && !hasCharges && !hasTerm && !hasArcDiff\n\n return (\n <div\n className=\"border-t bg-muted/10 px-12 py-3 space-y-3\"\n style={paddingLeft ? { paddingLeft: `calc(${paddingLeft} + 2rem)` } : undefined}\n >\n {hasArcDiff && (\n <ArcLineDiff line={line} currency={currency} />\n )}\n {isEmpty ? (\n <div className=\"text-xs text-muted-foreground space-y-1\">\n <div>\n No detailed breakdown for this line.\n {mirroredFromItemId && ' Mirrored from existing subscription item.'}\n </div>\n {(line.nrcTotal > 0 || line.mrcTotal > 0) && (\n <div className=\"flex gap-4\">\n {line.nrcTotal > 0 && (\n <span>NRC <span className=\"font-mono font-medium text-foreground\">{fmt(line.nrcTotal, currency)}</span></span>\n )}\n {line.mrcTotal > 0 && (\n <span>MRC <span className=\"font-mono font-medium text-foreground\">{fmt(line.mrcTotal, currency)}</span></span>\n )}\n </div>\n )}\n </div>\n ) : (\n <>\n {hasConfig && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-1\">Configuration</p>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-x-4 gap-y-1\">\n {visibleConfigEntries.map(([key, value]) => (\n <div key={key} className=\"text-xs\">\n <span className=\"text-muted-foreground\">{key}: </span>\n <span className=\"font-medium\">{String(value)}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {hasCharges && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-1\">Charges</p>\n <ChargeBreakdown\n line={line}\n lineIdx={lineIdx}\n currency={currency}\n pricingDetail={pricingDetail}\n onTogglePricingDetail={onTogglePricingDetail}\n />\n </div>\n )}\n\n {hasTerm && (\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n {line.startDate && <span>Start: {new Date(line.startDate).toLocaleDateString()}</span>}\n {line.termMonths && <span>Term: {line.termMonths}mo</span>}\n {line.endDate && <span>End: {new Date(line.endDate).toLocaleDateString()}</span>}\n </div>\n )}\n </>\n )}\n </div>\n )\n })()}\n </div>\n )\n}\n\n// Charge breakdown table with the waterfall (\"show pricing details\")\n// toggle. Same shape as the quote page so a charge looks identical on\n// both surfaces, including tier-by-tier subtotals and any price-rule\n// adjustments that fired during calculation.\nfunction ChargeBreakdown({ line, lineIdx, currency, pricingDetail, onTogglePricingDetail }: {\n line: OrderLineResult; lineIdx: number; currency: string\n pricingDetail: { lineIdx: number; chargeIdx: number } | null\n onTogglePricingDetail: (lineIdx: number, chargeIdx: number) => void\n}) {\n return (\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"text-muted-foreground\">\n <th className=\"text-left py-1 font-medium\">Charge</th>\n <th className=\"text-left py-1 font-medium\">Type</th>\n <th className=\"text-right py-1 font-medium\">Unit Price</th>\n <th className=\"text-right py-1 font-medium\">Qty</th>\n <th className=\"text-right py-1 font-medium\">Total</th>\n <th className=\"w-8\" />\n </tr>\n </thead>\n <tbody>\n {line.charges.map((c, i) => {\n const hasDetail = !!(c.breakdown?.tiers?.length || c.adjustments?.length)\n const isDetailOpen = pricingDetail?.lineIdx === lineIdx && pricingDetail?.chargeIdx === i\n return (\n <React.Fragment key={i}>\n <tr className=\"border-t border-dashed border-border/50\">\n <td className=\"py-1\">{c.chargeName ?? '\u2014'}</td>\n <td className=\"py-1 uppercase\">{c.chargeType ?? '\u2014'}</td>\n <td className=\"py-1 text-right font-mono\">{c.unitPrice != null ? fmt(c.unitPrice, currency) : '\u2014'}</td>\n <td className=\"py-1 text-right font-mono\">{c.quantity ?? '\u2014'}</td>\n <td className=\"py-1 text-right font-mono\">{c.totalPrice != null ? fmt(c.totalPrice, currency) : c.note ?? '\u2014'}</td>\n <td className=\"py-1 text-center\">\n {hasDetail && (\n <button\n onClick={() => onTogglePricingDetail(lineIdx, i)}\n className=\"inline-flex items-center justify-center rounded p-0.5 hover:bg-accent text-muted-foreground hover:text-foreground transition-colors\"\n title=\"Show pricing breakdown\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" className=\"w-3.5 h-3.5\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" />\n </svg>\n </button>\n )}\n </td>\n </tr>\n {isDetailOpen && (\n <tr>\n <td colSpan={6} className=\"pb-3 pt-1\">\n <div className=\"rounded border bg-background p-3 space-y-3 text-xs\">\n <div className=\"flex items-center justify-between\">\n <span className=\"font-semibold text-sm\">Pricing Details \u2014 {c.chargeName}</span>\n <span className=\"text-muted-foreground\">{c.pricingMethod ?? 'flat'}</span>\n </div>\n\n {c.breakdown?.tiers && c.breakdown.tiers.length > 0 && (\n <div>\n <div className=\"font-medium text-muted-foreground mb-1\">Tier Breakdown</div>\n <table className=\"w-full\">\n <thead>\n <tr className=\"text-muted-foreground\">\n <th className=\"text-left py-0.5 font-medium\">Tier</th>\n <th className=\"text-right py-0.5 font-medium\">Range</th>\n <th className=\"text-right py-0.5 font-medium\">Price/Unit</th>\n <th className=\"text-right py-0.5 font-medium\">Qty</th>\n <th className=\"text-right py-0.5 font-medium\">Subtotal</th>\n </tr>\n </thead>\n <tbody>\n {c.breakdown.tiers.map((t) => (\n <tr key={t.tier} className=\"border-t border-border/30\">\n <td className=\"py-0.5\">{t.tier}</td>\n <td className=\"py-0.5 text-right font-mono\">{t.from}\u2013{t.to}</td>\n <td className=\"py-0.5 text-right font-mono\">{fmt(t.pricePerUnit, currency)}</td>\n <td className=\"py-0.5 text-right font-mono\">{t.quantity}</td>\n <td className=\"py-0.5 text-right font-mono\">{fmt(t.subtotal, currency)}</td>\n </tr>\n ))}\n <tr className=\"border-t font-medium\">\n <td colSpan={4} className=\"py-0.5 text-right\">Tiered Total</td>\n <td className=\"py-0.5 text-right font-mono\">\n {fmt(c.breakdown.tiers.reduce((s, t) => s + t.subtotal, 0), currency)}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n )}\n\n {c.adjustments && c.adjustments.length > 0 && (\n <div>\n <div className=\"font-medium text-muted-foreground mb-1\">Applied Price Rules</div>\n <table className=\"w-full\">\n <thead>\n <tr className=\"text-muted-foreground\">\n <th className=\"text-left py-0.5 font-medium\">Rule</th>\n <th className=\"text-left py-0.5 font-medium\">Type</th>\n <th className=\"text-right py-0.5 font-medium\">Value</th>\n <th className=\"text-right py-0.5 font-medium\">Before</th>\n <th className=\"text-right py-0.5 font-medium\">After</th>\n <th className=\"text-right py-0.5 font-medium\">Delta</th>\n </tr>\n </thead>\n <tbody>\n {c.adjustments.map((adj, ai) => (\n <tr key={ai} className=\"border-t border-border/30\">\n <td className=\"py-0.5\">{adj.ruleName}</td>\n <td className=\"py-0.5\">{RULE_TYPE_LABELS[adj.ruleType] ?? adj.ruleType}</td>\n <td className=\"py-0.5 text-right font-mono\">{fmtRuleValue(adj, currency)}</td>\n <td className=\"py-0.5 text-right font-mono\">{fmt(adj.unitPriceBefore, currency)}</td>\n <td className=\"py-0.5 text-right font-mono\">{fmt(adj.unitPriceAfter, currency)}</td>\n <td className={`py-0.5 text-right font-mono ${adj.delta < 0 ? 'text-destructive' : adj.delta > 0 ? 'text-status-success-text' : ''}`}>\n {adj.delta > 0 ? '+' : ''}{fmt(adj.delta, currency)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n <div className=\"flex items-center justify-between pt-1 border-t text-sm font-semibold\">\n <span>Final Total</span>\n <span className=\"font-mono\">{c.totalPrice != null ? fmt(c.totalPrice, currency) : '\u2014'}</span>\n </div>\n </div>\n </td>\n </tr>\n )}\n </React.Fragment>\n )\n })}\n </tbody>\n </table>\n )\n}\n\nfunction Spinner() {\n return (\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )\n}\n\nfunction ErrorBanner({ message, onDismiss }: { message: string; onDismiss?: () => void }) {\n return (\n <Alert variant=\"destructive\" className=\"flex items-start gap-2\">\n <span className=\"flex-1\">{message}</span>\n {onDismiss && (\n <button\n onClick={onDismiss}\n className=\"text-destructive/70 hover:text-destructive text-sm font-bold\"\n aria-label=\"Dismiss\"\n >\n \u00D7\n </button>\n )}\n </Alert>\n )\n}\n\n// XD-250 ARC: side-by-side \"Before / After\" snapshot for a quote / order line\n// that mirrors an existing subscription item. \"Before\" comes from the live\n// CpqInventorySubscriptionItem at render time; \"After\" is what the line will\n// apply on activation. For 'cancel' lines the after column is greyed out.\nfunction ArcLineDiff({ line, currency }: { line: OrderLineResult; currency: string }) {\n const src = line.arcSource\n if (!src) return null\n const isCancel = line.action === 'cancel'\n\n const beforeMrc = src.mrcAmount\n const beforeNrc = src.nrcAmount\n const beforeQty = src.quantity\n const afterMrc = isCancel ? 0 : line.mrcTotal\n const afterNrc = isCancel ? 0 : line.nrcTotal\n const afterQty = isCancel ? 0 : line.quantity\n const mrcDelta = afterMrc - beforeMrc\n const nrcDelta = afterNrc - beforeNrc\n const qtyDelta = afterQty - beforeQty\n\n return (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-1.5\">Change Preview</p>\n <div className=\"rounded border bg-background overflow-hidden\">\n <table className=\"w-full text-xs\">\n <thead className=\"bg-muted/40\">\n <tr className=\"text-muted-foreground\">\n <th className=\"text-left px-3 py-1.5 font-medium\" />\n <th className=\"text-right px-3 py-1.5 font-medium\">Before</th>\n <th className=\"text-right px-3 py-1.5 font-medium\">After</th>\n <th className=\"text-right px-3 py-1.5 font-medium\">\u0394</th>\n </tr>\n </thead>\n <tbody>\n <ArcDiffRow label=\"Quantity\" before={beforeQty} after={afterQty} delta={qtyDelta} currency={null} dimAfter={isCancel} />\n <ArcDiffRow label=\"MRC\" before={beforeMrc} after={afterMrc} delta={mrcDelta} currency={currency} dimAfter={isCancel} />\n <ArcDiffRow label=\"NRC\" before={beforeNrc} after={afterNrc} delta={nrcDelta} currency={currency} dimAfter={isCancel} />\n </tbody>\n </table>\n </div>\n {isCancel && (\n <p className=\"text-xs text-destructive mt-1 italic\">\n Cancellation \u2014 item will be terminated on activation.\n </p>\n )}\n </div>\n )\n}\n\nfunction ArcDiffRow({\n label,\n before,\n after,\n delta,\n currency,\n dimAfter,\n}: {\n label: string\n before: number\n after: number\n delta: number\n currency: string | null\n dimAfter: boolean\n}) {\n const fmtVal = (v: number) => (currency ? fmt(v, currency) : String(v))\n const showDelta = delta !== 0\n return (\n <tr className=\"border-t border-dashed border-border/40\">\n <td className=\"px-3 py-1 text-muted-foreground\">{label}</td>\n <td className=\"px-3 py-1 text-right font-mono\">{fmtVal(before)}</td>\n <td className={`px-3 py-1 text-right font-mono ${dimAfter ? 'text-muted-foreground line-through' : ''}`}>\n {fmtVal(after)}\n </td>\n <td className={`px-3 py-1 text-right font-mono font-medium ${showDelta ? (delta > 0 ? 'text-status-success-text' : 'text-destructive') : 'text-muted-foreground'}`}>\n {showDelta ? `${delta > 0 ? '+' : ''}${fmtVal(delta)}` : '\u2014'}\n </td>\n </tr>\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 { ArrowRight, ExternalLink, Play, X } from 'lucide-react'\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 { FormHeader } from '@open-mercato/ui/backend/forms'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../../components/statusMaps'\nimport { StatusPath } from '../../../../components/StatusPath'\nimport { ChargeBreakdownTable, type ChargeRowView } from '../../../../components/ChargeBreakdownTable'\nimport { PricingSummaryCard, type PricingSummaryView } from '../../../../components/PricingSummaryCard'\nimport { ArcLineDiff, LineActionBadge } from '../../../../components/ArcLineDiff'\nimport { arcRecurringDelta } from '../../../../lib/quoteSummaryView'\nimport { isArcCancelledLine } from '../../../../services/arcLineRemoval'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\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\u2500\n\ntype ArcLineSource = {\n subscriptionItemId: string\n name: string\n mrcAmount: number\n nrcAmount: number\n quantity: number\n}\n\ntype TierBreakdownEntry = { tier: number; from: number; to: number; pricePerUnit: number; quantity: number; subtotal: number }\ntype RuleAdjustment = { ruleCode: string; ruleName: string; ruleType: string; value: number; unitPriceBefore: number; unitPriceAfter: number; delta: number; origin?: 'rule' | 'manual'; adjustmentId?: string; reasonCode?: string }\n\ntype ResolvedCharge = {\n chargeName?: string\n chargeType?: string\n pricingMethod?: 'flat' | 'tiered' | 'per_unit'\n unitPrice?: number\n quantity?: number | null\n totalPrice?: number | null\n note?: string | null\n breakdown?: { tiers: TierBreakdownEntry[] } | null\n adjustments?: RuleAdjustment[] | null\n listUnitPrice?: number\n listTotalPrice?: number | null\n standardUnitPrice?: number\n standardTotalPrice?: number | null\n}\n\n/** Order lines carry the quote's stored waterfall verbatim (no recalculation at conversion). */\nfunction toChargeRow(c: ResolvedCharge): ChargeRowView {\n return { ...c, chargeName: c.chargeName ?? '\u2014', chargeType: (c.chargeType ?? 'mrc') as 'nrc' | 'mrc' | 'usage', unitPrice: c.unitPrice ?? 0, totalPrice: c.totalPrice ?? null }\n}\n\ntype OrderLineResult = {\n lineId: string\n offeringId: string | null\n offeringName: string\n offeringType: string | null\n productId: string | null\n specId: string | null\n action: string\n parentLineId: string | null\n quantity: number\n configuration: Record<string, unknown>\n startDate: string | null\n termMonths: number | null\n endDate: string | null\n nrcTotal: number\n mrcTotal: number\n charges: ResolvedCharge[]\n sourceQuoteLineId: string | null\n arcSource: ArcLineSource | null\n}\n\ntype OrderResult = {\n id: string\n orderId: string\n orderNumber: string\n customerId: string\n cpqStatus: string\n sourceQuoteId: string | null\n quoteType: string\n currencyCode: string\n pricingSummary: PricingSummaryView & { currencyCode: string }\n activatedAt: string | null\n createdAt: string\n lines: OrderLineResult[]\n}\n\nconst ARC_BADGE_VARIANTS: Record<string, 'brand' | 'success' | 'error'> = {\n amend: 'brand',\n renew: 'success',\n cancel: 'error',\n}\n\n\n// \u2500\u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nfunction fmt(amount: number, currency: string): string {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nasync function apiJson<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await fetch(url, init)\n const json = await res.json()\n if (!res.ok) throw new Error(json?.error ?? `Request failed (${res.status})`)\n return json as T\n}\n\n// \u2500\u2500\u2500 Main Page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 CpqOrderDetailPage(props: { params?: { id?: string } }) {\n const router = useRouter()\n const urlParams = useParams()\n const cpqOrderId = (props.params?.id ?? urlParams?.id) as string\n\n const [order, setOrder] = React.useState<OrderResult | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [activating, setActivating] = React.useState(false)\n const [expandedLines, setExpandedLines] = React.useState<Set<string>>(new Set())\n const [pricingDetail, setPricingDetail] = React.useState<{ lineIdx: number; chargeIdx: number } | null>(null)\n const [customerName, setCustomerName] = React.useState<string | null>(null)\n const [linkedSubscriptions, setLinkedSubscriptions] = React.useState<Array<{\n id: string\n name: string\n code: string\n status: string\n }>>([])\n\n // Find every subscription this order touches. NEW orders write\n // `sourceOrderId` on the freshly-created subscription, so a\n // `?sourceOrderId=\u2026` filter is enough there. ARC orders (amend /\n // renew / cancel) mutate existing subscriptions in place \u2014 the\n // subscription's `sourceOrderId` stays pinned to the original\n // order, so we also resolve targets via the source quote.\n const fetchLinkedSubscriptions = React.useCallback(\n async (orderConfigId: string, sourceQuoteId: string | null) => {\n const byOrderId = fetch(\n `/api/cpq/inventory/subscriptions?sourceOrderId=${orderConfigId}&pageSize=10`,\n )\n .then((r) => (r.ok ? r.json() : null))\n .then((d) => (d?.items ?? (Array.isArray(d) ? d : [])) as Array<{ id: string; name: string; code: string; status: string }>)\n .catch(() => [])\n\n const byTargets = sourceQuoteId\n ? fetch(`/api/cpq/quotes/${sourceQuoteId}/target-subscriptions`)\n .then((r) => (r.ok ? r.json() : null))\n .then(async (d) => {\n const targets: Array<{ subscriptionId: string }> = d?.items ?? []\n const fetched = await Promise.all(\n targets.map((t) =>\n fetch(`/api/cpq/inventory/subscriptions?id=${t.subscriptionId}`)\n .then((r) => (r.ok ? r.json() : null))\n .catch(() => null),\n ),\n )\n return fetched.filter(Boolean) as Array<{ id: string; name: string; code: string; status: string }>\n })\n .catch(() => [] as Array<{ id: string; name: string; code: string; status: string }>)\n : Promise.resolve([] as Array<{ id: string; name: string; code: string; status: string }>)\n\n const [a, b] = await Promise.all([byOrderId, byTargets])\n // Dedupe by id \u2014 a single subscription may appear in both lists\n // (e.g. a NEW order that was later amended into the same sub).\n const seen = new Set<string>()\n const merged: Array<{ id: string; name: string; code: string; status: string }> = []\n for (const sub of [...a, ...b]) {\n if (!sub || seen.has(sub.id)) continue\n seen.add(sub.id)\n merged.push({ id: sub.id, name: sub.name, code: sub.code, status: sub.status })\n }\n setLinkedSubscriptions(merged)\n },\n [],\n )\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n try {\n const result = await apiJson<OrderResult>(`/api/cpq/orders/${cpqOrderId}`)\n if (!cancelled) {\n setOrder(result)\n fetch(`/api/customers/companies?id=${result.customerId}&pageSize=1`)\n .then((r) => r.json())\n .then((data) => {\n const items = data.items ?? data ?? []\n const c = items[0]\n if (c && !cancelled) setCustomerName(c.display_name || c.displayName || c.name || null)\n })\n .catch(() => {})\n if (result.cpqStatus === 'active' || result.cpqStatus === 'fulfilled') {\n void fetchLinkedSubscriptions(result.id, result.sourceQuoteId)\n }\n }\n } catch (err) {\n if (!cancelled) setError((err as Error).message)\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [cpqOrderId, fetchLinkedSubscriptions])\n\n const activateOrder = async () => {\n if (!order) return\n try {\n setActivating(true)\n setError(null)\n const result = await apiJson<OrderResult>(`/api/cpq/orders/${order.id}/activate`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n setOrder(result)\n void fetchLinkedSubscriptions(result.id, result.sourceQuoteId)\n } catch (err) {\n setError((err as Error).message)\n } finally {\n setActivating(false)\n }\n }\n\n const cancelOrder = async () => {\n if (!order) return\n try {\n setError(null)\n const result = await apiJson<OrderResult>(`/api/cpq/orders/${order.id}/status`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ targetStatus: 'cancelled' }),\n })\n setOrder(result)\n } catch (err) {\n setError((err as Error).message)\n }\n }\n\n const toggleLine = (id: string) => {\n setExpandedLines((prev) => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n })\n }\n\n // \u2500\u2500\u2500 Render: loading / error \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 (\n <div className=\"flex items-center gap-2 py-12 justify-center text-sm text-muted-foreground\">\n <Spinner /> Loading\u2026\n </div>\n )\n }\n\n if (!order) {\n return (\n <div className=\"space-y-4\">\n <button onClick={() => router.push('/backend/cpq/orders')} className=\"text-sm text-muted-foreground hover:text-foreground\">\u2190 Back to Orders</button>\n {error && <ErrorBanner message={error} />}\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">Order not found.</div>\n </div>\n )\n }\n\n // \u2500\u2500\u2500 Render: detail \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 canActivate = order.cpqStatus === 'draft' || order.cpqStatus === 'pending_activation'\n const canCancel = order.cpqStatus === 'draft' || order.cpqStatus === 'pending_activation' || order.cpqStatus === 'active'\n const currency = order.currencyCode\n\n const togglePricingDetail = (lineIdx: number, chargeIdx: number) => {\n setPricingDetail((prev) =>\n prev?.lineIdx === lineIdx && prev?.chargeIdx === chargeIdx ? null : { lineIdx, chargeIdx },\n )\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header \u2014 standard FormHeader detail mode, mirrors the CPQ quote\n layout so order \u2194 quote stays consistent. Title is just the order\n number; status / ARC / converted tags sit underneath; primary\n actions (Activate, then Cancel) live on the right next to the\n View Sales Order / Source Quote utility links. */}\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/cpq/orders\"\n backLabel=\"Back to CPQ Orders\"\n entityTypeLabel=\"CPQ Order\"\n title={order.orderNumber || order.orderId.slice(0, 8)}\n statusBadge={\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n <Tag variant={orderCpqStatusMap[order.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(order.cpqStatus)}\n </Tag>\n {order.quoteType && order.quoteType !== 'new' && (\n <Tag variant={ARC_BADGE_VARIANTS[order.quoteType] ?? 'neutral'} className=\"uppercase\">\n {order.quoteType}\n </Tag>\n )}\n </div>\n }\n actionsContent={\n <>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(`/backend/sales/orders/${order.orderId}`)}\n >\n <ExternalLink className=\"h-3.5 w-3.5\" />\n View Sales Order\n </Button>\n {order.sourceQuoteId && (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(`/backend/cpq/quotes/${order.sourceQuoteId}`)}\n >\n Source Quote\n </Button>\n )}\n {canActivate && (\n <Button type=\"button\" onClick={activateOrder} disabled={activating}>\n {activating ? <Spinner /> : <Play className=\"h-4 w-4\" />}\n Activate\n </Button>\n )}\n {canCancel && (\n <Button type=\"button\" variant=\"destructive-outline\" onClick={cancelOrder}>\n <X className=\"h-4 w-4\" />\n Cancel\n </Button>\n )}\n </>\n }\n />\n\n {/* Status path \u2014 visual progress only. Orders advance via the\n dedicated Activate / Cancel buttons because activation has\n backend side effects (subscription / asset creation). */}\n <div className=\"flex items-center gap-3 flex-wrap\">\n <StatusPath\n // Order path is read-only \u2014 activation has backend side effects\n // (subscription / asset creation) so transitions go through the\n // dedicated Activate / Cancel buttons.\n current={order.cpqStatus}\n path={['draft', 'pending_activation', 'active', 'fulfilled']}\n terminals={['cancelled']}\n statusMap={orderCpqStatusMap}\n ariaLabel=\"Order status path\"\n />\n </div>\n\n {error && <ErrorBanner message={error} onDismiss={() => setError(null)} />}\n\n {/* Linked subscriptions \u2014 one card per subscription this order\n touches. NEW orders write one fresh subscription; ARC orders\n (amend / renew / cancel) reach one or more existing\n subscriptions through the source quote's target list. */}\n {linkedSubscriptions.length > 0 && (\n <div className=\"space-y-2\">\n {linkedSubscriptions.map((sub) => (\n <div\n key={sub.id}\n className=\"rounded-lg border bg-card p-4 flex items-center gap-4\"\n >\n <div className=\"flex-1 min-w-0 space-y-1\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n Linked Subscription\n </span>\n <Tag\n variant={sub.status === 'active' ? 'success' : 'info'}\n dot\n className=\"text-[10px] px-1.5\"\n >\n {sub.status}\n </Tag>\n </div>\n <div className=\"text-sm font-medium\">\n {sub.name}{' '}\n <span className=\"text-muted-foreground font-mono text-xs\">({sub.code})</span>\n </div>\n {order.activatedAt && (\n <div className=\"text-xs text-muted-foreground\">\n Activated on {new Date(order.activatedAt).toLocaleString()}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(`/backend/cpq/inventory/subscriptions/${sub.id}`)}\n >\n <ArrowRight className=\"h-3.5 w-3.5\" />\n Open\n </Button>\n </div>\n ))}\n </div>\n )}\n\n {/* Meta cards \u2014 secondary reference info, matches the quote layout. */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n <MetaCard label=\"Customer\">\n {customerName ? (\n <span className=\"font-medium\">{customerName}</span>\n ) : (\n <span className=\"font-mono text-xs text-muted-foreground\">\n {order.customerId.slice(0, 8)}\u2026\n </span>\n )}\n </MetaCard>\n <MetaCard label=\"Created\">\n <span className=\"font-medium\">{new Date(order.createdAt).toLocaleDateString()}</span>\n </MetaCard>\n <MetaCard label=\"Currency\">\n <span className=\"font-medium\">{currency}</span>\n </MetaCard>\n </div>\n\n <PricingSummaryCard\n summary={order.pricingSummary}\n currency={currency}\n arcDelta={order.quoteType === 'amend' || order.quoteType === 'renew'\n ? arcRecurringDelta(order.lines.map((l) => ({ ...l, action: l.action as 'add' | 'modify' | 'cancel' })))\n : null}\n />\n\n {/* Order Lines */}\n <OrderLineTree\n lines={order.lines}\n quoteType={order.quoteType}\n currency={currency}\n expandedLines={expandedLines}\n pricingDetail={pricingDetail}\n onToggleLine={toggleLine}\n onTogglePricingDetail={togglePricingDetail}\n />\n </div>\n )\n}\n\nfunction MetaCard({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {label}\n </div>\n <div className=\"mt-1 text-sm\">{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Sub-components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nfunction OrderLineTree({\n lines,\n quoteType,\n currency,\n expandedLines,\n pricingDetail,\n onToggleLine,\n onTogglePricingDetail,\n}: {\n lines: OrderLineResult[]\n quoteType: string\n currency: string\n expandedLines: Set<string>\n pricingDetail: { lineIdx: number; chargeIdx: number } | null\n onToggleLine: (id: string) => void\n onTogglePricingDetail: (lineIdx: number, chargeIdx: number) => void\n}) {\n const rootLines = lines.filter((l) => !l.parentLineId)\n const childrenByParent = new Map<string, OrderLineResult[]>()\n for (const line of lines) {\n if (line.parentLineId) {\n const arr = childrenByParent.get(line.parentLineId) ?? []\n arr.push(line)\n childrenByParent.set(line.parentLineId, arr)\n }\n }\n\n // Stable index per visible line so the pricing-detail toggle can be\n // keyed by (lineIdx, chargeIdx) the same way the quote page does.\n const indexOf = new Map<string, number>()\n lines.forEach((l, i) => indexOf.set(l.lineId, i))\n\n return (\n <div>\n <h3 className=\"text-sm font-medium mb-2 px-1\">Line Items ({lines.length})</h3>\n {lines.length === 0 ? (\n <div className=\"rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground\">\n No line items.\n </div>\n ) : (\n <div className=\"rounded-lg border bg-card divide-y\">\n {rootLines.map((line) => {\n const isBundle = line.offeringType === 'bundle'\n const children = childrenByParent.get(line.lineId) ?? []\n const isExpanded = expandedLines.has(line.lineId)\n const lineIdx = indexOf.get(line.lineId) ?? 0\n return (\n <div key={line.lineId}>\n <OrderLineRow\n line={line}\n lineIdx={lineIdx}\n quoteType={quoteType}\n currency={currency}\n isExpanded={isExpanded}\n isBundle={isBundle}\n childCount={children.length}\n indent={0}\n pricingDetail={pricingDetail}\n onToggle={() => onToggleLine(line.lineId)}\n onTogglePricingDetail={onTogglePricingDetail}\n />\n {isBundle && isExpanded && children.length > 0 && (\n <div className=\"border-t border-dashed border-brand-violet/30 bg-brand-violet/5\">\n <div className=\"px-6 py-1.5\">\n <span className=\"text-[10px] font-medium text-brand-violet uppercase tracking-wider\">Bundle Components ({children.length})</span>\n </div>\n {children.map((child) => {\n const childIdx = indexOf.get(child.lineId) ?? 0\n return (\n <OrderLineRow\n key={child.lineId}\n line={child}\n lineIdx={childIdx}\n quoteType={quoteType}\n currency={currency}\n isExpanded={expandedLines.has(child.lineId)}\n isBundle={false}\n childCount={0}\n indent={1}\n pricingDetail={pricingDetail}\n onToggle={() => onToggleLine(child.lineId)}\n onTogglePricingDetail={onTogglePricingDetail}\n />\n )\n })}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nfunction OrderLineRow({ line, lineIdx, quoteType, currency, isExpanded, isBundle, childCount, indent, pricingDetail, onToggle, onTogglePricingDetail }: {\n line: OrderLineResult; lineIdx: number; quoteType: string; currency: string; isExpanded: boolean; isBundle: boolean; childCount: number; indent: number\n pricingDetail: { lineIdx: number; chargeIdx: number } | null\n onToggle: () => void\n onTogglePricingDetail: (lineIdx: number, chargeIdx: number) => void\n}) {\n const t = useT()\n const paddingLeft = indent > 0 ? `${indent * 2 + 1}rem` : undefined\n // Same presentation as the quote page: an existing item removed on an\n // Amend / Renew quote reads as \"remove\", struck through.\n const isRemoved = isArcCancelledLine(line, quoteType)\n\n return (\n <div>\n <div\n className={`flex items-center gap-3 px-4 py-3 hover:bg-muted/30 transition-colors cursor-pointer ${isRemoved ? 'bg-muted/20' : ''}`}\n style={paddingLeft ? { paddingLeft } : undefined}\n onClick={onToggle}\n data-testid=\"cpq-order-line\"\n data-removed={isRemoved ? 'true' : undefined}\n >\n <button className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground\">\n <svg className={`h-4 w-4 transition-transform ${isExpanded ? 'rotate-90' : ''}`} fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth=\"2\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n {indent > 0 && <span className=\"text-muted-foreground text-xs\">\u2514</span>}\n {isBundle && (\n <Tag variant=\"brand\" className=\"px-1.5 text-xs\">bundle</Tag>\n )}\n <span className={`font-medium text-sm ${isRemoved ? 'text-muted-foreground line-through' : ''}`}>{line.offeringName}</span>\n {line.quantity > 1 && <span className=\"rounded bg-muted px-1.5 py-0.5 text-xs font-medium\">\u00D7{line.quantity}</span>}\n <LineActionBadge\n action={line.action}\n label={isRemoved ? t('cpq.quotes.arc.lineRemoved', 'remove') : undefined}\n title={isRemoved ? t('cpq.quotes.arc.lineRemovedHint', 'This item is cancelled on the subscription when the order is activated') : undefined}\n />\n {isBundle && <span className=\"text-xs text-muted-foreground\">{childCount} component{childCount !== 1 ? 's' : ''}</span>}\n </div>\n </div>\n\n <div className=\"shrink-0 text-right text-xs space-y-0.5\">\n {isRemoved && line.arcSource && line.arcSource.mrcAmount > 0 && (\n <div>\n <span className=\"text-muted-foreground\">MRC </span>\n <span className=\"font-mono text-muted-foreground line-through\">{fmt(line.arcSource.mrcAmount, currency)}</span>\n </div>\n )}\n {line.nrcTotal > 0 && <div><span className=\"text-muted-foreground\">NRC </span><span className=\"font-mono font-medium\">{fmt(line.nrcTotal, currency)}</span></div>}\n {line.mrcTotal > 0 && <div><span className=\"text-muted-foreground\">MRC </span><span className=\"font-mono font-medium\">{fmt(line.mrcTotal, currency)}</span></div>}\n </div>\n </div>\n\n {isExpanded && (() => {\n const internalKeys = new Set(['_arcMirroredName', '_arcMirroredFromItemId', '_arcPriceFrozen', '_arcRepriced', 'offeringName'])\n const visibleConfigEntries = Object.entries(line.configuration).filter(\n ([key]) => !internalKeys.has(key),\n )\n const hasConfig = visibleConfigEntries.length > 0\n const hasCharges = line.charges.length > 0\n const hasTerm = !!(line.startDate || line.termMonths || line.endDate)\n const hasArcDiff = !!line.arcSource\n const mirroredFromItemId = (line.configuration?._arcMirroredFromItemId as string | undefined) ?? null\n const isEmpty = !hasConfig && !hasCharges && !hasTerm && !hasArcDiff\n\n return (\n <div\n className=\"border-t bg-muted/10 px-12 py-3 space-y-3\"\n style={paddingLeft ? { paddingLeft: `calc(${paddingLeft} + 2rem)` } : undefined}\n >\n {isEmpty ? (\n <div className=\"text-xs text-muted-foreground space-y-1\">\n <div>\n No detailed breakdown for this line.\n {mirroredFromItemId && ' Mirrored from existing subscription item.'}\n </div>\n {(line.nrcTotal > 0 || line.mrcTotal > 0) && (\n <div className=\"flex gap-4\">\n {line.nrcTotal > 0 && (\n <span>NRC <span className=\"font-mono font-medium text-foreground\">{fmt(line.nrcTotal, currency)}</span></span>\n )}\n {line.mrcTotal > 0 && (\n <span>MRC <span className=\"font-mono font-medium text-foreground\">{fmt(line.mrcTotal, currency)}</span></span>\n )}\n </div>\n )}\n </div>\n ) : (\n <>\n {hasConfig && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-1\">Configuration</p>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-x-4 gap-y-1\">\n {visibleConfigEntries.map(([key, value]) => (\n <div key={key} className=\"text-xs\">\n <span className=\"text-muted-foreground\">{key}: </span>\n <span className=\"font-medium\">{String(value)}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {hasCharges && (\n <ChargeBreakdownTable\n charges={line.charges.map(toChargeRow)}\n currency={currency}\n openDetailIndex={pricingDetail?.lineIdx === lineIdx ? pricingDetail.chargeIdx : null}\n onToggleDetail={(chargeIdx) => onTogglePricingDetail(lineIdx, chargeIdx)}\n />\n )}\n\n {hasTerm && (\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n {line.startDate && <span>Start: {new Date(line.startDate).toLocaleDateString()}</span>}\n {line.termMonths && <span>Term: {line.termMonths}mo</span>}\n {line.endDate && <span>End: {new Date(line.endDate).toLocaleDateString()}</span>}\n </div>\n )}\n\n {/* XD-250 ARC: before/after preview below the charges, as on the quote. */}\n {hasArcDiff && <ArcLineDiff line={line} currency={currency} />}\n </>\n )}\n </div>\n )\n })()}\n </div>\n )\n}\n\nfunction Spinner() {\n return (\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )\n}\n\nfunction ErrorBanner({ message, onDismiss }: { message: string; onDismiss?: () => void }) {\n return (\n <Alert variant=\"destructive\" className=\"flex items-start gap-2\">\n <span className=\"flex-1\">{message}</span>\n {onDismiss && (\n <button\n onClick={onDismiss}\n className=\"text-destructive/70 hover:text-destructive text-sm font-bold\"\n aria-label=\"Dismiss\"\n >\n \u00D7\n </button>\n )}\n </Alert>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/cpq/backend/cpq/orders/page.meta.ts"],
|
|
4
|
-
"sourcesContent": ["import React from 'react'\nimport { ClipboardList } from 'lucide-react'\n\nconst ordersIcon = React.createElement(ClipboardList, { size: 16 })\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['cpq.orders.view'],\n pageTitle: 'CPQ Orders',\n pageTitleKey: 'cpq.orders.title',\n pageGroup: 'CPQ',\n pageGroupKey: 'customers~sales~cpq.nav.group',\n pageOrder:
|
|
4
|
+
"sourcesContent": ["import React from 'react'\nimport { ClipboardList } from 'lucide-react'\n\nconst ordersIcon = React.createElement(ClipboardList, { size: 16 })\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['cpq.orders.view'],\n pageTitle: 'CPQ Orders',\n pageTitleKey: 'cpq.orders.title',\n pageGroup: 'CPQ',\n pageGroupKey: 'customers~sales~cpq.nav.group',\n pageOrder: 2,\n icon: ordersIcon,\n breadcrumb: [{ label: 'CPQ Orders', labelKey: 'cpq.orders.title' }],\n} as const\n"],
|
|
5
5
|
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAE9B,MAAM,aAAa,MAAM,cAAc,eAAe,EAAE,MAAM,GAAG,CAAC;AAE3D,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,iBAAiB;AAAA,EACnC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY,CAAC,EAAE,OAAO,cAAc,UAAU,mBAAmB,CAAC;AACpE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
6
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
8
|
+
import { Textarea } from "@open-mercato/ui/primitives/textarea";
|
|
9
|
+
import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
|
|
10
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
|
|
11
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@open-mercato/ui/primitives/select";
|
|
12
|
+
import {
|
|
13
|
+
ADJUSTMENT_ERROR_FALLBACKS,
|
|
14
|
+
adjustmentErrorCode,
|
|
15
|
+
allowedAdjustmentTypes,
|
|
16
|
+
buildAdjustmentDraft,
|
|
17
|
+
formatDepth,
|
|
18
|
+
discountDepth,
|
|
19
|
+
toAdjustmentPatch
|
|
20
|
+
} from "../../../../../lib/priceAdjustmentView.js";
|
|
21
|
+
const TYPE_FALLBACKS = {
|
|
22
|
+
price_override: "Set a new unit price",
|
|
23
|
+
discount_percent: "Percentage discount",
|
|
24
|
+
discount_absolute: "Amount off the charge total"
|
|
25
|
+
};
|
|
26
|
+
function money(amount, currency) {
|
|
27
|
+
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
|
|
28
|
+
}
|
|
29
|
+
function PriceAdjustmentDialog(props) {
|
|
30
|
+
const { open, quoteId, currency, pricingRevision, target, targetLabel, charge, existing, storedAdjustmentIds, reasons, onClose, onSaved, onStale } = props;
|
|
31
|
+
const t = useT();
|
|
32
|
+
const types = allowedAdjustmentTypes(target.level, charge);
|
|
33
|
+
const initialForm = React.useCallback(() => ({
|
|
34
|
+
adjustmentType: existing?.adjustmentType ?? types[0] ?? "discount_percent",
|
|
35
|
+
value: existing ? String(existing.value) : "",
|
|
36
|
+
reasonCode: existing?.reasonCode ?? "",
|
|
37
|
+
reasonNote: existing?.reasonNote ?? "",
|
|
38
|
+
chargeTypeFilter: existing?.chargeTypeFilter ?? ""
|
|
39
|
+
}), [existing, types]);
|
|
40
|
+
const [form, setForm] = React.useState(initialForm);
|
|
41
|
+
const [preview, setPreview] = React.useState(null);
|
|
42
|
+
const [previewing, setPreviewing] = React.useState(false);
|
|
43
|
+
const [errorCode, setErrorCode] = React.useState(null);
|
|
44
|
+
const [saving, setSaving] = React.useState(false);
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
if (open) {
|
|
47
|
+
setForm(initialForm());
|
|
48
|
+
setPreview(null);
|
|
49
|
+
setErrorCode(null);
|
|
50
|
+
}
|
|
51
|
+
}, [open]);
|
|
52
|
+
const draft = buildAdjustmentDraft(form, target, currency, pricingRevision);
|
|
53
|
+
const draftKey = draft && form.reasonCode ? JSON.stringify(draft) : null;
|
|
54
|
+
const message = (code) => t(`cpq.priceAdjustments.errors.${code}`, ADJUSTMENT_ERROR_FALLBACKS[code] ?? code);
|
|
55
|
+
React.useEffect(() => {
|
|
56
|
+
if (!open || !draftKey) {
|
|
57
|
+
setPreview(null);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
let cancelled = false;
|
|
61
|
+
const timer = window.setTimeout(async () => {
|
|
62
|
+
setPreviewing(true);
|
|
63
|
+
const call = await apiCall(
|
|
64
|
+
`/api/cpq/quotes/${quoteId}/price-adjustments/preview`,
|
|
65
|
+
{ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ draft: JSON.parse(draftKey), ...existing ? { replaceAdjustmentId: existing.id } : {} }) }
|
|
66
|
+
);
|
|
67
|
+
if (cancelled) return;
|
|
68
|
+
setPreviewing(false);
|
|
69
|
+
if (call.ok && call.result) {
|
|
70
|
+
setPreview(call.result);
|
|
71
|
+
setErrorCode(null);
|
|
72
|
+
} else {
|
|
73
|
+
setPreview(null);
|
|
74
|
+
setErrorCode(adjustmentErrorCode(call.status, call.result));
|
|
75
|
+
}
|
|
76
|
+
}, 400);
|
|
77
|
+
return () => {
|
|
78
|
+
cancelled = true;
|
|
79
|
+
window.clearTimeout(timer);
|
|
80
|
+
};
|
|
81
|
+
}, [open, draftKey, quoteId, existing]);
|
|
82
|
+
const previewLine = preview?.quote.lines.find((line) => line.lineId === target.quoteLineId);
|
|
83
|
+
const previewCharge = target.level === "charge" ? previewLine?.charges.find((entry) => entry.chargeCode === target.chargeCode) : void 0;
|
|
84
|
+
const previewErrors = preview?.errors.filter((error) => existing ? error.adjustmentId === existing.id : !storedAdjustmentIds.includes(error.adjustmentId)) ?? [];
|
|
85
|
+
const noteRequired = form.reasonCode === "other" && !form.reasonNote.trim();
|
|
86
|
+
const canSave = !!draft && !!form.reasonCode && !noteRequired && !saving && previewErrors.length === 0;
|
|
87
|
+
const save = async () => {
|
|
88
|
+
if (!draft || !canSave) return;
|
|
89
|
+
setSaving(true);
|
|
90
|
+
setErrorCode(null);
|
|
91
|
+
const call = existing ? await apiCall(`/api/cpq/quotes/${quoteId}/price-adjustments/${existing.id}`, {
|
|
92
|
+
method: "PATCH",
|
|
93
|
+
headers: { "content-type": "application/json" },
|
|
94
|
+
body: JSON.stringify(toAdjustmentPatch(draft))
|
|
95
|
+
}) : await apiCall(`/api/cpq/quotes/${quoteId}/price-adjustments`, {
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: { "content-type": "application/json" },
|
|
98
|
+
body: JSON.stringify(draft)
|
|
99
|
+
});
|
|
100
|
+
setSaving(false);
|
|
101
|
+
if (call.ok && call.result?.quote) {
|
|
102
|
+
onSaved(call.result.quote);
|
|
103
|
+
onClose();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
setErrorCode(adjustmentErrorCode(call.status, call.result));
|
|
107
|
+
};
|
|
108
|
+
const onKeyDown = (event) => {
|
|
109
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
void save();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const standardUnit = charge?.standardUnitPrice ?? charge?.unitPrice;
|
|
115
|
+
const valueHint = form.adjustmentType === "discount_percent" ? t("cpq.priceAdjustments.dialog.percentHint", "Percent off the standard price (0\u2013100)") : form.adjustmentType === "price_override" ? t("cpq.priceAdjustments.dialog.overrideHint", "New unit price, at most the standard price") : t("cpq.priceAdjustments.dialog.absoluteHint", "Amount taken off this charge\u2019s total");
|
|
116
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (next) => {
|
|
117
|
+
if (!next) onClose();
|
|
118
|
+
}, children: /* @__PURE__ */ jsxs(DialogContent, { onKeyDown, "data-testid": "cpq-price-adjustment-dialog", children: [
|
|
119
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
120
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: existing ? t("cpq.priceAdjustments.dialog.editTitle", "Edit price adjustment") : target.level === "line" ? t("cpq.priceAdjustments.dialog.lineTitle", "Discount line") : t("cpq.priceAdjustments.dialog.chargeTitle", "Adjust price") }),
|
|
121
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
122
|
+
targetLabel,
|
|
123
|
+
charge && standardUnit !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
124
|
+
" \xB7 ",
|
|
125
|
+
t("cpq.priceAdjustments.dialog.standard", "Standard"),
|
|
126
|
+
" ",
|
|
127
|
+
money(standardUnit, currency)
|
|
128
|
+
] })
|
|
129
|
+
] })
|
|
130
|
+
] }),
|
|
131
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3 text-sm", children: [
|
|
132
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1", children: [
|
|
133
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: t("cpq.priceAdjustments.dialog.type", "Adjustment") }),
|
|
134
|
+
/* @__PURE__ */ jsxs(Select, { value: form.adjustmentType, onValueChange: (value) => setForm({ ...form, adjustmentType: value }), children: [
|
|
135
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
136
|
+
/* @__PURE__ */ jsx(SelectContent, { children: types.map((type) => /* @__PURE__ */ jsx(SelectItem, { value: type, children: t(`cpq.priceAdjustments.dialog.types.${type}`, TYPE_FALLBACKS[type]) }, type)) })
|
|
137
|
+
] })
|
|
138
|
+
] }),
|
|
139
|
+
target.level === "line" && /* @__PURE__ */ jsxs("label", { className: "block space-y-1", children: [
|
|
140
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: t("cpq.priceAdjustments.dialog.appliesTo", "Applies to") }),
|
|
141
|
+
/* @__PURE__ */ jsxs(Select, { value: form.chargeTypeFilter || "all", onValueChange: (value) => setForm({ ...form, chargeTypeFilter: value === "all" ? "" : value }), children: [
|
|
142
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
143
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
144
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "all", children: t("cpq.priceAdjustments.dialog.allCharges", "All one-time and recurring charges") }),
|
|
145
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "mrc", children: t("cpq.priceAdjustments.dialog.mrcOnly", "Recurring charges only") }),
|
|
146
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "nrc", children: t("cpq.priceAdjustments.dialog.nrcOnly", "One-time charges only") })
|
|
147
|
+
] })
|
|
148
|
+
] })
|
|
149
|
+
] }),
|
|
150
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1", children: [
|
|
151
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: t("cpq.priceAdjustments.dialog.value", "Value") }),
|
|
152
|
+
/* @__PURE__ */ jsx(Input, { inputMode: "decimal", autoFocus: true, value: form.value, onChange: (event) => setForm({ ...form, value: event.target.value }), "aria-describedby": "cpq-adjustment-value-hint" }),
|
|
153
|
+
/* @__PURE__ */ jsx("span", { id: "cpq-adjustment-value-hint", className: "block text-xs text-muted-foreground", children: valueHint })
|
|
154
|
+
] }),
|
|
155
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1", children: [
|
|
156
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: t("cpq.priceAdjustments.dialog.reason", "Reason") }),
|
|
157
|
+
/* @__PURE__ */ jsxs(Select, { value: form.reasonCode, onValueChange: (value) => setForm({ ...form, reasonCode: value }), children: [
|
|
158
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("cpq.priceAdjustments.dialog.reasonPlaceholder", "Pick a reason") }) }),
|
|
159
|
+
/* @__PURE__ */ jsx(SelectContent, { children: reasons.map((reason) => /* @__PURE__ */ jsx(SelectItem, { value: reason.value, children: reason.label }, reason.value)) })
|
|
160
|
+
] })
|
|
161
|
+
] }),
|
|
162
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1", children: [
|
|
163
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", children: [
|
|
164
|
+
t("cpq.priceAdjustments.dialog.note", "Note"),
|
|
165
|
+
form.reasonCode === "other" ? " *" : ""
|
|
166
|
+
] }),
|
|
167
|
+
/* @__PURE__ */ jsx(Textarea, { rows: 2, maxLength: 500, value: form.reasonNote, onChange: (event) => setForm({ ...form, reasonNote: event.target.value }) })
|
|
168
|
+
] }),
|
|
169
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded border bg-muted/20 p-2 text-xs", "aria-live": "polite", "data-testid": "cpq-adjustment-preview", children: [
|
|
170
|
+
!draftKey && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("cpq.priceAdjustments.dialog.previewEmpty", "Enter a value and reason to preview the new price.") }),
|
|
171
|
+
draftKey && previewing && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("cpq.priceAdjustments.dialog.previewing", "Calculating\u2026") }),
|
|
172
|
+
draftKey && !previewing && previewCharge && /* @__PURE__ */ jsxs("span", { children: [
|
|
173
|
+
t("cpq.priceAdjustments.dialog.previewCharge", "New offer price"),
|
|
174
|
+
": ",
|
|
175
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: money(previewCharge.unitPrice, currency) }),
|
|
176
|
+
" ",
|
|
177
|
+
formatDepth(discountDepth(previewCharge.standardUnitPrice ?? standardUnit, previewCharge.unitPrice)) ?? ""
|
|
178
|
+
] }),
|
|
179
|
+
draftKey && !previewing && !previewCharge && previewLine && /* @__PURE__ */ jsxs("span", { children: [
|
|
180
|
+
t("cpq.priceAdjustments.dialog.previewLine", "Line totals"),
|
|
181
|
+
": MRC ",
|
|
182
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: money(previewLine.mrcTotal, currency) }),
|
|
183
|
+
" \xB7 ",
|
|
184
|
+
"NRC ",
|
|
185
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: money(previewLine.nrcTotal, currency) })
|
|
186
|
+
] })
|
|
187
|
+
] }),
|
|
188
|
+
(errorCode || previewErrors.length > 0 || noteRequired) && /* @__PURE__ */ jsx(Alert, { variant: "warning", children: /* @__PURE__ */ jsxs(AlertDescription, { children: [
|
|
189
|
+
errorCode ? message(errorCode) : previewErrors.length > 0 ? message(previewErrors[0].code) : message("REASON_NOTE_REQUIRED"),
|
|
190
|
+
errorCode === "STALE_REVISION" && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "ml-2", onClick: () => {
|
|
191
|
+
onStale();
|
|
192
|
+
onClose();
|
|
193
|
+
}, children: t("cpq.priceAdjustments.dialog.reload", "Reload") })
|
|
194
|
+
] }) })
|
|
195
|
+
] }),
|
|
196
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
197
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, children: t("cpq.priceAdjustments.dialog.cancel", "Cancel") }),
|
|
198
|
+
/* @__PURE__ */ jsx(Button, { onClick: () => void save(), disabled: !canSave, title: "Ctrl/Cmd+Enter", children: saving ? t("cpq.priceAdjustments.dialog.saving", "Saving\u2026") : t("cpq.priceAdjustments.dialog.save", "Save") })
|
|
199
|
+
] })
|
|
200
|
+
] }) });
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
PriceAdjustmentDialog
|
|
204
|
+
};
|
|
205
|
+
//# sourceMappingURL=PriceAdjustmentDialog.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../../src/modules/cpq/backend/cpq/quotes/%5Bid%5D/_components/PriceAdjustmentDialog.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport {\n ADJUSTMENT_ERROR_FALLBACKS,\n adjustmentErrorCode,\n allowedAdjustmentTypes,\n buildAdjustmentDraft,\n formatDepth,\n discountDepth,\n toAdjustmentPatch,\n type AdjustmentForm,\n type AdjustmentTarget,\n type AdjustmentType,\n type WaterfallChargeInput,\n} from '../../../../../lib/priceAdjustmentView'\n\nexport type AdjustmentReason = { value: string; label: string }\n\n/** Minimal view of the quote the dialog needs, kept local so the page owns the full type. */\ntype PreviewQuote = {\n pricingRevision?: number\n lines: Array<{ lineId: string; mrcTotal: number; nrcTotal: number; charges: Array<WaterfallChargeInput & { chargeCode: string; adjustmentErrors?: Array<{ adjustmentId: string; code: string }> }> }>\n}\n\nexport type ExistingAdjustment = {\n id: string\n adjustmentType: AdjustmentType\n value: number\n reasonCode: string\n reasonNote?: string | null\n chargeTypeFilter?: 'nrc' | 'mrc' | null\n}\n\nexport type PriceAdjustmentDialogProps<Q extends PreviewQuote> = {\n open: boolean\n quoteId: string\n currency: string\n pricingRevision: number\n target: AdjustmentTarget\n /** Display name of the line / charge being adjusted. */\n targetLabel: string\n /** The charge for charge-level targets (drives type options and the current price). */\n charge?: WaterfallChargeInput & { chargeCode: string; chargeName: string }\n existing?: ExistingAdjustment | null\n /** Ids of adjustments already stored on the quote; their errors don't block this draft. */\n storedAdjustmentIds: string[]\n reasons: AdjustmentReason[]\n onClose: () => void\n onSaved: (quote: Q) => void\n /** Called when the server reports a stale revision; the page reloads the quote. */\n onStale: () => void\n}\n\nconst TYPE_FALLBACKS: Record<AdjustmentType, string> = {\n price_override: 'Set a new unit price',\n discount_percent: 'Percentage discount',\n discount_absolute: 'Amount off the charge total',\n}\n\nfunction money(amount: number, currency: string) {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nexport function PriceAdjustmentDialog<Q extends PreviewQuote>(props: PriceAdjustmentDialogProps<Q>) {\n const { open, quoteId, currency, pricingRevision, target, targetLabel, charge, existing, storedAdjustmentIds, reasons, onClose, onSaved, onStale } = props\n const t = useT()\n const types = allowedAdjustmentTypes(target.level, charge)\n const initialForm = React.useCallback((): AdjustmentForm => ({\n adjustmentType: existing?.adjustmentType ?? types[0] ?? 'discount_percent',\n value: existing ? String(existing.value) : '',\n reasonCode: existing?.reasonCode ?? '',\n reasonNote: existing?.reasonNote ?? '',\n chargeTypeFilter: existing?.chargeTypeFilter ?? '',\n }), [existing, types])\n const [form, setForm] = React.useState<AdjustmentForm>(initialForm)\n const [preview, setPreview] = React.useState<{ quote: Q; errors: Array<{ adjustmentId: string; code: string }> } | null>(null)\n const [previewing, setPreviewing] = React.useState(false)\n const [errorCode, setErrorCode] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (open) { setForm(initialForm()); setPreview(null); setErrorCode(null) }\n // Reset only when the dialog (re)opens.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n const draft = buildAdjustmentDraft(form, target, currency, pricingRevision)\n const draftKey = draft && form.reasonCode ? JSON.stringify(draft) : null\n const message = (code: string) => t(`cpq.priceAdjustments.errors.${code}`, ADJUSTMENT_ERROR_FALLBACKS[code] ?? code)\n\n // Debounced, side-effect-free preview of the draft.\n React.useEffect(() => {\n if (!open || !draftKey) { setPreview(null); return }\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setPreviewing(true)\n const call = await apiCall<{ quote: Q; errors: Array<{ adjustmentId: string; code: string }> }>(\n `/api/cpq/quotes/${quoteId}/price-adjustments/preview`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ draft: JSON.parse(draftKey), ...(existing ? { replaceAdjustmentId: existing.id } : {}) }) },\n )\n if (cancelled) return\n setPreviewing(false)\n if (call.ok && call.result) { setPreview(call.result); setErrorCode(null) }\n else { setPreview(null); setErrorCode(adjustmentErrorCode(call.status, call.result)) }\n }, 400)\n return () => { cancelled = true; window.clearTimeout(timer) }\n }, [open, draftKey, quoteId, existing])\n\n const previewLine = preview?.quote.lines.find((line) => line.lineId === target.quoteLineId)\n const previewCharge = target.level === 'charge' ? previewLine?.charges.find((entry) => entry.chargeCode === target.chargeCode) : undefined\n // The draft's id is server-generated on create, so \"not stored\" identifies it; on edit it keeps its id.\n const previewErrors = preview?.errors.filter((error) => existing ? error.adjustmentId === existing.id : !storedAdjustmentIds.includes(error.adjustmentId)) ?? []\n const noteRequired = form.reasonCode === 'other' && !form.reasonNote.trim()\n const canSave = !!draft && !!form.reasonCode && !noteRequired && !saving && previewErrors.length === 0\n\n const save = async () => {\n if (!draft || !canSave) return\n setSaving(true); setErrorCode(null)\n const call = existing\n ? await apiCall<{ quote: Q }>(`/api/cpq/quotes/${quoteId}/price-adjustments/${existing.id}`, {\n method: 'PATCH', headers: { 'content-type': 'application/json' }, body: JSON.stringify(toAdjustmentPatch(draft)),\n })\n : await apiCall<{ quote: Q }>(`/api/cpq/quotes/${quoteId}/price-adjustments`, {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(draft),\n })\n setSaving(false)\n if (call.ok && call.result?.quote) { onSaved(call.result.quote); onClose(); return }\n setErrorCode(adjustmentErrorCode(call.status, call.result))\n }\n\n const onKeyDown = (event: React.KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') { event.preventDefault(); void save() }\n }\n\n const standardUnit = charge?.standardUnitPrice ?? charge?.unitPrice\n const valueHint = form.adjustmentType === 'discount_percent'\n ? t('cpq.priceAdjustments.dialog.percentHint', 'Percent off the standard price (0\u2013100)')\n : form.adjustmentType === 'price_override'\n ? t('cpq.priceAdjustments.dialog.overrideHint', 'New unit price, at most the standard price')\n : t('cpq.priceAdjustments.dialog.absoluteHint', 'Amount taken off this charge\u2019s total')\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!next) onClose() }}>\n <DialogContent onKeyDown={onKeyDown} data-testid=\"cpq-price-adjustment-dialog\">\n <DialogHeader>\n <DialogTitle>\n {existing\n ? t('cpq.priceAdjustments.dialog.editTitle', 'Edit price adjustment')\n : target.level === 'line'\n ? t('cpq.priceAdjustments.dialog.lineTitle', 'Discount line')\n : t('cpq.priceAdjustments.dialog.chargeTitle', 'Adjust price')}\n </DialogTitle>\n <DialogDescription>\n {targetLabel}\n {charge && standardUnit !== undefined && (\n <> \u00B7 {t('cpq.priceAdjustments.dialog.standard', 'Standard')} {money(standardUnit, currency)}</>\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-3 text-sm\">\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.type', 'Adjustment')}</span>\n <Select value={form.adjustmentType} onValueChange={(value) => setForm({ ...form, adjustmentType: value as AdjustmentType })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {types.map((type) => (\n <SelectItem key={type} value={type}>{t(`cpq.priceAdjustments.dialog.types.${type}`, TYPE_FALLBACKS[type])}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n\n {target.level === 'line' && (\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.appliesTo', 'Applies to')}</span>\n <Select value={form.chargeTypeFilter || 'all'} onValueChange={(value) => setForm({ ...form, chargeTypeFilter: value === 'all' ? '' : value as 'nrc' | 'mrc' })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{t('cpq.priceAdjustments.dialog.allCharges', 'All one-time and recurring charges')}</SelectItem>\n <SelectItem value=\"mrc\">{t('cpq.priceAdjustments.dialog.mrcOnly', 'Recurring charges only')}</SelectItem>\n <SelectItem value=\"nrc\">{t('cpq.priceAdjustments.dialog.nrcOnly', 'One-time charges only')}</SelectItem>\n </SelectContent>\n </Select>\n </label>\n )}\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.value', 'Value')}</span>\n <Input inputMode=\"decimal\" autoFocus value={form.value} onChange={(event) => setForm({ ...form, value: event.target.value })} aria-describedby=\"cpq-adjustment-value-hint\" />\n <span id=\"cpq-adjustment-value-hint\" className=\"block text-xs text-muted-foreground\">{valueHint}</span>\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.reason', 'Reason')}</span>\n <Select value={form.reasonCode} onValueChange={(value) => setForm({ ...form, reasonCode: value })}>\n <SelectTrigger><SelectValue placeholder={t('cpq.priceAdjustments.dialog.reasonPlaceholder', 'Pick a reason')} /></SelectTrigger>\n <SelectContent>\n {reasons.map((reason) => <SelectItem key={reason.value} value={reason.value}>{reason.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">\n {t('cpq.priceAdjustments.dialog.note', 'Note')}{form.reasonCode === 'other' ? ' *' : ''}\n </span>\n <Textarea rows={2} maxLength={500} value={form.reasonNote} onChange={(event) => setForm({ ...form, reasonNote: event.target.value })} />\n </label>\n\n <div className=\"rounded border bg-muted/20 p-2 text-xs\" aria-live=\"polite\" data-testid=\"cpq-adjustment-preview\">\n {!draftKey && <span className=\"text-muted-foreground\">{t('cpq.priceAdjustments.dialog.previewEmpty', 'Enter a value and reason to preview the new price.')}</span>}\n {draftKey && previewing && <span className=\"text-muted-foreground\">{t('cpq.priceAdjustments.dialog.previewing', 'Calculating\u2026')}</span>}\n {draftKey && !previewing && previewCharge && (\n <span>\n {t('cpq.priceAdjustments.dialog.previewCharge', 'New offer price')}: <span className=\"font-mono font-medium\">{money(previewCharge.unitPrice, currency)}</span>\n {' '}{formatDepth(discountDepth(previewCharge.standardUnitPrice ?? standardUnit, previewCharge.unitPrice)) ?? ''}\n </span>\n )}\n {draftKey && !previewing && !previewCharge && previewLine && (\n <span>\n {t('cpq.priceAdjustments.dialog.previewLine', 'Line totals')}: MRC <span className=\"font-mono font-medium\">{money(previewLine.mrcTotal, currency)}</span>\n {' \u00B7 '}NRC <span className=\"font-mono font-medium\">{money(previewLine.nrcTotal, currency)}</span>\n </span>\n )}\n </div>\n\n {(errorCode || previewErrors.length > 0 || noteRequired) && (\n <Alert variant=\"warning\">\n <AlertDescription>\n {errorCode ? message(errorCode) : previewErrors.length > 0 ? message(previewErrors[0].code) : message('REASON_NOTE_REQUIRED')}\n {errorCode === 'STALE_REVISION' && (\n <Button variant=\"outline\" size=\"sm\" className=\"ml-2\" onClick={() => { onStale(); onClose() }}>\n {t('cpq.priceAdjustments.dialog.reload', 'Reload')}\n </Button>\n )}\n </AlertDescription>\n </Alert>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose}>{t('cpq.priceAdjustments.dialog.cancel', 'Cancel')}</Button>\n <Button onClick={() => void save()} disabled={!canSave} title=\"Ctrl/Cmd+Enter\">\n {saving ? t('cpq.priceAdjustments.dialog.saving', 'Saving\u2026') : t('cpq.priceAdjustments.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|