@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/services/cpqQuotingService.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { SalesQuote, SalesQuoteLine } from '@open-mercato/core/modules/sales/data/entities'\nimport { CustomerEntity } from '@open-mercato/core/modules/customers/data/entities'\nimport type { SalesDocumentNumberGenerator } from '@open-mercato/core/modules/sales/services/salesDocumentNumberGenerator'\nimport {\n CpqQuoteConfiguration,\n CpqQuoteLineConfiguration,\n CpqQuoteTargetSubscription,\n CpqInventorySubscription,\n CpqInventorySubscriptionItem,\n CpqOrderConfiguration,\n CpqProductOffering,\n CpqProductSpecification,\n} from '../data/entities'\nimport type { DefaultCpqPricingService } from './cpqPricingService'\nimport type { DefaultCpqValidationService } from './cpqValidationService'\nimport type { DefaultCpqProductService } from './cpqProductService'\nimport type {\n CreateQuoteInput,\n QuoteItemInput,\n QuoteResult,\n QuoteLineResult,\n PricingSummary,\n ValidationError,\n ResolvedCharge,\n TenantScope,\n CpqStatus,\n CpqQuoteType,\n MergeAction,\n ArcReasonCode,\n ArcLineSource,\n} from './types'\nimport {\n ALLOWED_TRANSITIONS,\n TERMINAL_STATUSES,\n ARC_QUOTE_TYPES,\n getBaseCurrencyCode,\n} from './types'\n\ninterface QuotingServiceDeps {\n em: EntityManager\n cpqPricingService: DefaultCpqPricingService\n cpqValidationService: DefaultCpqValidationService\n cpqProductService: DefaultCpqProductService\n salesDocumentNumberGenerator: SalesDocumentNumberGenerator\n}\n\nexport class DefaultCpqQuotingService {\n private em: EntityManager\n private pricingService: DefaultCpqPricingService\n private validationService: DefaultCpqValidationService\n private productService: DefaultCpqProductService\n private numberGenerator: SalesDocumentNumberGenerator\n\n constructor(deps: QuotingServiceDeps) {\n this.em = deps.em\n this.pricingService = deps.cpqPricingService\n this.validationService = deps.cpqValidationService\n this.productService = deps.cpqProductService\n this.numberGenerator = deps.salesDocumentNumberGenerator\n }\n\n // \u2500\u2500\u2500 Create Quote \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async createQuote(input: CreateQuoteInput, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n // Validate customer exists (lookup by id + tenantId; organizationId may differ\n // between CPQ scope resolution and how the core customers API resolves it)\n const customer = await em.findOne(CustomerEntity, {\n id: input.customerId,\n tenantId: scope.tenantId,\n }, { populate: ['personProfile', 'companyProfile'] })\n\n if (!customer) {\n throw new QuotingError(404, 'Customer not found')\n }\n\n // Build customer snapshot\n const customerSnapshot = buildCustomerSnapshot(customer)\n\n // Build initial quote context from customer\n const quoteContext: Record<string, string | number | boolean> = {\n ...(input.quoteContext ?? {}),\n }\n if (customer.kind) quoteContext.customer_type = customer.kind\n if (customer.companyProfile?.domain) quoteContext.customer_domain = customer.companyProfile.domain\n\n const currencyCode = input.currencyCode ?? await getBaseCurrencyCode(em, scope)\n\n let salesQuote: SalesQuote\n let salesQuoteId: string\n\n if (input.quoteId) {\n // Link to existing SalesQuote\n const existing = await em.findOne(SalesQuote, {\n id: input.quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!existing) throw new QuotingError(404, 'Sales quote not found')\n\n // Check if CPQ config already exists\n const existingConfig = await em.findOne(CpqQuoteConfiguration, {\n quoteId: input.quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (existingConfig) {\n // Already initialized \u2014 just return the existing config\n const lines = await this.loadLineConfigs(em, existingConfig.id, scope)\n return this.buildQuoteResult(em, existingConfig, existing, lines)\n }\n\n salesQuote = existing\n salesQuoteId = existing.id\n } else {\n // Create new SalesQuote \u2014 assign UUID upfront so CpqQuoteConfiguration can reference it before flush\n salesQuoteId = crypto.randomUUID()\n\n const { number: quoteNumber } = await this.numberGenerator.generate({\n kind: 'quote',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n salesQuote = em.create(SalesQuote, {\n id: salesQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteNumber,\n customerEntityId: input.customerId,\n customerSnapshot,\n currencyCode,\n subtotalNetAmount: '0',\n subtotalGrossAmount: '0',\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n grandTotalNetAmount: '0',\n grandTotalGrossAmount: '0',\n lineItemCount: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(salesQuote)\n }\n\n // Create CpqQuoteConfiguration\n const cpqConfig = em.create(CpqQuoteConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: salesQuoteId,\n customerId: input.customerId,\n cpqStatus: 'new',\n version: 1,\n currencyCode,\n quoteContext,\n validationResult: { valid: true, errors: [] },\n pricingSummary: emptyPricingSummary(currencyCode),\n })\n em.persist(cpqConfig)\n\n await em.flush()\n\n return this.buildQuoteResult(em, cpqConfig, salesQuote, [])\n }\n\n // \u2500\u2500\u2500 Add Quote Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async addQuoteItem(quoteId: string, item: QuoteItemInput, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n // Resolve offering -> spec -> product\n const { offering, spec } = await this.resolveOffering(em, item, scope)\n\n // Merge context: quoteContext + designTimeValues + user configuration\n const mergedConfig = {\n ...(cpqConfig.quoteContext ?? {}),\n ...(offering?.designTimeValues ?? {}),\n ...item.configuration,\n }\n\n // If termMonths is provided, include it in the merged config for pricing\n if (item.termMonths) {\n mergedConfig.term_months = item.termMonths\n }\n\n // Validate configuration\n let validationErrors: ValidationError[] = []\n if (offering) {\n const validation = await this.validationService.validateOfferingConfiguration({\n offeringId: offering.id,\n configuration: item.configuration,\n scope,\n })\n validationErrors = validation.errors\n }\n\n // Resolve charges\n const charges = await this.pricingService.resolveProductCharges({\n offeringId: offering?.id,\n productId: item.productId ?? spec?.productId,\n configuration: mergedConfig,\n currencyCode: cpqConfig.currencyCode,\n ...scope,\n })\n\n const quantity = item.quantity ?? 1\n\n // Compute line totals\n const { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated } = computeLineTotals(charges, quantity, item.usageEstimates)\n\n const isBundleOffering = offering?.offeringType === 'bundle'\n const isConfigured = validationErrors.length === 0 && (charges.length > 0 || isBundleOffering)\n\n // Compute end date\n const endDate = computeEndDate(item.startDate, item.termMonths, item.endDate)\n\n // Get current line count\n const existingLines = await em.find(SalesQuoteLine, {\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const lineNumber = existingLines.length + 1\n\n // Per-instance unit price (NRC + MRC for one instance)\n const perInstanceNrc = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const perInstanceMrc = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const unitPriceNet = perInstanceNrc + perInstanceMrc\n const totalNetAmount = unitPriceNet * quantity\n\n // Create SalesQuoteLine \u2014 assign UUID upfront so CpqQuoteLineConfiguration can reference it\n const quoteLineId = crypto.randomUUID()\n const quoteLine = em.create(SalesQuoteLine, {\n id: quoteLineId,\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber,\n kind: 'product',\n productId: spec?.productId ?? item.productId ?? null,\n name: offering?.name ?? spec?.name ?? 'Configured Item',\n quantity: String(quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(totalNetAmount),\n totalGrossAmount: String(totalNetAmount),\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: cpqConfig.currencyCode,\n configuration: {\n offeringId: offering?.id ?? null,\n offeringCode: offering?.code ?? null,\n action: item.action ?? 'add',\n nrcTotal: Number(nrcTotal),\n mrcTotal: Number(mrcTotal),\n parentLineId: item.parentLineId ?? null,\n },\n normalizedQuantity: String(quantity),\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(quoteLine)\n\n // XD-250 ARC: a new line on an ARC quote must point at one of the\n // attached target subscriptions (validateArcQuote enforces this on\n // submit-for-approval). Auto-inherit when there's exactly one target;\n // for merge-renew (\u22652 targets, all 'absorb') leave it null per spec.\n // The operator can override via item.targetSubscriptionId when a quote\n // has multiple non-merge targets.\n const arcTargetSubscriptionId = await resolveArcLineTargetSubscriptionId(\n em,\n cpqConfig,\n scope,\n item.targetSubscriptionId ?? undefined,\n )\n\n // Create CpqQuoteLineConfiguration\n const lineConfig = em.create(CpqQuoteLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteLineId: quoteLine.id,\n quoteConfigurationId: cpqConfig.id,\n offeringId: offering?.id ?? null,\n productId: spec?.productId ?? item.productId ?? null,\n specId: spec?.id ?? null,\n action: item.action ?? 'add',\n parentLineId: item.parentLineId ?? null,\n startDate: item.startDate ? new Date(item.startDate) : null,\n termMonths: item.termMonths ?? null,\n endDate: endDate ? new Date(endDate) : null,\n configuration: item.configuration,\n quantity,\n charges: charges as unknown as Array<Record<string, unknown>>,\n nrcTotal: String(nrcTotal),\n mrcTotal: String(mrcTotal),\n usageEstimates: usageEstimates ?? null,\n usageTotalEstimated: usageTotalEstimated != null ? String(usageTotalEstimated) : null,\n validationErrors: validationErrors.length > 0 ? validationErrors as unknown as Array<Record<string, unknown>> : null,\n isConfigured,\n targetSubscriptionId: arcTargetSubscriptionId,\n })\n em.persist(lineConfig)\n\n await em.flush()\n\n // Recalculate quote-level totals\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Update Quote Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async updateQuoteItem(\n quoteId: string,\n lineId: string,\n update: { configuration: Record<string, unknown>; quantity?: number; usageEstimates?: Array<{ chargeCode: string; estimatedQuantity: number }>; startDate?: string; termMonths?: number; endDate?: string },\n scope: TenantScope,\n ): Promise<QuoteResult> {\n const em = this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n const lineConfig = await em.findOne(CpqQuoteLineConfiguration, {\n quoteLineId: lineId,\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!lineConfig) throw new QuotingError(404, 'Quote line not found')\n\n const quoteLine = await em.findOne(SalesQuoteLine, {\n id: lineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!quoteLine) throw new QuotingError(404, 'Quote line not found')\n\n // Load offering for context merge\n let offering: CpqProductOffering | null = null\n if (lineConfig.offeringId) {\n offering = await em.findOne(CpqProductOffering, {\n id: lineConfig.offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n\n const mergedConfig = {\n ...(cpqConfig.quoteContext ?? {}),\n ...(offering?.designTimeValues ?? {}),\n ...update.configuration,\n }\n\n if (update.termMonths) {\n mergedConfig.term_months = update.termMonths\n }\n\n // Validate\n let validationErrors: ValidationError[] = []\n if (lineConfig.offeringId) {\n const validation = await this.validationService.validateOfferingConfiguration({\n offeringId: lineConfig.offeringId,\n configuration: update.configuration,\n scope,\n })\n validationErrors = validation.errors\n }\n\n // Preserve XD-250 ARC markers across edits \u2014 the UI doesn't echo them\n // back in `update.configuration`, so we'd lose `_arcMirroredFromItemId` /\n // `_arcMirroredName` (and downstream \"Mirrored from existing subscription\n // item\" rendering, plus the recalc / validate paths that key off them).\n const existingCfg = lineConfig.configuration as Record<string, unknown> | null\n const arcMarkers: Record<string, unknown> = {}\n if (existingCfg?._arcMirroredFromItemId !== undefined) {\n arcMarkers._arcMirroredFromItemId = existingCfg._arcMirroredFromItemId\n }\n if (existingCfg?._arcMirroredName !== undefined) {\n arcMarkers._arcMirroredName = existingCfg._arcMirroredName\n }\n update.configuration = { ...update.configuration, ...arcMarkers }\n mergedConfig._arcMirroredFromItemId = arcMarkers._arcMirroredFromItemId\n mergedConfig._arcMirroredName = arcMarkers._arcMirroredName\n\n // Re-price \u2014 same ARC mirror handling as recalculateInternal: skip the\n // pricing service when the line carries no offering / product (XD-250\n // mirror lines were created free-form). Without this guard, edits like\n // changing quantity wipe the synthesized charges and the line collapses\n // to \"incomplete\" with mrcTotal=0.\n const isArcMirrored = !!(arcMarkers._arcMirroredFromItemId)\n let charges: ResolvedCharge[]\n if (lineConfig.offeringId || lineConfig.productId) {\n charges = await this.pricingService.resolveProductCharges({\n offeringId: lineConfig.offeringId ?? undefined,\n productId: lineConfig.productId ?? undefined,\n configuration: mergedConfig,\n currencyCode: cpqConfig.currencyCode,\n ...scope,\n })\n } else {\n charges = (lineConfig.charges ?? []) as unknown as ResolvedCharge[]\n }\n\n const quantity = update.quantity ?? lineConfig.quantity\n const { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated } = computeLineTotals(charges, quantity, update.usageEstimates)\n const isBundleOffering = offering?.offeringType === 'bundle'\n const isConfigured =\n validationErrors.length === 0 && (charges.length > 0 || isBundleOffering || isArcMirrored)\n\n const endDate = computeEndDate(update.startDate ?? lineConfig.startDate?.toISOString(), update.termMonths ?? lineConfig.termMonths ?? undefined, update.endDate)\n\n // Update line config\n em.assign(lineConfig, {\n configuration: update.configuration,\n quantity,\n charges: charges as unknown as Array<Record<string, unknown>>,\n nrcTotal: String(nrcTotal),\n mrcTotal: String(mrcTotal),\n usageEstimates: usageEstimates ?? null,\n usageTotalEstimated: usageTotalEstimated != null ? String(usageTotalEstimated) : null,\n validationErrors: validationErrors.length > 0 ? validationErrors as unknown as Array<Record<string, unknown>> : null,\n isConfigured,\n startDate: update.startDate ? new Date(update.startDate) : lineConfig.startDate,\n termMonths: update.termMonths ?? lineConfig.termMonths,\n endDate: endDate ? new Date(endDate) : lineConfig.endDate,\n })\n\n // Update SalesQuoteLine totals\n const perInstanceNrc = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const perInstanceMrc = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const unitPriceNet = perInstanceNrc + perInstanceMrc\n\n em.assign(quoteLine, {\n quantity: String(quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(unitPriceNet * quantity),\n totalGrossAmount: String(unitPriceNet * quantity),\n updatedAt: new Date(),\n })\n\n await em.flush()\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Remove Quote Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async removeQuoteItem(quoteId: string, lineId: string, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n // Soft-delete the line and its children\n const lineConfig = await em.findOne(CpqQuoteLineConfiguration, {\n quoteLineId: lineId,\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!lineConfig) throw new QuotingError(404, 'Quote line not found')\n\n const now = new Date()\n lineConfig.deletedAt = now\n\n // Soft-delete children\n const children = await em.find(CpqQuoteLineConfiguration, {\n parentLineId: lineId,\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const child of children) {\n child.deletedAt = now\n // Also soft-delete the SalesQuoteLine\n const childSalesLine = await em.findOne(SalesQuoteLine, {\n id: child.quoteLineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (childSalesLine) childSalesLine.deletedAt = now\n }\n\n // Soft-delete the SalesQuoteLine\n const salesLine = await em.findOne(SalesQuoteLine, {\n id: lineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (salesLine) salesLine.deletedAt = now\n\n await em.flush()\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Get Quote (read from DB, no recalculation) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async getQuote(quoteId: string, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n const lineConfigs = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n return this.buildQuoteResult(em, cpqConfig, salesQuote, lineConfigs)\n }\n\n // \u2500\u2500\u2500 Recalculate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async recalculate(quoteId: string, options: { save: boolean }, scope: TenantScope): Promise<QuoteResult> {\n const em = options.save ? this.em.fork() : this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, options.save)\n }\n\n // \u2500\u2500\u2500 Clone Quote \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async cloneQuote(quoteId: string, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n const original = await this.loadCpqConfig(em, quoteId, scope)\n const originalQuote = await this.loadSalesQuote(em, original.quoteId, scope)\n\n // Generate new quote number\n const { number: quoteNumber } = await this.numberGenerator.generate({\n kind: 'quote',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n // Create new SalesQuote \u2014 assign UUID upfront\n const newSalesQuoteId = crypto.randomUUID()\n const newSalesQuote = em.create(SalesQuote, {\n id: newSalesQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteNumber,\n customerEntityId: originalQuote.customerEntityId,\n customerSnapshot: originalQuote.customerSnapshot,\n currencyCode: original.currencyCode,\n subtotalNetAmount: '0',\n subtotalGrossAmount: '0',\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n grandTotalNetAmount: '0',\n grandTotalGrossAmount: '0',\n lineItemCount: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(newSalesQuote)\n\n // Create new CpqQuoteConfiguration\n const newCpqConfig = em.create(CpqQuoteConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: newSalesQuoteId,\n customerId: original.customerId,\n cpqStatus: 'new',\n version: original.version + 1,\n parentQuoteId: original.id,\n currencyCode: original.currencyCode,\n quoteContext: original.quoteContext ? { ...original.quoteContext } : null,\n validationResult: { valid: true, errors: [] },\n pricingSummary: emptyPricingSummary(original.currencyCode),\n })\n em.persist(newCpqConfig)\n\n // Copy all lines\n const originalLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: original.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n // Map old lineId -> new lineId for parent references\n const lineIdMap = new Map<string, string>()\n\n for (const origLine of originalLines) {\n const origSalesLine = await em.findOne(SalesQuoteLine, {\n id: origLine.quoteLineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const newSalesLineId = crypto.randomUUID()\n const newSalesLine = em.create(SalesQuoteLine, {\n id: newSalesLineId,\n quote: newSalesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: origSalesLine?.lineNumber ?? 1,\n kind: origSalesLine?.kind ?? 'product',\n productId: origSalesLine?.productId ?? null,\n name: origSalesLine?.name ?? null,\n quantity: origSalesLine?.quantity ?? '1',\n unitPriceNet: origSalesLine?.unitPriceNet ?? '0',\n unitPriceGross: origSalesLine?.unitPriceGross ?? '0',\n totalNetAmount: origSalesLine?.totalNetAmount ?? '0',\n totalGrossAmount: origSalesLine?.totalGrossAmount ?? '0',\n discountAmount: origSalesLine?.discountAmount ?? '0',\n discountPercent: origSalesLine?.discountPercent ?? '0',\n taxRate: origSalesLine?.taxRate ?? '0',\n taxAmount: origSalesLine?.taxAmount ?? '0',\n currencyCode: origSalesLine?.currencyCode ?? original.currencyCode,\n configuration: origSalesLine?.configuration ?? null,\n normalizedQuantity: origSalesLine?.normalizedQuantity ?? '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(newSalesLine)\n\n lineIdMap.set(origLine.quoteLineId, newSalesLine.id)\n\n const newLineConfig = em.create(CpqQuoteLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteLineId: newSalesLine.id,\n quoteConfigurationId: newCpqConfig.id,\n offeringId: origLine.offeringId,\n productId: origLine.productId,\n specId: origLine.specId,\n action: origLine.action,\n parentLineId: null, // Will be resolved after all lines are created\n startDate: origLine.startDate,\n termMonths: origLine.termMonths,\n endDate: origLine.endDate,\n configuration: { ...origLine.configuration },\n quantity: origLine.quantity,\n charges: origLine.charges ? [...origLine.charges] : null,\n nrcTotal: origLine.nrcTotal,\n mrcTotal: origLine.mrcTotal,\n usageEstimates: origLine.usageEstimates,\n usageTotalEstimated: origLine.usageTotalEstimated,\n validationErrors: origLine.validationErrors,\n isConfigured: origLine.isConfigured,\n })\n em.persist(newLineConfig)\n }\n\n // Resolve parent line references\n const newLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: newCpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n for (const origLine of originalLines) {\n if (origLine.parentLineId) {\n const newParentLineId = lineIdMap.get(origLine.parentLineId)\n const newLine = newLines.find((l) => l.quoteLineId === lineIdMap.get(origLine.quoteLineId))\n if (newLine && newParentLineId) {\n newLine.parentLineId = newParentLineId\n }\n }\n }\n\n await em.flush()\n\n // Recalculate the new quote at current rates\n return this.recalculateInternal(em, newCpqConfig, newSalesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Transition Status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async transitionStatus(quoteId: string, targetStatus: string, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n const currentStatus = cpqConfig.cpqStatus as CpqStatus\n const allowed = ALLOWED_TRANSITIONS[currentStatus] ?? []\n\n if (!allowed.includes(targetStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot transition from '${currentStatus}' to '${targetStatus}'`)\n }\n\n // XD-250 ARC: at submit-for-approval (and the no-approval shortcuts that\n // bypass it), validate ARC invariants. Spec \u00A7 Services /\n // validateArcQuote: \"Called automatically on the submit-for-approval\n // transition.\" `quoteType ?? 'new'` defends against pre-existing rows\n // (and against test stubs) that may not carry the column \u2014 we only run\n // the ARC validator when the quote is explicitly an ARC type.\n const isSubmitForApproval =\n targetStatus === 'in_approval' ||\n targetStatus === 'pre_approved' ||\n targetStatus === 'with_customer'\n const quoteType = cpqConfig.quoteType ?? 'new'\n if (isSubmitForApproval && quoteType !== 'new') {\n const validation = await this.validateArcQuote(quoteId, scope)\n if (!validation.ok) {\n throw new QuotingError(\n 422,\n `ARC quote validation failed: ${validation.errors.join('; ')}`,\n )\n }\n }\n\n // The previous service-level guard required `with_customer` to come\n // from `approved` / `pre_approved` / `ready`. That conflicted with the\n // product decision to let operators jump between any pair of statuses,\n // so it was removed. ARC validation above remains as the real guard\n // against semantic inconsistency on the submit-for-approval path.\n\n cpqConfig.cpqStatus = targetStatus\n await em.flush()\n\n const lines = await this.loadLineConfigs(em, cpqConfig.id, scope)\n return this.buildQuoteResult(em, cpqConfig, salesQuote, lines)\n }\n\n // \u2500\u2500\u2500 Internal: Recalculate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 private async recalculateInternal(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n scope: TenantScope,\n save: boolean,\n ): Promise<QuoteResult> {\n const lineConfigs = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n let allValid = true\n const allErrors: ValidationError[] = []\n\n // Collect freshly computed data for each line (used for response regardless of save)\n const computedLines: Array<{\n lineConfig: CpqQuoteLineConfiguration\n charges: ResolvedCharge[]\n nrcTotal: number\n mrcTotal: number\n usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null\n usageTotalEstimated: number | null\n validationErrors: ValidationError[]\n isConfigured: boolean\n }> = []\n\n for (const lineConfig of lineConfigs) {\n let offering: CpqProductOffering | null = null\n if (lineConfig.offeringId) {\n offering = await em.findOne(CpqProductOffering, {\n id: lineConfig.offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n\n const mergedConfig = {\n ...(cpqConfig.quoteContext ?? {}),\n ...(offering?.designTimeValues ?? {}),\n ...lineConfig.configuration,\n }\n\n if (lineConfig.termMonths) {\n mergedConfig.term_months = lineConfig.termMonths\n }\n\n let validationErrors: ValidationError[] = []\n if (lineConfig.offeringId) {\n const validation = await this.validationService.validateOfferingConfiguration({\n offeringId: lineConfig.offeringId,\n configuration: lineConfig.configuration,\n scope,\n })\n validationErrors = validation.errors\n }\n\n // ARC-mirrored lines (XD-250) carry no offering/product because the\n // source subscription item was created free-form (e.g. seeded with just\n // a name + mrcAmount). Pricing service has nothing to resolve from, so\n // skip the call and keep the synthesized / copied charges already on\n // lineConfig \u2014 otherwise quantity edits would wipe them and flip the\n // line to \"incomplete\".\n const cfgRecord = lineConfig.configuration as Record<string, unknown> | null\n const isArcMirrored = !!(cfgRecord?._arcMirroredFromItemId)\n let charges: ResolvedCharge[]\n if (lineConfig.offeringId || lineConfig.productId) {\n charges = await this.pricingService.resolveProductCharges({\n offeringId: lineConfig.offeringId ?? undefined,\n productId: lineConfig.productId ?? undefined,\n configuration: mergedConfig,\n currencyCode: cpqConfig.currencyCode,\n ...scope,\n })\n } else {\n charges = (lineConfig.charges ?? []) as unknown as ResolvedCharge[]\n }\n\n const { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated } = computeLineTotals(\n charges,\n lineConfig.quantity,\n lineConfig.usageEstimates?.map((e) => ({ chargeCode: e.chargeCode, estimatedQuantity: e.estimatedQuantity })),\n )\n\n const isBundleOffering = offering?.offeringType === 'bundle'\n const isConfigured =\n validationErrors.length === 0 && (charges.length > 0 || isBundleOffering || isArcMirrored)\n if (!isConfigured) allValid = false\n allErrors.push(...validationErrors)\n\n computedLines.push({ lineConfig, charges, nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated, validationErrors, isConfigured })\n\n if (save) {\n em.assign(lineConfig, {\n charges: charges as unknown as Array<Record<string, unknown>>,\n nrcTotal: String(nrcTotal),\n mrcTotal: String(mrcTotal),\n usageEstimates: usageEstimates ?? null,\n usageTotalEstimated: usageTotalEstimated != null ? String(usageTotalEstimated) : null,\n validationErrors: validationErrors.length > 0 ? validationErrors as unknown as Array<Record<string, unknown>> : null,\n isConfigured,\n })\n\n const salesLine = await em.findOne(SalesQuoteLine, {\n id: lineConfig.quoteLineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (salesLine) {\n const perInstanceNrc = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const perInstanceMrc = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const unitPriceNet = perInstanceNrc + perInstanceMrc\n em.assign(salesLine, {\n quantity: String(lineConfig.quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(unitPriceNet * lineConfig.quantity),\n totalGrossAmount: String(unitPriceNet * lineConfig.quantity),\n updatedAt: new Date(),\n })\n }\n }\n }\n\n const relationshipErrors = await this.validationService.validateRelationships({\n lines: lineConfigs.map((l) => ({\n lineId: l.quoteLineId,\n specId: l.specId ?? null,\n parentLineId: l.parentLineId ?? null,\n })),\n scope,\n })\n allErrors.push(...relationshipErrors)\n if (relationshipErrors.length > 0) allValid = false\n\n let cpqStatus: CpqStatus\n if (lineConfigs.length === 0) {\n cpqStatus = 'new'\n } else if (!allValid) {\n cpqStatus = 'incomplete'\n } else {\n cpqStatus = 'ready'\n }\n\n const autoManagedStatuses: CpqStatus[] = ['new', 'incomplete', 'ready']\n if (autoManagedStatuses.includes(cpqConfig.cpqStatus as CpqStatus)) {\n cpqConfig.cpqStatus = cpqStatus\n }\n\n // Build pricing summary from freshly computed data (not from stale entity fields)\n const pricingSummary = computePricingSummaryFromComputed(computedLines, cpqConfig.currencyCode)\n\n const validationResult = { valid: allValid, errors: allErrors }\n\n if (save) {\n cpqConfig.validationResult = validationResult\n cpqConfig.pricingSummary = pricingSummary as unknown as Record<string, unknown>\n\n const grandTotal = pricingSummary.nrcTotal + pricingSummary.mrcTotal\n em.assign(salesQuote, {\n subtotalNetAmount: String(grandTotal),\n subtotalGrossAmount: String(grandTotal),\n grandTotalNetAmount: String(grandTotal),\n grandTotalGrossAmount: String(grandTotal),\n lineItemCount: lineConfigs.length,\n updatedAt: new Date(),\n })\n\n await em.flush()\n }\n\n return this.buildQuoteResultFromComputed(em, cpqConfig, salesQuote, computedLines, validationResult, pricingSummary)\n }\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async loadCpqConfig(em: EntityManager, quoteId: string, scope: TenantScope): Promise<CpqQuoteConfiguration> {\n // Try finding by CpqQuoteConfiguration.id first, then by quoteId\n let config = await em.findOne(CpqQuoteConfiguration, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqQuoteConfiguration, {\n quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new QuotingError(404, 'Quote not found')\n return config\n }\n\n private async loadSalesQuote(em: EntityManager, quoteId: string, scope: TenantScope): Promise<SalesQuote> {\n const quote = await em.findOne(SalesQuote, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!quote) throw new QuotingError(404, 'Sales quote not found')\n return quote\n }\n\n private async loadLineConfigs(em: EntityManager, cpqConfigId: string, scope: TenantScope): Promise<CpqQuoteLineConfiguration[]> {\n return em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n\n private async resolveOffering(\n em: EntityManager,\n item: QuoteItemInput,\n scope: TenantScope,\n ): Promise<{ offering: CpqProductOffering | null; spec: CpqProductSpecification | null }> {\n const dbScope = { organizationId: scope.organizationId, tenantId: scope.tenantId, deletedAt: null }\n\n if (item.offeringId) {\n const offering = await em.findOne(CpqProductOffering, { id: item.offeringId, ...dbScope })\n if (!offering) throw new QuotingError(404, `Offering ${item.offeringId} not found`)\n const spec = await em.findOne(CpqProductSpecification, { id: offering.specId, ...dbScope })\n return { offering, spec }\n }\n\n if (item.productId) {\n const spec = await em.findOne(CpqProductSpecification, { productId: item.productId, ...dbScope })\n return { offering: null, spec }\n }\n\n throw new QuotingError(400, 'Either offeringId or productId is required')\n }\n\n private async buildQuoteResult(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n lineConfigs: CpqQuoteLineConfiguration[],\n validationResult?: { valid: boolean; errors: ValidationError[] },\n pricingSummary?: PricingSummary,\n ): Promise<QuoteResult> {\n const lines: QuoteLineResult[] = []\n const arcSourceMap = await loadArcSourceMap(em, lineConfigs, cpqConfig)\n\n for (const lc of lineConfigs) {\n let offeringName: string | null = null\n let offeringType: string | null = null\n if (lc.offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: lc.offeringId,\n organizationId: cpqConfig.organizationId,\n tenantId: cpqConfig.tenantId,\n })\n if (offering) {\n offeringName = offering.name\n offeringType = offering.offeringType ?? 'simple'\n }\n }\n if (!offeringName) {\n const cfg = lc.configuration as Record<string, unknown> | null\n offeringName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n }\n\n lines.push({\n lineId: lc.quoteLineId,\n offeringId: lc.offeringId ?? null,\n offeringName,\n offeringType,\n productId: lc.productId ?? null,\n action: lc.action,\n parentLineId: lc.parentLineId ?? null,\n quantity: lc.quantity,\n configuration: lc.configuration ?? {},\n startDate: lc.startDate?.toISOString() ?? null,\n termMonths: lc.termMonths ?? null,\n endDate: lc.endDate?.toISOString() ?? null,\n nrcTotal: Number(lc.nrcTotal),\n mrcTotal: Number(lc.mrcTotal),\n usageEstimates: lc.usageEstimates ?? null,\n usageTotalEstimated: lc.usageTotalEstimated != null ? Number(lc.usageTotalEstimated) : null,\n charges: (lc.charges ?? []) as unknown as ResolvedCharge[],\n isConfigured: lc.isConfigured,\n validationErrors: lc.validationErrors as unknown as ValidationError[] ?? null,\n arcSource: pickArcSource(lc, arcSourceMap),\n targetSubscriptionId: lc.targetSubscriptionId ?? null,\n })\n }\n\n const finalValidation = validationResult ?? (cpqConfig.validationResult as { valid: boolean; errors: ValidationError[] }) ?? { valid: true, errors: [] }\n const finalPricing = pricingSummary ?? computePricingSummary(lineConfigs, cpqConfig.currencyCode)\n\n const { customerName, convertedOrderId } = await resolveQuoteSideData(em, cpqConfig)\n\n return {\n id: cpqConfig.id,\n quoteId: cpqConfig.quoteId,\n quoteNumber: salesQuote.quoteNumber ?? '',\n customerId: cpqConfig.customerId,\n customerName,\n cpqStatus: cpqConfig.cpqStatus,\n version: cpqConfig.version,\n parentQuoteId: cpqConfig.parentQuoteId ?? null,\n currencyCode: cpqConfig.currencyCode,\n convertedOrderId,\n validationResult: finalValidation,\n pricingSummary: finalPricing,\n lines,\n }\n }\n\n /**\n * Build quote result from freshly computed line data instead of (potentially stale) entity fields.\n * Used by recalculateInternal to ensure both save:true and save:false return current prices.\n */\n private async buildQuoteResultFromComputed(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n computedLines: Array<{\n lineConfig: CpqQuoteLineConfiguration\n charges: ResolvedCharge[]\n nrcTotal: number\n mrcTotal: number\n usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null\n usageTotalEstimated: number | null\n validationErrors: ValidationError[]\n isConfigured: boolean\n }>,\n validationResult: { valid: boolean; errors: ValidationError[] },\n pricingSummary: PricingSummary,\n ): Promise<QuoteResult> {\n const lines: QuoteLineResult[] = []\n const arcSourceMap = await loadArcSourceMap(\n em,\n computedLines.map((c) => c.lineConfig),\n cpqConfig,\n )\n\n for (const { lineConfig: lc, charges, nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated, validationErrors, isConfigured } of computedLines) {\n let offeringName: string | null = null\n let offeringType: string | null = null\n if (lc.offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: lc.offeringId,\n organizationId: cpqConfig.organizationId,\n tenantId: cpqConfig.tenantId,\n })\n if (offering) {\n offeringName = offering.name\n offeringType = offering.offeringType ?? 'simple'\n }\n }\n if (!offeringName) {\n const cfg = lc.configuration as Record<string, unknown> | null\n offeringName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n }\n\n lines.push({\n lineId: lc.quoteLineId,\n offeringId: lc.offeringId ?? null,\n offeringName,\n offeringType,\n productId: lc.productId ?? null,\n action: lc.action,\n parentLineId: lc.parentLineId ?? null,\n quantity: lc.quantity,\n configuration: lc.configuration ?? {},\n startDate: lc.startDate?.toISOString() ?? null,\n termMonths: lc.termMonths ?? null,\n endDate: lc.endDate?.toISOString() ?? null,\n nrcTotal,\n mrcTotal,\n usageEstimates,\n usageTotalEstimated,\n charges,\n isConfigured,\n validationErrors: validationErrors.length > 0 ? validationErrors : null,\n arcSource: pickArcSource(lc, arcSourceMap),\n targetSubscriptionId: lc.targetSubscriptionId ?? null,\n })\n }\n\n const { customerName, convertedOrderId } = await resolveQuoteSideData(em, cpqConfig)\n\n return {\n id: cpqConfig.id,\n quoteId: cpqConfig.quoteId,\n quoteNumber: salesQuote.quoteNumber ?? '',\n customerId: cpqConfig.customerId,\n customerName,\n cpqStatus: cpqConfig.cpqStatus,\n version: cpqConfig.version,\n parentQuoteId: cpqConfig.parentQuoteId ?? null,\n currencyCode: cpqConfig.currencyCode,\n convertedOrderId,\n validationResult,\n pricingSummary,\n lines,\n }\n }\n}\n\n// \u2500\u2500\u2500 Pure helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Load the bits of `QuoteResult` that don't live on `CpqQuoteConfiguration`\n * itself: the customer display name (for header / drawer labels) and any\n * existing converted order id (locks editing in the UI).\n */\nasync function resolveQuoteSideData(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n): Promise<{ customerName: string | null; convertedOrderId: string | null }> {\n const scope = {\n organizationId: cpqConfig.organizationId,\n tenantId: cpqConfig.tenantId,\n }\n\n const [customer, existingOrder] = await Promise.all([\n em.findOne(CustomerEntity, { id: cpqConfig.customerId, ...scope }),\n em.findOne(\n CpqOrderConfiguration,\n { sourceQuoteId: cpqConfig.id, ...scope, deletedAt: null },\n { fields: ['id', 'orderId'] as never },\n ),\n ])\n\n return {\n customerName: customer?.displayName ?? null,\n convertedOrderId: existingOrder?.orderId ?? null,\n }\n}\n\nfunction buildCustomerSnapshot(customer: CustomerEntity): Record<string, unknown> {\n return {\n customer: {\n id: customer.id,\n kind: customer.kind,\n displayName: customer.displayName,\n primaryEmail: customer.primaryEmail ?? null,\n primaryPhone: customer.primaryPhone ?? null,\n personProfile: customer.personProfile\n ? {\n id: customer.personProfile.id,\n firstName: customer.personProfile.firstName ?? null,\n lastName: customer.personProfile.lastName ?? null,\n preferredName: customer.personProfile.preferredName ?? null,\n }\n : null,\n companyProfile: customer.companyProfile\n ? {\n id: customer.companyProfile.id,\n legalName: customer.companyProfile.legalName ?? null,\n brandName: customer.companyProfile.brandName ?? null,\n domain: customer.companyProfile.domain ?? null,\n websiteUrl: customer.companyProfile.websiteUrl ?? null,\n }\n : null,\n },\n contact: null,\n }\n}\n\nfunction computeLineTotals(\n charges: ResolvedCharge[],\n quantity: number,\n usageEstimateInputs?: Array<{ chargeCode: string; estimatedQuantity: number }>,\n) {\n const nrcPerInstance = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const mrcPerInstance = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n\n const nrcTotal = nrcPerInstance * quantity\n const mrcTotal = mrcPerInstance * quantity\n\n let usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null = null\n let usageTotalEstimated: number | null = null\n\n if (usageEstimateInputs && usageEstimateInputs.length > 0) {\n const usageCharges = charges.filter((c) => c.chargeType === 'usage')\n usageEstimates = usageEstimateInputs.map((est) => {\n const charge = usageCharges.find((c) => c.chargeCode === est.chargeCode)\n const estimatedTotal = (charge?.unitPrice ?? 0) * est.estimatedQuantity\n return {\n chargeCode: est.chargeCode,\n estimatedQuantity: est.estimatedQuantity,\n estimatedTotal,\n }\n })\n usageTotalEstimated = usageEstimates.reduce((s, e) => s + e.estimatedTotal, 0) * quantity\n }\n\n return { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated }\n}\n\nfunction computeEndDate(startDate?: string | null, termMonths?: number, endDate?: string | null): string | null {\n if (endDate) return endDate\n if (startDate && termMonths) {\n const start = new Date(startDate)\n start.setMonth(start.getMonth() + termMonths)\n return start.toISOString().split('T')[0]\n }\n return null\n}\n\nfunction aggregateAdjustmentTotals(allCharges: ResolvedCharge[]): { discountTotal: number; surchargeTotal: number } {\n let discountTotal = 0\n let surchargeTotal = 0\n for (const charge of allCharges) {\n if (!charge.adjustments) continue\n for (const adj of charge.adjustments) {\n if (adj.delta < 0) {\n discountTotal += Math.abs(adj.delta) * (charge.quantity ?? 1)\n } else if (adj.delta > 0) {\n surchargeTotal += adj.delta * (charge.quantity ?? 1)\n }\n }\n }\n return { discountTotal, surchargeTotal }\n}\n\nfunction computePricingSummary(lineConfigs: CpqQuoteLineConfiguration[], currencyCode: string): PricingSummary {\n let nrcTotal = 0\n let mrcTotal = 0\n let usageTotalEstimated: number | null = null\n const usageCharges: PricingSummary['usageCharges'] = []\n const allCharges: ResolvedCharge[] = []\n\n for (const lc of lineConfigs) {\n nrcTotal += Number(lc.nrcTotal)\n mrcTotal += Number(lc.mrcTotal)\n if (lc.usageTotalEstimated != null) {\n usageTotalEstimated = (usageTotalEstimated ?? 0) + Number(lc.usageTotalEstimated)\n }\n\n const charges = (lc.charges ?? []) as unknown as ResolvedCharge[]\n allCharges.push(...charges)\n for (const charge of charges) {\n if (charge.chargeType === 'usage') {\n usageCharges.push({\n chargeCode: charge.chargeCode,\n chargeName: charge.chargeName,\n unitPrice: charge.unitPrice,\n note: charge.note ?? null,\n })\n }\n }\n }\n\n const { discountTotal, surchargeTotal } = aggregateAdjustmentTotals(allCharges)\n\n return {\n nrcTotal,\n mrcTotal,\n usageCharges,\n usageTotalEstimated,\n discountTotal,\n surchargeTotal,\n currencyCode,\n }\n}\n\nfunction computePricingSummaryFromComputed(\n computedLines: Array<{\n lineConfig: CpqQuoteLineConfiguration\n charges: ResolvedCharge[]\n nrcTotal: number\n mrcTotal: number\n usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null\n usageTotalEstimated: number | null\n }>,\n currencyCode: string,\n): PricingSummary {\n let nrcTotal = 0\n let mrcTotal = 0\n let usageTotalEstimated: number | null = null\n const usageCharges: PricingSummary['usageCharges'] = []\n const allCharges: ResolvedCharge[] = []\n\n for (const { charges, nrcTotal: lineNrc, mrcTotal: lineMrc, usageTotalEstimated: lineUsageEst } of computedLines) {\n nrcTotal += lineNrc\n mrcTotal += lineMrc\n if (lineUsageEst != null) {\n usageTotalEstimated = (usageTotalEstimated ?? 0) + lineUsageEst\n }\n\n allCharges.push(...charges)\n for (const charge of charges) {\n if (charge.chargeType === 'usage') {\n usageCharges.push({\n chargeCode: charge.chargeCode,\n chargeName: charge.chargeName,\n unitPrice: charge.unitPrice,\n note: charge.note ?? null,\n })\n }\n }\n }\n\n const { discountTotal, surchargeTotal } = aggregateAdjustmentTotals(allCharges)\n\n return {\n nrcTotal,\n mrcTotal,\n usageCharges,\n usageTotalEstimated,\n discountTotal,\n surchargeTotal,\n currencyCode,\n }\n}\n\nfunction emptyPricingSummary(currencyCode: string): Record<string, unknown> {\n return {\n nrcTotal: 0,\n mrcTotal: 0,\n usageCharges: [],\n usageTotalEstimated: null,\n discountTotal: 0,\n surchargeTotal: 0,\n currencyCode,\n }\n}\n\n// \u2500\u2500\u2500 Error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// Cross-realm brand. Next bundles this package once per server layer (page\n// SSR vs route handler), and the DI container is shared through globalThis,\n// so a route handler can catch a QuotingError built from the *other* copy of\n// this class \u2014 `instanceof` is then false and a typed 404/409 turns into a\n// 500. `Symbol.for` resolves to the same symbol in every copy. Same approach\n// as `isCrudHttpError` in @open-mercato/shared. Use `isQuotingError`.\nconst QUOTING_ERROR_BRAND = Symbol.for('@dainamite/cpq/QuotingError')\n\nexport class QuotingError extends Error {\n readonly [QUOTING_ERROR_BRAND] = true\n\n constructor(\n public status: number,\n message: string,\n public cpqStatus?: string,\n /**\n * Structured payload merged into the route's JSON response body.\n * Used to surface actionable context to the UI \u2014 e.g. the\n * `existingQuoteId` of the conflicting ARC quote on a 409 from\n * `ensureNoConcurrentArcQuote`, so the operator can be offered a\n * \"Open the existing quote\" confirm instead of just a dead alert.\n */\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'QuotingError'\n }\n}\n\nexport function isQuotingError(err: unknown): err is QuotingError {\n return !!err && typeof err === 'object' && (err as Record<symbol, unknown>)[QUOTING_ERROR_BRAND] === true\n}\n\n// \u2500\u2500\u2500 ARC orchestration (XD-250) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// All ARC user-journey logic lives on the CPQ Quote module:\n// \u2022 createQuoteFromSubscription \u2014 entry point from \"Amend / Renew / Cancel\"\n// \u2022 setQuoteType \u2014 one-way new \u2192 arc transition\n// \u2022 attach/detach/updateTargetSubscription \u2014 manage attached targets\n// \u2022 setCancelMeta / setMergeMeta \u2014 stamp ARC-specific meta on the quote\n// \u2022 validateArcQuote \u2014 invariants enforced before approval\n// \u2022 listTargetSubscriptions \u2014 readonly fetch for UI\n//\n// The actual subscription mutations happen in cpqInventoryService.apply* at\n// order activation. This service only owns the quote-level state.\n\nexport interface ArcRenewTermInput {\n newTermStart: string | Date\n newTermEnd: string | Date\n newTermMonths?: number | null\n}\n\nexport interface AttachTargetInput {\n subscriptionId: string\n quoteType: Exclude<CpqQuoteType, 'new'>\n mergeAction?: MergeAction\n newTermStart?: string | Date | null\n newTermEnd?: string | Date | null\n newTermMonths?: number | null\n}\n\nexport interface UpdateTargetInput {\n mergeAction?: MergeAction\n newTermStart?: string | Date | null\n newTermEnd?: string | Date | null\n newTermMonths?: number | null\n}\n\nexport interface CancelMetaInput {\n reasonCode: ArcReasonCode\n reasonText?: string | null\n etfAmount?: string | number | null\n etfCurrency?: string | null\n}\n\nexport interface MergeMetaInput {\n newTermStart: string | Date\n newTermEnd: string | Date\n newTermMonths?: number | null\n newSubCode?: string | null\n newSubName?: string | null\n}\n\nexport interface TargetSubscriptionView {\n id: string\n subscriptionId: string\n quoteType: string\n mergeAction: string | null\n newTermStart: string | null\n newTermEnd: string | null\n newTermMonths: number | null\n subscription: {\n code: string\n name: string\n status: string\n customerId: string\n currencyCode: string\n billingCycle: string\n currentTermStart: string | null\n currentTermEnd: string | null\n termMonths: number | null\n mrcAmount: number\n } | null\n}\n\nexport interface ArcQuoteValidationResult {\n ok: boolean\n errors: string[]\n}\n\nconst EDITABLE_QUOTE_STATUSES: ReadonlySet<string> = new Set([\n 'new',\n 'incomplete',\n 'ready',\n])\n\nfunction ensureEditable(cpqConfig: CpqQuoteConfiguration): void {\n if (!EDITABLE_QUOTE_STATUSES.has(cpqConfig.cpqStatus)) {\n throw new QuotingError(\n 409,\n `Cannot modify ARC attachments \u2014 quote is in '${cpqConfig.cpqStatus}' status`,\n )\n }\n}\n\nfunction toDateOrNull(value: string | Date | null | undefined): Date | null {\n if (value == null) return null\n return value instanceof Date ? value : new Date(value)\n}\n\n/**\n * Render a Date / string-date value as ISO-8601. MikroORM hydrates\n * `@Property({ type: 'date' })` columns as strings (YYYY-MM-DD) on Postgres\n * \u2014 calling `.toISOString()` on them throws. This helper accepts either form.\n */\nfunction toIsoOrNull(value: Date | string | null | undefined): string | null {\n if (value == null) return null\n if (value instanceof Date) return value.toISOString()\n // String already in ISO-ish form (YYYY-MM-DD or full ISO) \u2014 pass through.\n return String(value)\n}\n\n// \u2500\u2500\u2500 Module helpers extending DefaultCpqQuotingService \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndeclare module './cpqQuotingService' {\n interface DefaultCpqQuotingService {\n setQuoteType(quoteId: string, type: CpqQuoteType, scope: TenantScope): Promise<QuoteResult>\n createQuoteFromSubscription(input: {\n subscriptionId: string\n type: Exclude<CpqQuoteType, 'new'>\n renewTerm?: ArcRenewTermInput\n }, scope: TenantScope): Promise<{ quoteId: string; cpqConfigId: string }>\n listTargetSubscriptions(quoteId: string, scope: TenantScope): Promise<TargetSubscriptionView[]>\n attachTargetSubscription(\n quoteId: string,\n input: AttachTargetInput,\n scope: TenantScope,\n ): Promise<TargetSubscriptionView>\n detachTargetSubscription(\n quoteId: string,\n targetId: string,\n scope: TenantScope,\n ): Promise<{ ok: true }>\n updateTargetSubscription(\n quoteId: string,\n targetId: string,\n patch: UpdateTargetInput,\n scope: TenantScope,\n ): Promise<TargetSubscriptionView>\n setCancelMeta(quoteId: string, meta: CancelMetaInput, scope: TenantScope): Promise<QuoteResult>\n setMergeMeta(quoteId: string, meta: MergeMetaInput, scope: TenantScope): Promise<QuoteResult>\n validateArcQuote(quoteId: string, scope: TenantScope): Promise<ArcQuoteValidationResult>\n }\n}\n\nDefaultCpqQuotingService.prototype.setQuoteType = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n type: CpqQuoteType,\n scope: TenantScope,\n): Promise<QuoteResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n if (cpqConfig.quoteType === type) {\n // No-op \u2014 caller can repeat the PATCH freely.\n } else if (cpqConfig.quoteType !== 'new') {\n throw new QuotingError(409, `Quote type is immutable (current: '${cpqConfig.quoteType}')`)\n } else if (type === 'new') {\n throw new QuotingError(400, `Cannot transition quote type back to 'new'`)\n } else {\n cpqConfig.quoteType = type\n await em.flush()\n }\n\n const salesQuote = await loadSalesQuoteStrict(em, cpqConfig.quoteId, scope)\n const lines = await loadLines(em, cpqConfig.id, scope)\n return (this as unknown as InternalQuoting).buildQuoteResult(em, cpqConfig, salesQuote, lines)\n}\n\nDefaultCpqQuotingService.prototype.createQuoteFromSubscription = async function (\n this: DefaultCpqQuotingService,\n input: {\n subscriptionId: string\n type: Exclude<CpqQuoteType, 'new'>\n renewTerm?: ArcRenewTermInput\n },\n scope: TenantScope,\n): Promise<{ quoteId: string; cpqConfigId: string }> {\n const em = (this as unknown as { em: EntityManager }).em\n\n // 1. Load source subscription + active items.\n const sub = await em.findOne(CpqInventorySubscription, {\n id: input.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!sub) throw new QuotingError(404, 'Subscription not found')\n if (sub.status !== 'active' && sub.status !== 'suspended') {\n throw new QuotingError(\n 409,\n `Subscription must be active or suspended (current: '${sub.status}')`,\n )\n }\n\n await ensureNoConcurrentArcQuote(em, sub.id, scope)\n\n const items = await em.find(CpqInventorySubscriptionItem, {\n subscriptionId: sub.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n status: { $nin: ['terminated', 'expired', 'superseded'] },\n })\n\n // 2. Create SalesQuote + CpqQuoteConfiguration with quoteType=type.\n const numberGenerator = (this as unknown as InternalQuoting).numberGenerator\n const { number: quoteNumber } = await numberGenerator.generate({\n kind: 'quote',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const salesQuoteId = crypto.randomUUID()\n const salesQuote = em.create(SalesQuote, {\n id: salesQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteNumber,\n customerEntityId: sub.customerId,\n currencyCode: sub.currencyCode,\n subtotalNetAmount: '0',\n subtotalGrossAmount: '0',\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n grandTotalNetAmount: '0',\n grandTotalGrossAmount: '0',\n lineItemCount: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesQuote)\n\n // Pre-generate id so child rows (target subscription + quote lines) can\n // reference it before flush. The DB-side `defaultRaw: 'gen_random_uuid()'`\n // only fires at INSERT, not at em.create() \u2014 so the id would be undefined\n // when CpqQuoteLineConfiguration tries to set quoteConfigurationId.\n const cpqConfigId = crypto.randomUUID()\n const cpqConfig = em.create(CpqQuoteConfiguration, {\n id: cpqConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: salesQuoteId,\n customerId: sub.customerId,\n cpqStatus: 'new',\n version: 1,\n currencyCode: sub.currencyCode,\n quoteType: input.type,\n quoteContext: { arcSourceSubscriptionId: sub.id },\n validationResult: { valid: true, errors: [] },\n pricingSummary: emptyArcPricingSummary(sub.currencyCode),\n })\n em.persist(cpqConfig)\n\n // 3. Attach the source subscription as the (sole) target. For renew, fall\n // back to \"renew for same length starting at current term end\" so the\n // operator can hit Convert\u2192Activate without opening the drawer at all\n // when the default behaviour is fine. Operator override is still\n // available via the drawer's config-renew step.\n const renewDefaults = input.type === 'renew' ? buildRenewDefaults(sub, input.renewTerm) : null\n const target = em.create(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: cpqConfig.id,\n subscriptionId: sub.id,\n quoteType: input.type,\n mergeAction: input.type === 'renew' ? 'standalone' : null,\n newTermStart: renewDefaults?.start ?? null,\n newTermEnd: renewDefaults?.end ?? null,\n newTermMonths: renewDefaults?.months ?? null,\n })\n em.persist(target)\n\n // 4. Pre-fill quote lines from the subscription's active items via the\n // shared mirror helper (also used when attaching extra targets).\n await mirrorTargetSubscriptionItems(em, cpqConfig, sub, salesQuote, input.type, scope)\n\n await em.flush()\n return { quoteId: salesQuoteId, cpqConfigId: cpqConfig.id }\n}\n\nDefaultCpqQuotingService.prototype.listTargetSubscriptions = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n scope: TenantScope,\n): Promise<TargetSubscriptionView[]> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n if (targets.length === 0) return []\n\n const subs = await em.find(CpqInventorySubscription, {\n id: { $in: targets.map((t) => t.subscriptionId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const subMap = new Map(subs.map((s) => [s.id, s]))\n\n return targets.map((t) => {\n const s = subMap.get(t.subscriptionId)\n return {\n id: t.id,\n subscriptionId: t.subscriptionId,\n quoteType: t.quoteType,\n mergeAction: t.mergeAction ?? null,\n newTermStart: toIsoOrNull(t.newTermStart),\n newTermEnd: toIsoOrNull(t.newTermEnd),\n newTermMonths: t.newTermMonths ?? null,\n subscription: s\n ? {\n code: s.code,\n name: s.name,\n status: s.status,\n customerId: s.customerId,\n currencyCode: s.currencyCode,\n billingCycle: s.billingCycle,\n currentTermStart: toIsoOrNull(s.currentTermStart),\n currentTermEnd: toIsoOrNull(s.currentTermEnd),\n termMonths: s.termMonths ?? null,\n mrcAmount: Number(s.mrcAmount),\n }\n : null,\n }\n })\n}\n\nDefaultCpqQuotingService.prototype.attachTargetSubscription = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n input: AttachTargetInput,\n scope: TenantScope,\n): Promise<TargetSubscriptionView> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n if (cpqConfig.quoteType === 'new') {\n throw new QuotingError(409, `Cannot attach a target subscription \u2014 quote_type is 'new'`)\n }\n if (cpqConfig.quoteType !== input.quoteType) {\n throw new QuotingError(\n 400,\n `Quote type mismatch: quote is '${cpqConfig.quoteType}', payload says '${input.quoteType}'`,\n )\n }\n\n // Idempotency on (quote, subscription).\n const existing = await em.findOne(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n quoteId: cpqConfig.id,\n subscriptionId: input.subscriptionId,\n })\n if (existing) {\n return mapTargetView(em, existing, scope)\n }\n\n // Subscription must exist and be in {active, suspended}.\n const sub = await em.findOne(CpqInventorySubscription, {\n id: input.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!sub) throw new QuotingError(404, 'Subscription not found')\n if (sub.status !== 'active' && sub.status !== 'suspended') {\n throw new QuotingError(\n 409,\n `Subscription must be active or suspended (current: '${sub.status}')`,\n )\n }\n\n // Customer / currency / billingCycle must match the quote and any existing targets.\n if (sub.customerId !== cpqConfig.customerId) {\n throw new QuotingError(400, 'Subscription customer must match quote customer')\n }\n if (sub.currencyCode !== cpqConfig.currencyCode) {\n throw new QuotingError(400, 'Subscription currency must match quote currency')\n }\n\n const otherTargets = await em.find(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n quoteId: cpqConfig.id,\n })\n if (input.quoteType === 'renew' && otherTargets.length > 0) {\n // Merge mode: every target (existing + this) must share billingCycle.\n const otherSubs = await em.find(CpqInventorySubscription, {\n id: { $in: otherTargets.map((t) => t.subscriptionId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const o of otherSubs) {\n if (o.billingCycle !== sub.billingCycle) {\n throw new QuotingError(\n 400,\n 'Merge targets must share the same billing cycle',\n )\n }\n }\n }\n\n await ensureNoConcurrentArcQuote(em, input.subscriptionId, scope, cpqConfig.id)\n\n const target = em.create(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: cpqConfig.id,\n subscriptionId: input.subscriptionId,\n quoteType: input.quoteType,\n mergeAction:\n input.quoteType === 'renew'\n ? input.mergeAction ?? (otherTargets.length === 0 ? 'standalone' : 'absorb')\n : null,\n newTermStart: toDateOrNull(input.newTermStart),\n newTermEnd: toDateOrNull(input.newTermEnd),\n newTermMonths: input.newTermMonths ?? null,\n })\n em.persist(target)\n await em.flush()\n\n // After attaching a 2nd renew target, retroactively flip the original\n // 'standalone' target to 'absorb' so the whole quote enters merge mode.\n let renewMergeJustEntered = false\n if (input.quoteType === 'renew') {\n const allTargets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (allTargets.length >= 2) {\n const wasStandalone = allTargets.some((t) => t.mergeAction === 'standalone')\n for (const t of allTargets) {\n t.mergeAction = 'absorb'\n t.newTermStart = null\n t.newTermEnd = null\n t.newTermMonths = null\n }\n await em.flush()\n renewMergeJustEntered = wasStandalone\n }\n }\n\n // XD-250 multi-target ARC: mirror the newly attached subscription's items\n // so the operator can see / edit / cancel them in the quote UI. Without\n // this the target row existed but the quote had no lines for it, so\n // activation produced an empty change-log entry on that sub. For renew\n // merge, mirrored lines carry `targetSubscriptionId: null` (the merged\n // sub doesn't exist yet at quote time) and any lines created earlier for\n // the original standalone target get re-tagged to null too.\n const salesQuote = await em.findOne(SalesQuote, {\n id: cpqConfig.quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (salesQuote) {\n const isRenewMerge = input.quoteType === 'renew' && otherTargets.length > 0\n await mirrorTargetSubscriptionItems(\n em,\n cpqConfig,\n sub,\n salesQuote,\n input.quoteType,\n scope,\n { mergeMode: isRenewMerge },\n )\n\n if (renewMergeJustEntered) {\n const existingLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const lc of existingLines) {\n if (lc.targetSubscriptionId !== null) lc.targetSubscriptionId = null\n }\n }\n\n await em.flush()\n }\n\n return mapTargetView(em, target, scope)\n}\n\nDefaultCpqQuotingService.prototype.detachTargetSubscription = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n targetId: string,\n scope: TenantScope,\n): Promise<{ ok: true }> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n const target = await em.findOne(CpqQuoteTargetSubscription, {\n id: targetId,\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!target) throw new QuotingError(404, 'Target subscription not found')\n\n // Drop any quote lines that pointed at this target.\n const lines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n targetSubscriptionId: target.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const now = new Date()\n for (const line of lines) {\n line.deletedAt = now\n const salesLine = await em.findOne(SalesQuoteLine, { id: line.quoteLineId })\n if (salesLine) salesLine.deletedAt = now\n }\n\n target.deletedAt = now\n\n // Auto-revert merge mode if only one renew target remains.\n if (target.quoteType === 'renew') {\n const remaining = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n id: { $ne: target.id },\n })\n if (remaining.length === 1) {\n remaining[0].mergeAction = 'standalone'\n }\n }\n\n await em.flush()\n return { ok: true }\n}\n\nDefaultCpqQuotingService.prototype.updateTargetSubscription = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n targetId: string,\n patch: UpdateTargetInput,\n scope: TenantScope,\n): Promise<TargetSubscriptionView> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n const target = await em.findOne(CpqQuoteTargetSubscription, {\n id: targetId,\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!target) throw new QuotingError(404, 'Target subscription not found')\n\n if (target.quoteType !== 'renew') {\n throw new QuotingError(\n 409,\n `Cannot update target on a '${target.quoteType}' quote \u2014 only renew targets carry term/merge fields`,\n )\n }\n\n if (patch.mergeAction !== undefined) target.mergeAction = patch.mergeAction\n if (patch.newTermStart !== undefined) target.newTermStart = toDateOrNull(patch.newTermStart)\n if (patch.newTermEnd !== undefined) target.newTermEnd = toDateOrNull(patch.newTermEnd)\n if (patch.newTermMonths !== undefined) target.newTermMonths = patch.newTermMonths ?? null\n\n await em.flush()\n return mapTargetView(em, target, scope)\n}\n\nDefaultCpqQuotingService.prototype.setCancelMeta = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n meta: CancelMetaInput,\n scope: TenantScope,\n): Promise<QuoteResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n if (cpqConfig.quoteType !== 'cancel') {\n throw new QuotingError(\n 409,\n `Cancel meta can only be set on a cancel quote (current: '${cpqConfig.quoteType}')`,\n )\n }\n cpqConfig.arcReasonCode = meta.reasonCode\n cpqConfig.arcReasonText = meta.reasonText ?? null\n cpqConfig.arcEtfAmount = meta.etfAmount != null ? String(meta.etfAmount) : null\n cpqConfig.arcEtfCurrency = meta.etfCurrency ?? cpqConfig.currencyCode\n await em.flush()\n\n const salesQuote = await loadSalesQuoteStrict(em, cpqConfig.quoteId, scope)\n const lines = await loadLines(em, cpqConfig.id, scope)\n return (this as unknown as InternalQuoting).buildQuoteResult(em, cpqConfig, salesQuote, lines)\n}\n\nDefaultCpqQuotingService.prototype.setMergeMeta = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n meta: MergeMetaInput,\n scope: TenantScope,\n): Promise<QuoteResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n if (cpqConfig.quoteType !== 'renew') {\n throw new QuotingError(\n 409,\n `Merge meta can only be set on a renew quote (current: '${cpqConfig.quoteType}')`,\n )\n }\n cpqConfig.arcMergeNewTermStart = toDateOrNull(meta.newTermStart)\n cpqConfig.arcMergeNewTermEnd = toDateOrNull(meta.newTermEnd)\n cpqConfig.arcMergeNewTermMonths = meta.newTermMonths ?? null\n cpqConfig.arcMergeNewSubCode = meta.newSubCode ?? null\n cpqConfig.arcMergeNewSubName = meta.newSubName ?? null\n await em.flush()\n\n const salesQuote = await loadSalesQuoteStrict(em, cpqConfig.quoteId, scope)\n const lines = await loadLines(em, cpqConfig.id, scope)\n return (this as unknown as InternalQuoting).buildQuoteResult(em, cpqConfig, salesQuote, lines)\n}\n\nDefaultCpqQuotingService.prototype.validateArcQuote = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n scope: TenantScope,\n): Promise<ArcQuoteValidationResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n const errors: string[] = []\n\n if (cpqConfig.quoteType === 'new') {\n return { ok: true, errors: [] }\n }\n if (!ARC_QUOTE_TYPES.includes(cpqConfig.quoteType as Exclude<CpqQuoteType, 'new'>)) {\n errors.push(`Unknown quote type '${cpqConfig.quoteType}'`)\n return { ok: false, errors }\n }\n\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) {\n errors.push(`ARC quote requires at least one target subscription`)\n return { ok: false, errors }\n }\n\n // Fetch attached subscriptions and check status + same customer/currency/billingCycle.\n const subs = await em.find(CpqInventorySubscription, {\n id: { $in: targets.map((t) => t.subscriptionId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const subMap = new Map(subs.map((s) => [s.id, s]))\n for (const t of targets) {\n const s = subMap.get(t.subscriptionId)\n if (!s) {\n errors.push(`Target subscription ${t.subscriptionId} not found`)\n continue\n }\n if (s.status !== 'active' && s.status !== 'suspended') {\n errors.push(\n `Target subscription ${s.code} must be active or suspended (current: '${s.status}')`,\n )\n }\n if (s.customerId !== cpqConfig.customerId) {\n errors.push(`Target subscription ${s.code} belongs to a different customer`)\n }\n if (s.currencyCode !== cpqConfig.currencyCode) {\n errors.push(`Target subscription ${s.code} has currency mismatch`)\n }\n }\n\n // Type-specific invariants.\n if (cpqConfig.quoteType === 'renew') {\n const standaloneCount = targets.filter((t) => t.mergeAction === 'standalone').length\n const absorbCount = targets.filter((t) => t.mergeAction === 'absorb').length\n\n if (targets.length === 1) {\n if (standaloneCount !== 1) {\n errors.push(`Single-target renew must have merge_action='standalone'`)\n }\n const t = targets[0]\n if (!t.newTermStart || !t.newTermEnd) {\n errors.push(`Standalone renew target must have newTermStart and newTermEnd`)\n } else if (t.newTermStart >= t.newTermEnd) {\n errors.push(`newTermStart must be earlier than newTermEnd`)\n }\n } else {\n if (absorbCount !== targets.length) {\n errors.push(`Multi-target renew (merge) requires every target merge_action='absorb'`)\n }\n if (\n !cpqConfig.arcMergeNewTermStart ||\n !cpqConfig.arcMergeNewTermEnd\n ) {\n errors.push(`Merge renew requires quote-level arc_merge_new_term_start and arc_merge_new_term_end`)\n } else if (cpqConfig.arcMergeNewTermStart >= cpqConfig.arcMergeNewTermEnd) {\n errors.push(`arc_merge_new_term_start must be earlier than arc_merge_new_term_end`)\n }\n // Same billing cycle across all sources.\n const cycles = new Set(\n targets\n .map((t) => subMap.get(t.subscriptionId)?.billingCycle)\n .filter(Boolean),\n )\n if (cycles.size > 1) {\n errors.push(`Merge targets must share the same billing cycle`)\n }\n }\n }\n\n if (cpqConfig.quoteType === 'cancel') {\n if (!cpqConfig.arcReasonCode) {\n errors.push(`Cancel quote requires arc_reason_code (call /cancel-meta first)`)\n }\n }\n\n // Quote line invariants.\n const lines = await loadLines(em, cpqConfig.id, scope)\n const targetSubIds = new Set(targets.map((t) => t.subscriptionId))\n const isMerge =\n cpqConfig.quoteType === 'renew' &&\n targets.length >= 2 &&\n targets.every((t) => t.mergeAction === 'absorb')\n\n for (const line of lines) {\n if (cpqConfig.quoteType === 'amend' || cpqConfig.quoteType === 'cancel') {\n if (!line.targetSubscriptionId) {\n errors.push(`Quote line ${line.quoteLineId} missing target_subscription_id`)\n } else if (!targetSubIds.has(line.targetSubscriptionId)) {\n errors.push(\n `Quote line ${line.quoteLineId} target_subscription_id does not match any attached target`,\n )\n }\n } else if (cpqConfig.quoteType === 'renew') {\n if (isMerge) {\n if (line.targetSubscriptionId) {\n errors.push(\n `Merge-renew line ${line.quoteLineId} must have null target_subscription_id`,\n )\n }\n } else {\n // standalone \u2014 single target.\n if (!line.targetSubscriptionId || !targetSubIds.has(line.targetSubscriptionId)) {\n errors.push(\n `Standalone renew line ${line.quoteLineId} must target the renewing subscription`,\n )\n }\n }\n }\n if (\n (line.action === 'cancel' || line.action === 'modify') &&\n cpqConfig.quoteType !== 'cancel' &&\n !line.sourceSubscriptionItemId\n ) {\n errors.push(\n `Quote line ${line.quoteLineId} action='${line.action}' requires source_subscription_item_id`,\n )\n }\n }\n\n // Concurrency: each attached sub must not be on another non-terminal ARC quote.\n for (const t of targets) {\n await ensureNoConcurrentArcQuoteForValidation(em, t.subscriptionId, scope, cpqConfig.id, errors)\n }\n\n return { ok: errors.length === 0, errors }\n}\n\n// \u2500\u2500\u2500 ARC private/module helpers (XD-250) \u2500\u2500\u2500\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\ninterface InternalQuoting {\n numberGenerator: SalesDocumentNumberGenerator\n buildQuoteResult: (\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n lineConfigs: CpqQuoteLineConfiguration[],\n validationResult?: { valid: boolean; errors: ValidationError[] },\n ) => Promise<QuoteResult>\n}\n\nasync function loadCpqConfigStrict(\n em: EntityManager,\n quoteId: string,\n scope: TenantScope,\n): Promise<CpqQuoteConfiguration> {\n let config = await em.findOne(CpqQuoteConfiguration, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqQuoteConfiguration, {\n quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new QuotingError(404, 'Quote not found')\n return config\n}\n\nasync function loadSalesQuoteStrict(\n em: EntityManager,\n quoteId: string,\n scope: TenantScope,\n): Promise<SalesQuote> {\n const quote = await em.findOne(SalesQuote, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!quote) throw new QuotingError(404, 'Sales quote not found')\n return quote\n}\n\nasync function loadLines(\n em: EntityManager,\n cpqConfigId: string,\n scope: TenantScope,\n): Promise<CpqQuoteLineConfiguration[]> {\n return em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n}\n\nasync function ensureNoConcurrentArcQuote(\n em: EntityManager,\n subscriptionId: string,\n scope: TenantScope,\n excludeQuoteConfigId?: string,\n): Promise<void> {\n const conflicting = await em.find(CpqQuoteTargetSubscription, {\n subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (conflicting.length === 0) return\n const cfgIds = conflicting.map((c) => c.quoteId)\n const cfgs = await em.find(CpqQuoteConfiguration, {\n id: { $in: cfgIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const cfg of cfgs) {\n if (excludeQuoteConfigId && cfg.id === excludeQuoteConfigId) continue\n if (!TERMINAL_STATUSES.includes(cfg.cpqStatus as CpqStatus)) {\n throw new QuotingError(\n 409,\n `Subscription has another ARC quote in progress (quoteId=${cfg.quoteId})`,\n undefined,\n // Surface the conflicting quote id so the UI can offer \"Open the\n // existing quote\" instead of just showing a dead-end alert. Use\n // `quoteId` (the SalesQuote UUID, what the URL bar shows after the\n // first Amend) \u2014 not `cfg.id` (the CpqQuoteConfiguration UUID) \u2014\n // so the redirect URL matches the URL the operator would see on a\n // fresh first-time create, and so the test assertion can compare\n // the two with `toContain`.\n { existingQuoteId: cfg.quoteId, existingQuoteStatus: cfg.cpqStatus },\n )\n }\n }\n}\n\nasync function ensureNoConcurrentArcQuoteForValidation(\n em: EntityManager,\n subscriptionId: string,\n scope: TenantScope,\n excludeQuoteConfigId: string,\n errors: string[],\n): Promise<void> {\n try {\n await ensureNoConcurrentArcQuote(em, subscriptionId, scope, excludeQuoteConfigId)\n } catch (err) {\n if (err instanceof QuotingError) errors.push(err.message)\n else throw err\n }\n}\n\nasync function mapTargetView(\n em: EntityManager,\n target: CpqQuoteTargetSubscription,\n scope: TenantScope,\n): Promise<TargetSubscriptionView> {\n const sub = await em.findOne(CpqInventorySubscription, {\n id: target.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return {\n id: target.id,\n subscriptionId: target.subscriptionId,\n quoteType: target.quoteType,\n mergeAction: target.mergeAction ?? null,\n newTermStart: toIsoOrNull(target.newTermStart),\n newTermEnd: toIsoOrNull(target.newTermEnd),\n newTermMonths: target.newTermMonths ?? null,\n subscription: sub\n ? {\n code: sub.code,\n name: sub.name,\n status: sub.status,\n customerId: sub.customerId,\n currencyCode: sub.currencyCode,\n billingCycle: sub.billingCycle,\n currentTermStart: toIsoOrNull(sub.currentTermStart),\n currentTermEnd: toIsoOrNull(sub.currentTermEnd),\n termMonths: sub.termMonths ?? null,\n mrcAmount: Number(sub.mrcAmount),\n }\n : null,\n }\n}\n\nfunction emptyArcPricingSummary(currencyCode: string): Record<string, unknown> {\n return {\n nrcTotal: 0,\n mrcTotal: 0,\n usageCharges: [],\n usageTotalEstimated: null,\n discountTotal: 0,\n surchargeTotal: 0,\n currencyCode,\n }\n}\n\n// XD-250 ARC: batch-load source subscription items referenced by the lines'\n// `_arcMirroredFromItemId` markers and / or `sourceSubscriptionItemId`. Used\n// by buildQuoteResult / buildOrderResult to surface a \"before\" snapshot per\n// line so the operator can compare current sub state vs. what's about to\n// change. Returns a map keyed by subscription-item id.\nasync function loadArcSourceMap(\n em: EntityManager,\n lineConfigs: Array<{\n configuration?: Record<string, unknown> | null\n sourceSubscriptionItemId?: string | null\n }>,\n scope: { organizationId: string; tenantId: string },\n): Promise<Map<string, CpqInventorySubscriptionItem>> {\n const ids = new Set<string>()\n for (const lc of lineConfigs) {\n const fromMarker = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n if (typeof fromMarker === 'string') ids.add(fromMarker)\n if (lc.sourceSubscriptionItemId) ids.add(lc.sourceSubscriptionItemId)\n }\n if (ids.size === 0) return new Map()\n\n const items = await em.find(CpqInventorySubscriptionItem, {\n id: { $in: Array.from(ids) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return new Map(items.map((it) => [it.id, it]))\n}\n\nfunction pickArcSource(\n lc: {\n configuration?: Record<string, unknown> | null\n sourceSubscriptionItemId?: string | null\n },\n map: Map<string, CpqInventorySubscriptionItem>,\n): ArcLineSource | null {\n const fromMarker = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n const id =\n (typeof fromMarker === 'string' ? fromMarker : null) ?? lc.sourceSubscriptionItemId ?? null\n if (!id) return null\n const item = map.get(id)\n if (!item) return null\n return {\n subscriptionItemId: item.id,\n name: item.name,\n mrcAmount: Number(item.mrcAmount),\n nrcAmount: Number(item.nrcAmount),\n quantity: item.quantity,\n }\n}\n\n// XD-250 ARC renew defaults \u2014 when the operator clicks \"Renew\" we pre-fill\n// the target row with \"same length starting at current term end\" so they\n// don't have to open the drawer just to confirm. Honours an explicit\n// `input.renewTerm` override and falls back gracefully when the source\n// subscription has missing `currentTermEnd` / `termMonths` (e.g. fixture\n// data without dates) \u2014 start defaults to today and length to 12 months.\nfunction buildRenewDefaults(\n sub: CpqInventorySubscription,\n override?: ArcRenewTermInput,\n): { start: Date; end: Date; months: number } {\n if (override) {\n const start = toDateOrNull(override.newTermStart)\n const end = toDateOrNull(override.newTermEnd)\n const months = override.newTermMonths ?? null\n if (start && end && months != null) return { start, end, months }\n // Fall through to derived defaults if override was incomplete.\n }\n const months = sub.termMonths ?? 12\n const start = sub.currentTermEnd ? new Date(sub.currentTermEnd) : new Date()\n const end = new Date(start)\n end.setMonth(end.getMonth() + months)\n return { start, end, months }\n}\n\n// XD-250 ARC: mirror a subscription's active items as quote lines on the\n// given quote \u2014 used both at quote creation (initial target) and when the\n// operator attaches additional targets via the modify-subscription drawer.\n// For amend \u2192 action='modify', for cancel \u2192 action='cancel'. Preserves\n// parent-child structure (bundle \u2192 components) by pre-generating SalesQuote\n// line ids before the loop. No-op when the sub has no eligible items.\nasync function mirrorTargetSubscriptionItems(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n sub: CpqInventorySubscription,\n salesQuote: SalesQuote,\n quoteType: 'amend' | 'cancel' | 'renew',\n scope: TenantScope,\n options?: { mergeMode?: boolean },\n): Promise<void> {\n const items = await em.find(CpqInventorySubscriptionItem, {\n subscriptionId: sub.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n status: { $nin: ['terminated', 'expired', 'superseded'] },\n })\n if (items.length === 0) return\n\n const existingLines = await em.find(SalesQuoteLine, {\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n let nextLineNumber = existingLines.length + 1\n\n const subItemIdToSalesLineId = new Map<string, string>()\n for (const item of items) {\n subItemIdToSalesLineId.set(item.id, crypto.randomUUID())\n }\n\n const lineAction: 'modify' | 'cancel' = quoteType === 'cancel' ? 'cancel' : 'modify'\n\n for (const item of items) {\n const salesLineId = subItemIdToSalesLineId.get(item.id)!\n const parentLineId = item.parentItemId\n ? subItemIdToSalesLineId.get(item.parentItemId) ?? null\n : null\n\n const salesLine = em.create(SalesQuoteLine, {\n id: salesLineId,\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: nextLineNumber++,\n kind: 'product',\n productId: item.productId ?? null,\n name: item.name,\n quantity: String(item.quantity),\n unitPriceNet: '0',\n unitPriceGross: '0',\n totalNetAmount: '0',\n totalGrossAmount: '0',\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: sub.currencyCode,\n configuration: item.configuration ?? null,\n normalizedQuantity: '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesLine)\n\n const lineConfig = em.create(CpqQuoteLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteLineId: salesLineId,\n quoteConfigurationId: cpqConfig.id,\n offeringId: item.offeringId ?? null,\n productId: item.productId ?? null,\n specId: item.specId ?? null,\n action: lineAction,\n parentLineId,\n startDate: null,\n termMonths: null,\n endDate: null,\n configuration: {\n ...item.configuration,\n _arcMirroredFromItemId: item.id,\n _arcMirroredName: item.name,\n },\n quantity: item.quantity,\n charges: pickArcMirrorCharges(item, sub.currencyCode),\n nrcTotal: String(item.nrcAmount ?? 0),\n mrcTotal: String(item.mrcAmount),\n isConfigured: true,\n // XD-250 spec: merge-renew lines must have null `target_subscription_id`\n // (the source subs are absorbed into a brand-new sub at activation, so\n // there's no existing item to bind the line to). For amend / cancel /\n // standalone-renew, bind to the source sub so per-target validation /\n // groupings work.\n targetSubscriptionId: options?.mergeMode ? null : sub.id,\n sourceSubscriptionItemId: item.id,\n })\n em.persist(lineConfig)\n }\n}\n\n// XD-250 ARC: when adding a line to an ARC quote, decide which target\n// subscription the line acts on. Returns null for non-ARC quotes and for\n// merge-renew quotes (per validateArcQuote: merge-renew lines must have null\n// target_subscription_id). For amend / cancel / standalone-renew with one\n// attached target, returns that target. With multiple targets, the caller\n// must pass an explicit targetSubscriptionId in QuoteItemInput.\nasync function resolveArcLineTargetSubscriptionId(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n scope: TenantScope,\n explicit?: string,\n): Promise<string | null> {\n const quoteType = cpqConfig.quoteType ?? 'new'\n if (quoteType === 'new') return null\n\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) return null\n\n const isMerge =\n quoteType === 'renew' &&\n targets.length >= 2 &&\n targets.every((t) => t.mergeAction === 'absorb')\n if (isMerge) return null\n\n if (explicit) {\n if (!targets.some((t) => t.subscriptionId === explicit)) {\n throw new QuotingError(\n 422,\n `targetSubscriptionId '${explicit}' is not attached to this quote`,\n )\n }\n return explicit\n }\n\n if (targets.length === 1) return targets[0].subscriptionId\n\n throw new QuotingError(\n 422,\n `Quote has ${targets.length} attached targets \u2014 specify targetSubscriptionId on the line`,\n )\n}\n\n// Build the per-instance charges JSON for an ARC-mirrored quote line. If the\n// source subscription item already has explicit charges, copy them. Otherwise\n// synthesize a flat MRC / NRC charge from the item's stored amounts so that\n// recalculate (which scales totalPrice by lineConfig.quantity) has something\n// to work with \u2014 without this, changing quantity on a mirrored line wipes the\n// charges array and the line flips to \"incomplete\".\nfunction pickArcMirrorCharges(\n item: { mrcAmount: string | number; nrcAmount?: string | number; quantity: number; charges?: unknown },\n currencyCode: string,\n): Array<Record<string, unknown>> | null {\n const existing = (item.charges ?? null) as Array<Record<string, unknown>> | null\n if (existing && existing.length > 0) return [...existing]\n\n const sourceQty = Math.max(1, Number(item.quantity) || 1)\n const mrc = Number(item.mrcAmount) || 0\n const nrc = Number(item.nrcAmount ?? 0) || 0\n const synth: Array<Record<string, unknown>> = []\n if (mrc > 0) {\n const perInstance = mrc / sourceQty\n synth.push({\n chargeCode: 'mrc',\n chargeName: 'Monthly Recurring',\n chargeType: 'mrc',\n pricingMethod: 'flat',\n unitPrice: perInstance,\n quantity: 1,\n totalPrice: perInstance,\n currencyCode,\n })\n }\n if (nrc > 0) {\n const perInstance = nrc / sourceQty\n synth.push({\n chargeCode: 'nrc',\n chargeName: 'Non-Recurring',\n chargeType: 'nrc',\n pricingMethod: 'flat',\n unitPrice: perInstance,\n quantity: 1,\n totalPrice: perInstance,\n currencyCode,\n })\n }\n return synth.length > 0 ? synth : null\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { cloneQuoteAdjustments, removeQuoteLineTree } from './priceAdjustments/quoteAdjustmentLifecycle'\nimport type { PriceAdjustment } from '../data/price-adjustments'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { loadQuoteAdjustments } from './priceAdjustments/loadQuoteAdjustments'\nimport { resolveManualAdjustments } from './priceAdjustments/resolveManualAdjustments'\nimport { withChargeWaterfall } from './priceAdjustments/chargeWaterfall'\nimport { withQuotePricingWrite } from './priceAdjustments/quotePricingWrite'\nimport { emitQuoteWriteEvents, type QuoteWriteEvents } from './priceAdjustments/quotePricingEvents'\nimport { computeWaterfallSummary } from './priceAdjustments/pricingSnapshot'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { SalesQuote, SalesQuoteLine } from '@open-mercato/core/modules/sales/data/entities'\nimport { CustomerEntity } from '@open-mercato/core/modules/customers/data/entities'\nimport type { SalesDocumentNumberGenerator } from '@open-mercato/core/modules/sales/services/salesDocumentNumberGenerator'\nimport {\n CpqQuoteConfiguration,\n CpqQuoteLineConfiguration,\n CpqQuoteTargetSubscription,\n CpqInventorySubscription,\n CpqInventorySubscriptionItem,\n CpqOrderConfiguration,\n CpqProductOffering,\n CpqProductSpecification,\n} from '../data/entities'\nimport type { DefaultCpqPricingService } from './cpqPricingService'\nimport type { DefaultCpqValidationService } from './cpqValidationService'\nimport type { DefaultCpqProductService } from './cpqProductService'\nimport type {\n CreateQuoteInput,\n QuoteItemInput,\n QuoteResult,\n QuoteLineResult,\n PricingSummary,\n ValidationError,\n ResolvedCharge,\n TenantScope,\n CpqStatus,\n CpqQuoteType,\n MergeAction,\n ArcReasonCode,\n ArcLineSource,\n} from './types'\nimport {\n ALLOWED_TRANSITIONS,\n TERMINAL_STATUSES,\n ARC_QUOTE_TYPES,\n getBaseCurrencyCode,\n} from './types'\nimport {\n ARC_PRICE_FROZEN_KEY,\n ARC_REPRICED_KEY,\n arcPricingInputsChanged,\n buildArcMirrorConfiguration,\n isFrozenAmendMirrorLine,\n isArcMirrorLine,\n stripArcMarkers,\n stripQuoteOnlyArcMarkers,\n} from './arcPriceFreeze'\nimport { isArcCancelledLine, planArcLineRemoval, planArcLineRestore, removalCancelsItem } from './arcLineRemoval'\n\ninterface QuotingServiceDeps {\n em: EntityManager\n cpqPricingService: DefaultCpqPricingService\n cpqValidationService: DefaultCpqValidationService\n cpqProductService: DefaultCpqProductService\n salesDocumentNumberGenerator: SalesDocumentNumberGenerator\n}\n\nexport class DefaultCpqQuotingService {\n private em: EntityManager\n private pricingService: DefaultCpqPricingService\n private validationService: DefaultCpqValidationService\n private productService: DefaultCpqProductService\n private numberGenerator: SalesDocumentNumberGenerator\n\n constructor(deps: QuotingServiceDeps) {\n this.em = deps.em\n this.pricingService = deps.cpqPricingService\n this.validationService = deps.cpqValidationService\n this.productService = deps.cpqProductService\n this.numberGenerator = deps.salesDocumentNumberGenerator\n }\n\n // \u2500\u2500\u2500 Create Quote \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async createQuote(input: CreateQuoteInput, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n // Validate customer exists (lookup by id + tenantId; organizationId may differ\n // between CPQ scope resolution and how the core customers API resolves it)\n const customer = await em.findOne(CustomerEntity, {\n id: input.customerId,\n tenantId: scope.tenantId,\n }, { populate: ['personProfile', 'companyProfile'] })\n\n if (!customer) {\n throw new QuotingError(404, 'Customer not found')\n }\n\n // Build customer snapshot\n const customerSnapshot = buildCustomerSnapshot(customer)\n\n // Build initial quote context from customer\n const quoteContext: Record<string, string | number | boolean> = {\n ...(input.quoteContext ?? {}),\n }\n if (customer.kind) quoteContext.customer_type = customer.kind\n if (customer.companyProfile?.domain) quoteContext.customer_domain = customer.companyProfile.domain\n\n const currencyCode = input.currencyCode ?? await getBaseCurrencyCode(em, scope)\n\n let salesQuote: SalesQuote\n let salesQuoteId: string\n\n if (input.quoteId) {\n // Link to existing SalesQuote\n const existing = await em.findOne(SalesQuote, {\n id: input.quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!existing) throw new QuotingError(404, 'Sales quote not found')\n\n // Check if CPQ config already exists\n const existingConfig = await em.findOne(CpqQuoteConfiguration, {\n quoteId: input.quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (existingConfig) {\n // Already initialized \u2014 just return the existing config\n const lines = await this.loadLineConfigs(em, existingConfig.id, scope)\n return this.buildQuoteResult(em, existingConfig, existing, lines)\n }\n\n salesQuote = existing\n salesQuoteId = existing.id\n } else {\n // Create new SalesQuote \u2014 assign UUID upfront so CpqQuoteConfiguration can reference it before flush\n salesQuoteId = crypto.randomUUID()\n\n const { number: quoteNumber } = await this.numberGenerator.generate({\n kind: 'quote',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n salesQuote = em.create(SalesQuote, {\n id: salesQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteNumber,\n customerEntityId: input.customerId,\n customerSnapshot,\n currencyCode,\n subtotalNetAmount: '0',\n subtotalGrossAmount: '0',\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n grandTotalNetAmount: '0',\n grandTotalGrossAmount: '0',\n lineItemCount: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(salesQuote)\n }\n\n // Create CpqQuoteConfiguration\n const cpqConfig = em.create(CpqQuoteConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: salesQuoteId,\n customerId: input.customerId,\n cpqStatus: 'new',\n version: 1,\n currencyCode,\n quoteContext,\n validationResult: { valid: true, errors: [] },\n pricingSummary: emptyPricingSummary(currencyCode),\n })\n em.persist(cpqConfig)\n\n await em.flush()\n\n return this.buildQuoteResult(em, cpqConfig, salesQuote, [])\n }\n\n // \u2500\u2500\u2500 Add Quote Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async addQuoteItem(quoteId: string, item: QuoteItemInput, scope: TenantScope): Promise<QuoteResult> {\n return this.writeQuote(quoteId, scope, (em, quote) => this.addQuoteItemInTransaction(quoteId, item, scope, em, quote), undefined, undefined, LINE_EVENTS)\n }\n\n private async addQuoteItemInTransaction(quoteId: string, item: QuoteItemInput, scope: TenantScope, em: EntityManager, cpqConfig: CpqQuoteConfiguration): Promise<QuoteResult> {\n // ARC markers (`_arc*`) are server-owned \u2014 never accept them from callers.\n item = { ...item, configuration: stripArcMarkers(item.configuration) }\n\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n if (item.parentLineId && cpqConfig.quoteType && cpqConfig.quoteType !== 'new') {\n const parent = await em.findOne(CpqQuoteLineConfiguration, {\n quoteLineId: item.parentLineId,\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (parent && isArcCancelledLine(parent, cpqConfig.quoteType)) {\n throw new QuotingError(409, 'Cannot add a component to a subscription item marked for removal')\n }\n }\n\n // Resolve offering -> spec -> product\n const { offering, spec } = await this.resolveOffering(em, item, scope)\n\n // Merge context: quoteContext + designTimeValues + user configuration\n const mergedConfig = {\n ...(cpqConfig.quoteContext ?? {}),\n ...(offering?.designTimeValues ?? {}),\n ...item.configuration,\n }\n\n // If termMonths is provided, include it in the merged config for pricing\n if (item.termMonths) {\n mergedConfig.term_months = item.termMonths\n }\n\n // Validate configuration\n let validationErrors: ValidationError[] = []\n if (offering) {\n const validation = await this.validationService.validateOfferingConfiguration({\n offeringId: offering.id,\n configuration: item.configuration,\n scope,\n })\n validationErrors = validation.errors\n }\n\n // Resolve charges\n const charges = await this.pricingService.resolveProductCharges({\n offeringId: offering?.id,\n productId: item.productId ?? spec?.productId,\n configuration: mergedConfig,\n currencyCode: cpqConfig.currencyCode,\n ...scope,\n })\n\n const quantity = item.quantity ?? 1\n\n // Compute line totals\n const { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated } = computeLineTotals(charges, quantity, item.usageEstimates)\n\n const isBundleOffering = offering?.offeringType === 'bundle'\n const isConfigured = validationErrors.length === 0 && (charges.length > 0 || isBundleOffering)\n\n // Compute end date\n const endDate = computeEndDate(item.startDate, item.termMonths, item.endDate)\n\n // Get current line count\n const existingLines = await em.find(SalesQuoteLine, {\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const lineNumber = existingLines.length + 1\n\n // Per-instance unit price (NRC + MRC for one instance)\n const perInstanceNrc = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const perInstanceMrc = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const unitPriceNet = perInstanceNrc + perInstanceMrc\n const totalNetAmount = unitPriceNet * quantity\n\n // Create SalesQuoteLine \u2014 assign UUID upfront so CpqQuoteLineConfiguration can reference it\n const quoteLineId = crypto.randomUUID()\n const quoteLine = em.create(SalesQuoteLine, {\n id: quoteLineId,\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber,\n kind: 'product',\n productId: spec?.productId ?? item.productId ?? null,\n name: offering?.name ?? spec?.name ?? 'Configured Item',\n quantity: String(quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(totalNetAmount),\n totalGrossAmount: String(totalNetAmount),\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: cpqConfig.currencyCode,\n configuration: {\n offeringId: offering?.id ?? null,\n offeringCode: offering?.code ?? null,\n action: item.action ?? 'add',\n nrcTotal: Number(nrcTotal),\n mrcTotal: Number(mrcTotal),\n parentLineId: item.parentLineId ?? null,\n },\n normalizedQuantity: String(quantity),\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(quoteLine)\n\n // XD-250 ARC: a new line on an ARC quote must point at one of the\n // attached target subscriptions (validateArcQuote enforces this on\n // submit-for-approval). Auto-inherit when there's exactly one target;\n // for merge-renew (\u22652 targets, all 'absorb') leave it null per spec.\n // The operator can override via item.targetSubscriptionId when a quote\n // has multiple non-merge targets.\n const arcTargetSubscriptionId = await resolveArcLineTargetSubscriptionId(\n em,\n cpqConfig,\n scope,\n item.targetSubscriptionId ?? undefined,\n )\n\n // Create CpqQuoteLineConfiguration\n const lineConfig = em.create(CpqQuoteLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteLineId: quoteLine.id,\n quoteConfigurationId: cpqConfig.id,\n offeringId: offering?.id ?? null,\n productId: spec?.productId ?? item.productId ?? null,\n specId: spec?.id ?? null,\n action: item.action ?? 'add',\n parentLineId: item.parentLineId ?? null,\n startDate: item.startDate ? new Date(item.startDate) : null,\n termMonths: item.termMonths ?? null,\n endDate: endDate ? new Date(endDate) : null,\n configuration: item.configuration,\n quantity,\n charges: charges as unknown as Array<Record<string, unknown>>,\n nrcTotal: String(nrcTotal),\n mrcTotal: String(mrcTotal),\n usageEstimates: usageEstimates ?? null,\n usageTotalEstimated: usageTotalEstimated != null ? String(usageTotalEstimated) : null,\n validationErrors: validationErrors.length > 0 ? validationErrors as unknown as Array<Record<string, unknown>> : null,\n isConfigured,\n targetSubscriptionId: arcTargetSubscriptionId,\n })\n em.persist(lineConfig)\n\n await em.flush()\n\n // Recalculate quote-level totals\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Update Quote Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async updateQuoteItem(quoteId: string,\n lineId: string,\n update: { configuration: Record<string, unknown>; quantity?: number; usageEstimates?: Array<{ chargeCode: string; estimatedQuantity: number }>; startDate?: string; termMonths?: number; endDate?: string },\n scope: TenantScope): Promise<QuoteResult> {\n return this.writeQuote(quoteId, scope, (em, quote) => this.updateQuoteItemInTransaction(quoteId, lineId, update, scope, em, quote), undefined, undefined, LINE_EVENTS)\n }\n\n private async updateQuoteItemInTransaction(\n quoteId: string,\n lineId: string,\n update: { configuration: Record<string, unknown>; quantity?: number; usageEstimates?: Array<{ chargeCode: string; estimatedQuantity: number }>; startDate?: string; termMonths?: number; endDate?: string },\n scope: TenantScope, em: EntityManager, cpqConfig: CpqQuoteConfiguration): Promise<QuoteResult> {\n // ARC markers (`_arc*`) are server-owned: the quote page echoes the line's\n // stored configuration (markers included) back, so drop them here and\n // re-apply the server's own markers below.\n update = { ...update, configuration: stripArcMarkers(update.configuration) }\n\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n const lineConfig = await em.findOne(CpqQuoteLineConfiguration, {\n quoteLineId: lineId,\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!lineConfig) throw new QuotingError(404, 'Quote line not found')\n if (isArcCancelledLine(lineConfig, cpqConfig.quoteType)) {\n throw new QuotingError(409, 'This subscription item is marked for removal \u2014 restore it before changing it')\n }\n\n const quoteLine = await em.findOne(SalesQuoteLine, {\n id: lineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!quoteLine) throw new QuotingError(404, 'Quote line not found')\n\n // Load offering for context merge\n let offering: CpqProductOffering | null = null\n if (lineConfig.offeringId) {\n offering = await em.findOne(CpqProductOffering, {\n id: lineConfig.offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n\n const mergedConfig = {\n ...(cpqConfig.quoteContext ?? {}),\n ...(offering?.designTimeValues ?? {}),\n ...update.configuration,\n }\n\n if (update.termMonths) {\n mergedConfig.term_months = update.termMonths\n }\n\n // Validate\n let validationErrors: ValidationError[] = []\n if (lineConfig.offeringId) {\n const validation = await this.validationService.validateOfferingConfiguration({\n offeringId: lineConfig.offeringId,\n configuration: update.configuration,\n scope,\n })\n validationErrors = validation.errors\n }\n\n // Preserve XD-250 ARC markers across edits \u2014 client-sent markers were\n // stripped above, so carry `_arcMirroredFromItemId` / `_arcMirroredName`\n // over from the stored configuration (downstream \"Mirrored from existing\n // subscription item\" rendering plus the recalc / validate paths key off\n // them).\n const existingCfg = lineConfig.configuration as Record<string, unknown> | null\n const arcMarkers: Record<string, unknown> = {}\n if (existingCfg?._arcMirroredFromItemId !== undefined) {\n arcMarkers._arcMirroredFromItemId = existingCfg._arcMirroredFromItemId\n }\n if (existingCfg?._arcMirroredName !== undefined) {\n arcMarkers._arcMirroredName = existingCfg._arcMirroredName\n }\n // A frozen Amend mirror line keeps the subscription's stored price until\n // a pricing input changes; then it is unfrozen, marked re-priced and\n // priced as usual.\n const wasFrozen = isFrozenAmendMirrorLine(existingCfg, cpqConfig.quoteType)\n const pricingInputsChanged =\n wasFrozen &&\n arcPricingInputsChanged(\n {\n configuration: existingCfg,\n quantity: lineConfig.quantity,\n termMonths: lineConfig.termMonths,\n startDate: lineConfig.startDate,\n endDate: lineConfig.endDate,\n usageEstimates: lineConfig.usageEstimates,\n },\n update,\n )\n const staysFrozen = wasFrozen && !pricingInputsChanged\n if (staysFrozen) arcMarkers[ARC_PRICE_FROZEN_KEY] = true\n if (pricingInputsChanged || existingCfg?.[ARC_REPRICED_KEY] === true) arcMarkers[ARC_REPRICED_KEY] = true\n update.configuration = { ...update.configuration, ...arcMarkers }\n mergedConfig._arcMirroredFromItemId = arcMarkers._arcMirroredFromItemId\n mergedConfig._arcMirroredName = arcMarkers._arcMirroredName\n\n // Re-price \u2014 same ARC mirror handling as recalculateInternal: skip the\n // pricing service when the line carries no offering / product (XD-250\n // mirror lines were created free-form). Without this guard, edits like\n // changing quantity wipe the synthesized charges and the line collapses\n // to \"incomplete\" with mrcTotal=0.\n const isArcMirrored = !!(arcMarkers._arcMirroredFromItemId)\n let charges: ResolvedCharge[]\n if ((lineConfig.offeringId || lineConfig.productId) && !staysFrozen) {\n charges = await this.pricingService.resolveProductCharges({\n offeringId: lineConfig.offeringId ?? undefined,\n productId: lineConfig.productId ?? undefined,\n configuration: mergedConfig,\n currencyCode: cpqConfig.currencyCode,\n ...scope,\n })\n } else {\n charges = (lineConfig.charges ?? []) as unknown as ResolvedCharge[]\n }\n\n const quantity = update.quantity ?? lineConfig.quantity\n const { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated } = computeLineTotals(charges, quantity, update.usageEstimates)\n const isBundleOffering = offering?.offeringType === 'bundle'\n const isConfigured =\n validationErrors.length === 0 && (charges.length > 0 || isBundleOffering || isArcMirrored)\n\n const endDate = computeEndDate(update.startDate ?? lineConfig.startDate?.toISOString(), update.termMonths ?? lineConfig.termMonths ?? undefined, update.endDate)\n\n // Update line config\n em.assign(lineConfig, {\n configuration: update.configuration,\n quantity,\n charges: charges as unknown as Array<Record<string, unknown>>,\n nrcTotal: String(nrcTotal),\n mrcTotal: String(mrcTotal),\n usageEstimates: usageEstimates ?? null,\n usageTotalEstimated: usageTotalEstimated != null ? String(usageTotalEstimated) : null,\n validationErrors: validationErrors.length > 0 ? validationErrors as unknown as Array<Record<string, unknown>> : null,\n isConfigured,\n startDate: update.startDate ? new Date(update.startDate) : lineConfig.startDate,\n termMonths: update.termMonths ?? lineConfig.termMonths,\n endDate: endDate ? new Date(endDate) : lineConfig.endDate,\n })\n\n // Update SalesQuoteLine totals\n const perInstanceNrc = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const perInstanceMrc = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const unitPriceNet = perInstanceNrc + perInstanceMrc\n\n em.assign(quoteLine, {\n quantity: String(quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(unitPriceNet * quantity),\n totalGrossAmount: String(unitPriceNet * quantity),\n updatedAt: new Date(),\n })\n\n await em.flush()\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Remove Quote Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async removeQuoteItem(quoteId: string, lineId: string, scope: TenantScope): Promise<QuoteResult> {\n return this.writeQuote(quoteId, scope, (em, quote) => this.removeQuoteItemInTransaction(quoteId, lineId, scope, em, quote), undefined, undefined, LINE_EVENTS)\n }\n\n private async removeQuoteItemInTransaction(quoteId: string, lineId: string, scope: TenantScope, em: EntityManager, cpqConfig: CpqQuoteConfiguration): Promise<QuoteResult> {\n\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n // Soft-delete the line and its children\n const lineConfig = await em.findOne(CpqQuoteLineConfiguration, {\n quoteLineId: lineId,\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!lineConfig) throw new QuotingError(404, 'Quote line not found')\n\n if (removalCancelsItem(lineConfig, cpqConfig.quoteType)) {\n // Amend / Renew: a line mirroring a live subscription item becomes a\n // `cancel` line so activation terminates the item (see arcLineRemoval.ts).\n if (lineConfig.action === 'cancel') {\n throw new QuotingError(409, 'This subscription item is already marked for removal')\n }\n const plan = planArcLineRemoval(lineConfig, await loadLines(em, cpqConfig.id, scope), cpqConfig.quoteType)\n for (const root of plan.removeRoots) await removeQuoteLineTree(em, cpqConfig.id, root, scope)\n await withAtomicFlush(em, [() => {\n for (const line of plan.cancel) {\n line.action = 'cancel'\n line.charges = []\n line.nrcTotal = '0'\n line.mrcTotal = '0'\n line.isConfigured = true\n line.validationErrors = null\n }\n }])\n } else {\n await removeQuoteLineTree(em, cpqConfig.id, lineConfig, scope)\n }\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Restore a removed subscription item (Amend / Renew) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async restoreQuoteItem(quoteId: string, lineId: string, scope: TenantScope): Promise<QuoteResult> {\n return this.writeQuote(quoteId, scope, (em, quote) => this.restoreQuoteItemInTransaction(lineId, scope, em, quote), undefined, undefined, LINE_EVENTS)\n }\n\n private async restoreQuoteItemInTransaction(lineId: string, scope: TenantScope, em: EntityManager, cpqConfig: CpqQuoteConfiguration): Promise<QuoteResult> {\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n if (TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot modify quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n const lines = await loadLines(em, cpqConfig.id, scope)\n const lineConfig = lines.find((line) => line.quoteLineId === lineId)\n if (!lineConfig) throw new QuotingError(404, 'Quote line not found')\n if (!isArcCancelledLine(lineConfig, cpqConfig.quoteType) || !isArcMirrorLine(lineConfig.configuration, cpqConfig.quoteType)) {\n throw new QuotingError(409, 'Only subscription items marked for removal can be restored')\n }\n\n const plan = planArcLineRestore(lineConfig, lines, cpqConfig.quoteType)\n if (!plan.ok) throw new QuotingError(409, 'Restore the parent item first')\n\n const itemIdOf = (line: CpqQuoteLineConfiguration) =>\n line.sourceSubscriptionItemId ?? ((line.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId as string | undefined) ?? null\n const itemIds = plan.restore.map(itemIdOf).filter((id): id is string => !!id)\n const items = itemIds.length\n ? await em.find(CpqInventorySubscriptionItem, { id: { $in: itemIds }, organizationId: scope.organizationId, tenantId: scope.tenantId, deletedAt: null })\n : []\n const itemById = new Map(items.map((item) => [item.id, item]))\n const salesLines = await em.find(SalesQuoteLine, {\n id: { $in: plan.restore.map((line) => line.quoteLineId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const salesLineById = new Map(salesLines.map((line) => [line.id, line]))\n\n const restores = plan.restore.map((line) => {\n const itemId = itemIdOf(line)\n const item = itemId ? itemById.get(itemId) : undefined\n if (!item || ['terminated', 'expired', 'superseded'].includes(item.status)) {\n throw new QuotingError(409, 'The subscription item is no longer active and cannot be restored')\n }\n return { line, item }\n })\n const arcType = cpqConfig.quoteType as 'amend' | 'renew'\n await withAtomicFlush(em, [() => {\n for (const { line, item } of restores) {\n line.action = 'modify'\n line.configuration = buildArcMirrorConfiguration(item.configuration, item, arcType)\n line.charges = pickArcMirrorCharges(item, cpqConfig.currencyCode)\n line.quantity = item.quantity\n line.nrcTotal = String(item.nrcAmount ?? 0)\n line.mrcTotal = String(item.mrcAmount)\n line.isConfigured = true\n line.validationErrors = null\n const salesLine = salesLineById.get(line.quoteLineId)\n if (salesLine) salesLine.quantity = String(item.quantity)\n }\n }])\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Get Quote (read from DB, no recalculation) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async getQuote(quoteId: string, scope: TenantScope): Promise<QuoteResult> {\n const em = this.em\n\n const cpqConfig = await this.loadCpqConfig(em, quoteId, scope)\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n const lineConfigs = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n return this.buildQuoteResult(em, cpqConfig, salesQuote, lineConfigs)\n }\n\n // \u2500\u2500\u2500 Recalculate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async recalculate(quoteId: string, options: { save: boolean }, scope: TenantScope): Promise<QuoteResult> {\n if (options.save) {\n return this.writeQuote(quoteId, scope, (em, quote) => this.recalculateFromConfig(em, quote, scope, true), undefined,\n (quote) => {\n if (TERMINAL_STATUSES.includes(quote.cpqStatus as CpqStatus)) throw new QuotingError(409, `Cannot recalculate quote in '${quote.cpqStatus}' status`)\n })\n }\n const cpqConfig = await this.loadCpqConfig(this.em, quoteId, scope)\n return this.recalculateFromConfig(this.em, { ...cpqConfig } as CpqQuoteConfiguration, scope, false)\n }\n\n private async recalculateFromConfig(em: EntityManager, cpqConfig: CpqQuoteConfiguration, scope: TenantScope, save: boolean): Promise<QuoteResult> {\n\n // A terminal quote's stored prices are final (accepted quotes are the\n // basis for order conversion) \u2014 a saved recalculation must not move them.\n if (save && TERMINAL_STATUSES.includes(cpqConfig.cpqStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot recalculate quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n return this.recalculateInternal(em, cpqConfig, salesQuote, scope, save)\n }\n\n // \u2500\u2500\u2500 Clone Quote \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async cloneQuote(quoteId: string, scope: TenantScope): Promise<QuoteResult> {\n const created: { quote?: CpqQuoteConfiguration } = {}\n const result = await this.writeQuote(quoteId, scope,\n (em, quote) => this.cloneQuoteInTransaction(quoteId, scope, em, quote, created),\n undefined, undefined, { pricingCause: 'clone' })\n // The copy is a new aggregate: its first committed snapshot is a pricing signal.\n if (created.quote) await emitQuoteWriteEvents(null, created.quote, { pricingCause: 'clone' })\n return result\n }\n\n private async cloneQuoteInTransaction(\n quoteId: string, scope: TenantScope, em: EntityManager, original: CpqQuoteConfiguration,\n created: { quote?: CpqQuoteConfiguration } = {},\n ): Promise<QuoteResult> {\n\n const originalQuote = await this.loadSalesQuote(em, original.quoteId, scope)\n\n // Generate new quote number\n const { number: quoteNumber } = await this.numberGenerator.generate({\n kind: 'quote',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n // Create new SalesQuote \u2014 assign UUID upfront\n const newSalesQuoteId = crypto.randomUUID()\n const newSalesQuote = em.create(SalesQuote, {\n id: newSalesQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteNumber,\n customerEntityId: originalQuote.customerEntityId,\n customerSnapshot: originalQuote.customerSnapshot,\n currencyCode: original.currencyCode,\n subtotalNetAmount: '0',\n subtotalGrossAmount: '0',\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n grandTotalNetAmount: '0',\n grandTotalGrossAmount: '0',\n lineItemCount: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(newSalesQuote)\n\n // Create new CpqQuoteConfiguration\n const newCpqConfig = em.create(CpqQuoteConfiguration, {\n id: crypto.randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: newSalesQuoteId,\n customerId: original.customerId,\n cpqStatus: 'new',\n pricingRevision: 1,\n version: original.version + 1,\n parentQuoteId: original.id,\n currencyCode: original.currencyCode,\n quoteContext: original.quoteContext ? { ...original.quoteContext } : null,\n validationResult: { valid: true, errors: [] },\n pricingSummary: emptyPricingSummary(original.currencyCode),\n })\n em.persist(newCpqConfig)\n created.quote = newCpqConfig\n await em.flush()\n\n // Copy all lines\n const originalLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: original.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n // Map old lineId -> new lineId for parent references\n const lineIdMap = new Map<string, string>()\n\n for (const origLine of originalLines) {\n const origSalesLine = await em.findOne(SalesQuoteLine, {\n id: origLine.quoteLineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const newSalesLineId = crypto.randomUUID()\n const newSalesLine = em.create(SalesQuoteLine, {\n id: newSalesLineId,\n quote: newSalesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: origSalesLine?.lineNumber ?? 1,\n kind: origSalesLine?.kind ?? 'product',\n productId: origSalesLine?.productId ?? null,\n name: origSalesLine?.name ?? null,\n quantity: origSalesLine?.quantity ?? '1',\n unitPriceNet: origSalesLine?.unitPriceNet ?? '0',\n unitPriceGross: origSalesLine?.unitPriceGross ?? '0',\n totalNetAmount: origSalesLine?.totalNetAmount ?? '0',\n totalGrossAmount: origSalesLine?.totalGrossAmount ?? '0',\n discountAmount: origSalesLine?.discountAmount ?? '0',\n discountPercent: origSalesLine?.discountPercent ?? '0',\n taxRate: origSalesLine?.taxRate ?? '0',\n taxAmount: origSalesLine?.taxAmount ?? '0',\n currencyCode: origSalesLine?.currencyCode ?? original.currencyCode,\n configuration: origSalesLine?.configuration ?? null,\n normalizedQuantity: origSalesLine?.normalizedQuantity ?? '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(newSalesLine)\n\n lineIdMap.set(origLine.quoteLineId, newSalesLine.id)\n\n const newLineConfig = em.create(CpqQuoteLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteLineId: newSalesLine.id,\n quoteConfigurationId: newCpqConfig.id,\n offeringId: origLine.offeringId,\n productId: origLine.productId,\n specId: origLine.specId,\n action: origLine.action,\n parentLineId: null, // Will be resolved after all lines are created\n startDate: origLine.startDate,\n termMonths: origLine.termMonths,\n endDate: origLine.endDate,\n // A clone is a new quote: quote-only ARC pricing markers don't apply.\n configuration: { ...stripQuoteOnlyArcMarkers(origLine.configuration) },\n quantity: origLine.quantity,\n charges: origLine.charges ? [...origLine.charges] : null,\n nrcTotal: origLine.nrcTotal,\n mrcTotal: origLine.mrcTotal,\n usageEstimates: origLine.usageEstimates,\n usageTotalEstimated: origLine.usageTotalEstimated,\n validationErrors: origLine.validationErrors,\n isConfigured: origLine.isConfigured,\n })\n em.persist(newLineConfig)\n }\n\n // Resolve parent line references\n const newLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: newCpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n for (const origLine of originalLines) {\n if (origLine.parentLineId) {\n const newParentLineId = lineIdMap.get(origLine.parentLineId)\n const newLine = newLines.find((l) => l.quoteLineId === lineIdMap.get(origLine.quoteLineId))\n if (newLine && newParentLineId) {\n newLine.parentLineId = newParentLineId\n }\n }\n }\n\n await em.flush()\n\n // Recalculate the new quote at current rates\n await cloneQuoteAdjustments(em, original.id, newCpqConfig, lineIdMap, scope)\n await em.flush()\n\n return this.recalculateInternal(em, newCpqConfig, newSalesQuote, scope, true)\n }\n\n // \u2500\u2500\u2500 Transition Status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 async transitionStatus(quoteId: string, targetStatus: string, scope: TenantScope, actorUserId: string | null = null): Promise<QuoteResult> {\n return this.writeQuote(quoteId, scope, (em, quote) => this.transitionStatusInTransaction(quoteId, targetStatus, scope, em, quote),\n undefined, undefined, { pricingCause: 'recalculate', statusCause: 'manual', actorUserId })\n }\n\n private async transitionStatusInTransaction(quoteId: string, targetStatus: string, scope: TenantScope, em: EntityManager, cpqConfig: CpqQuoteConfiguration): Promise<QuoteResult> {\n\n const salesQuote = await this.loadSalesQuote(em, cpqConfig.quoteId, scope)\n\n const currentStatus = cpqConfig.cpqStatus as CpqStatus\n const allowed = ALLOWED_TRANSITIONS[currentStatus] ?? []\n\n if (!allowed.includes(targetStatus as CpqStatus)) {\n throw new QuotingError(409, `Cannot transition from '${currentStatus}' to '${targetStatus}'`)\n }\n\n // XD-250 ARC: at submit-for-approval (and the no-approval shortcuts that\n // bypass it), validate ARC invariants. Spec \u00A7 Services /\n // validateArcQuote: \"Called automatically on the submit-for-approval\n // transition.\" `quoteType ?? 'new'` defends against pre-existing rows\n // (and against test stubs) that may not carry the column \u2014 we only run\n // the ARC validator when the quote is explicitly an ARC type.\n const isSubmitForApproval =\n targetStatus === 'in_approval' ||\n targetStatus === 'pre_approved' ||\n targetStatus === 'with_customer'\n const quoteType = cpqConfig.quoteType ?? 'new'\n if (isSubmitForApproval && quoteType !== 'new') {\n const validation = await this.validateArcQuote(quoteId, scope, em)\n if (!validation.ok) {\n throw new QuotingError(\n 422,\n `ARC quote validation failed: ${validation.errors.join('; ')}`,\n )\n }\n }\n\n // The previous service-level guard required `with_customer` to come\n // from `approved` / `pre_approved` / `ready`. That conflicted with the\n // product decision to let operators jump between any pair of statuses,\n // so it was removed. ARC validation above remains as the real guard\n // against semantic inconsistency on the submit-for-approval path.\n\n cpqConfig.cpqStatus = targetStatus\n await em.flush()\n\n const lines = await this.loadLineConfigs(em, cpqConfig.id, scope)\n return this.buildQuoteResult(em, cpqConfig, salesQuote, lines)\n }\n\n private async writeQuote(\n quoteId: string,\n scope: TenantScope,\n execute: (em: EntityManager, quote: CpqQuoteConfiguration) => Promise<QuoteResult>,\n expectedRevision?: number,\n validate?: (quote: CpqQuoteConfiguration) => void,\n events: QuoteWriteEvents = { pricingCause: 'recalculate' },\n ): Promise<QuoteResult> {\n return withQuotePricingWrite(this.em, quoteId, scope, execute,\n (status, message) => new QuotingError(status, message), expectedRevision, validate, events)\n }\n\n /** Called by adjustment commands that already own the quote lock/revision. */\n async recalculateLockedQuote(\n em: EntityManager, quote: CpqQuoteConfiguration, scope: TenantScope,\n save = true, adjustments?: PriceAdjustment[],\n ): Promise<QuoteResult> {\n const salesQuote = await this.loadSalesQuote(em, quote.quoteId, scope)\n const config = save ? quote : { ...quote } as CpqQuoteConfiguration\n return this.recalculateInternal(em, config, salesQuote, scope, save, adjustments)\n }\n\n // \u2500\u2500\u2500 Internal: Recalculate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 private async recalculateInternal(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n scope: TenantScope,\n save: boolean,\n draftAdjustments?: PriceAdjustment[],\n ): Promise<QuoteResult> {\n const lineConfigs = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n let allValid = true\n const allErrors: ValidationError[] = []\n\n // Collect freshly computed data for each line (used for response regardless of save)\n const computedLines: Array<{\n lineConfig: CpqQuoteLineConfiguration\n charges: ResolvedCharge[]\n nrcTotal: number\n mrcTotal: number\n usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null\n usageTotalEstimated: number | null\n validationErrors: ValidationError[]\n isConfigured: boolean\n }> = []\n\n for (const lineConfig of lineConfigs) {\n let offering: CpqProductOffering | null = null\n if (lineConfig.offeringId) {\n offering = await em.findOne(CpqProductOffering, {\n id: lineConfig.offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n\n const mergedConfig = {\n ...(cpqConfig.quoteContext ?? {}),\n ...(offering?.designTimeValues ?? {}),\n ...lineConfig.configuration,\n }\n\n if (lineConfig.termMonths) {\n mergedConfig.term_months = lineConfig.termMonths\n }\n\n let validationErrors: ValidationError[] = []\n if (lineConfig.offeringId && !isArcCancelledLine(lineConfig, cpqConfig.quoteType)) {\n const validation = await this.validationService.validateOfferingConfiguration({\n offeringId: lineConfig.offeringId,\n configuration: lineConfig.configuration,\n scope,\n })\n validationErrors = validation.errors\n }\n\n // ARC-mirrored lines (XD-250) carry no offering/product because the\n // source subscription item was created free-form (e.g. seeded with just\n // a name + mrcAmount). Pricing service has nothing to resolve from, so\n // skip the call and keep the synthesized / copied charges already on\n // lineConfig \u2014 otherwise quantity edits would wipe them and flip the\n // line to \"incomplete\".\n const cfgRecord = lineConfig.configuration as Record<string, unknown> | null\n const isArcMirrored = !!(cfgRecord?._arcMirroredFromItemId)\n // Frozen Amend mirror lines keep the subscription item's stored charges\n // (see arcPriceFreeze.ts) \u2014 re-pricing them would silently move the\n // contracted price of items the amendment does not touch.\n const isFrozen = isFrozenAmendMirrorLine(cfgRecord, cpqConfig.quoteType)\n let charges: ResolvedCharge[]\n if (isArcCancelledLine(lineConfig, cpqConfig.quoteType)) {\n // Item marked for removal: it leaves the subscription, so it adds\n // nothing to the quote (its current price is shown via `arcSource`).\n charges = []\n } else if ((lineConfig.offeringId || lineConfig.productId) && !isFrozen) {\n charges = await this.pricingService.resolveProductCharges({\n offeringId: lineConfig.offeringId ?? undefined,\n productId: lineConfig.productId ?? undefined,\n configuration: mergedConfig,\n currencyCode: cpqConfig.currencyCode,\n ...scope,\n })\n } else {\n charges = (lineConfig.charges ?? []) as unknown as ResolvedCharge[]\n }\n\n const { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated } = computeLineTotals(\n charges,\n lineConfig.quantity,\n lineConfig.usageEstimates?.map((e) => ({ chargeCode: e.chargeCode, estimatedQuantity: e.estimatedQuantity })),\n )\n\n const isBundleOffering = offering?.offeringType === 'bundle'\n const isConfigured =\n validationErrors.length === 0 && (charges.length > 0 || isBundleOffering || isArcMirrored)\n if (!isConfigured) allValid = false\n allErrors.push(...validationErrors)\n\n computedLines.push({ lineConfig, charges, nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated, validationErrors, isConfigured })\n\n }\n const adjustments = draftAdjustments ?? await loadQuoteAdjustments(em, cpqConfig.id, scope)\n const adjusted = resolveManualAdjustments(computedLines.map(({ lineConfig, charges }) => ({\n lineId: lineConfig.quoteLineId, parentLineId: lineConfig.parentLineId ?? null,\n enginePriced: !!(lineConfig.offeringId || lineConfig.productId),\n mirrored: isArcMirrorLine(lineConfig.configuration, cpqConfig.quoteType), charges,\n })), adjustments, cpqConfig.currencyCode)\n const adjustedById = new Map(adjusted.lines.map((line) => [line.lineId, line]))\n const computedIds = new Set(computedLines.map((line) => line.lineConfig.quoteLineId))\n for (const computed of computedLines) {\n const { lineConfig } = computed\n // No adjustments: preserve legacy/frozen snapshots byte-for-byte on disk.\n if (adjustments.length) computed.charges = adjustedById.get(lineConfig.quoteLineId)!.charges\n const adjustmentErrors = adjusted.errors.filter((error) => error.quoteLineId === lineConfig.quoteLineId)\n if (adjustmentErrors.length) {\n computed.isConfigured = false\n allValid = false\n const errors = adjustmentErrors.map((error) => ({ message: error.code, attribute: error.chargeCode, lineId: error.quoteLineId, adjustmentId: error.adjustmentId }))\n computed.validationErrors.push(...errors)\n allErrors.push(...errors)\n }\n Object.assign(computed, computeLineTotals(computed.charges, lineConfig.quantity,\n lineConfig.usageEstimates?.map((entry) => ({ chargeCode: entry.chargeCode, estimatedQuantity: entry.estimatedQuantity }))))\n const { charges, nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated, validationErrors, isConfigured } = computed\n if (save) {\n await withAtomicFlush(em, [\n () => {\n em.assign(lineConfig, {\n charges: charges as unknown as Array<Record<string, unknown>>,\n nrcTotal: String(nrcTotal),\n mrcTotal: String(mrcTotal),\n usageEstimates: usageEstimates ?? null,\n usageTotalEstimated: usageTotalEstimated != null ? String(usageTotalEstimated) : null,\n validationErrors: validationErrors.length > 0 ? validationErrors as unknown as Array<Record<string, unknown>> : null,\n isConfigured,\n })\n },\n async () => {\n const salesLine = await em.findOne(SalesQuoteLine, {\n id: lineConfig.quoteLineId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (salesLine) {\n const perInstanceNrc = charges.filter((charge) => charge.chargeType === 'nrc').reduce((sum, charge) => sum + (charge.totalPrice ?? 0), 0)\n const perInstanceMrc = charges.filter((charge) => charge.chargeType === 'mrc').reduce((sum, charge) => sum + (charge.totalPrice ?? 0), 0)\n const unitPriceNet = perInstanceNrc + perInstanceMrc\n em.assign(salesLine, {\n quantity: String(lineConfig.quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(unitPriceNet * lineConfig.quantity),\n totalGrossAmount: String(unitPriceNet * lineConfig.quantity),\n updatedAt: new Date(),\n })\n }\n },\n ])\n }\n }\n // A missing line target must still invalidate the quote (normally removal\n // soft-deletes its adjustments in the same aggregate transaction).\n for (const error of adjusted.errors.filter((entry) => !computedIds.has(entry.quoteLineId))) {\n allValid = false\n allErrors.push({ message: error.code, attribute: error.chargeCode, lineId: error.quoteLineId, adjustmentId: error.adjustmentId })\n }\n\n const relationshipErrors = await this.validationService.validateRelationships({\n lines: lineConfigs.map((l) => ({\n lineId: l.quoteLineId,\n specId: l.specId ?? null,\n parentLineId: l.parentLineId ?? null,\n })),\n scope,\n })\n allErrors.push(...relationshipErrors)\n if (relationshipErrors.length > 0) allValid = false\n\n let cpqStatus: CpqStatus\n if (lineConfigs.length === 0) {\n cpqStatus = 'new'\n } else if (!allValid) {\n cpqStatus = 'incomplete'\n } else {\n cpqStatus = 'ready'\n }\n\n const autoManagedStatuses: CpqStatus[] = ['new', 'incomplete', 'ready']\n if (autoManagedStatuses.includes(cpqConfig.cpqStatus as CpqStatus)) {\n cpqConfig.cpqStatus = cpqStatus\n }\n\n // Build pricing summary from freshly computed data (not from stale entity fields)\n const pricingSummary = computePricingSummaryFromComputed(computedLines, cpqConfig.currencyCode)\n Object.assign(pricingSummary, computeWaterfallSummary(computedLines.map(({ lineConfig, charges }) => ({\n lineId: lineConfig.quoteLineId, quantity: lineConfig.quantity, termMonths: lineConfig.termMonths,\n includeInDeal: !isArcMirrorLine(lineConfig.configuration, cpqConfig.quoteType), charges,\n })), adjustments, cpqConfig.currencyCode))\n\n const validationResult = { valid: allValid, errors: allErrors }\n\n if (save) {\n cpqConfig.validationResult = validationResult\n cpqConfig.pricingSummary = pricingSummary as unknown as Record<string, unknown>\n\n const grandTotal = pricingSummary.nrcTotal + pricingSummary.mrcTotal\n em.assign(salesQuote, {\n subtotalNetAmount: String(grandTotal),\n subtotalGrossAmount: String(grandTotal),\n grandTotalNetAmount: String(grandTotal),\n grandTotalGrossAmount: String(grandTotal),\n lineItemCount: lineConfigs.length,\n updatedAt: new Date(),\n })\n\n await em.flush()\n }\n\n const result = await this.buildQuoteResultFromComputed(em, cpqConfig, salesQuote, computedLines, validationResult, pricingSummary)\n result.adjustmentErrors = adjusted.errors\n return result\n }\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async loadCpqConfig(em: EntityManager, quoteId: string, scope: TenantScope): Promise<CpqQuoteConfiguration> {\n // Try finding by CpqQuoteConfiguration.id first, then by quoteId\n let config = await em.findOne(CpqQuoteConfiguration, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqQuoteConfiguration, {\n quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new QuotingError(404, 'Quote not found')\n return config\n }\n\n private async loadSalesQuote(em: EntityManager, quoteId: string, scope: TenantScope): Promise<SalesQuote> {\n const quote = await em.findOne(SalesQuote, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!quote) throw new QuotingError(404, 'Sales quote not found')\n return quote\n }\n\n private async loadLineConfigs(em: EntityManager, cpqConfigId: string, scope: TenantScope): Promise<CpqQuoteLineConfiguration[]> {\n return em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n\n private async resolveOffering(\n em: EntityManager,\n item: QuoteItemInput,\n scope: TenantScope,\n ): Promise<{ offering: CpqProductOffering | null; spec: CpqProductSpecification | null }> {\n const dbScope = { organizationId: scope.organizationId, tenantId: scope.tenantId, deletedAt: null }\n\n if (item.offeringId) {\n const offering = await em.findOne(CpqProductOffering, { id: item.offeringId, ...dbScope })\n if (!offering) throw new QuotingError(404, `Offering ${item.offeringId} not found`)\n const spec = await em.findOne(CpqProductSpecification, { id: offering.specId, ...dbScope })\n return { offering, spec }\n }\n\n if (item.productId) {\n const spec = await em.findOne(CpqProductSpecification, { productId: item.productId, ...dbScope })\n return { offering: null, spec }\n }\n\n throw new QuotingError(400, 'Either offeringId or productId is required')\n }\n\n private async buildQuoteResult(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n lineConfigs: CpqQuoteLineConfiguration[],\n validationResult?: { valid: boolean; errors: ValidationError[] },\n pricingSummary?: PricingSummary,\n ): Promise<QuoteResult> {\n const lines: QuoteLineResult[] = []\n const arcSourceMap = await loadArcSourceMap(em, lineConfigs, cpqConfig)\n\n for (const lc of lineConfigs) {\n let offeringName: string | null = null\n let offeringType: string | null = null\n if (lc.offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: lc.offeringId,\n organizationId: cpqConfig.organizationId,\n tenantId: cpqConfig.tenantId,\n })\n if (offering) {\n offeringName = offering.name\n offeringType = offering.offeringType ?? 'simple'\n }\n }\n if (!offeringName) {\n const cfg = lc.configuration as Record<string, unknown> | null\n offeringName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n }\n\n lines.push({\n lineId: lc.quoteLineId,\n offeringId: lc.offeringId ?? null,\n offeringName,\n offeringType,\n productId: lc.productId ?? null,\n action: lc.action,\n parentLineId: lc.parentLineId ?? null,\n quantity: lc.quantity,\n configuration: lc.configuration ?? {},\n startDate: lc.startDate?.toISOString() ?? null,\n termMonths: lc.termMonths ?? null,\n endDate: lc.endDate?.toISOString() ?? null,\n nrcTotal: Number(lc.nrcTotal),\n mrcTotal: Number(lc.mrcTotal),\n usageEstimates: lc.usageEstimates ?? null,\n usageTotalEstimated: lc.usageTotalEstimated != null ? Number(lc.usageTotalEstimated) : null,\n charges: ((lc.charges ?? []) as unknown as ResolvedCharge[]).map(withChargeWaterfall),\n isConfigured: lc.isConfigured,\n validationErrors: lc.validationErrors as unknown as ValidationError[] ?? null,\n arcSource: pickArcSource(lc, arcSourceMap),\n targetSubscriptionId: lc.targetSubscriptionId ?? null,\n })\n }\n\n const finalValidation = validationResult ?? (cpqConfig.validationResult as { valid: boolean; errors: ValidationError[] }) ?? { valid: true, errors: [] }\n const finalPricing = pricingSummary ?? computePricingSummary(lineConfigs, cpqConfig.currencyCode)\n if (!pricingSummary) {\n const adjustments = await loadQuoteAdjustments(em, cpqConfig.id, { organizationId: cpqConfig.organizationId, tenantId: cpqConfig.tenantId })\n Object.assign(finalPricing, computeWaterfallSummary(lines.map((line) => ({\n lineId: line.lineId, quantity: line.quantity, termMonths: line.termMonths,\n includeInDeal: !isArcMirrorLine(line.configuration, cpqConfig.quoteType), charges: line.charges,\n })), adjustments, cpqConfig.currencyCode))\n }\n\n const { customerName, convertedOrderId } = await resolveQuoteSideData(em, cpqConfig)\n\n return {\n id: cpqConfig.id,\n quoteId: cpqConfig.quoteId,\n quoteNumber: salesQuote.quoteNumber ?? '',\n customerId: cpqConfig.customerId,\n customerName,\n cpqStatus: cpqConfig.cpqStatus,\n version: cpqConfig.version,\n pricingRevision: cpqConfig.pricingRevision ?? 0,\n parentQuoteId: cpqConfig.parentQuoteId ?? null,\n currencyCode: cpqConfig.currencyCode,\n convertedOrderId,\n validationResult: finalValidation,\n pricingSummary: finalPricing,\n lines,\n }\n }\n\n /**\n * Build quote result from freshly computed line data instead of (potentially stale) entity fields.\n * Used by recalculateInternal to ensure both save:true and save:false return current prices.\n */\n private async buildQuoteResultFromComputed(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n computedLines: Array<{\n lineConfig: CpqQuoteLineConfiguration\n charges: ResolvedCharge[]\n nrcTotal: number\n mrcTotal: number\n usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null\n usageTotalEstimated: number | null\n validationErrors: ValidationError[]\n isConfigured: boolean\n }>,\n validationResult: { valid: boolean; errors: ValidationError[] },\n pricingSummary: PricingSummary,\n ): Promise<QuoteResult> {\n const lines: QuoteLineResult[] = []\n const arcSourceMap = await loadArcSourceMap(\n em,\n computedLines.map((c) => c.lineConfig),\n cpqConfig,\n )\n\n for (const { lineConfig: lc, charges, nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated, validationErrors, isConfigured } of computedLines) {\n let offeringName: string | null = null\n let offeringType: string | null = null\n if (lc.offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: lc.offeringId,\n organizationId: cpqConfig.organizationId,\n tenantId: cpqConfig.tenantId,\n })\n if (offering) {\n offeringName = offering.name\n offeringType = offering.offeringType ?? 'simple'\n }\n }\n if (!offeringName) {\n const cfg = lc.configuration as Record<string, unknown> | null\n offeringName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n }\n\n lines.push({\n lineId: lc.quoteLineId,\n offeringId: lc.offeringId ?? null,\n offeringName,\n offeringType,\n productId: lc.productId ?? null,\n action: lc.action,\n parentLineId: lc.parentLineId ?? null,\n quantity: lc.quantity,\n configuration: lc.configuration ?? {},\n startDate: lc.startDate?.toISOString() ?? null,\n termMonths: lc.termMonths ?? null,\n endDate: lc.endDate?.toISOString() ?? null,\n nrcTotal,\n mrcTotal,\n usageEstimates,\n usageTotalEstimated,\n charges: charges.map(withChargeWaterfall),\n isConfigured,\n validationErrors: validationErrors.length > 0 ? validationErrors : null,\n arcSource: pickArcSource(lc, arcSourceMap),\n targetSubscriptionId: lc.targetSubscriptionId ?? null,\n })\n }\n\n const { customerName, convertedOrderId } = await resolveQuoteSideData(em, cpqConfig)\n\n return {\n id: cpqConfig.id,\n quoteId: cpqConfig.quoteId,\n quoteNumber: salesQuote.quoteNumber ?? '',\n customerId: cpqConfig.customerId,\n customerName,\n cpqStatus: cpqConfig.cpqStatus,\n version: cpqConfig.version,\n pricingRevision: cpqConfig.pricingRevision ?? 0,\n parentQuoteId: cpqConfig.parentQuoteId ?? null,\n currencyCode: cpqConfig.currencyCode,\n convertedOrderId,\n validationResult,\n pricingSummary,\n lines,\n }\n }\n}\n\n// \u2500\u2500\u2500 Pure helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Load the bits of `QuoteResult` that don't live on `CpqQuoteConfiguration`\n * itself: the customer display name (for header / drawer labels) and any\n * existing converted order id (locks editing in the UI).\n */\nasync function resolveQuoteSideData(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n): Promise<{ customerName: string | null; convertedOrderId: string | null }> {\n const scope = {\n organizationId: cpqConfig.organizationId,\n tenantId: cpqConfig.tenantId,\n }\n\n const [customer, existingOrder] = await Promise.all([\n em.findOne(CustomerEntity, { id: cpqConfig.customerId, ...scope }),\n em.findOne(\n CpqOrderConfiguration,\n { sourceQuoteId: cpqConfig.id, ...scope, deletedAt: null },\n { fields: ['id', 'orderId'] as never },\n ),\n ])\n\n return {\n customerName: customer?.displayName ?? null,\n convertedOrderId: existingOrder?.orderId ?? null,\n }\n}\n\nfunction buildCustomerSnapshot(customer: CustomerEntity): Record<string, unknown> {\n return {\n customer: {\n id: customer.id,\n kind: customer.kind,\n displayName: customer.displayName,\n primaryEmail: customer.primaryEmail ?? null,\n primaryPhone: customer.primaryPhone ?? null,\n personProfile: customer.personProfile\n ? {\n id: customer.personProfile.id,\n firstName: customer.personProfile.firstName ?? null,\n lastName: customer.personProfile.lastName ?? null,\n preferredName: customer.personProfile.preferredName ?? null,\n }\n : null,\n companyProfile: customer.companyProfile\n ? {\n id: customer.companyProfile.id,\n legalName: customer.companyProfile.legalName ?? null,\n brandName: customer.companyProfile.brandName ?? null,\n domain: customer.companyProfile.domain ?? null,\n websiteUrl: customer.companyProfile.websiteUrl ?? null,\n }\n : null,\n },\n contact: null,\n }\n}\n\nfunction computeLineTotals(\n charges: ResolvedCharge[],\n quantity: number,\n usageEstimateInputs?: Array<{ chargeCode: string; estimatedQuantity: number }>,\n) {\n const nrcPerInstance = charges.filter((c) => c.chargeType === 'nrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n const mrcPerInstance = charges.filter((c) => c.chargeType === 'mrc').reduce((s, c) => s + (c.totalPrice ?? 0), 0)\n\n const nrcTotal = nrcPerInstance * quantity\n const mrcTotal = mrcPerInstance * quantity\n\n let usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null = null\n let usageTotalEstimated: number | null = null\n\n if (usageEstimateInputs && usageEstimateInputs.length > 0) {\n const usageCharges = charges.filter((c) => c.chargeType === 'usage')\n usageEstimates = usageEstimateInputs.map((est) => {\n const charge = usageCharges.find((c) => c.chargeCode === est.chargeCode)\n const estimatedTotal = (charge?.unitPrice ?? 0) * est.estimatedQuantity\n return {\n chargeCode: est.chargeCode,\n estimatedQuantity: est.estimatedQuantity,\n estimatedTotal,\n }\n })\n usageTotalEstimated = usageEstimates.reduce((s, e) => s + e.estimatedTotal, 0) * quantity\n }\n\n return { nrcTotal, mrcTotal, usageEstimates, usageTotalEstimated }\n}\n\nfunction computeEndDate(startDate?: string | null, termMonths?: number, endDate?: string | null): string | null {\n if (endDate) return endDate\n if (startDate && termMonths) {\n const start = new Date(startDate)\n start.setMonth(start.getMonth() + termMonths)\n return start.toISOString().split('T')[0]\n }\n return null\n}\n\nfunction aggregateAdjustmentTotals(allCharges: ResolvedCharge[]): { discountTotal: number; surchargeTotal: number } {\n let discountTotal = 0\n let surchargeTotal = 0\n for (const charge of allCharges) {\n if (!charge.adjustments) continue\n for (const adj of charge.adjustments) {\n if (adj.origin === 'manual') continue\n if (adj.delta < 0) {\n discountTotal += Math.abs(adj.delta) * (charge.quantity ?? 1)\n } else if (adj.delta > 0) {\n surchargeTotal += adj.delta * (charge.quantity ?? 1)\n }\n }\n }\n return { discountTotal, surchargeTotal }\n}\n\nfunction computePricingSummary(lineConfigs: CpqQuoteLineConfiguration[], currencyCode: string): PricingSummary {\n let nrcTotal = 0\n let mrcTotal = 0\n let usageTotalEstimated: number | null = null\n const usageCharges: PricingSummary['usageCharges'] = []\n const allCharges: ResolvedCharge[] = []\n\n for (const lc of lineConfigs) {\n nrcTotal += Number(lc.nrcTotal)\n mrcTotal += Number(lc.mrcTotal)\n if (lc.usageTotalEstimated != null) {\n usageTotalEstimated = (usageTotalEstimated ?? 0) + Number(lc.usageTotalEstimated)\n }\n\n const charges = (lc.charges ?? []) as unknown as ResolvedCharge[]\n allCharges.push(...charges)\n for (const charge of charges) {\n if (charge.chargeType === 'usage') {\n usageCharges.push({\n chargeCode: charge.chargeCode,\n chargeName: charge.chargeName,\n unitPrice: charge.unitPrice,\n note: charge.note ?? null,\n })\n }\n }\n }\n\n const { discountTotal, surchargeTotal } = aggregateAdjustmentTotals(allCharges)\n\n return {\n nrcTotal,\n mrcTotal,\n usageCharges,\n usageTotalEstimated,\n discountTotal,\n surchargeTotal,\n currencyCode,\n }\n}\n\nfunction computePricingSummaryFromComputed(\n computedLines: Array<{\n lineConfig: CpqQuoteLineConfiguration\n charges: ResolvedCharge[]\n nrcTotal: number\n mrcTotal: number\n usageEstimates: Array<{ chargeCode: string; estimatedQuantity: number; estimatedTotal: number }> | null\n usageTotalEstimated: number | null\n }>,\n currencyCode: string,\n): PricingSummary {\n let nrcTotal = 0\n let mrcTotal = 0\n let usageTotalEstimated: number | null = null\n const usageCharges: PricingSummary['usageCharges'] = []\n const allCharges: ResolvedCharge[] = []\n\n for (const { charges, nrcTotal: lineNrc, mrcTotal: lineMrc, usageTotalEstimated: lineUsageEst } of computedLines) {\n nrcTotal += lineNrc\n mrcTotal += lineMrc\n if (lineUsageEst != null) {\n usageTotalEstimated = (usageTotalEstimated ?? 0) + lineUsageEst\n }\n\n allCharges.push(...charges)\n for (const charge of charges) {\n if (charge.chargeType === 'usage') {\n usageCharges.push({\n chargeCode: charge.chargeCode,\n chargeName: charge.chargeName,\n unitPrice: charge.unitPrice,\n note: charge.note ?? null,\n })\n }\n }\n }\n\n const { discountTotal, surchargeTotal } = aggregateAdjustmentTotals(allCharges)\n\n return {\n nrcTotal,\n mrcTotal,\n usageCharges,\n usageTotalEstimated,\n discountTotal,\n surchargeTotal,\n currencyCode,\n }\n}\n\nconst LINE_EVENTS: QuoteWriteEvents = { pricingCause: 'line' }\n\nfunction emptyPricingSummary(currencyCode: string): Record<string, unknown> {\n return {\n // A new quote starts with a real baseline hash, so its first priced line is\n // a pricing change; only pre-feature quotes have no stored hash.\n snapshotHash: computeWaterfallSummary([], [], currencyCode).snapshotHash,\n nrcTotal: 0,\n mrcTotal: 0,\n usageCharges: [],\n usageTotalEstimated: null,\n discountTotal: 0,\n surchargeTotal: 0,\n currencyCode,\n }\n}\n\n// \u2500\u2500\u2500 Error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// Cross-realm brand. Next bundles this package once per server layer (page\n// SSR vs route handler), and the DI container is shared through globalThis,\n// so a route handler can catch a QuotingError built from the *other* copy of\n// this class \u2014 `instanceof` is then false and a typed 404/409 turns into a\n// 500. `Symbol.for` resolves to the same symbol in every copy. Same approach\n// as `isCrudHttpError` in @open-mercato/shared. Use `isQuotingError`.\nconst QUOTING_ERROR_BRAND = Symbol.for('@dainamite/cpq/QuotingError')\n\nexport class QuotingError extends Error {\n readonly [QUOTING_ERROR_BRAND] = true\n\n constructor(\n public status: number,\n message: string,\n public cpqStatus?: string,\n /**\n * Structured payload merged into the route's JSON response body.\n * Used to surface actionable context to the UI \u2014 e.g. the\n * `existingQuoteId` of the conflicting ARC quote on a 409 from\n * `ensureNoConcurrentArcQuote`, so the operator can be offered a\n * \"Open the existing quote\" confirm instead of just a dead alert.\n */\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'QuotingError'\n }\n}\n\nexport function isQuotingError(err: unknown): err is QuotingError {\n return !!err && typeof err === 'object' && (err as Record<symbol, unknown>)[QUOTING_ERROR_BRAND] === true\n}\n\n// \u2500\u2500\u2500 ARC orchestration (XD-250) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// All ARC user-journey logic lives on the CPQ Quote module:\n// \u2022 createQuoteFromSubscription \u2014 entry point from \"Amend / Renew / Cancel\"\n// \u2022 setQuoteType \u2014 one-way new \u2192 arc transition\n// \u2022 attach/detach/updateTargetSubscription \u2014 manage attached targets\n// \u2022 setCancelMeta / setMergeMeta \u2014 stamp ARC-specific meta on the quote\n// \u2022 validateArcQuote \u2014 invariants enforced before approval\n// \u2022 listTargetSubscriptions \u2014 readonly fetch for UI\n//\n// The actual subscription mutations happen in cpqInventoryService.apply* at\n// order activation. This service only owns the quote-level state.\n\nexport interface ArcRenewTermInput {\n newTermStart: string | Date\n newTermEnd: string | Date\n newTermMonths?: number | null\n}\n\nexport interface AttachTargetInput {\n subscriptionId: string\n quoteType: Exclude<CpqQuoteType, 'new'>\n mergeAction?: MergeAction\n newTermStart?: string | Date | null\n newTermEnd?: string | Date | null\n newTermMonths?: number | null\n}\n\nexport interface UpdateTargetInput {\n mergeAction?: MergeAction\n newTermStart?: string | Date | null\n newTermEnd?: string | Date | null\n newTermMonths?: number | null\n}\n\nexport interface CancelMetaInput {\n reasonCode: ArcReasonCode\n reasonText?: string | null\n etfAmount?: string | number | null\n etfCurrency?: string | null\n}\n\nexport interface MergeMetaInput {\n newTermStart: string | Date\n newTermEnd: string | Date\n newTermMonths?: number | null\n newSubCode?: string | null\n newSubName?: string | null\n}\n\nexport interface TargetSubscriptionView {\n id: string\n subscriptionId: string\n quoteType: string\n mergeAction: string | null\n newTermStart: string | null\n newTermEnd: string | null\n newTermMonths: number | null\n subscription: {\n code: string\n name: string\n status: string\n customerId: string\n currencyCode: string\n billingCycle: string\n currentTermStart: string | null\n currentTermEnd: string | null\n termMonths: number | null\n mrcAmount: number\n } | null\n}\n\nexport interface ArcQuoteValidationResult {\n ok: boolean\n errors: string[]\n}\n\nconst EDITABLE_QUOTE_STATUSES: ReadonlySet<string> = new Set([\n 'new',\n 'incomplete',\n 'ready',\n])\n\nfunction ensureEditable(cpqConfig: CpqQuoteConfiguration): void {\n if (!EDITABLE_QUOTE_STATUSES.has(cpqConfig.cpqStatus)) {\n throw new QuotingError(\n 409,\n `Cannot modify ARC attachments \u2014 quote is in '${cpqConfig.cpqStatus}' status`,\n )\n }\n}\n\nfunction toDateOrNull(value: string | Date | null | undefined): Date | null {\n if (value == null) return null\n return value instanceof Date ? value : new Date(value)\n}\n\n/**\n * Render a Date / string-date value as ISO-8601. MikroORM hydrates\n * `@Property({ type: 'date' })` columns as strings (YYYY-MM-DD) on Postgres\n * \u2014 calling `.toISOString()` on them throws. This helper accepts either form.\n */\nfunction toIsoOrNull(value: Date | string | null | undefined): string | null {\n if (value == null) return null\n if (value instanceof Date) return value.toISOString()\n // String already in ISO-ish form (YYYY-MM-DD or full ISO) \u2014 pass through.\n return String(value)\n}\n\n// \u2500\u2500\u2500 Module helpers extending DefaultCpqQuotingService \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndeclare module './cpqQuotingService' {\n interface DefaultCpqQuotingService {\n setQuoteType(quoteId: string, type: CpqQuoteType, scope: TenantScope): Promise<QuoteResult>\n createQuoteFromSubscription(input: {\n subscriptionId: string\n type: Exclude<CpqQuoteType, 'new'>\n renewTerm?: ArcRenewTermInput\n }, scope: TenantScope): Promise<{ quoteId: string; cpqConfigId: string }>\n listTargetSubscriptions(quoteId: string, scope: TenantScope): Promise<TargetSubscriptionView[]>\n attachTargetSubscription(\n quoteId: string,\n input: AttachTargetInput,\n scope: TenantScope,\n ): Promise<TargetSubscriptionView>\n detachTargetSubscription(\n quoteId: string,\n targetId: string,\n scope: TenantScope,\n ): Promise<{ ok: true }>\n updateTargetSubscription(\n quoteId: string,\n targetId: string,\n patch: UpdateTargetInput,\n scope: TenantScope,\n ): Promise<TargetSubscriptionView>\n setCancelMeta(quoteId: string, meta: CancelMetaInput, scope: TenantScope): Promise<QuoteResult>\n setMergeMeta(quoteId: string, meta: MergeMetaInput, scope: TenantScope): Promise<QuoteResult>\n validateArcQuote(quoteId: string, scope: TenantScope, transactionEm?: EntityManager): Promise<ArcQuoteValidationResult>\n }\n}\n\nDefaultCpqQuotingService.prototype.setQuoteType = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n type: CpqQuoteType,\n scope: TenantScope,\n): Promise<QuoteResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n if (cpqConfig.quoteType === type) {\n // No-op \u2014 caller can repeat the PATCH freely.\n } else if (cpqConfig.quoteType !== 'new') {\n throw new QuotingError(409, `Quote type is immutable (current: '${cpqConfig.quoteType}')`)\n } else if (type === 'new') {\n throw new QuotingError(400, `Cannot transition quote type back to 'new'`)\n } else {\n cpqConfig.quoteType = type\n await em.flush()\n }\n\n const salesQuote = await loadSalesQuoteStrict(em, cpqConfig.quoteId, scope)\n const lines = await loadLines(em, cpqConfig.id, scope)\n return (this as unknown as InternalQuoting).buildQuoteResult(em, cpqConfig, salesQuote, lines)\n}\n\nDefaultCpqQuotingService.prototype.createQuoteFromSubscription = async function (\n this: DefaultCpqQuotingService,\n input: {\n subscriptionId: string\n type: Exclude<CpqQuoteType, 'new'>\n renewTerm?: ArcRenewTermInput\n },\n scope: TenantScope,\n): Promise<{ quoteId: string; cpqConfigId: string }> {\n const em = (this as unknown as { em: EntityManager }).em\n\n // 1. Load source subscription + active items.\n const sub = await em.findOne(CpqInventorySubscription, {\n id: input.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!sub) throw new QuotingError(404, 'Subscription not found')\n if (sub.status !== 'active' && sub.status !== 'suspended') {\n throw new QuotingError(\n 409,\n `Subscription must be active or suspended (current: '${sub.status}')`,\n )\n }\n\n await ensureNoConcurrentArcQuote(em, sub.id, scope)\n\n const items = await em.find(CpqInventorySubscriptionItem, {\n subscriptionId: sub.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n status: { $nin: ['terminated', 'expired', 'superseded'] },\n })\n\n // 2. Create SalesQuote + CpqQuoteConfiguration with quoteType=type.\n const numberGenerator = (this as unknown as InternalQuoting).numberGenerator\n const { number: quoteNumber } = await numberGenerator.generate({\n kind: 'quote',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const salesQuoteId = crypto.randomUUID()\n const salesQuote = em.create(SalesQuote, {\n id: salesQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteNumber,\n customerEntityId: sub.customerId,\n currencyCode: sub.currencyCode,\n subtotalNetAmount: '0',\n subtotalGrossAmount: '0',\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n grandTotalNetAmount: '0',\n grandTotalGrossAmount: '0',\n lineItemCount: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesQuote)\n\n // Pre-generate id so child rows (target subscription + quote lines) can\n // reference it before flush. The DB-side `defaultRaw: 'gen_random_uuid()'`\n // only fires at INSERT, not at em.create() \u2014 so the id would be undefined\n // when CpqQuoteLineConfiguration tries to set quoteConfigurationId.\n const cpqConfigId = crypto.randomUUID()\n const cpqConfig = em.create(CpqQuoteConfiguration, {\n id: cpqConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: salesQuoteId,\n customerId: sub.customerId,\n cpqStatus: 'new',\n version: 1,\n currencyCode: sub.currencyCode,\n quoteType: input.type,\n quoteContext: { arcSourceSubscriptionId: sub.id },\n validationResult: { valid: true, errors: [] },\n pricingSummary: emptyArcPricingSummary(sub.currencyCode),\n })\n em.persist(cpqConfig)\n\n // 3. Attach the source subscription as the (sole) target. For renew, fall\n // back to \"renew for same length starting at current term end\" so the\n // operator can hit Convert\u2192Activate without opening the drawer at all\n // when the default behaviour is fine. Operator override is still\n // available via the drawer's config-renew step.\n const renewDefaults = input.type === 'renew' ? buildRenewDefaults(sub, input.renewTerm) : null\n const target = em.create(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: cpqConfig.id,\n subscriptionId: sub.id,\n quoteType: input.type,\n mergeAction: input.type === 'renew' ? 'standalone' : null,\n newTermStart: renewDefaults?.start ?? null,\n newTermEnd: renewDefaults?.end ?? null,\n newTermMonths: renewDefaults?.months ?? null,\n })\n em.persist(target)\n\n // 4. Pre-fill quote lines from the subscription's active items via the\n // shared mirror helper (also used when attaching extra targets).\n await mirrorTargetSubscriptionItems(em, cpqConfig, sub, salesQuote, input.type, scope)\n\n await em.flush()\n return { quoteId: salesQuoteId, cpqConfigId: cpqConfig.id }\n}\n\nDefaultCpqQuotingService.prototype.listTargetSubscriptions = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n scope: TenantScope,\n): Promise<TargetSubscriptionView[]> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n if (targets.length === 0) return []\n\n const subs = await em.find(CpqInventorySubscription, {\n id: { $in: targets.map((t) => t.subscriptionId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const subMap = new Map(subs.map((s) => [s.id, s]))\n\n return targets.map((t) => {\n const s = subMap.get(t.subscriptionId)\n return {\n id: t.id,\n subscriptionId: t.subscriptionId,\n quoteType: t.quoteType,\n mergeAction: t.mergeAction ?? null,\n newTermStart: toIsoOrNull(t.newTermStart),\n newTermEnd: toIsoOrNull(t.newTermEnd),\n newTermMonths: t.newTermMonths ?? null,\n subscription: s\n ? {\n code: s.code,\n name: s.name,\n status: s.status,\n customerId: s.customerId,\n currencyCode: s.currencyCode,\n billingCycle: s.billingCycle,\n currentTermStart: toIsoOrNull(s.currentTermStart),\n currentTermEnd: toIsoOrNull(s.currentTermEnd),\n termMonths: s.termMonths ?? null,\n mrcAmount: Number(s.mrcAmount),\n }\n : null,\n }\n })\n}\n\nDefaultCpqQuotingService.prototype.attachTargetSubscription = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n input: AttachTargetInput,\n scope: TenantScope,\n): Promise<TargetSubscriptionView> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n if (cpqConfig.quoteType === 'new') {\n throw new QuotingError(409, `Cannot attach a target subscription \u2014 quote_type is 'new'`)\n }\n if (cpqConfig.quoteType !== input.quoteType) {\n throw new QuotingError(\n 400,\n `Quote type mismatch: quote is '${cpqConfig.quoteType}', payload says '${input.quoteType}'`,\n )\n }\n\n // Idempotency on (quote, subscription).\n const existing = await em.findOne(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n quoteId: cpqConfig.id,\n subscriptionId: input.subscriptionId,\n })\n if (existing) {\n return mapTargetView(em, existing, scope)\n }\n\n // Subscription must exist and be in {active, suspended}.\n const sub = await em.findOne(CpqInventorySubscription, {\n id: input.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!sub) throw new QuotingError(404, 'Subscription not found')\n if (sub.status !== 'active' && sub.status !== 'suspended') {\n throw new QuotingError(\n 409,\n `Subscription must be active or suspended (current: '${sub.status}')`,\n )\n }\n\n // Customer / currency / billingCycle must match the quote and any existing targets.\n if (sub.customerId !== cpqConfig.customerId) {\n throw new QuotingError(400, 'Subscription customer must match quote customer')\n }\n if (sub.currencyCode !== cpqConfig.currencyCode) {\n throw new QuotingError(400, 'Subscription currency must match quote currency')\n }\n\n const otherTargets = await em.find(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n quoteId: cpqConfig.id,\n })\n if (input.quoteType === 'renew' && otherTargets.length > 0) {\n // Merge mode: every target (existing + this) must share billingCycle.\n const otherSubs = await em.find(CpqInventorySubscription, {\n id: { $in: otherTargets.map((t) => t.subscriptionId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const o of otherSubs) {\n if (o.billingCycle !== sub.billingCycle) {\n throw new QuotingError(\n 400,\n 'Merge targets must share the same billing cycle',\n )\n }\n }\n }\n\n await ensureNoConcurrentArcQuote(em, input.subscriptionId, scope, cpqConfig.id)\n\n const target = em.create(CpqQuoteTargetSubscription, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteId: cpqConfig.id,\n subscriptionId: input.subscriptionId,\n quoteType: input.quoteType,\n mergeAction:\n input.quoteType === 'renew'\n ? input.mergeAction ?? (otherTargets.length === 0 ? 'standalone' : 'absorb')\n : null,\n newTermStart: toDateOrNull(input.newTermStart),\n newTermEnd: toDateOrNull(input.newTermEnd),\n newTermMonths: input.newTermMonths ?? null,\n })\n em.persist(target)\n await em.flush()\n\n // After attaching a 2nd renew target, retroactively flip the original\n // 'standalone' target to 'absorb' so the whole quote enters merge mode.\n let renewMergeJustEntered = false\n if (input.quoteType === 'renew') {\n const allTargets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (allTargets.length >= 2) {\n const wasStandalone = allTargets.some((t) => t.mergeAction === 'standalone')\n for (const t of allTargets) {\n t.mergeAction = 'absorb'\n t.newTermStart = null\n t.newTermEnd = null\n t.newTermMonths = null\n }\n await em.flush()\n renewMergeJustEntered = wasStandalone\n }\n }\n\n // XD-250 multi-target ARC: mirror the newly attached subscription's items\n // so the operator can see / edit / cancel them in the quote UI. Without\n // this the target row existed but the quote had no lines for it, so\n // activation produced an empty change-log entry on that sub. For renew\n // merge, mirrored lines carry `targetSubscriptionId: null` (the merged\n // sub doesn't exist yet at quote time) and any lines created earlier for\n // the original standalone target get re-tagged to null too.\n const salesQuote = await em.findOne(SalesQuote, {\n id: cpqConfig.quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (salesQuote) {\n const isRenewMerge = input.quoteType === 'renew' && otherTargets.length > 0\n await mirrorTargetSubscriptionItems(\n em,\n cpqConfig,\n sub,\n salesQuote,\n input.quoteType,\n scope,\n { mergeMode: isRenewMerge },\n )\n\n if (renewMergeJustEntered) {\n const existingLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const lc of existingLines) {\n if (lc.targetSubscriptionId !== null) lc.targetSubscriptionId = null\n }\n }\n\n await em.flush()\n }\n\n return mapTargetView(em, target, scope)\n}\n\nDefaultCpqQuotingService.prototype.detachTargetSubscription = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n targetId: string,\n scope: TenantScope,\n): Promise<{ ok: true }> {\n const em = (this as unknown as { em: EntityManager }).em\n // Detaching removes priced lines (rep-added lines may carry negotiated\n // prices), so it takes the same aggregate lock and revision bump as any\n // other pricing write and re-prices the remaining lines.\n await withQuotePricingWrite(em, quoteId, scope, async (tx, cpqConfig) => {\n const target = await tx.findOne(CpqQuoteTargetSubscription, {\n id: targetId,\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!target) throw new QuotingError(404, 'Target subscription not found')\n\n // Drop quote lines that pointed at this target, with their bundle\n // children, sales lines and price adjustments.\n const lines = await tx.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n targetSubscriptionId: target.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const line of lines) {\n if (line.deletedAt) continue\n await removeQuoteLineTree(tx, cpqConfig.id, line, scope)\n }\n\n // Read the remaining renew targets before mutating, so no query runs\n // between a scalar change and its flush.\n const remaining = target.quoteType === 'renew'\n ? await tx.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n id: { $ne: target.id },\n })\n : []\n await withAtomicFlush(tx, [() => {\n target.deletedAt = new Date()\n // Auto-revert merge mode if only one renew target remains.\n if (remaining.length === 1) remaining[0].mergeAction = 'standalone'\n }])\n await this.recalculateLockedQuote(tx, cpqConfig, scope, true)\n }, (status, message) => new QuotingError(status, message), undefined, ensureEditable, { pricingCause: 'line' })\n return { ok: true }\n}\n\nDefaultCpqQuotingService.prototype.updateTargetSubscription = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n targetId: string,\n patch: UpdateTargetInput,\n scope: TenantScope,\n): Promise<TargetSubscriptionView> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n\n const target = await em.findOne(CpqQuoteTargetSubscription, {\n id: targetId,\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!target) throw new QuotingError(404, 'Target subscription not found')\n\n if (target.quoteType !== 'renew') {\n throw new QuotingError(\n 409,\n `Cannot update target on a '${target.quoteType}' quote \u2014 only renew targets carry term/merge fields`,\n )\n }\n\n if (patch.mergeAction !== undefined) target.mergeAction = patch.mergeAction\n if (patch.newTermStart !== undefined) target.newTermStart = toDateOrNull(patch.newTermStart)\n if (patch.newTermEnd !== undefined) target.newTermEnd = toDateOrNull(patch.newTermEnd)\n if (patch.newTermMonths !== undefined) target.newTermMonths = patch.newTermMonths ?? null\n\n await em.flush()\n return mapTargetView(em, target, scope)\n}\n\nDefaultCpqQuotingService.prototype.setCancelMeta = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n meta: CancelMetaInput,\n scope: TenantScope,\n): Promise<QuoteResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n if (cpqConfig.quoteType !== 'cancel') {\n throw new QuotingError(\n 409,\n `Cancel meta can only be set on a cancel quote (current: '${cpqConfig.quoteType}')`,\n )\n }\n cpqConfig.arcReasonCode = meta.reasonCode\n cpqConfig.arcReasonText = meta.reasonText ?? null\n cpqConfig.arcEtfAmount = meta.etfAmount != null ? String(meta.etfAmount) : null\n cpqConfig.arcEtfCurrency = meta.etfCurrency ?? cpqConfig.currencyCode\n await em.flush()\n\n const salesQuote = await loadSalesQuoteStrict(em, cpqConfig.quoteId, scope)\n const lines = await loadLines(em, cpqConfig.id, scope)\n return (this as unknown as InternalQuoting).buildQuoteResult(em, cpqConfig, salesQuote, lines)\n}\n\nDefaultCpqQuotingService.prototype.setMergeMeta = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n meta: MergeMetaInput,\n scope: TenantScope,\n): Promise<QuoteResult> {\n const em = (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n ensureEditable(cpqConfig)\n if (cpqConfig.quoteType !== 'renew') {\n throw new QuotingError(\n 409,\n `Merge meta can only be set on a renew quote (current: '${cpqConfig.quoteType}')`,\n )\n }\n cpqConfig.arcMergeNewTermStart = toDateOrNull(meta.newTermStart)\n cpqConfig.arcMergeNewTermEnd = toDateOrNull(meta.newTermEnd)\n cpqConfig.arcMergeNewTermMonths = meta.newTermMonths ?? null\n cpqConfig.arcMergeNewSubCode = meta.newSubCode ?? null\n cpqConfig.arcMergeNewSubName = meta.newSubName ?? null\n await em.flush()\n\n const salesQuote = await loadSalesQuoteStrict(em, cpqConfig.quoteId, scope)\n const lines = await loadLines(em, cpqConfig.id, scope)\n return (this as unknown as InternalQuoting).buildQuoteResult(em, cpqConfig, salesQuote, lines)\n}\n\nDefaultCpqQuotingService.prototype.validateArcQuote = async function (\n this: DefaultCpqQuotingService,\n quoteId: string,\n scope: TenantScope,\n transactionEm?: EntityManager,\n): Promise<ArcQuoteValidationResult> {\n const em = transactionEm ?? (this as unknown as { em: EntityManager }).em\n const cpqConfig = await loadCpqConfigStrict(em, quoteId, scope)\n const errors: string[] = []\n\n if (cpqConfig.quoteType === 'new') {\n return { ok: true, errors: [] }\n }\n if (!ARC_QUOTE_TYPES.includes(cpqConfig.quoteType as Exclude<CpqQuoteType, 'new'>)) {\n errors.push(`Unknown quote type '${cpqConfig.quoteType}'`)\n return { ok: false, errors }\n }\n\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) {\n errors.push(`ARC quote requires at least one target subscription`)\n return { ok: false, errors }\n }\n\n // Fetch attached subscriptions and check status + same customer/currency/billingCycle.\n const subs = await em.find(CpqInventorySubscription, {\n id: { $in: targets.map((t) => t.subscriptionId) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const subMap = new Map(subs.map((s) => [s.id, s]))\n for (const t of targets) {\n const s = subMap.get(t.subscriptionId)\n if (!s) {\n errors.push(`Target subscription ${t.subscriptionId} not found`)\n continue\n }\n if (s.status !== 'active' && s.status !== 'suspended') {\n errors.push(\n `Target subscription ${s.code} must be active or suspended (current: '${s.status}')`,\n )\n }\n if (s.customerId !== cpqConfig.customerId) {\n errors.push(`Target subscription ${s.code} belongs to a different customer`)\n }\n if (s.currencyCode !== cpqConfig.currencyCode) {\n errors.push(`Target subscription ${s.code} has currency mismatch`)\n }\n }\n\n // Type-specific invariants.\n if (cpqConfig.quoteType === 'renew') {\n const standaloneCount = targets.filter((t) => t.mergeAction === 'standalone').length\n const absorbCount = targets.filter((t) => t.mergeAction === 'absorb').length\n\n if (targets.length === 1) {\n if (standaloneCount !== 1) {\n errors.push(`Single-target renew must have merge_action='standalone'`)\n }\n const t = targets[0]\n if (!t.newTermStart || !t.newTermEnd) {\n errors.push(`Standalone renew target must have newTermStart and newTermEnd`)\n } else if (t.newTermStart >= t.newTermEnd) {\n errors.push(`newTermStart must be earlier than newTermEnd`)\n }\n } else {\n if (absorbCount !== targets.length) {\n errors.push(`Multi-target renew (merge) requires every target merge_action='absorb'`)\n }\n if (\n !cpqConfig.arcMergeNewTermStart ||\n !cpqConfig.arcMergeNewTermEnd\n ) {\n errors.push(`Merge renew requires quote-level arc_merge_new_term_start and arc_merge_new_term_end`)\n } else if (cpqConfig.arcMergeNewTermStart >= cpqConfig.arcMergeNewTermEnd) {\n errors.push(`arc_merge_new_term_start must be earlier than arc_merge_new_term_end`)\n }\n // Same billing cycle across all sources.\n const cycles = new Set(\n targets\n .map((t) => subMap.get(t.subscriptionId)?.billingCycle)\n .filter(Boolean),\n )\n if (cycles.size > 1) {\n errors.push(`Merge targets must share the same billing cycle`)\n }\n }\n }\n\n if (cpqConfig.quoteType === 'cancel') {\n if (!cpqConfig.arcReasonCode) {\n errors.push(`Cancel quote requires arc_reason_code (call /cancel-meta first)`)\n }\n }\n\n // Quote line invariants.\n const lines = await loadLines(em, cpqConfig.id, scope)\n const targetSubIds = new Set(targets.map((t) => t.subscriptionId))\n const isMerge =\n cpqConfig.quoteType === 'renew' &&\n targets.length >= 2 &&\n targets.every((t) => t.mergeAction === 'absorb')\n\n for (const line of lines) {\n if (cpqConfig.quoteType === 'amend' || cpqConfig.quoteType === 'cancel') {\n if (!line.targetSubscriptionId) {\n errors.push(`Quote line ${line.quoteLineId} missing target_subscription_id`)\n } else if (!targetSubIds.has(line.targetSubscriptionId)) {\n errors.push(\n `Quote line ${line.quoteLineId} target_subscription_id does not match any attached target`,\n )\n }\n } else if (cpqConfig.quoteType === 'renew') {\n if (isMerge) {\n if (line.targetSubscriptionId) {\n errors.push(\n `Merge-renew line ${line.quoteLineId} must have null target_subscription_id`,\n )\n }\n } else {\n // standalone \u2014 single target.\n if (!line.targetSubscriptionId || !targetSubIds.has(line.targetSubscriptionId)) {\n errors.push(\n `Standalone renew line ${line.quoteLineId} must target the renewing subscription`,\n )\n }\n }\n }\n if (\n (line.action === 'cancel' || line.action === 'modify') &&\n cpqConfig.quoteType !== 'cancel' &&\n !line.sourceSubscriptionItemId\n ) {\n errors.push(\n `Quote line ${line.quoteLineId} action='${line.action}' requires source_subscription_item_id`,\n )\n }\n }\n\n // Concurrency: each attached sub must not be on another non-terminal ARC quote.\n for (const t of targets) {\n await ensureNoConcurrentArcQuoteForValidation(em, t.subscriptionId, scope, cpqConfig.id, errors)\n }\n\n return { ok: errors.length === 0, errors }\n}\n\n// \u2500\u2500\u2500 ARC private/module helpers (XD-250) \u2500\u2500\u2500\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\ninterface InternalQuoting {\n numberGenerator: SalesDocumentNumberGenerator\n buildQuoteResult: (\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n salesQuote: SalesQuote,\n lineConfigs: CpqQuoteLineConfiguration[],\n validationResult?: { valid: boolean; errors: ValidationError[] },\n ) => Promise<QuoteResult>\n}\n\nasync function loadCpqConfigStrict(\n em: EntityManager,\n quoteId: string,\n scope: TenantScope,\n): Promise<CpqQuoteConfiguration> {\n let config = await em.findOne(CpqQuoteConfiguration, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqQuoteConfiguration, {\n quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new QuotingError(404, 'Quote not found')\n return config\n}\n\nasync function loadSalesQuoteStrict(\n em: EntityManager,\n quoteId: string,\n scope: TenantScope,\n): Promise<SalesQuote> {\n const quote = await em.findOne(SalesQuote, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!quote) throw new QuotingError(404, 'Sales quote not found')\n return quote\n}\n\nasync function loadLines(\n em: EntityManager,\n cpqConfigId: string,\n scope: TenantScope,\n): Promise<CpqQuoteLineConfiguration[]> {\n return em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n}\n\nasync function ensureNoConcurrentArcQuote(\n em: EntityManager,\n subscriptionId: string,\n scope: TenantScope,\n excludeQuoteConfigId?: string,\n): Promise<void> {\n const conflicting = await em.find(CpqQuoteTargetSubscription, {\n subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (conflicting.length === 0) return\n const cfgIds = conflicting.map((c) => c.quoteId)\n const cfgs = await em.find(CpqQuoteConfiguration, {\n id: { $in: cfgIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const cfg of cfgs) {\n if (excludeQuoteConfigId && cfg.id === excludeQuoteConfigId) continue\n if (!TERMINAL_STATUSES.includes(cfg.cpqStatus as CpqStatus)) {\n throw new QuotingError(\n 409,\n `Subscription has another ARC quote in progress (quoteId=${cfg.quoteId})`,\n undefined,\n // Surface the conflicting quote id so the UI can offer \"Open the\n // existing quote\" instead of just showing a dead-end alert. Use\n // `quoteId` (the SalesQuote UUID, what the URL bar shows after the\n // first Amend) \u2014 not `cfg.id` (the CpqQuoteConfiguration UUID) \u2014\n // so the redirect URL matches the URL the operator would see on a\n // fresh first-time create, and so the test assertion can compare\n // the two with `toContain`.\n { existingQuoteId: cfg.quoteId, existingQuoteStatus: cfg.cpqStatus },\n )\n }\n }\n}\n\nasync function ensureNoConcurrentArcQuoteForValidation(\n em: EntityManager,\n subscriptionId: string,\n scope: TenantScope,\n excludeQuoteConfigId: string,\n errors: string[],\n): Promise<void> {\n try {\n await ensureNoConcurrentArcQuote(em, subscriptionId, scope, excludeQuoteConfigId)\n } catch (err) {\n if (err instanceof QuotingError) errors.push(err.message)\n else throw err\n }\n}\n\nasync function mapTargetView(\n em: EntityManager,\n target: CpqQuoteTargetSubscription,\n scope: TenantScope,\n): Promise<TargetSubscriptionView> {\n const sub = await em.findOne(CpqInventorySubscription, {\n id: target.subscriptionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return {\n id: target.id,\n subscriptionId: target.subscriptionId,\n quoteType: target.quoteType,\n mergeAction: target.mergeAction ?? null,\n newTermStart: toIsoOrNull(target.newTermStart),\n newTermEnd: toIsoOrNull(target.newTermEnd),\n newTermMonths: target.newTermMonths ?? null,\n subscription: sub\n ? {\n code: sub.code,\n name: sub.name,\n status: sub.status,\n customerId: sub.customerId,\n currencyCode: sub.currencyCode,\n billingCycle: sub.billingCycle,\n currentTermStart: toIsoOrNull(sub.currentTermStart),\n currentTermEnd: toIsoOrNull(sub.currentTermEnd),\n termMonths: sub.termMonths ?? null,\n mrcAmount: Number(sub.mrcAmount),\n }\n : null,\n }\n}\n\nfunction emptyArcPricingSummary(currencyCode: string): Record<string, unknown> {\n return {\n snapshotHash: computeWaterfallSummary([], [], currencyCode).snapshotHash,\n nrcTotal: 0,\n mrcTotal: 0,\n usageCharges: [],\n usageTotalEstimated: null,\n discountTotal: 0,\n surchargeTotal: 0,\n currencyCode,\n }\n}\n\n// XD-250 ARC: batch-load source subscription items referenced by the lines'\n// `_arcMirroredFromItemId` markers and / or `sourceSubscriptionItemId`. Used\n// by buildQuoteResult / buildOrderResult to surface a \"before\" snapshot per\n// line so the operator can compare current sub state vs. what's about to\n// change. Returns a map keyed by subscription-item id.\nasync function loadArcSourceMap(\n em: EntityManager,\n lineConfigs: Array<{\n configuration?: Record<string, unknown> | null\n sourceSubscriptionItemId?: string | null\n }>,\n scope: { organizationId: string; tenantId: string },\n): Promise<Map<string, CpqInventorySubscriptionItem>> {\n const ids = new Set<string>()\n for (const lc of lineConfigs) {\n const fromMarker = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n if (typeof fromMarker === 'string') ids.add(fromMarker)\n if (lc.sourceSubscriptionItemId) ids.add(lc.sourceSubscriptionItemId)\n }\n if (ids.size === 0) return new Map()\n\n const items = await em.find(CpqInventorySubscriptionItem, {\n id: { $in: Array.from(ids) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return new Map(items.map((it) => [it.id, it]))\n}\n\nfunction pickArcSource(\n lc: {\n configuration?: Record<string, unknown> | null\n sourceSubscriptionItemId?: string | null\n },\n map: Map<string, CpqInventorySubscriptionItem>,\n): ArcLineSource | null {\n const fromMarker = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n const id =\n (typeof fromMarker === 'string' ? fromMarker : null) ?? lc.sourceSubscriptionItemId ?? null\n if (!id) return null\n const item = map.get(id)\n if (!item) return null\n return {\n subscriptionItemId: item.id,\n name: item.name,\n mrcAmount: Number(item.mrcAmount),\n nrcAmount: Number(item.nrcAmount),\n quantity: item.quantity,\n }\n}\n\n// XD-250 ARC renew defaults \u2014 when the operator clicks \"Renew\" we pre-fill\n// the target row with \"same length starting at current term end\" so they\n// don't have to open the drawer just to confirm. Honours an explicit\n// `input.renewTerm` override and falls back gracefully when the source\n// subscription has missing `currentTermEnd` / `termMonths` (e.g. fixture\n// data without dates) \u2014 start defaults to today and length to 12 months.\nfunction buildRenewDefaults(\n sub: CpqInventorySubscription,\n override?: ArcRenewTermInput,\n): { start: Date; end: Date; months: number } {\n if (override) {\n const start = toDateOrNull(override.newTermStart)\n const end = toDateOrNull(override.newTermEnd)\n const months = override.newTermMonths ?? null\n if (start && end && months != null) return { start, end, months }\n // Fall through to derived defaults if override was incomplete.\n }\n const months = sub.termMonths ?? 12\n const start = sub.currentTermEnd ? new Date(sub.currentTermEnd) : new Date()\n const end = new Date(start)\n end.setMonth(end.getMonth() + months)\n return { start, end, months }\n}\n\n// XD-250 ARC: mirror a subscription's active items as quote lines on the\n// given quote \u2014 used both at quote creation (initial target) and when the\n// operator attaches additional targets via the modify-subscription drawer.\n// For amend \u2192 action='modify', for cancel \u2192 action='cancel'. Preserves\n// parent-child structure (bundle \u2192 components) by pre-generating SalesQuote\n// line ids before the loop. No-op when the sub has no eligible items.\nasync function mirrorTargetSubscriptionItems(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n sub: CpqInventorySubscription,\n salesQuote: SalesQuote,\n quoteType: 'amend' | 'cancel' | 'renew',\n scope: TenantScope,\n options?: { mergeMode?: boolean },\n): Promise<void> {\n const items = await em.find(CpqInventorySubscriptionItem, {\n subscriptionId: sub.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n status: { $nin: ['terminated', 'expired', 'superseded'] },\n })\n if (items.length === 0) return\n\n const existingLines = await em.find(SalesQuoteLine, {\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n let nextLineNumber = existingLines.length + 1\n\n const subItemIdToSalesLineId = new Map<string, string>()\n for (const item of items) {\n subItemIdToSalesLineId.set(item.id, crypto.randomUUID())\n }\n\n const lineAction: 'modify' | 'cancel' = quoteType === 'cancel' ? 'cancel' : 'modify'\n\n for (const item of items) {\n const salesLineId = subItemIdToSalesLineId.get(item.id)!\n const parentLineId = item.parentItemId\n ? subItemIdToSalesLineId.get(item.parentItemId) ?? null\n : null\n\n const salesLine = em.create(SalesQuoteLine, {\n id: salesLineId,\n quote: salesQuote,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: nextLineNumber++,\n kind: 'product',\n productId: item.productId ?? null,\n name: item.name,\n quantity: String(item.quantity),\n unitPriceNet: '0',\n unitPriceGross: '0',\n totalNetAmount: '0',\n totalGrossAmount: '0',\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: sub.currencyCode,\n configuration: item.configuration ?? null,\n normalizedQuantity: '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesLine)\n\n const lineConfig = em.create(CpqQuoteLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n quoteLineId: salesLineId,\n quoteConfigurationId: cpqConfig.id,\n offeringId: item.offeringId ?? null,\n productId: item.productId ?? null,\n specId: item.specId ?? null,\n action: lineAction,\n parentLineId,\n startDate: null,\n termMonths: null,\n endDate: null,\n configuration: buildArcMirrorConfiguration(item.configuration, item, quoteType),\n quantity: item.quantity,\n charges: pickArcMirrorCharges(item, sub.currencyCode),\n nrcTotal: String(item.nrcAmount ?? 0),\n mrcTotal: String(item.mrcAmount),\n isConfigured: true,\n // XD-250 spec: merge-renew lines must have null `target_subscription_id`\n // (the source subs are absorbed into a brand-new sub at activation, so\n // there's no existing item to bind the line to). For amend / cancel /\n // standalone-renew, bind to the source sub so per-target validation /\n // groupings work.\n targetSubscriptionId: options?.mergeMode ? null : sub.id,\n sourceSubscriptionItemId: item.id,\n })\n em.persist(lineConfig)\n }\n}\n\n// XD-250 ARC: when adding a line to an ARC quote, decide which target\n// subscription the line acts on. Returns null for non-ARC quotes and for\n// merge-renew quotes (per validateArcQuote: merge-renew lines must have null\n// target_subscription_id). For amend / cancel / standalone-renew with one\n// attached target, returns that target. With multiple targets, the caller\n// must pass an explicit targetSubscriptionId in QuoteItemInput.\nasync function resolveArcLineTargetSubscriptionId(\n em: EntityManager,\n cpqConfig: CpqQuoteConfiguration,\n scope: TenantScope,\n explicit?: string,\n): Promise<string | null> {\n const quoteType = cpqConfig.quoteType ?? 'new'\n if (quoteType === 'new') return null\n\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) return null\n\n const isMerge =\n quoteType === 'renew' &&\n targets.length >= 2 &&\n targets.every((t) => t.mergeAction === 'absorb')\n if (isMerge) return null\n\n if (explicit) {\n if (!targets.some((t) => t.subscriptionId === explicit)) {\n throw new QuotingError(\n 422,\n `targetSubscriptionId '${explicit}' is not attached to this quote`,\n )\n }\n return explicit\n }\n\n if (targets.length === 1) return targets[0].subscriptionId\n\n throw new QuotingError(\n 422,\n `Quote has ${targets.length} attached targets \u2014 specify targetSubscriptionId on the line`,\n )\n}\n\n// Build the per-instance charges JSON for an ARC-mirrored quote line. If the\n// source subscription item already has explicit charges, copy them. Otherwise\n// synthesize a flat MRC / NRC charge from the item's stored amounts so that\n// recalculate (which scales totalPrice by lineConfig.quantity) has something\n// to work with \u2014 without this, changing quantity on a mirrored line wipes the\n// charges array and the line flips to \"incomplete\".\nfunction pickArcMirrorCharges(\n item: { mrcAmount: string | number; nrcAmount?: string | number; quantity: number; charges?: unknown },\n currencyCode: string,\n): Array<Record<string, unknown>> | null {\n const existing = (item.charges ?? null) as Array<Record<string, unknown>> | null\n if (existing && existing.length > 0) return [...existing]\n\n const sourceQty = Math.max(1, Number(item.quantity) || 1)\n const mrc = Number(item.mrcAmount) || 0\n const nrc = Number(item.nrcAmount ?? 0) || 0\n const synth: Array<Record<string, unknown>> = []\n if (mrc > 0) {\n const perInstance = mrc / sourceQty\n synth.push({\n chargeCode: 'mrc',\n chargeName: 'Monthly Recurring',\n chargeType: 'mrc',\n pricingMethod: 'flat',\n unitPrice: perInstance,\n quantity: 1,\n totalPrice: perInstance,\n currencyCode,\n })\n }\n if (nrc > 0) {\n const perInstance = nrc / sourceQty\n synth.push({\n chargeCode: 'nrc',\n chargeName: 'Non-Recurring',\n chargeType: 'nrc',\n pricingMethod: 'flat',\n unitPrice: perInstance,\n quantity: 1,\n totalPrice: perInstance,\n currencyCode,\n })\n }\n return synth.length > 0 ? synth : null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["start", "end", "months"]
|
|
7
7
|
}
|