@dainamite/cpq 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/MIGRATION.md +74 -0
  3. package/dist/modules/cpq/acl.js +1 -0
  4. package/dist/modules/cpq/acl.js.map +2 -2
  5. package/dist/modules/cpq/api/_helpers/adjustmentCommandRoute.js +45 -0
  6. package/dist/modules/cpq/api/_helpers/adjustmentCommandRoute.js.map +7 -0
  7. package/dist/modules/cpq/api/_helpers/quoteMutationGuard.js +23 -0
  8. package/dist/modules/cpq/api/_helpers/quoteMutationGuard.js.map +7 -0
  9. package/dist/modules/cpq/api/_helpers/quoteRouteOpenApi.js +19 -0
  10. package/dist/modules/cpq/api/_helpers/quoteRouteOpenApi.js.map +7 -0
  11. package/dist/modules/cpq/api/orders/[orderId]/route.js +17 -1
  12. package/dist/modules/cpq/api/orders/[orderId]/route.js.map +2 -2
  13. package/dist/modules/cpq/api/orders/route.js +47 -2
  14. package/dist/modules/cpq/api/orders/route.js.map +2 -2
  15. package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/restore/route.js +54 -0
  16. package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/restore/route.js.map +7 -0
  17. package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js +42 -2
  18. package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js.map +2 -2
  19. package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js +27 -2
  20. package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js.map +2 -2
  21. package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/[adjustmentId]/route.js +47 -0
  22. package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/[adjustmentId]/route.js.map +7 -0
  23. package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/preview/route.js +30 -0
  24. package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/preview/route.js.map +7 -0
  25. package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/route.js +47 -0
  26. package/dist/modules/cpq/api/quotes/[quoteId]/price-adjustments/route.js.map +7 -0
  27. package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js +32 -2
  28. package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js.map +2 -2
  29. package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js +33 -2
  30. package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js.map +2 -2
  31. package/dist/modules/cpq/api/quotes/price/route.js +43 -3
  32. package/dist/modules/cpq/api/quotes/price/route.js.map +2 -2
  33. package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +3 -9
  34. package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +2 -2
  35. package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +21 -25
  36. package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +2 -2
  37. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +48 -47
  38. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +2 -2
  39. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +1 -1
  40. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +2 -2
  41. package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +3 -3
  42. package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +2 -2
  43. package/dist/modules/cpq/backend/cpq/inventory/shared.js +37 -2
  44. package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +2 -2
  45. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +174 -184
  46. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
  47. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +1 -1
  48. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +2 -2
  49. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +168 -143
  50. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
  51. package/dist/modules/cpq/backend/cpq/offerings/page.js +36 -34
  52. package/dist/modules/cpq/backend/cpq/offerings/page.js.map +2 -2
  53. package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +140 -280
  54. package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +2 -2
  55. package/dist/modules/cpq/backend/cpq/orders/page.js +6 -6
  56. package/dist/modules/cpq/backend/cpq/orders/page.js.map +2 -2
  57. package/dist/modules/cpq/backend/cpq/orders/page.meta.js +1 -1
  58. package/dist/modules/cpq/backend/cpq/orders/page.meta.js.map +1 -1
  59. package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +41 -36
  60. package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +2 -2
  61. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +76 -72
  62. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +2 -2
  63. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +1 -1
  64. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +2 -2
  65. package/dist/modules/cpq/backend/cpq/price-rules/page.js +18 -15
  66. package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +2 -2
  67. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +23 -21
  68. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
  69. package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +22 -50
  70. package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +2 -2
  71. package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +74 -52
  72. package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +2 -2
  73. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +20 -17
  74. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +2 -2
  75. package/dist/modules/cpq/backend/cpq/pricing/page.js +1 -1
  76. package/dist/modules/cpq/backend/cpq/pricing/page.js.map +2 -2
  77. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +115 -123
  78. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +2 -2
  79. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js +208 -0
  80. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js.map +7 -0
  81. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentsPanel.js +79 -0
  82. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentsPanel.js.map +7 -0
  83. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/arcLineRemoval.js +53 -0
  84. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/arcLineRemoval.js.map +7 -0
  85. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/priceAdjustmentContext.js +107 -0
  86. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/priceAdjustmentContext.js.map +7 -0
  87. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/usePriceAdjustments.js +130 -0
  88. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/usePriceAdjustments.js.map +7 -0
  89. package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +269 -311
  90. package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +3 -3
  91. package/dist/modules/cpq/backend/cpq/quotes/page.js +23 -19
  92. package/dist/modules/cpq/backend/cpq/quotes/page.js.map +2 -2
  93. package/dist/modules/cpq/backend/cpq/quotes/page.meta.js +1 -1
  94. package/dist/modules/cpq/backend/cpq/quotes/page.meta.js.map +1 -1
  95. package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +19 -15
  96. package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +2 -2
  97. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +171 -178
  98. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
  99. package/dist/modules/cpq/backend/cpq/specifications/page.js +2 -2
  100. package/dist/modules/cpq/backend/cpq/specifications/page.js.map +2 -2
  101. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +60 -50
  102. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +2 -2
  103. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +22 -18
  104. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +2 -2
  105. package/dist/modules/cpq/backend/cpq/wizards/page.js +1 -1
  106. package/dist/modules/cpq/backend/cpq/wizards/page.js.map +2 -2
  107. package/dist/modules/cpq/ce.js +8 -0
  108. package/dist/modules/cpq/ce.js.map +2 -2
  109. package/dist/modules/cpq/cli.js +34 -1
  110. package/dist/modules/cpq/cli.js.map +2 -2
  111. package/dist/modules/cpq/commands/price-adjustments.js +107 -0
  112. package/dist/modules/cpq/commands/price-adjustments.js.map +7 -0
  113. package/dist/modules/cpq/components/ArcLineDiff.js +53 -0
  114. package/dist/modules/cpq/components/ArcLineDiff.js.map +7 -0
  115. package/dist/modules/cpq/components/ChargeBreakdownTable.js +148 -0
  116. package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +7 -0
  117. package/dist/modules/cpq/components/PriceWaterfall.js +68 -0
  118. package/dist/modules/cpq/components/PriceWaterfall.js.map +7 -0
  119. package/dist/modules/cpq/components/PricingSummaryCard.js +112 -0
  120. package/dist/modules/cpq/components/PricingSummaryCard.js.map +7 -0
  121. package/dist/modules/cpq/components/StatusPath.js +5 -3
  122. package/dist/modules/cpq/components/StatusPath.js.map +2 -2
  123. package/dist/modules/cpq/components/useCpqRowActions.js +10 -22
  124. package/dist/modules/cpq/components/useCpqRowActions.js.map +2 -2
  125. package/dist/modules/cpq/components/useGrantedFeatures.js +27 -0
  126. package/dist/modules/cpq/components/useGrantedFeatures.js.map +7 -0
  127. package/dist/modules/cpq/data/entities.js +97 -0
  128. package/dist/modules/cpq/data/entities.js.map +2 -2
  129. package/dist/modules/cpq/data/price-adjustments.js +70 -0
  130. package/dist/modules/cpq/data/price-adjustments.js.map +7 -0
  131. package/dist/modules/cpq/data/validators.js +4 -0
  132. package/dist/modules/cpq/data/validators.js.map +2 -2
  133. package/dist/modules/cpq/di.js +6 -0
  134. package/dist/modules/cpq/di.js.map +2 -2
  135. package/dist/modules/cpq/events.js +47 -0
  136. package/dist/modules/cpq/events.js.map +2 -2
  137. package/dist/modules/cpq/i18n/de.json +1220 -0
  138. package/dist/modules/cpq/i18n/en.json +1220 -0
  139. package/dist/modules/cpq/i18n/es.json +1220 -0
  140. package/dist/modules/cpq/i18n/pl.json +1220 -0
  141. package/dist/modules/cpq/index.js +1 -1
  142. package/dist/modules/cpq/index.js.map +2 -2
  143. package/dist/modules/cpq/lib/auditActor.js +10 -0
  144. package/dist/modules/cpq/lib/auditActor.js.map +7 -0
  145. package/dist/modules/cpq/lib/formatMoney.js +7 -0
  146. package/dist/modules/cpq/lib/formatMoney.js.map +7 -0
  147. package/dist/modules/cpq/lib/priceAdjustmentDefaults.js +60 -0
  148. package/dist/modules/cpq/lib/priceAdjustmentDefaults.js.map +7 -0
  149. package/dist/modules/cpq/lib/priceAdjustmentView.js +169 -0
  150. package/dist/modules/cpq/lib/priceAdjustmentView.js.map +7 -0
  151. package/dist/modules/cpq/lib/quotePermissions.js +13 -0
  152. package/dist/modules/cpq/lib/quotePermissions.js.map +7 -0
  153. package/dist/modules/cpq/lib/quoteSummaryView.js +28 -0
  154. package/dist/modules/cpq/lib/quoteSummaryView.js.map +7 -0
  155. package/dist/modules/cpq/migrations/Migration20261110213052.js +22 -0
  156. package/dist/modules/cpq/migrations/Migration20261110213052.js.map +7 -0
  157. package/dist/modules/cpq/services/arcLineRemoval.js +53 -0
  158. package/dist/modules/cpq/services/arcLineRemoval.js.map +7 -0
  159. package/dist/modules/cpq/services/arcPriceFreeze.js +79 -0
  160. package/dist/modules/cpq/services/arcPriceFreeze.js.map +7 -0
  161. package/dist/modules/cpq/services/cpqOrderService.js +25 -28
  162. package/dist/modules/cpq/services/cpqOrderService.js.map +2 -2
  163. package/dist/modules/cpq/services/cpqPricingService.js +7 -0
  164. package/dist/modules/cpq/services/cpqPricingService.js.map +2 -2
  165. package/dist/modules/cpq/services/cpqQuotingService.js +330 -109
  166. package/dist/modules/cpq/services/cpqQuotingService.js.map +2 -2
  167. package/dist/modules/cpq/services/orderPricingSummary.js +26 -0
  168. package/dist/modules/cpq/services/orderPricingSummary.js.map +7 -0
  169. package/dist/modules/cpq/services/priceAdjustments/adjustmentService.js +264 -0
  170. package/dist/modules/cpq/services/priceAdjustments/adjustmentService.js.map +7 -0
  171. package/dist/modules/cpq/services/priceAdjustments/chargeWaterfall.js +25 -0
  172. package/dist/modules/cpq/services/priceAdjustments/chargeWaterfall.js.map +7 -0
  173. package/dist/modules/cpq/services/priceAdjustments/loadQuoteAdjustments.js +38 -0
  174. package/dist/modules/cpq/services/priceAdjustments/loadQuoteAdjustments.js.map +7 -0
  175. package/dist/modules/cpq/services/priceAdjustments/pricingSnapshot.js +104 -0
  176. package/dist/modules/cpq/services/priceAdjustments/pricingSnapshot.js.map +7 -0
  177. package/dist/modules/cpq/services/priceAdjustments/quoteAdjustmentLifecycle.js +102 -0
  178. package/dist/modules/cpq/services/priceAdjustments/quoteAdjustmentLifecycle.js.map +7 -0
  179. package/dist/modules/cpq/services/priceAdjustments/quotePricingEvents.js +52 -0
  180. package/dist/modules/cpq/services/priceAdjustments/quotePricingEvents.js.map +7 -0
  181. package/dist/modules/cpq/services/priceAdjustments/quotePricingWrite.js +37 -0
  182. package/dist/modules/cpq/services/priceAdjustments/quotePricingWrite.js.map +7 -0
  183. package/dist/modules/cpq/services/priceAdjustments/resolveManualAdjustments.js +107 -0
  184. package/dist/modules/cpq/services/priceAdjustments/resolveManualAdjustments.js.map +7 -0
  185. package/dist/modules/cpq/services/priceAdjustments/storedAdjustmentFailure.js +30 -0
  186. package/dist/modules/cpq/services/priceAdjustments/storedAdjustmentFailure.js.map +7 -0
  187. package/dist/modules/cpq/services/types.js.map +2 -2
  188. package/dist/modules/cpq/setup.js +6 -0
  189. package/dist/modules/cpq/setup.js.map +2 -2
  190. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +39 -31
  191. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +2 -2
  192. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +13 -5
  193. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +2 -2
  194. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +41 -21
  195. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +2 -2
  196. package/dist/modules/cpq/widgets/injection-table.js +2 -2
  197. package/dist/modules/cpq/widgets/injection-table.js.map +2 -2
  198. package/dist/modules/cpq/workflows/WizardRunner.js +10 -8
  199. package/dist/modules/cpq/workflows/WizardRunner.js.map +2 -2
  200. package/dist/modules/cpq/workflows/WizardTrigger.js +15 -9
  201. package/dist/modules/cpq/workflows/WizardTrigger.js.map +2 -2
  202. package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +9 -7
  203. package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +2 -2
  204. package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +9 -4
  205. package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +2 -2
  206. package/dist/modules/cpq/workflows/steps/ItemListStep.js +16 -19
  207. package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +2 -2
  208. package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +19 -32
  209. package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +2 -2
  210. package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +8 -6
  211. package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +2 -2
  212. package/dist/modules/cpq/workflows/steps/ReviewStep.js +32 -30
  213. package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +2 -2
  214. package/dist/modules/cpq/workflows/steps/index.js +12 -0
  215. package/dist/modules/cpq/workflows/steps/index.js.map +2 -2
  216. package/package.json +1 -1
  217. package/src/modules/cpq/__integration__/TC-CPQ-ARC-012.spec.ts +134 -0
  218. package/src/modules/cpq/__tests__/i18n/dictionaries.test.ts +62 -0
  219. package/src/modules/cpq/__tests__/i18n/hardcodedStrings.test.ts +35 -0
  220. package/src/modules/cpq/__tests__/i18n/sourceScan.ts +109 -0
  221. package/src/modules/cpq/acl.ts +1 -0
  222. package/src/modules/cpq/api/__tests__/adjustmentRoutes.test.ts +79 -0
  223. package/src/modules/cpq/api/__tests__/quoteWriteGuards.test.ts +100 -0
  224. package/src/modules/cpq/api/_helpers/__tests__/quoteMutationGuard.test.ts +48 -0
  225. package/src/modules/cpq/api/_helpers/adjustmentCommandRoute.ts +45 -0
  226. package/src/modules/cpq/api/_helpers/quoteMutationGuard.ts +38 -0
  227. package/src/modules/cpq/api/_helpers/quoteRouteOpenApi.ts +19 -0
  228. package/src/modules/cpq/api/orders/[orderId]/route.ts +18 -0
  229. package/src/modules/cpq/api/orders/route.ts +51 -1
  230. package/src/modules/cpq/api/quotes/[quoteId]/items/[lineId]/restore/route.ts +56 -0
  231. package/src/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.ts +48 -1
  232. package/src/modules/cpq/api/quotes/[quoteId]/items/route.ts +31 -1
  233. package/src/modules/cpq/api/quotes/[quoteId]/price-adjustments/[adjustmentId]/route.ts +39 -0
  234. package/src/modules/cpq/api/quotes/[quoteId]/price-adjustments/preview/route.ts +24 -0
  235. package/src/modules/cpq/api/quotes/[quoteId]/price-adjustments/route.ts +40 -0
  236. package/src/modules/cpq/api/quotes/[quoteId]/recalculate/__tests__/route.test.ts +95 -0
  237. package/src/modules/cpq/api/quotes/[quoteId]/recalculate/route.ts +40 -1
  238. package/src/modules/cpq/api/quotes/[quoteId]/status/__tests__/route.test.ts +74 -0
  239. package/src/modules/cpq/api/quotes/[quoteId]/status/route.ts +37 -1
  240. package/src/modules/cpq/api/quotes/price/__tests__/route.test.ts +37 -0
  241. package/src/modules/cpq/api/quotes/price/route.ts +28 -2
  242. package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +3 -9
  243. package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +22 -26
  244. package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +1 -1
  245. package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +43 -46
  246. package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +3 -3
  247. package/src/modules/cpq/backend/cpq/inventory/shared.tsx +37 -1
  248. package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +1 -1
  249. package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +164 -120
  250. package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +169 -130
  251. package/src/modules/cpq/backend/cpq/offerings/page.tsx +34 -24
  252. package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +122 -308
  253. package/src/modules/cpq/backend/cpq/orders/page.meta.ts +1 -1
  254. package/src/modules/cpq/backend/cpq/orders/page.tsx +6 -6
  255. package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +48 -34
  256. package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +1 -1
  257. package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +76 -70
  258. package/src/modules/cpq/backend/cpq/price-rules/page.tsx +25 -16
  259. package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -18
  260. package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +29 -19
  261. package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +95 -47
  262. package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +23 -15
  263. package/src/modules/cpq/backend/cpq/pricing/page.tsx +1 -1
  264. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +111 -88
  265. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.tsx +260 -0
  266. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentsPanel.tsx +124 -0
  267. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/__tests__/PriceAdjustmentsPanel.test.tsx +76 -0
  268. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/arcLineRemoval.tsx +76 -0
  269. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/priceAdjustmentContext.tsx +133 -0
  270. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/usePriceAdjustments.tsx +165 -0
  271. package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +304 -348
  272. package/src/modules/cpq/backend/cpq/quotes/page.meta.ts +1 -1
  273. package/src/modules/cpq/backend/cpq/quotes/page.tsx +29 -21
  274. package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +19 -15
  275. package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +171 -171
  276. package/src/modules/cpq/backend/cpq/specifications/page.tsx +2 -2
  277. package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +51 -41
  278. package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +17 -13
  279. package/src/modules/cpq/backend/cpq/wizards/page.tsx +1 -1
  280. package/src/modules/cpq/ce.ts +8 -0
  281. package/src/modules/cpq/cli.ts +48 -1
  282. package/src/modules/cpq/commands/__tests__/price-adjustments.test.ts +54 -0
  283. package/src/modules/cpq/commands/price-adjustments.ts +90 -0
  284. package/src/modules/cpq/components/ArcLineDiff.tsx +87 -0
  285. package/src/modules/cpq/components/ChargeBreakdownTable.tsx +203 -0
  286. package/src/modules/cpq/components/PriceWaterfall.tsx +96 -0
  287. package/src/modules/cpq/components/PricingSummaryCard.tsx +128 -0
  288. package/src/modules/cpq/components/StatusPath.tsx +7 -4
  289. package/src/modules/cpq/components/__tests__/PriceWaterfall.test.tsx +38 -0
  290. package/src/modules/cpq/components/useCpqRowActions.tsx +17 -25
  291. package/src/modules/cpq/components/useGrantedFeatures.ts +35 -0
  292. package/src/modules/cpq/data/__tests__/price-adjustment-migration.test.ts +11 -0
  293. package/src/modules/cpq/data/__tests__/price-adjustments.test.ts +26 -0
  294. package/src/modules/cpq/data/entities.ts +83 -0
  295. package/src/modules/cpq/data/price-adjustments.ts +67 -0
  296. package/src/modules/cpq/data/validators.ts +3 -0
  297. package/src/modules/cpq/di.ts +6 -0
  298. package/src/modules/cpq/events.ts +53 -2
  299. package/src/modules/cpq/i18n/de.json +1220 -0
  300. package/src/modules/cpq/i18n/en.json +1220 -0
  301. package/src/modules/cpq/i18n/es.json +1220 -0
  302. package/src/modules/cpq/i18n/pl.json +1220 -0
  303. package/src/modules/cpq/index.ts +1 -1
  304. package/src/modules/cpq/lib/__tests__/auditActor.test.ts +12 -0
  305. package/src/modules/cpq/lib/__tests__/priceAdjustmentDefaults.test.ts +37 -0
  306. package/src/modules/cpq/lib/__tests__/priceAdjustmentView.test.ts +152 -0
  307. package/src/modules/cpq/lib/__tests__/quotePermissions.test.ts +30 -0
  308. package/src/modules/cpq/lib/__tests__/quoteSummaryView.test.ts +56 -0
  309. package/src/modules/cpq/lib/auditActor.ts +13 -0
  310. package/src/modules/cpq/lib/formatMoney.ts +4 -0
  311. package/src/modules/cpq/lib/priceAdjustmentDefaults.ts +36 -0
  312. package/src/modules/cpq/lib/priceAdjustmentView.ts +259 -0
  313. package/src/modules/cpq/lib/quotePermissions.ts +22 -0
  314. package/src/modules/cpq/lib/quoteSummaryView.ts +51 -0
  315. package/src/modules/cpq/migrations/.snapshot-open-mercato.json +3298 -2423
  316. package/src/modules/cpq/migrations/Migration20261110213052.ts +22 -0
  317. package/src/modules/cpq/services/__tests__/_helpers/mockEm.ts +9 -2
  318. package/src/modules/cpq/services/__tests__/adjustmentService.test.ts +183 -0
  319. package/src/modules/cpq/services/__tests__/arcLineRemoval.test.ts +109 -0
  320. package/src/modules/cpq/services/__tests__/arcPriceFreeze.test.ts +141 -0
  321. package/src/modules/cpq/services/__tests__/chargeWaterfall.test.ts +28 -0
  322. package/src/modules/cpq/services/__tests__/cpqOrderService.test.ts +35 -2
  323. package/src/modules/cpq/services/__tests__/cpqPricingService.test.ts +57 -0
  324. package/src/modules/cpq/services/__tests__/cpqQuotingService.arc.test.ts +237 -0
  325. package/src/modules/cpq/services/__tests__/cpqQuotingService.test.ts +58 -3
  326. package/src/modules/cpq/services/__tests__/orderPricingSummary.test.ts +50 -0
  327. package/src/modules/cpq/services/__tests__/pricingSnapshot.test.ts +62 -0
  328. package/src/modules/cpq/services/__tests__/quoteAdjustmentLifecycle.test.ts +35 -0
  329. package/src/modules/cpq/services/__tests__/quoteAdjustmentPricing.test.ts +65 -0
  330. package/src/modules/cpq/services/__tests__/quoteCloneAdjustments.test.ts +45 -0
  331. package/src/modules/cpq/services/__tests__/quoteDetachTargetAdjustments.test.ts +54 -0
  332. package/src/modules/cpq/services/__tests__/quoteEventsService.test.ts +72 -0
  333. package/src/modules/cpq/services/__tests__/quotePricingEvents.test.ts +126 -0
  334. package/src/modules/cpq/services/__tests__/quotePricingIsolation.test.ts +52 -0
  335. package/src/modules/cpq/services/__tests__/quotePricingWrite.test.ts +74 -0
  336. package/src/modules/cpq/services/__tests__/resolveManualAdjustments.test.ts +90 -0
  337. package/src/modules/cpq/services/__tests__/storedAdjustmentFailure.test.ts +9 -0
  338. package/src/modules/cpq/services/arcLineRemoval.ts +87 -0
  339. package/src/modules/cpq/services/arcPriceFreeze.ts +165 -0
  340. package/src/modules/cpq/services/cpqOrderService.ts +22 -28
  341. package/src/modules/cpq/services/cpqPricingService.ts +8 -0
  342. package/src/modules/cpq/services/cpqQuotingService.ts +374 -125
  343. package/src/modules/cpq/services/orderPricingSummary.ts +47 -0
  344. package/src/modules/cpq/services/priceAdjustments/adjustmentService.ts +249 -0
  345. package/src/modules/cpq/services/priceAdjustments/chargeWaterfall.ts +28 -0
  346. package/src/modules/cpq/services/priceAdjustments/loadQuoteAdjustments.ts +25 -0
  347. package/src/modules/cpq/services/priceAdjustments/pricingSnapshot.ts +86 -0
  348. package/src/modules/cpq/services/priceAdjustments/quoteAdjustmentLifecycle.ts +68 -0
  349. package/src/modules/cpq/services/priceAdjustments/quotePricingEvents.ts +94 -0
  350. package/src/modules/cpq/services/priceAdjustments/quotePricingWrite.ts +51 -0
  351. package/src/modules/cpq/services/priceAdjustments/resolveManualAdjustments.ts +116 -0
  352. package/src/modules/cpq/services/priceAdjustments/storedAdjustmentFailure.ts +31 -0
  353. package/src/modules/cpq/services/types.ts +34 -1
  354. package/src/modules/cpq/setup.ts +7 -1
  355. package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +38 -31
  356. package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +7 -5
  357. package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +36 -21
  358. package/src/modules/cpq/widgets/injection-table.ts +8 -2
  359. package/src/modules/cpq/workflows/WizardRunner.tsx +8 -5
  360. package/src/modules/cpq/workflows/WizardTrigger.tsx +15 -9
  361. package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +11 -7
  362. package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +9 -5
  363. package/src/modules/cpq/workflows/steps/ItemListStep.tsx +18 -12
  364. package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +20 -16
  365. package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +8 -6
  366. package/src/modules/cpq/workflows/steps/ReviewStep.tsx +33 -18
  367. package/src/modules/cpq/workflows/steps/index.ts +12 -0
  368. package/src/modules/cpq/workflows/types.ts +4 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/cpq/services/arcPriceFreeze.ts"],
4
+ "sourcesContent": ["/**\n * Frozen Amend mirror lines.\n *\n * An Amend quote mirrors every live subscription item as a `modify` line.\n * Engine-priced mirror lines used to be re-priced at today's catalog price on\n * every recalculation, and activation wrote that price back to the\n * subscription item \u2014 so amending one item silently moved every other item's\n * price. A mirror line on an Amend quote is therefore created **frozen**: it\n * keeps the source item's stored charges until a pricing input of that line\n * changes, at which point it is re-priced as before.\n *\n * The flag lives in the line configuration jsonb next to the existing\n * `_arcMirrored*` markers, so no schema change is needed.\n */\n\nexport const ARC_PRICE_FROZEN_KEY = '_arcPriceFrozen'\n\n/**\n * Set when the server unfreezes an Amend mirror line because a pricing input\n * changed \u2014 drives the \"re-priced at the current catalog price\" notice (an\n * explicit marker, so Amend quotes created before freezing existed don't\n * show it).\n */\nexport const ARC_REPRICED_KEY = '_arcRepriced'\n\n/** Markers that describe quote-time pricing state and never leave the quote. */\nconst QUOTE_ONLY_ARC_KEYS = [ARC_PRICE_FROZEN_KEY, ARC_REPRICED_KEY] as const\n\nconst ARC_MARKER_PREFIX = '_arc'\n\nexport type ArcMirrorQuoteType = 'amend' | 'cancel' | 'renew'\n\nexport function isArcPriceFrozen(configuration: Record<string, unknown> | null | undefined): boolean {\n return configuration?.[ARC_PRICE_FROZEN_KEY] === true\n}\n\n/**\n * Whether recalculation must keep a line's stored charges. Only server-made\n * mirror lines on Amend quotes qualify \u2014 the flag alone is never trusted\n * (client input is stripped of `_arc*` keys, and a clone of an Amend quote\n * is a new quote).\n */\nexport function isArcMirrorLine(configuration: Record<string, unknown> | null | undefined, quoteType: string | null | undefined): boolean {\n return (quoteType === 'amend' || quoteType === 'renew' || quoteType === 'cancel') && typeof configuration?._arcMirroredFromItemId === 'string'\n}\n\nexport function isFrozenAmendMirrorLine(\n configuration: Record<string, unknown> | null | undefined,\n quoteType: string | null | undefined,\n): boolean {\n return (\n quoteType === 'amend' &&\n typeof configuration?._arcMirroredFromItemId === 'string' &&\n isArcPriceFrozen(configuration)\n )\n}\n\n/**\n * Configuration for a mirror line: the item's configuration plus the ARC\n * markers. Only Amend lines are frozen \u2014 Renew re-prices by product decision\n * and Cancel lines are not priced.\n */\nexport function buildArcMirrorConfiguration(\n itemConfiguration: Record<string, unknown> | null | undefined,\n item: { id: string; name: string },\n quoteType: ArcMirrorQuoteType,\n): Record<string, unknown> {\n return {\n // An item's configuration can carry markers from an earlier ARC quote\n // (activation copies line configuration onto the item); never inherit them.\n ...stripArcMarkers(itemConfiguration),\n _arcMirroredFromItemId: item.id,\n _arcMirroredName: item.name,\n ...(quoteType === 'amend' ? { [ARC_PRICE_FROZEN_KEY]: true } : {}),\n }\n}\n\n/**\n * Line configuration as it may leave the quote (order lines, subscription\n * items, clones): quote-only pricing markers are dropped; the descriptive\n * `_arcMirrored*` markers stay.\n */\nexport function stripQuoteOnlyArcMarkers(\n configuration: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null | undefined {\n if (!configuration || !QUOTE_ONLY_ARC_KEYS.some((key) => key in configuration)) return configuration\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(configuration)) {\n if (!(QUOTE_ONLY_ARC_KEYS as readonly string[]).includes(key)) out[key] = value\n }\n return out\n}\n\n/**\n * Configuration without any `_arc*` marker. ARC markers are server-owned:\n * client-supplied configuration goes through this before it is stored.\n */\nexport function stripArcMarkers(configuration: Record<string, unknown> | null | undefined): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(configuration ?? {})) {\n if (!key.startsWith(ARC_MARKER_PREFIX)) out[key] = value\n }\n return out\n}\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`\n if (value && typeof value === 'object') {\n const entries = Object.keys(value as Record<string, unknown>)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${canonical((value as Record<string, unknown>)[key])}`)\n return `{${entries.join(',')}}`\n }\n return JSON.stringify(value ?? null)\n}\n\nfunction isoDay(value: Date | string | null | undefined): string | null {\n if (!value) return null\n if (value instanceof Date) return value.toISOString().slice(0, 10)\n return String(value).slice(0, 10)\n}\n\nexport type ArcLinePricingState = {\n configuration: Record<string, unknown> | null | undefined\n quantity: number\n termMonths?: number | null\n startDate?: Date | string | null\n endDate?: Date | string | null\n usageEstimates?: Array<{ chargeCode: string; estimatedQuantity: number }> | null\n}\n\nexport type ArcLinePricingUpdate = {\n configuration: Record<string, unknown>\n quantity?: number\n termMonths?: number\n startDate?: string\n endDate?: string\n usageEstimates?: Array<{ chargeCode: string; estimatedQuantity: number }>\n}\n\n/**\n * Whether an update changes any input the pricing engine reads. The quote UI\n * always resubmits the full configuration, so \"a field was sent\" is not a\n * change \u2014 values are compared (ARC markers ignored, key order ignored).\n * Fields the update omits keep their stored value.\n */\nexport function arcPricingInputsChanged(before: ArcLinePricingState, update: ArcLinePricingUpdate): boolean {\n if (canonical(stripArcMarkers(before.configuration)) !== canonical(stripArcMarkers(update.configuration))) {\n return true\n }\n if (update.quantity !== undefined && update.quantity !== before.quantity) return true\n if (update.termMonths !== undefined && update.termMonths !== (before.termMonths ?? undefined)) return true\n if (update.startDate !== undefined && isoDay(update.startDate) !== isoDay(before.startDate)) return true\n if (update.endDate !== undefined && isoDay(update.endDate) !== isoDay(before.endDate)) return true\n if (update.usageEstimates !== undefined) {\n const normalize = (list: Array<{ chargeCode: string; estimatedQuantity: number }> | null | undefined) =>\n canonical(\n [...(list ?? [])]\n .map((e) => ({ chargeCode: e.chargeCode, estimatedQuantity: e.estimatedQuantity }))\n .sort((a, b) => a.chargeCode.localeCompare(b.chargeCode)),\n )\n if (normalize(update.usageEstimates) !== normalize(before.usageEstimates)) return true\n }\n return false\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,4 +1,6 @@
1
1
  var _a, _b;
2
+ import { storedAdjustmentFailure } from "./priceAdjustments/storedAdjustmentFailure.js";
3
+ import { withQuotePricingWrite } from "./priceAdjustments/quotePricingWrite.js";
2
4
  import { SalesOrder, SalesOrderLine } from "@open-mercato/core/modules/sales/data/entities";
3
5
  import {
4
6
  CpqQuoteConfiguration,
@@ -14,6 +16,8 @@ import {
14
16
  CPQ_ORDER_TRANSITIONS
15
17
  } from "./types.js";
16
18
  import { emitCpqEvent } from "../events.js";
19
+ import { stripQuoteOnlyArcMarkers } from "./arcPriceFreeze.js";
20
+ import { summarizeOrderPricing } from "./orderPricingSummary.js";
17
21
  const CPQ_TO_SALES_ORDER_STATUS = {
18
22
  draft: "draft",
19
23
  pending_activation: "pending",
@@ -29,27 +33,15 @@ class DefaultCpqOrderService {
29
33
  }
30
34
  // ─── Convert Quote to Order ─────────────────────────────────
31
35
  async convertQuoteToOrder(quoteId, scope) {
32
- const em = this.em;
33
- const cpqConfig = await em.findOne(CpqQuoteConfiguration, {
34
- id: quoteId,
35
- organizationId: scope.organizationId,
36
- tenantId: scope.tenantId,
37
- deletedAt: null
38
- });
39
- if (!cpqConfig) {
40
- const byQuoteId = await em.findOne(CpqQuoteConfiguration, {
41
- quoteId,
42
- organizationId: scope.organizationId,
43
- tenantId: scope.tenantId,
44
- deletedAt: null
45
- });
46
- if (!byQuoteId) throw new OrderError(404, "Quote not found");
47
- return this.convertFromConfig(byQuoteId, scope);
48
- }
49
- return this.convertFromConfig(cpqConfig, scope);
36
+ return withQuotePricingWrite(
37
+ this.em,
38
+ quoteId,
39
+ scope,
40
+ (em, quote) => this.convertFromConfig(quote, scope, em),
41
+ (status, message) => new OrderError(status, message)
42
+ );
50
43
  }
51
- async convertFromConfig(cpqConfig, scope) {
52
- const em = this.em;
44
+ async convertFromConfig(cpqConfig, scope, em) {
53
45
  const blockedStatuses = ["cancelled", "rejected"];
54
46
  if (blockedStatuses.includes(cpqConfig.cpqStatus)) {
55
47
  throw new OrderError(409, `Cannot convert a quote in '${cpqConfig.cpqStatus}' status`);
@@ -75,6 +67,8 @@ class DefaultCpqOrderService {
75
67
  if (quoteLines.length === 0) {
76
68
  throw new OrderError(422, "Cannot convert a quote with no line items");
77
69
  }
70
+ const invalidAdjustment = storedAdjustmentFailure(cpqConfig, quoteLines);
71
+ if (invalidAdjustment) throw new OrderError(422, "ADJUSTMENT_INVALID", invalidAdjustment);
78
72
  const { number: orderNumber } = await this.numberGenerator.generate({
79
73
  kind: "order",
80
74
  organizationId: scope.organizationId,
@@ -189,7 +183,8 @@ class DefaultCpqOrderService {
189
183
  startDate: ql.startDate,
190
184
  termMonths: ql.termMonths ?? null,
191
185
  endDate: ql.endDate,
192
- configuration: { ...ql.configuration, offeringName },
186
+ // Quote-only ARC pricing markers stay on the quote.
187
+ configuration: { ...stripQuoteOnlyArcMarkers(ql.configuration), offeringName },
193
188
  quantity: ql.quantity,
194
189
  charges: ql.charges ? [...ql.charges] : null,
195
190
  nrcTotal: ql.nrcTotal,
@@ -457,7 +452,7 @@ class DefaultCpqOrderService {
457
452
  offeringId: line.offeringId ?? void 0,
458
453
  specId: line.specId ?? void 0,
459
454
  name: this.getLineName(line),
460
- configuration: line.configuration ?? {},
455
+ configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? {},
461
456
  charges: line.charges ?? [],
462
457
  mrcAmount: Number(line.mrcTotal),
463
458
  nrcAmount: Number(line.nrcTotal),
@@ -519,7 +514,7 @@ class DefaultCpqOrderService {
519
514
  purchasePrice: Number(line.nrcTotal),
520
515
  quantity: line.quantity,
521
516
  purchaseDate: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
522
- configuration: line.configuration ?? {},
517
+ configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? {},
523
518
  charges: line.charges ?? [],
524
519
  sourceOrderId: orderConfig.id,
525
520
  sourceQuoteLineId: line.sourceQuoteLineId ?? void 0
@@ -712,7 +707,7 @@ class DefaultCpqOrderService {
712
707
  action: lc.action,
713
708
  parentLineId: lc.parentLineId ?? null,
714
709
  quantity: lc.quantity,
715
- configuration: lc.configuration ?? {},
710
+ configuration: stripQuoteOnlyArcMarkers(lc.configuration) ?? {},
716
711
  startDate: lc.startDate?.toISOString() ?? null,
717
712
  termMonths: lc.termMonths ?? null,
718
713
  endDate: lc.endDate?.toISOString() ?? null,
@@ -745,7 +740,8 @@ class DefaultCpqOrderService {
745
740
  pricingSummary: {
746
741
  nrcTotal: Number(pricing.nrcTotal ?? 0),
747
742
  mrcTotal: Number(pricing.mrcTotal ?? 0),
748
- currencyCode: orderConfig.currencyCode
743
+ currencyCode: orderConfig.currencyCode,
744
+ ...summarizeOrderPricing(lines, quoteType, orderConfig.currencyCode)
749
745
  },
750
746
  activatedAt: orderConfig.activatedAt?.toISOString() ?? null,
751
747
  createdAt: orderConfig.createdAt.toISOString(),
@@ -768,9 +764,10 @@ function pickArcSourceFromConfig(cfg, map) {
768
764
  }
769
765
  const ORDER_ERROR_BRAND = /* @__PURE__ */ Symbol.for("@dainamite/cpq/OrderError");
770
766
  class OrderError extends (_b = Error, _a = ORDER_ERROR_BRAND, _b) {
771
- constructor(status, message) {
767
+ constructor(status, message, details) {
772
768
  super(message);
773
769
  this.status = status;
770
+ this.details = details;
774
771
  this[_a] = true;
775
772
  this.name = "OrderError";
776
773
  }
@@ -786,7 +783,7 @@ function buildArcLineChange(line, specMap) {
786
783
  offeringId: line.offeringId ?? void 0,
787
784
  specId: line.specId ?? void 0,
788
785
  name: resolveLineName(line, specMap),
789
- configuration: line.configuration ?? {},
786
+ configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? {},
790
787
  charges: line.charges ?? null,
791
788
  mrcAmount: Number(line.mrcTotal),
792
789
  nrcAmount: Number(line.nrcTotal),
@@ -812,7 +809,7 @@ function buildArcLineChange(line, specMap) {
812
809
  action,
813
810
  sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,
814
811
  modifyPatch: {
815
- configuration: line.configuration ?? void 0,
812
+ configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? void 0,
816
813
  charges: line.charges ?? void 0,
817
814
  mrcAmount: Number(line.mrcTotal),
818
815
  nrcAmount: Number(line.nrcTotal),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/cpq/services/cpqOrderService.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { SalesOrder, SalesOrderLine } from '@open-mercato/core/modules/sales/data/entities'\nimport type { SalesDocumentNumberGenerator } from '@open-mercato/core/modules/sales/services/salesDocumentNumberGenerator'\nimport {\n CpqQuoteConfiguration,\n CpqQuoteLineConfiguration,\n CpqQuoteTargetSubscription,\n CpqInventorySubscription,\n CpqOrderConfiguration,\n CpqOrderLineConfiguration,\n CpqProductOffering,\n CpqProductSpecification,\n CpqInventorySubscriptionItem,\n} from '../data/entities'\nimport type {\n ApplyArcResult,\n ApplyMergeRenewalResult,\n ArcLineChange,\n CreateSubscriptionItemInput,\n DefaultCpqInventoryService,\n} from './cpqInventoryService'\nimport {\n CPQ_ORDER_TRANSITIONS,\n type CpqOrderStatus,\n type TenantScope,\n} from './types'\nimport { emitCpqEvent } from '../events'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface OrderListFilters {\n customerId?: string\n sourceQuoteId?: string\n salesOrderId?: string\n cpqStatus?: string | string[]\n currencyCode?: string\n search?: string\n sortField?: 'createdAt' | 'updatedAt' | 'cpqStatus' | 'activatedAt' | 'currencyCode'\n sortDir?: 'asc' | 'desc'\n page?: number\n pageSize?: number\n}\n\ninterface PaginatedResult<T> {\n items: T[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ninterface OrderLineResult {\n lineId: string\n offeringId: string | null\n offeringName: string\n offeringType: string | null\n productId: string | null\n specId: string | null\n action: string\n parentLineId: string | null\n quantity: number\n configuration: Record<string, unknown>\n startDate: string | null\n termMonths: number | null\n endDate: string | null\n nrcTotal: number\n mrcTotal: number\n charges: Array<Record<string, unknown>>\n sourceQuoteLineId: string | null\n /** XD-250 ARC: snapshot of the source subscription item's current state.\n * Null for non-ARC lines and for fresh `add` lines on amend quotes. */\n arcSource: {\n subscriptionItemId: string\n name: string\n mrcAmount: number\n nrcAmount: number\n quantity: number\n } | null\n}\n\ninterface OrderResult {\n id: string\n orderId: string\n orderNumber: string\n customerId: string\n cpqStatus: string\n sourceQuoteId: string | null\n /** XD-250 ARC quote type carried over from the source quote \u2014 used by the\n * order detail page to render the AMEND / RENEW / CANCEL badge. */\n quoteType: string\n currencyCode: string\n pricingSummary: {\n nrcTotal: number\n mrcTotal: number\n currencyCode: string\n }\n activatedAt: string | null\n createdAt: string\n lines: OrderLineResult[]\n}\n\ninterface OrderServiceDeps {\n em: EntityManager\n cpqInventoryService: DefaultCpqInventoryService\n salesDocumentNumberGenerator: SalesDocumentNumberGenerator\n}\n\nconst CPQ_TO_SALES_ORDER_STATUS: Record<CpqOrderStatus, string> = {\n draft: 'draft',\n pending_activation: 'pending',\n active: 'active',\n cancelled: 'cancelled',\n fulfilled: 'fulfilled',\n}\n\n// \u2500\u2500\u2500 Service \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class DefaultCpqOrderService {\n private em: EntityManager\n private inventoryService: DefaultCpqInventoryService\n private numberGenerator: SalesDocumentNumberGenerator\n\n constructor(deps: OrderServiceDeps) {\n this.em = deps.em\n this.inventoryService = deps.cpqInventoryService\n this.numberGenerator = deps.salesDocumentNumberGenerator\n }\n\n // \u2500\u2500\u2500 Convert Quote to Order \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 convertQuoteToOrder(quoteId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const cpqConfig = await em.findOne(CpqQuoteConfiguration, {\n id: quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!cpqConfig) {\n const byQuoteId = await em.findOne(CpqQuoteConfiguration, {\n quoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!byQuoteId) throw new OrderError(404, 'Quote not found')\n return this.convertFromConfig(byQuoteId, scope)\n }\n return this.convertFromConfig(cpqConfig, scope)\n }\n\n private async convertFromConfig(cpqConfig: CpqQuoteConfiguration, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const blockedStatuses = ['cancelled', 'rejected']\n if (blockedStatuses.includes(cpqConfig.cpqStatus)) {\n throw new OrderError(409, `Cannot convert a quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n // Idempotency guard: a quote may only convert once. If an order with\n // this quote as its `sourceQuoteId` already exists, the UI should\n // surface \"Go to order\" instead of re-running conversion \u2014 return\n // 409 with the existing id so the caller can redirect.\n const existingOrder = await em.findOne(CpqOrderConfiguration, {\n sourceQuoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (existingOrder) {\n throw new OrderError(\n 409,\n `Quote has already been converted to order ${existingOrder.orderId}`,\n )\n }\n\n const quoteLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n if (quoteLines.length === 0) {\n throw new OrderError(422, 'Cannot convert a quote with no line items')\n }\n\n const { number: orderNumber } = await this.numberGenerator.generate({\n kind: 'order',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const salesOrderId = crypto.randomUUID()\n const pricingSummary = cpqConfig.pricingSummary as Record<string, unknown> | null\n const nrcTotal = Number(pricingSummary?.nrcTotal ?? 0)\n const mrcTotal = Number(pricingSummary?.mrcTotal ?? 0)\n const grandTotal = nrcTotal + mrcTotal\n\n const salesOrder = em.create(SalesOrder, {\n id: salesOrderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderNumber,\n customerEntityId: cpqConfig.customerId,\n currencyCode: cpqConfig.currencyCode,\n status: 'draft',\n subtotalNetAmount: String(grandTotal),\n subtotalGrossAmount: String(grandTotal),\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n shippingNetAmount: '0',\n shippingGrossAmount: '0',\n surchargeTotalAmount: '0',\n paidTotalAmount: '0',\n grandTotalNetAmount: String(grandTotal),\n grandTotalGrossAmount: String(grandTotal),\n lineItemCount: quoteLines.length,\n metadata: { sourceQuoteId: cpqConfig.id },\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesOrder)\n\n const cpqOrderConfigId = crypto.randomUUID()\n const cpqOrderConfig = em.create(CpqOrderConfiguration, {\n id: cpqOrderConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderId: salesOrderId,\n sourceQuoteId: cpqConfig.id,\n customerId: cpqConfig.customerId,\n cpqStatus: 'draft',\n currencyCode: cpqConfig.currencyCode,\n pricingSummary: {\n nrcTotal,\n mrcTotal,\n currencyCode: cpqConfig.currencyCode,\n },\n })\n em.persist(cpqOrderConfig)\n\n const quoteLineIdToOrderLineId = new Map<string, string>()\n\n for (let i = 0; i < quoteLines.length; i++) {\n const ql = quoteLines[i]\n\n const perInstanceNrc = Number(ql.nrcTotal)\n const perInstanceMrc = Number(ql.mrcTotal)\n const unitPriceNet = (perInstanceNrc + perInstanceMrc) / ql.quantity\n const totalNet = perInstanceNrc + perInstanceMrc\n\n const orderLineId = crypto.randomUUID()\n quoteLineIdToOrderLineId.set(ql.quoteLineId, orderLineId)\n\n const offeringName = await this.resolveOfferingName(\n em,\n ql.offeringId,\n scope,\n ql.configuration as Record<string, unknown> | null,\n )\n\n const orderLine = em.create(SalesOrderLine, {\n id: orderLineId,\n order: salesOrder,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: i + 1,\n kind: 'product',\n productId: ql.productId ?? null,\n name: offeringName,\n quantity: String(ql.quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(totalNet),\n totalGrossAmount: String(totalNet),\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: cpqConfig.currencyCode,\n configuration: {\n offeringId: ql.offeringId ?? null,\n action: ql.action,\n nrcTotal: perInstanceNrc,\n mrcTotal: perInstanceMrc,\n parentLineId: ql.parentLineId ?? null,\n },\n normalizedQuantity: String(ql.quantity),\n reservedQuantity: '0',\n fulfilledQuantity: '0',\n invoicedQuantity: '0',\n returnedQuantity: '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(orderLine)\n const orderLineConfig = em.create(CpqOrderLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderLineId,\n orderConfigurationId: cpqOrderConfig.id,\n offeringId: ql.offeringId ?? null,\n productId: ql.productId ?? null,\n specId: ql.specId ?? null,\n action: ql.action,\n parentLineId: null,\n startDate: ql.startDate,\n termMonths: ql.termMonths ?? null,\n endDate: ql.endDate,\n configuration: { ...ql.configuration, offeringName },\n quantity: ql.quantity,\n charges: ql.charges ? [...ql.charges] : null,\n nrcTotal: ql.nrcTotal,\n mrcTotal: ql.mrcTotal,\n sourceQuoteLineId: ql.quoteLineId,\n })\n em.persist(orderLineConfig)\n }\n\n await em.flush()\n\n // Resolve parent line references using the quote\u2192order line ID map\n const orderLineConfigs = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: cpqOrderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n for (const olc of orderLineConfigs) {\n if (olc.sourceQuoteLineId) {\n const sourceQl = quoteLines.find((ql) => ql.quoteLineId === olc.sourceQuoteLineId)\n if (sourceQl?.parentLineId) {\n const mappedParent = quoteLineIdToOrderLineId.get(sourceQl.parentLineId)\n if (mappedParent) olc.parentLineId = mappedParent\n }\n }\n }\n\n await em.flush()\n\n return this.buildOrderResult(em, cpqOrderConfig, salesOrder, orderLineConfigs, scope)\n }\n\n // \u2500\u2500\u2500 Activate Order \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 activateOrder(orderId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n\n const currentStatus = orderConfig.cpqStatus as CpqOrderStatus\n if (currentStatus !== 'draft' && currentStatus !== 'pending_activation') {\n throw new OrderError(409, `Cannot activate order in '${currentStatus}' status`)\n }\n\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n const orderLines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n // Branch on the source quote's quoteType. ARC quotes mutate existing\n // subscriptions; new-sale quotes materialize a fresh subscription.\n const sourceQuote = orderConfig.sourceQuoteId\n ? await em.findOne(CpqQuoteConfiguration, {\n id: orderConfig.sourceQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : null\n\n const quoteType = sourceQuote?.quoteType ?? 'new'\n const postCommitEvents: Array<() => Promise<void>> = []\n\n if (quoteType === 'new') {\n const inventory = await this.createInventoryFromOrder(orderConfig, orderLines, scope)\n if (inventory) {\n postCommitEvents.push(() => emitActivatedEvent(orderConfig, inventory, scope))\n }\n } else {\n postCommitEvents.push(\n ...(await this.applyArcOrder(orderConfig, sourceQuote!, orderLines, scope)),\n )\n }\n\n orderConfig.cpqStatus = 'active'\n orderConfig.activatedAt = new Date()\n salesOrder.status = 'active'\n salesOrder.placedAt = new Date()\n\n await em.flush()\n\n // Emit lifecycle events AFTER the activation transaction commits.\n for (const fire of postCommitEvents) {\n try {\n await fire()\n } catch (err) {\n // Don't roll back the activation just because a subscriber blew up \u2014\n // events are best-effort once the DB state is committed.\n console.error('[cpq.arc] event emission failed', err)\n }\n }\n\n return this.buildOrderResult(em, orderConfig, salesOrder, orderLines, scope)\n }\n\n // \u2500\u2500\u2500 ARC activation branch (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\n //\n // Reads the source quote's targets + lines, then dispatches per target to\n // cpqInventoryService.apply* primitives. Returns the list of post-commit\n // event emissions so the caller can fire them outside the activation TX.\n private async applyArcOrder(\n orderConfig: CpqOrderConfiguration,\n sourceQuote: CpqQuoteConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<Array<() => Promise<void>>> {\n const em = this.em\n const quoteType = sourceQuote.quoteType as 'amend' | 'renew' | 'cancel'\n\n // Load attached targets.\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: sourceQuote.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) {\n throw new OrderError(\n 409,\n `ARC quote ${sourceQuote.id} has no target subscriptions to activate`,\n )\n }\n\n const inventory = this.inventoryService\n\n // Group order lines by target_subscription_id \u2014 ARC order lines mirror the\n // quote lines' ARC fields (target_subscription_id is preserved through\n // convertQuoteToOrder via line.configuration when needed).\n // Source quote lines are the source of truth for ARC line data because\n // CpqOrderLineConfiguration doesn't carry target/source-item fields.\n const sourceQuoteLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: sourceQuote.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const linesByTarget = new Map<string | null, CpqQuoteLineConfiguration[]>()\n for (const line of sourceQuoteLines) {\n const key = line.targetSubscriptionId ?? null\n const list = linesByTarget.get(key) ?? []\n list.push(line)\n linesByTarget.set(key, list)\n }\n\n // Look up specs for `add` lines so we can build itemInput correctly.\n const specIds = [\n ...new Set(sourceQuoteLines.map((l) => l.specId).filter((x): x is string => Boolean(x))),\n ]\n const specs =\n specIds.length > 0\n ? await em.find(CpqProductSpecification, {\n id: { $in: specIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : []\n const specMap = new Map(specs.map((s) => [s.id, s]))\n\n const events: Array<() => Promise<void>> = []\n const eventBaseEnvelope = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n } as const\n\n if (quoteType === 'amend') {\n for (const target of targets) {\n const lines = linesByTarget.get(target.subscriptionId) ?? []\n const result = await inventory.applyAmendment(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n lineChanges: lines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n events.push(() => emitAmendedEvent(result, eventBaseEnvelope))\n }\n } else if (quoteType === 'cancel') {\n for (const target of targets) {\n const result = await inventory.applyCancel(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n etfAmount: sourceQuote.arcEtfAmount ?? null,\n etfCurrency: sourceQuote.arcEtfCurrency ?? null,\n reasonCode: sourceQuote.arcReasonCode ?? null,\n reasonText: sourceQuote.arcReasonText ?? null,\n },\n scope,\n )\n events.push(() => emitCancelledEvent(result, eventBaseEnvelope))\n }\n } else if (quoteType === 'renew') {\n const standalone = targets.filter((t) => t.mergeAction === 'standalone')\n const absorb = targets.filter((t) => t.mergeAction === 'absorb')\n\n if (standalone.length > 0 && absorb.length === 0) {\n for (const target of standalone) {\n if (!target.newTermStart || !target.newTermEnd) {\n throw new OrderError(\n 409,\n `Standalone renew target ${target.id} missing newTermStart/newTermEnd`,\n )\n }\n const lines = linesByTarget.get(target.subscriptionId) ?? []\n const result = await inventory.applyRenewal(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n term: {\n newTermStart: target.newTermStart,\n newTermEnd: target.newTermEnd,\n newTermMonths: target.newTermMonths ?? null,\n },\n lineChanges: lines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n events.push(() => emitRenewedEvent(result, eventBaseEnvelope))\n }\n } else if (absorb.length >= 2 && standalone.length === 0) {\n if (!sourceQuote.arcMergeNewTermStart || !sourceQuote.arcMergeNewTermEnd) {\n throw new OrderError(\n 409,\n `Merge renew quote ${sourceQuote.id} missing arc_merge_new_term_*`,\n )\n }\n // Lines targeting null are operator-edits on the new merge sub M.\n const mergeLines = linesByTarget.get(null) ?? []\n const merge = await inventory.applyMergeRenewal(\n {\n sourceIds: absorb.map((t) => t.subscriptionId),\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n term: {\n newTermStart: sourceQuote.arcMergeNewTermStart,\n newTermEnd: sourceQuote.arcMergeNewTermEnd,\n newTermMonths: sourceQuote.arcMergeNewTermMonths ?? null,\n },\n mergeMeta: {\n newSubCode: sourceQuote.arcMergeNewSubCode ?? null,\n newSubName: sourceQuote.arcMergeNewSubName ?? null,\n },\n lineChanges: mergeLines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n\n // One event per source (`superseded`) + one for M (`merged`).\n const mergedFromSubscriptionIds = absorb.map((t) => t.subscriptionId)\n events.push(() =>\n emitMergedEvent(merge, eventBaseEnvelope, mergedFromSubscriptionIds),\n )\n for (const sourceLog of merge.sourceChangeLogs) {\n events.push(() =>\n emitSupersededEvent(\n sourceLog,\n iso10(merge.mergedSubscription.currentTermStart),\n eventBaseEnvelope,\n ),\n )\n }\n } else {\n throw new OrderError(\n 409,\n `Inconsistent renew targets \u2014 must be either single standalone or \u22652 absorb`,\n )\n }\n } else {\n throw new OrderError(500, `Unknown quote_type '${quoteType}' for ARC activation`)\n }\n\n return events\n }\n\n // \u2500\u2500\u2500 Inventory Creation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 createInventoryFromOrder(\n orderConfig: CpqOrderConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<ActivatedInventory | null> {\n if (orderLines.length === 0) return null\n\n const specIds = [...new Set(orderLines.map((l) => l.specId).filter(Boolean))] as string[]\n const specs = specIds.length > 0\n ? await this.em.find(CpqProductSpecification, {\n id: { $in: specIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : []\n const specMap = new Map(specs.map((s) => [s.id, s]))\n\n const subscriptionLines = orderLines.filter((l) => {\n const spec = l.specId ? specMap.get(l.specId) : null\n return !spec?.isAssetizable\n })\n const assetLines = orderLines.filter((l) => {\n const spec = l.specId ? specMap.get(l.specId) : null\n return spec?.isAssetizable === true\n })\n\n const hasSubscriptionContent = subscriptionLines.some(\n (l) => Number(l.mrcTotal) > 0 || Number(l.nrcTotal) > 0,\n )\n if (!hasSubscriptionContent && assetLines.length === 0) return null\n\n const subscriptionName = await this.buildSubscriptionName(orderConfig, orderLines, scope)\n\n const lineWithDates = orderLines.find((l) => l.startDate != null) ?? orderLines[0]\n const lineWithTerm = orderLines.find((l) => l.termMonths != null) ?? orderLines[0]\n const subscriptionItems = subscriptionLines.map((line) => ({\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: this.getLineName(line),\n configuration: line.configuration ?? {},\n charges: (line.charges ?? []) as Array<Record<string, unknown>>,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n currencyCode: orderConfig.currencyCode,\n quantity: line.quantity,\n sourceQuoteLineId: line.sourceQuoteLineId ?? undefined,\n sortOrder: orderLines.indexOf(line),\n }))\n\n const subscription = await this.inventoryService.createSubscription(\n {\n customerId: orderConfig.customerId,\n name: subscriptionName,\n billingCycle: 'monthly',\n currencyCode: orderConfig.currencyCode,\n startDate: lineWithDates?.startDate?.toISOString?.() ?? undefined,\n termMonths: lineWithTerm?.termMonths ?? undefined,\n sourceQuoteId: orderConfig.sourceQuoteId ?? undefined,\n sourceOrderId: orderConfig.id,\n items: subscriptionItems.length > 0\n ? subscriptionItems\n : [{ name: subscriptionName, mrcAmount: 0, nrcAmount: 0 }],\n },\n scope,\n )\n\n const orderLineToSubItem = new Map<string, string>()\n const allSubItems = await this.em.find(CpqInventorySubscriptionItem, {\n subscriptionId: subscription.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, { orderBy: { sortOrder: 'asc' } })\n\n for (let i = 0; i < subscriptionLines.length && i < allSubItems.length; i++) {\n orderLineToSubItem.set(subscriptionLines[i].orderLineId, allSubItems[i].id)\n }\n\n for (let i = 0; i < subscriptionLines.length && i < allSubItems.length; i++) {\n const orderLine = subscriptionLines[i]\n if (orderLine.parentLineId) {\n const parentSubItemId = orderLineToSubItem.get(orderLine.parentLineId)\n if (parentSubItemId) {\n allSubItems[i].parentItemId = parentSubItemId\n }\n }\n }\n await this.em.flush()\n\n for (const line of assetLines) {\n let subscriptionItemId: string | undefined\n if (line.parentLineId) {\n subscriptionItemId = orderLineToSubItem.get(line.parentLineId) ?? undefined\n }\n\n await this.inventoryService.createAsset(\n {\n customerId: orderConfig.customerId,\n subscriptionId: subscription.id,\n subscriptionItemId,\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: this.getLineName(line),\n assetType: 'one_time',\n currencyCode: orderConfig.currencyCode,\n purchasePrice: Number(line.nrcTotal),\n quantity: line.quantity,\n purchaseDate: new Date().toISOString().split('T')[0],\n configuration: line.configuration ?? {},\n charges: (line.charges ?? []) as Array<Record<string, unknown>>,\n sourceOrderId: orderConfig.id,\n sourceQuoteLineId: line.sourceQuoteLineId ?? undefined,\n },\n scope,\n )\n }\n\n // Pair each subscription line with its created subscription item \u2014\n // input for the `cpq.subscription.activated` billing-onboarding event.\n const eventItems = subscriptionLines\n .slice(0, allSubItems.length)\n .map((line, i) => ({\n subscriptionItemId: allSubItems[i].id,\n productName: this.getLineName(line),\n mrcTotal: Number(line.mrcTotal),\n nrcTotal: Number(line.nrcTotal),\n }))\n // Only lines with a billable charge \u2014 a zero-value line yields\n // no Billing Item anyway; emitting it would just make the\n // connector create a needless shell account.\n .filter((it) => it.mrcTotal > 0 || it.nrcTotal > 0)\n return { subscriptionId: subscription.id, items: eventItems }\n }\n\n // \u2500\u2500\u2500 Get / List \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 getOrder(orderId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n const lines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return this.buildOrderResult(em, orderConfig, salesOrder, lines, scope)\n }\n\n async listOrders(filters: OrderListFilters, scope: TenantScope) {\n const page = Math.max(1, filters.page ?? 1)\n const pageSize = Math.min(100, Math.max(1, filters.pageSize ?? 50))\n const offset = (page - 1) * pageSize\n\n const where: Record<string, unknown> = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }\n\n if (filters.customerId) where.customerId = filters.customerId\n if (filters.sourceQuoteId) where.sourceQuoteId = filters.sourceQuoteId\n if (filters.salesOrderId) where.orderId = filters.salesOrderId\n if (filters.currencyCode) where.currencyCode = filters.currencyCode\n if (filters.cpqStatus) {\n where.cpqStatus = Array.isArray(filters.cpqStatus)\n ? { $in: filters.cpqStatus }\n : filters.cpqStatus\n }\n\n const search = filters.search?.trim()\n if (search) {\n where.$or = [\n { orderId: { $ilike: `%${search}%` } },\n { customerId: { $ilike: `%${search}%` } },\n ]\n }\n\n const sortField = filters.sortField ?? 'createdAt'\n const sortDir = filters.sortDir === 'asc' ? 'asc' : 'desc'\n\n const [configs, total] = await this.em.findAndCount(\n CpqOrderConfiguration,\n where,\n { limit: pageSize, offset, orderBy: { [sortField]: sortDir } },\n )\n\n const orderIds = configs.map((c) => c.orderId)\n const salesOrders = orderIds.length > 0\n ? await this.em.find(SalesOrder, { id: { $in: orderIds } })\n : []\n const salesOrderMap = new Map(salesOrders.map((o) => [o.id, o]))\n\n const items = configs.map((c) => ({\n ...c,\n orderNumber: salesOrderMap.get(c.orderId)?.orderNumber ?? null,\n }))\n\n return { items, total, page, pageSize, totalPages: Math.ceil(total / pageSize) }\n }\n\n // \u2500\u2500\u2500 Status Transition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 transitionOrderStatus(orderId: string, targetStatus: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n\n const currentStatus = orderConfig.cpqStatus as CpqOrderStatus\n const allowed = CPQ_ORDER_TRANSITIONS[currentStatus] ?? []\n\n if (!allowed.includes(targetStatus as CpqOrderStatus)) {\n throw new OrderError(409, `Cannot transition from '${currentStatus}' to '${targetStatus}'`)\n }\n\n if (targetStatus === 'active') {\n return this.activateOrder(orderId, scope)\n }\n\n orderConfig.cpqStatus = targetStatus\n salesOrder.status = CPQ_TO_SALES_ORDER_STATUS[targetStatus as CpqOrderStatus] ?? targetStatus\n\n await em.flush()\n\n const lines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return this.buildOrderResult(em, orderConfig, salesOrder, lines, scope)\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\n\n private async loadOrderConfig(em: EntityManager, orderId: string, scope: TenantScope): Promise<CpqOrderConfiguration> {\n let config = await em.findOne(CpqOrderConfiguration, {\n id: orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqOrderConfiguration, {\n orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new OrderError(404, 'Order not found')\n return config\n }\n\n private async loadSalesOrder(em: EntityManager, orderId: string, scope: TenantScope): Promise<SalesOrder> {\n const order = await em.findOne(SalesOrder, {\n id: orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!order) throw new OrderError(404, 'Sales order not found')\n return order\n }\n\n private async resolveOfferingInfo(\n em: EntityManager,\n offeringId: string | null | undefined,\n scope: TenantScope,\n fallbackConfig?: Record<string, unknown> | null,\n ): Promise<{ name: string; type: string | null }> {\n if (offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (offering) return { name: offering.name, type: offering.offeringType ?? 'simple' }\n }\n const cfg = fallbackConfig ?? null\n const fallbackName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n return { name: fallbackName, type: null }\n }\n\n private async resolveOfferingName(\n em: EntityManager,\n offeringId: string | null | undefined,\n scope: TenantScope,\n fallbackConfig?: Record<string, unknown> | null,\n ): Promise<string> {\n const info = await this.resolveOfferingInfo(em, offeringId, scope, fallbackConfig)\n return info.name\n }\n\n private getLineName(line: CpqOrderLineConfiguration): string {\n const config = line.configuration as Record<string, unknown> | null\n return (\n (config?._arcMirroredName as string | undefined) ??\n (config?.offeringName as string | undefined) ??\n (config?.name as string | undefined) ??\n 'Configured Item'\n )\n }\n\n private async buildSubscriptionName(\n orderConfig: CpqOrderConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<string> {\n if (orderLines.length === 1 && orderLines[0].offeringId) {\n return this.resolveOfferingName(this.em, orderLines[0].offeringId, scope)\n }\n const names: string[] = []\n for (const line of orderLines.slice(0, 3)) {\n if (line.offeringId) {\n names.push(await this.resolveOfferingName(this.em, line.offeringId, scope))\n }\n }\n if (names.length > 0) {\n const suffix = orderLines.length > 3 ? ` (+${orderLines.length - 3} more)` : ''\n return names.join(', ') + suffix\n }\n return `Order ${orderConfig.orderId.slice(0, 8)}`\n }\n\n private async buildOrderResult(\n em: EntityManager,\n orderConfig: CpqOrderConfiguration,\n salesOrder: SalesOrder,\n lineConfigs: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<OrderResult> {\n const lines: OrderLineResult[] = []\n\n // XD-250 ARC: batch-load source subscription items so we can render the\n // before/after diff per line on the order detail page.\n const arcItemIds = new Set<string>()\n for (const lc of lineConfigs) {\n const m = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n if (typeof m === 'string') arcItemIds.add(m)\n }\n const arcItemMap = new Map<string, CpqInventorySubscriptionItem>()\n if (arcItemIds.size > 0) {\n const items = await em.find(CpqInventorySubscriptionItem, {\n id: { $in: Array.from(arcItemIds) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const it of items) arcItemMap.set(it.id, it)\n }\n\n for (const lc of lineConfigs) {\n const offeringInfo = await this.resolveOfferingInfo(\n em,\n lc.offeringId,\n scope,\n lc.configuration as Record<string, unknown> | null,\n )\n const arcSource = pickArcSourceFromConfig(lc.configuration as Record<string, unknown> | null, arcItemMap)\n lines.push({\n lineId: lc.orderLineId,\n offeringId: lc.offeringId ?? null,\n offeringName: offeringInfo.name,\n offeringType: offeringInfo.type,\n productId: lc.productId ?? null,\n specId: lc.specId ?? 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 charges: (lc.charges ?? []) as Array<Record<string, unknown>>,\n sourceQuoteLineId: lc.sourceQuoteLineId ?? null,\n arcSource,\n })\n }\n\n // Source quote's quoteType \u2014 surfaced to the order header so the UI can\n // render an AMEND / RENEW / CANCEL badge alongside the order number.\n // CpqOrderConfiguration.sourceQuoteId stores CpqQuoteConfiguration.id\n // (see convertFromConfig \u2014 sourceQuoteId: cpqConfig.id), NOT the\n // SalesQuote.id, so we look it up by `id` rather than by `quoteId`.\n let quoteType = 'new'\n if (orderConfig.sourceQuoteId) {\n const sourceCfg = await em.findOne(CpqQuoteConfiguration, {\n id: orderConfig.sourceQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (sourceCfg?.quoteType) quoteType = sourceCfg.quoteType\n }\n\n const pricing = orderConfig.pricingSummary ?? {}\n\n return {\n id: orderConfig.id,\n orderId: orderConfig.orderId,\n orderNumber: salesOrder.orderNumber ?? '',\n customerId: orderConfig.customerId,\n cpqStatus: orderConfig.cpqStatus,\n sourceQuoteId: orderConfig.sourceQuoteId ?? null,\n quoteType,\n currencyCode: orderConfig.currencyCode,\n pricingSummary: {\n nrcTotal: Number((pricing as Record<string, unknown>).nrcTotal ?? 0),\n mrcTotal: Number((pricing as Record<string, unknown>).mrcTotal ?? 0),\n currencyCode: orderConfig.currencyCode,\n },\n activatedAt: orderConfig.activatedAt?.toISOString() ?? null,\n createdAt: orderConfig.createdAt.toISOString(),\n lines,\n }\n }\n}\n\nfunction pickArcSourceFromConfig(\n cfg: Record<string, unknown> | null,\n map: Map<string, CpqInventorySubscriptionItem>,\n): OrderLineResult['arcSource'] {\n const m = cfg?._arcMirroredFromItemId\n if (typeof m !== 'string') return null\n const item = map.get(m)\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// \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 \u2014 see QUOTING_ERROR_BRAND in cpqQuotingService.ts for why\n// route handlers must not rely on `instanceof`. Use `isOrderError`.\nconst ORDER_ERROR_BRAND = Symbol.for('@dainamite/cpq/OrderError')\n\nexport class OrderError extends Error {\n readonly [ORDER_ERROR_BRAND] = true\n\n constructor(\n public status: number,\n message: string,\n ) {\n super(message)\n this.name = 'OrderError'\n }\n}\n\nexport function isOrderError(err: unknown): err is OrderError {\n return !!err && typeof err === 'object' && (err as Record<symbol, unknown>)[ORDER_ERROR_BRAND] === true\n}\n\n// \u2500\u2500\u2500 ARC 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Build a service-layer ArcLineChange from a CpqQuoteLineConfiguration.\n * For 'add' actions, materializes the itemInput from line + spec data.\n */\nfunction buildArcLineChange(\n line: CpqQuoteLineConfiguration,\n specMap: Map<string, CpqProductSpecification>,\n): ArcLineChange {\n const action = line.action as 'add' | 'modify' | 'cancel'\n if (action === 'add') {\n const itemInput: Omit<CreateSubscriptionItemInput, 'name'> & { name: string } = {\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: resolveLineName(line, specMap),\n configuration: line.configuration ?? {},\n charges: (line.charges ?? null) as Array<Record<string, unknown>> | undefined,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n quantity: line.quantity,\n sourceQuoteLineId: line.quoteLineId,\n }\n return {\n quoteLineId: line.quoteLineId,\n action,\n itemInput,\n parentQuoteLineId: line.parentLineId ?? null,\n }\n }\n if (action === 'cancel') {\n return {\n quoteLineId: line.quoteLineId,\n action,\n sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,\n }\n }\n // modify\n return {\n quoteLineId: line.quoteLineId,\n action,\n sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,\n modifyPatch: {\n configuration: line.configuration ?? undefined,\n charges: (line.charges ?? undefined) as Array<Record<string, unknown>> | undefined,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n quantity: line.quantity,\n },\n }\n}\n\nfunction resolveLineName(\n line: CpqQuoteLineConfiguration,\n specMap: Map<string, CpqProductSpecification>,\n): string {\n const cfg = line.configuration as Record<string, unknown> | null\n const cfgName = (cfg?._arcMirroredName as string | undefined) ?? null\n if (cfgName) return cfgName\n if (line.specId) {\n const spec = specMap.get(line.specId)\n if (spec?.name) return spec.name\n }\n return 'Configured Item'\n}\n\ninterface ArcEventEnvelope {\n organizationId: string\n tenantId: string\n sourceQuoteId: string\n sourceOrderId: string\n}\n\n// \u2500\u2500\u2500 Subscription-activated event (new-sale billing onboarding) \u2500\u2500\n\ntype ActivatedInventory = {\n subscriptionId: string\n items: Array<{\n subscriptionItemId: string\n productName: string\n /** Line totals \u2014 CPQ pricing has already applied line quantity. */\n mrcTotal: number\n nrcTotal: number\n }>\n}\n\n/**\n * Emit `cpq.subscription.activated` after a new-sale order activation.\n *\n * Payload matches the `@dainamite/cpq-billing-connector`\n * `cpq-subscription-activated` subscriber contract: one CPQ charge per\n * non-zero MRC / NRC total on each subscription item. The connector\n * get-or-creates the Billing Account (keyed on `customerId`) and turns\n * each charge into a Billing Item.\n */\nasync function emitActivatedEvent(\n orderConfig: CpqOrderConfiguration,\n inventory: ActivatedInventory,\n scope: TenantScope,\n): Promise<void> {\n const items = inventory.items.map((it) => ({\n subscriptionItemId: it.subscriptionItemId,\n productName: it.productName,\n // `mrcTotal` / `nrcTotal` are line totals \u2014 CPQ pricing already\n // applied the line quantity. Quantity is therefore 1 here so\n // `unitPrice \u00D7 quantity` stays internally consistent no matter\n // how the connector treats the multiplier.\n quantity: 1,\n charges: [\n ...(it.mrcTotal > 0\n ? [{ type: 'recurring', unitPrice: it.mrcTotal, description: 'Recurring charge' }]\n : []),\n ...(it.nrcTotal > 0\n ? [{ type: 'one_time', amount: it.nrcTotal, description: 'One-time charge' }]\n : []),\n ],\n }))\n await emitCpqEvent('cpq.subscription.activated' as never, {\n subscriptionId: inventory.subscriptionId,\n customerId: orderConfig.customerId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n currencyCode: orderConfig.currencyCode,\n timestamp: new Date().toISOString(),\n activationDate: new Date().toISOString().slice(0, 10),\n sourceQuoteId: orderConfig.sourceQuoteId ?? null,\n sourceOrderId: orderConfig.id,\n items,\n } as never)\n}\n\n/** Coerce a Date or `date`-column string to a `YYYY-MM-DD` string. */\nfunction iso10(value: Date | string | null | undefined): string | null {\n if (!value) return null\n if (value instanceof Date) return value.toISOString().slice(0, 10)\n return String(value).slice(0, 10)\n}\n\ntype ArcChargeItem = {\n subscriptionItemId: string\n productName: string\n quantity: number\n charges: Array<Record<string, unknown>>\n}\n\n/**\n * Build the connector's `addedItems` from a change log's `add` line\n * changes. `mrcAmount` / `nrcAmount` are line totals (CPQ pricing has\n * already applied quantity) \u2192 emit `quantity: 1` with the totals as the\n * charge rate, exactly as `emitActivatedEvent`.\n */\nfunction buildArcAddedItems(changeLog: ApplyArcResult['changeLog']): ArcChargeItem[] {\n const after = changeLog.afterSnapshot as\n | { items?: Array<{ id?: string; name?: string }> }\n | null\n const nameById = new Map(\n (after?.items ?? []).map((i) => [String(i.id), i.name ?? '']),\n )\n const summary = (changeLog.lineChanges ?? []) as Array<{\n action?: string\n itemId?: string\n mrcAmount?: unknown\n nrcAmount?: unknown\n }>\n const out: ArcChargeItem[] = []\n for (const change of summary) {\n if (change.action !== 'add' || typeof change.itemId !== 'string') continue\n const mrc = Number(change.mrcAmount)\n const nrc = Number(change.nrcAmount)\n out.push({\n subscriptionItemId: change.itemId,\n productName: nameById.get(change.itemId) || 'Configured item',\n quantity: 1,\n charges: [\n ...(mrc > 0\n ? [{ type: 'recurring', unitPrice: mrc, description: 'Recurring charge' }]\n : []),\n ...(nrc > 0\n ? [{ type: 'one_time', amount: nrc, description: 'One-time charge' }]\n : []),\n ],\n })\n }\n return out\n}\n\n/** Subscription-item ids removed by a change log's `cancel` line changes. */\nfunction buildArcRemovedItemIds(changeLog: ApplyArcResult['changeLog']): string[] {\n const summary = (changeLog.lineChanges ?? []) as Array<{\n action?: string\n itemId?: string\n }>\n return summary\n .filter((c) => c.action === 'cancel' && typeof c.itemId === 'string')\n .map((c) => c.itemId as string)\n}\n\nasync function emitAmendedEvent(\n result: ApplyArcResult,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.amended' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: result.subscription.id,\n customerId: result.subscription.customerId,\n // No operator-chosen amend date today \u2014 the activation moment is\n // the effective date. The billing connector computes the mid-cycle\n // proration from this date + the account's billing cycle.\n effectiveDate: iso10(result.changeLog.effectiveAt),\n addedItems: buildArcAddedItems(result.changeLog),\n removedSubscriptionItemIds: buildArcRemovedItemIds(result.changeLog),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitRenewedEvent(\n result: ApplyArcResult,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.renewed' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: result.subscription.id,\n customerId: result.subscription.customerId,\n newTermStart: iso10(result.subscription.currentTermStart),\n newTermEnd: iso10(result.subscription.currentTermEnd),\n addedItems: buildArcAddedItems(result.changeLog),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitCancelledEvent(\n result: ApplyArcResult,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.cancelled' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: result.subscription.id,\n customerId: result.subscription.customerId,\n effectiveDate: iso10(result.changeLog.effectiveAt),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitMergedEvent(\n merge: ApplyMergeRenewalResult,\n envelope: ArcEventEnvelope,\n sourceSubscriptionIds: string[],\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.merged' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n mergedSubscriptionId: merge.mergedSubscription.id,\n sourceSubscriptionIds,\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitSupersededEvent(\n sourceLog: { id: string; subscriptionId: string },\n effectiveDate: string | null,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.superseded' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: sourceLog.subscriptionId,\n effectiveDate,\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { storedAdjustmentFailure } from './priceAdjustments/storedAdjustmentFailure'\nimport { withQuotePricingWrite } from './priceAdjustments/quotePricingWrite'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { SalesOrder, SalesOrderLine } from '@open-mercato/core/modules/sales/data/entities'\nimport type { SalesDocumentNumberGenerator } from '@open-mercato/core/modules/sales/services/salesDocumentNumberGenerator'\nimport {\n CpqQuoteConfiguration,\n CpqQuoteLineConfiguration,\n CpqQuoteTargetSubscription,\n CpqInventorySubscription,\n CpqOrderConfiguration,\n CpqOrderLineConfiguration,\n CpqProductOffering,\n CpqProductSpecification,\n CpqInventorySubscriptionItem,\n} from '../data/entities'\nimport type {\n ApplyArcResult,\n ApplyMergeRenewalResult,\n ArcLineChange,\n CreateSubscriptionItemInput,\n DefaultCpqInventoryService,\n} from './cpqInventoryService'\nimport {\n CPQ_ORDER_TRANSITIONS,\n type CpqOrderStatus,\n type TenantScope,\n} from './types'\nimport { emitCpqEvent } from '../events'\nimport { stripQuoteOnlyArcMarkers } from './arcPriceFreeze'\nimport { summarizeOrderPricing, type OrderWaterfallSummary } from './orderPricingSummary'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface OrderListFilters {\n customerId?: string\n sourceQuoteId?: string\n salesOrderId?: string\n cpqStatus?: string | string[]\n currencyCode?: string\n search?: string\n sortField?: 'createdAt' | 'updatedAt' | 'cpqStatus' | 'activatedAt' | 'currencyCode'\n sortDir?: 'asc' | 'desc'\n page?: number\n pageSize?: number\n}\n\ninterface PaginatedResult<T> {\n items: T[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\ninterface OrderLineResult {\n lineId: string\n offeringId: string | null\n offeringName: string\n offeringType: string | null\n productId: string | null\n specId: string | null\n action: string\n parentLineId: string | null\n quantity: number\n configuration: Record<string, unknown>\n startDate: string | null\n termMonths: number | null\n endDate: string | null\n nrcTotal: number\n mrcTotal: number\n charges: Array<Record<string, unknown>>\n sourceQuoteLineId: string | null\n /** XD-250 ARC: snapshot of the source subscription item's current state.\n * Null for non-ARC lines and for fresh `add` lines on amend quotes. */\n arcSource: {\n subscriptionItemId: string\n name: string\n mrcAmount: number\n nrcAmount: number\n quantity: number\n } | null\n}\n\ninterface OrderResult {\n id: string\n orderId: string\n orderNumber: string\n customerId: string\n cpqStatus: string\n sourceQuoteId: string | null\n /** XD-250 ARC quote type carried over from the source quote \u2014 used by the\n * order detail page to render the AMEND / RENEW / CANCEL badge. */\n quoteType: string\n currencyCode: string\n /** NRC / MRC totals plus the source quote's list / discount / deal-value figures. */\n pricingSummary: {\n nrcTotal: number\n mrcTotal: number\n currencyCode: string\n } & OrderWaterfallSummary\n activatedAt: string | null\n createdAt: string\n lines: OrderLineResult[]\n}\n\ninterface OrderServiceDeps {\n em: EntityManager\n cpqInventoryService: DefaultCpqInventoryService\n salesDocumentNumberGenerator: SalesDocumentNumberGenerator\n}\n\nconst CPQ_TO_SALES_ORDER_STATUS: Record<CpqOrderStatus, string> = {\n draft: 'draft',\n pending_activation: 'pending',\n active: 'active',\n cancelled: 'cancelled',\n fulfilled: 'fulfilled',\n}\n\n// \u2500\u2500\u2500 Service \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class DefaultCpqOrderService {\n private em: EntityManager\n private inventoryService: DefaultCpqInventoryService\n private numberGenerator: SalesDocumentNumberGenerator\n\n constructor(deps: OrderServiceDeps) {\n this.em = deps.em\n this.inventoryService = deps.cpqInventoryService\n this.numberGenerator = deps.salesDocumentNumberGenerator\n }\n\n // \u2500\u2500\u2500 Convert Quote to Order \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 convertQuoteToOrder(quoteId: string, scope: TenantScope): Promise<OrderResult> {\n return withQuotePricingWrite(this.em, quoteId, scope,\n (em, quote) => this.convertFromConfig(quote, scope, em),\n (status, message) => new OrderError(status, message))\n }\n\n private async convertFromConfig(cpqConfig: CpqQuoteConfiguration, scope: TenantScope, em: EntityManager): Promise<OrderResult> {\n\n const blockedStatuses = ['cancelled', 'rejected']\n if (blockedStatuses.includes(cpqConfig.cpqStatus)) {\n throw new OrderError(409, `Cannot convert a quote in '${cpqConfig.cpqStatus}' status`)\n }\n\n // Idempotency guard: a quote may only convert once. If an order with\n // this quote as its `sourceQuoteId` already exists, the UI should\n // surface \"Go to order\" instead of re-running conversion \u2014 return\n // 409 with the existing id so the caller can redirect.\n const existingOrder = await em.findOne(CpqOrderConfiguration, {\n sourceQuoteId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (existingOrder) {\n throw new OrderError(\n 409,\n `Quote has already been converted to order ${existingOrder.orderId}`,\n )\n }\n\n const quoteLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: cpqConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n if (quoteLines.length === 0) {\n throw new OrderError(422, 'Cannot convert a quote with no line items')\n }\n\n const invalidAdjustment = storedAdjustmentFailure(cpqConfig, quoteLines)\n if (invalidAdjustment) throw new OrderError(422, 'ADJUSTMENT_INVALID', invalidAdjustment)\n\n const { number: orderNumber } = await this.numberGenerator.generate({\n kind: 'order',\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n\n const salesOrderId = crypto.randomUUID()\n const pricingSummary = cpqConfig.pricingSummary as Record<string, unknown> | null\n const nrcTotal = Number(pricingSummary?.nrcTotal ?? 0)\n const mrcTotal = Number(pricingSummary?.mrcTotal ?? 0)\n const grandTotal = nrcTotal + mrcTotal\n\n const salesOrder = em.create(SalesOrder, {\n id: salesOrderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderNumber,\n customerEntityId: cpqConfig.customerId,\n currencyCode: cpqConfig.currencyCode,\n status: 'draft',\n subtotalNetAmount: String(grandTotal),\n subtotalGrossAmount: String(grandTotal),\n discountTotalAmount: '0',\n taxTotalAmount: '0',\n shippingNetAmount: '0',\n shippingGrossAmount: '0',\n surchargeTotalAmount: '0',\n paidTotalAmount: '0',\n grandTotalNetAmount: String(grandTotal),\n grandTotalGrossAmount: String(grandTotal),\n lineItemCount: quoteLines.length,\n metadata: { sourceQuoteId: cpqConfig.id },\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(salesOrder)\n\n const cpqOrderConfigId = crypto.randomUUID()\n const cpqOrderConfig = em.create(CpqOrderConfiguration, {\n id: cpqOrderConfigId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderId: salesOrderId,\n sourceQuoteId: cpqConfig.id,\n customerId: cpqConfig.customerId,\n cpqStatus: 'draft',\n currencyCode: cpqConfig.currencyCode,\n pricingSummary: {\n nrcTotal,\n mrcTotal,\n currencyCode: cpqConfig.currencyCode,\n },\n })\n em.persist(cpqOrderConfig)\n\n const quoteLineIdToOrderLineId = new Map<string, string>()\n\n for (let i = 0; i < quoteLines.length; i++) {\n const ql = quoteLines[i]\n\n const perInstanceNrc = Number(ql.nrcTotal)\n const perInstanceMrc = Number(ql.mrcTotal)\n const unitPriceNet = (perInstanceNrc + perInstanceMrc) / ql.quantity\n const totalNet = perInstanceNrc + perInstanceMrc\n\n const orderLineId = crypto.randomUUID()\n quoteLineIdToOrderLineId.set(ql.quoteLineId, orderLineId)\n\n const offeringName = await this.resolveOfferingName(\n em,\n ql.offeringId,\n scope,\n ql.configuration as Record<string, unknown> | null,\n )\n\n const orderLine = em.create(SalesOrderLine, {\n id: orderLineId,\n order: salesOrder,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n lineNumber: i + 1,\n kind: 'product',\n productId: ql.productId ?? null,\n name: offeringName,\n quantity: String(ql.quantity),\n unitPriceNet: String(unitPriceNet),\n unitPriceGross: String(unitPriceNet),\n totalNetAmount: String(totalNet),\n totalGrossAmount: String(totalNet),\n discountAmount: '0',\n discountPercent: '0',\n taxRate: '0',\n taxAmount: '0',\n currencyCode: cpqConfig.currencyCode,\n configuration: {\n offeringId: ql.offeringId ?? null,\n action: ql.action,\n nrcTotal: perInstanceNrc,\n mrcTotal: perInstanceMrc,\n parentLineId: ql.parentLineId ?? null,\n },\n normalizedQuantity: String(ql.quantity),\n reservedQuantity: '0',\n fulfilledQuantity: '0',\n invoicedQuantity: '0',\n returnedQuantity: '0',\n createdAt: new Date(),\n updatedAt: new Date(),\n } as never)\n em.persist(orderLine)\n const orderLineConfig = em.create(CpqOrderLineConfiguration, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n orderLineId,\n orderConfigurationId: cpqOrderConfig.id,\n offeringId: ql.offeringId ?? null,\n productId: ql.productId ?? null,\n specId: ql.specId ?? null,\n action: ql.action,\n parentLineId: null,\n startDate: ql.startDate,\n termMonths: ql.termMonths ?? null,\n endDate: ql.endDate,\n // Quote-only ARC pricing markers stay on the quote.\n configuration: { ...stripQuoteOnlyArcMarkers(ql.configuration), offeringName },\n quantity: ql.quantity,\n charges: ql.charges ? [...ql.charges] : null,\n nrcTotal: ql.nrcTotal,\n mrcTotal: ql.mrcTotal,\n sourceQuoteLineId: ql.quoteLineId,\n })\n em.persist(orderLineConfig)\n }\n\n await em.flush()\n\n // Resolve parent line references using the quote\u2192order line ID map\n const orderLineConfigs = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: cpqOrderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n for (const olc of orderLineConfigs) {\n if (olc.sourceQuoteLineId) {\n const sourceQl = quoteLines.find((ql) => ql.quoteLineId === olc.sourceQuoteLineId)\n if (sourceQl?.parentLineId) {\n const mappedParent = quoteLineIdToOrderLineId.get(sourceQl.parentLineId)\n if (mappedParent) olc.parentLineId = mappedParent\n }\n }\n }\n\n await em.flush()\n\n return this.buildOrderResult(em, cpqOrderConfig, salesOrder, orderLineConfigs, scope)\n }\n\n // \u2500\u2500\u2500 Activate Order \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 activateOrder(orderId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n\n const currentStatus = orderConfig.cpqStatus as CpqOrderStatus\n if (currentStatus !== 'draft' && currentStatus !== 'pending_activation') {\n throw new OrderError(409, `Cannot activate order in '${currentStatus}' status`)\n }\n\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n const orderLines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n\n // Branch on the source quote's quoteType. ARC quotes mutate existing\n // subscriptions; new-sale quotes materialize a fresh subscription.\n const sourceQuote = orderConfig.sourceQuoteId\n ? await em.findOne(CpqQuoteConfiguration, {\n id: orderConfig.sourceQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : null\n\n const quoteType = sourceQuote?.quoteType ?? 'new'\n const postCommitEvents: Array<() => Promise<void>> = []\n\n if (quoteType === 'new') {\n const inventory = await this.createInventoryFromOrder(orderConfig, orderLines, scope)\n if (inventory) {\n postCommitEvents.push(() => emitActivatedEvent(orderConfig, inventory, scope))\n }\n } else {\n postCommitEvents.push(\n ...(await this.applyArcOrder(orderConfig, sourceQuote!, orderLines, scope)),\n )\n }\n\n orderConfig.cpqStatus = 'active'\n orderConfig.activatedAt = new Date()\n salesOrder.status = 'active'\n salesOrder.placedAt = new Date()\n\n await em.flush()\n\n // Emit lifecycle events AFTER the activation transaction commits.\n for (const fire of postCommitEvents) {\n try {\n await fire()\n } catch (err) {\n // Don't roll back the activation just because a subscriber blew up \u2014\n // events are best-effort once the DB state is committed.\n console.error('[cpq.arc] event emission failed', err)\n }\n }\n\n return this.buildOrderResult(em, orderConfig, salesOrder, orderLines, scope)\n }\n\n // \u2500\u2500\u2500 ARC activation branch (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\n //\n // Reads the source quote's targets + lines, then dispatches per target to\n // cpqInventoryService.apply* primitives. Returns the list of post-commit\n // event emissions so the caller can fire them outside the activation TX.\n private async applyArcOrder(\n orderConfig: CpqOrderConfiguration,\n sourceQuote: CpqQuoteConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<Array<() => Promise<void>>> {\n const em = this.em\n const quoteType = sourceQuote.quoteType as 'amend' | 'renew' | 'cancel'\n\n // Load attached targets.\n const targets = await em.find(CpqQuoteTargetSubscription, {\n quoteId: sourceQuote.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (targets.length === 0) {\n throw new OrderError(\n 409,\n `ARC quote ${sourceQuote.id} has no target subscriptions to activate`,\n )\n }\n\n const inventory = this.inventoryService\n\n // Group order lines by target_subscription_id \u2014 ARC order lines mirror the\n // quote lines' ARC fields (target_subscription_id is preserved through\n // convertQuoteToOrder via line.configuration when needed).\n // Source quote lines are the source of truth for ARC line data because\n // CpqOrderLineConfiguration doesn't carry target/source-item fields.\n const sourceQuoteLines = await em.find(CpqQuoteLineConfiguration, {\n quoteConfigurationId: sourceQuote.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n const linesByTarget = new Map<string | null, CpqQuoteLineConfiguration[]>()\n for (const line of sourceQuoteLines) {\n const key = line.targetSubscriptionId ?? null\n const list = linesByTarget.get(key) ?? []\n list.push(line)\n linesByTarget.set(key, list)\n }\n\n // Look up specs for `add` lines so we can build itemInput correctly.\n const specIds = [\n ...new Set(sourceQuoteLines.map((l) => l.specId).filter((x): x is string => Boolean(x))),\n ]\n const specs =\n specIds.length > 0\n ? await em.find(CpqProductSpecification, {\n id: { $in: specIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : []\n const specMap = new Map(specs.map((s) => [s.id, s]))\n\n const events: Array<() => Promise<void>> = []\n const eventBaseEnvelope = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n } as const\n\n if (quoteType === 'amend') {\n for (const target of targets) {\n const lines = linesByTarget.get(target.subscriptionId) ?? []\n const result = await inventory.applyAmendment(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n lineChanges: lines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n events.push(() => emitAmendedEvent(result, eventBaseEnvelope))\n }\n } else if (quoteType === 'cancel') {\n for (const target of targets) {\n const result = await inventory.applyCancel(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n etfAmount: sourceQuote.arcEtfAmount ?? null,\n etfCurrency: sourceQuote.arcEtfCurrency ?? null,\n reasonCode: sourceQuote.arcReasonCode ?? null,\n reasonText: sourceQuote.arcReasonText ?? null,\n },\n scope,\n )\n events.push(() => emitCancelledEvent(result, eventBaseEnvelope))\n }\n } else if (quoteType === 'renew') {\n const standalone = targets.filter((t) => t.mergeAction === 'standalone')\n const absorb = targets.filter((t) => t.mergeAction === 'absorb')\n\n if (standalone.length > 0 && absorb.length === 0) {\n for (const target of standalone) {\n if (!target.newTermStart || !target.newTermEnd) {\n throw new OrderError(\n 409,\n `Standalone renew target ${target.id} missing newTermStart/newTermEnd`,\n )\n }\n const lines = linesByTarget.get(target.subscriptionId) ?? []\n const result = await inventory.applyRenewal(\n {\n subscriptionId: target.subscriptionId,\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n term: {\n newTermStart: target.newTermStart,\n newTermEnd: target.newTermEnd,\n newTermMonths: target.newTermMonths ?? null,\n },\n lineChanges: lines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n events.push(() => emitRenewedEvent(result, eventBaseEnvelope))\n }\n } else if (absorb.length >= 2 && standalone.length === 0) {\n if (!sourceQuote.arcMergeNewTermStart || !sourceQuote.arcMergeNewTermEnd) {\n throw new OrderError(\n 409,\n `Merge renew quote ${sourceQuote.id} missing arc_merge_new_term_*`,\n )\n }\n // Lines targeting null are operator-edits on the new merge sub M.\n const mergeLines = linesByTarget.get(null) ?? []\n const merge = await inventory.applyMergeRenewal(\n {\n sourceIds: absorb.map((t) => t.subscriptionId),\n sourceQuoteId: sourceQuote.id,\n sourceOrderId: orderConfig.id,\n performedByUserId: null,\n term: {\n newTermStart: sourceQuote.arcMergeNewTermStart,\n newTermEnd: sourceQuote.arcMergeNewTermEnd,\n newTermMonths: sourceQuote.arcMergeNewTermMonths ?? null,\n },\n mergeMeta: {\n newSubCode: sourceQuote.arcMergeNewSubCode ?? null,\n newSubName: sourceQuote.arcMergeNewSubName ?? null,\n },\n lineChanges: mergeLines.map((l) => buildArcLineChange(l, specMap)),\n },\n scope,\n )\n\n // One event per source (`superseded`) + one for M (`merged`).\n const mergedFromSubscriptionIds = absorb.map((t) => t.subscriptionId)\n events.push(() =>\n emitMergedEvent(merge, eventBaseEnvelope, mergedFromSubscriptionIds),\n )\n for (const sourceLog of merge.sourceChangeLogs) {\n events.push(() =>\n emitSupersededEvent(\n sourceLog,\n iso10(merge.mergedSubscription.currentTermStart),\n eventBaseEnvelope,\n ),\n )\n }\n } else {\n throw new OrderError(\n 409,\n `Inconsistent renew targets \u2014 must be either single standalone or \u22652 absorb`,\n )\n }\n } else {\n throw new OrderError(500, `Unknown quote_type '${quoteType}' for ARC activation`)\n }\n\n return events\n }\n\n // \u2500\u2500\u2500 Inventory Creation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 createInventoryFromOrder(\n orderConfig: CpqOrderConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<ActivatedInventory | null> {\n if (orderLines.length === 0) return null\n\n const specIds = [...new Set(orderLines.map((l) => l.specId).filter(Boolean))] as string[]\n const specs = specIds.length > 0\n ? await this.em.find(CpqProductSpecification, {\n id: { $in: specIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n : []\n const specMap = new Map(specs.map((s) => [s.id, s]))\n\n const subscriptionLines = orderLines.filter((l) => {\n const spec = l.specId ? specMap.get(l.specId) : null\n return !spec?.isAssetizable\n })\n const assetLines = orderLines.filter((l) => {\n const spec = l.specId ? specMap.get(l.specId) : null\n return spec?.isAssetizable === true\n })\n\n const hasSubscriptionContent = subscriptionLines.some(\n (l) => Number(l.mrcTotal) > 0 || Number(l.nrcTotal) > 0,\n )\n if (!hasSubscriptionContent && assetLines.length === 0) return null\n\n const subscriptionName = await this.buildSubscriptionName(orderConfig, orderLines, scope)\n\n const lineWithDates = orderLines.find((l) => l.startDate != null) ?? orderLines[0]\n const lineWithTerm = orderLines.find((l) => l.termMonths != null) ?? orderLines[0]\n const subscriptionItems = subscriptionLines.map((line) => ({\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: this.getLineName(line),\n configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? {},\n charges: (line.charges ?? []) as Array<Record<string, unknown>>,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n currencyCode: orderConfig.currencyCode,\n quantity: line.quantity,\n sourceQuoteLineId: line.sourceQuoteLineId ?? undefined,\n sortOrder: orderLines.indexOf(line),\n }))\n\n const subscription = await this.inventoryService.createSubscription(\n {\n customerId: orderConfig.customerId,\n name: subscriptionName,\n billingCycle: 'monthly',\n currencyCode: orderConfig.currencyCode,\n startDate: lineWithDates?.startDate?.toISOString?.() ?? undefined,\n termMonths: lineWithTerm?.termMonths ?? undefined,\n sourceQuoteId: orderConfig.sourceQuoteId ?? undefined,\n sourceOrderId: orderConfig.id,\n items: subscriptionItems.length > 0\n ? subscriptionItems\n : [{ name: subscriptionName, mrcAmount: 0, nrcAmount: 0 }],\n },\n scope,\n )\n\n const orderLineToSubItem = new Map<string, string>()\n const allSubItems = await this.em.find(CpqInventorySubscriptionItem, {\n subscriptionId: subscription.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, { orderBy: { sortOrder: 'asc' } })\n\n for (let i = 0; i < subscriptionLines.length && i < allSubItems.length; i++) {\n orderLineToSubItem.set(subscriptionLines[i].orderLineId, allSubItems[i].id)\n }\n\n for (let i = 0; i < subscriptionLines.length && i < allSubItems.length; i++) {\n const orderLine = subscriptionLines[i]\n if (orderLine.parentLineId) {\n const parentSubItemId = orderLineToSubItem.get(orderLine.parentLineId)\n if (parentSubItemId) {\n allSubItems[i].parentItemId = parentSubItemId\n }\n }\n }\n await this.em.flush()\n\n for (const line of assetLines) {\n let subscriptionItemId: string | undefined\n if (line.parentLineId) {\n subscriptionItemId = orderLineToSubItem.get(line.parentLineId) ?? undefined\n }\n\n await this.inventoryService.createAsset(\n {\n customerId: orderConfig.customerId,\n subscriptionId: subscription.id,\n subscriptionItemId,\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: this.getLineName(line),\n assetType: 'one_time',\n currencyCode: orderConfig.currencyCode,\n purchasePrice: Number(line.nrcTotal),\n quantity: line.quantity,\n purchaseDate: new Date().toISOString().split('T')[0],\n configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? {},\n charges: (line.charges ?? []) as Array<Record<string, unknown>>,\n sourceOrderId: orderConfig.id,\n sourceQuoteLineId: line.sourceQuoteLineId ?? undefined,\n },\n scope,\n )\n }\n\n // Pair each subscription line with its created subscription item \u2014\n // input for the `cpq.subscription.activated` billing-onboarding event.\n const eventItems = subscriptionLines\n .slice(0, allSubItems.length)\n .map((line, i) => ({\n subscriptionItemId: allSubItems[i].id,\n productName: this.getLineName(line),\n mrcTotal: Number(line.mrcTotal),\n nrcTotal: Number(line.nrcTotal),\n }))\n // Only lines with a billable charge \u2014 a zero-value line yields\n // no Billing Item anyway; emitting it would just make the\n // connector create a needless shell account.\n .filter((it) => it.mrcTotal > 0 || it.nrcTotal > 0)\n return { subscriptionId: subscription.id, items: eventItems }\n }\n\n // \u2500\u2500\u2500 Get / List \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 getOrder(orderId: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n const lines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return this.buildOrderResult(em, orderConfig, salesOrder, lines, scope)\n }\n\n async listOrders(filters: OrderListFilters, scope: TenantScope) {\n const page = Math.max(1, filters.page ?? 1)\n const pageSize = Math.min(100, Math.max(1, filters.pageSize ?? 50))\n const offset = (page - 1) * pageSize\n\n const where: Record<string, unknown> = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }\n\n if (filters.customerId) where.customerId = filters.customerId\n if (filters.sourceQuoteId) where.sourceQuoteId = filters.sourceQuoteId\n if (filters.salesOrderId) where.orderId = filters.salesOrderId\n if (filters.currencyCode) where.currencyCode = filters.currencyCode\n if (filters.cpqStatus) {\n where.cpqStatus = Array.isArray(filters.cpqStatus)\n ? { $in: filters.cpqStatus }\n : filters.cpqStatus\n }\n\n const search = filters.search?.trim()\n if (search) {\n where.$or = [\n { orderId: { $ilike: `%${search}%` } },\n { customerId: { $ilike: `%${search}%` } },\n ]\n }\n\n const sortField = filters.sortField ?? 'createdAt'\n const sortDir = filters.sortDir === 'asc' ? 'asc' : 'desc'\n\n const [configs, total] = await this.em.findAndCount(\n CpqOrderConfiguration,\n where,\n { limit: pageSize, offset, orderBy: { [sortField]: sortDir } },\n )\n\n const orderIds = configs.map((c) => c.orderId)\n const salesOrders = orderIds.length > 0\n ? await this.em.find(SalesOrder, { id: { $in: orderIds } })\n : []\n const salesOrderMap = new Map(salesOrders.map((o) => [o.id, o]))\n\n const items = configs.map((c) => ({\n ...c,\n orderNumber: salesOrderMap.get(c.orderId)?.orderNumber ?? null,\n }))\n\n return { items, total, page, pageSize, totalPages: Math.ceil(total / pageSize) }\n }\n\n // \u2500\u2500\u2500 Status Transition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 transitionOrderStatus(orderId: string, targetStatus: string, scope: TenantScope): Promise<OrderResult> {\n const em = this.em\n const orderConfig = await this.loadOrderConfig(em, orderId, scope)\n const salesOrder = await this.loadSalesOrder(em, orderConfig.orderId, scope)\n\n const currentStatus = orderConfig.cpqStatus as CpqOrderStatus\n const allowed = CPQ_ORDER_TRANSITIONS[currentStatus] ?? []\n\n if (!allowed.includes(targetStatus as CpqOrderStatus)) {\n throw new OrderError(409, `Cannot transition from '${currentStatus}' to '${targetStatus}'`)\n }\n\n if (targetStatus === 'active') {\n return this.activateOrder(orderId, scope)\n }\n\n orderConfig.cpqStatus = targetStatus\n salesOrder.status = CPQ_TO_SALES_ORDER_STATUS[targetStatus as CpqOrderStatus] ?? targetStatus\n\n await em.flush()\n\n const lines = await em.find(CpqOrderLineConfiguration, {\n orderConfigurationId: orderConfig.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n return this.buildOrderResult(em, orderConfig, salesOrder, lines, scope)\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\n\n private async loadOrderConfig(em: EntityManager, orderId: string, scope: TenantScope): Promise<CpqOrderConfiguration> {\n let config = await em.findOne(CpqOrderConfiguration, {\n id: orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (!config) {\n config = await em.findOne(CpqOrderConfiguration, {\n orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n }\n if (!config) throw new OrderError(404, 'Order not found')\n return config\n }\n\n private async loadSalesOrder(em: EntityManager, orderId: string, scope: TenantScope): Promise<SalesOrder> {\n const order = await em.findOne(SalesOrder, {\n id: orderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (!order) throw new OrderError(404, 'Sales order not found')\n return order\n }\n\n private async resolveOfferingInfo(\n em: EntityManager,\n offeringId: string | null | undefined,\n scope: TenantScope,\n fallbackConfig?: Record<string, unknown> | null,\n ): Promise<{ name: string; type: string | null }> {\n if (offeringId) {\n const offering = await em.findOne(CpqProductOffering, {\n id: offeringId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n if (offering) return { name: offering.name, type: offering.offeringType ?? 'simple' }\n }\n const cfg = fallbackConfig ?? null\n const fallbackName =\n (cfg?._arcMirroredName as string | undefined) ??\n (cfg?.offeringName as string | undefined) ??\n 'Configured Item'\n return { name: fallbackName, type: null }\n }\n\n private async resolveOfferingName(\n em: EntityManager,\n offeringId: string | null | undefined,\n scope: TenantScope,\n fallbackConfig?: Record<string, unknown> | null,\n ): Promise<string> {\n const info = await this.resolveOfferingInfo(em, offeringId, scope, fallbackConfig)\n return info.name\n }\n\n private getLineName(line: CpqOrderLineConfiguration): string {\n const config = line.configuration as Record<string, unknown> | null\n return (\n (config?._arcMirroredName as string | undefined) ??\n (config?.offeringName as string | undefined) ??\n (config?.name as string | undefined) ??\n 'Configured Item'\n )\n }\n\n private async buildSubscriptionName(\n orderConfig: CpqOrderConfiguration,\n orderLines: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<string> {\n if (orderLines.length === 1 && orderLines[0].offeringId) {\n return this.resolveOfferingName(this.em, orderLines[0].offeringId, scope)\n }\n const names: string[] = []\n for (const line of orderLines.slice(0, 3)) {\n if (line.offeringId) {\n names.push(await this.resolveOfferingName(this.em, line.offeringId, scope))\n }\n }\n if (names.length > 0) {\n const suffix = orderLines.length > 3 ? ` (+${orderLines.length - 3} more)` : ''\n return names.join(', ') + suffix\n }\n return `Order ${orderConfig.orderId.slice(0, 8)}`\n }\n\n private async buildOrderResult(\n em: EntityManager,\n orderConfig: CpqOrderConfiguration,\n salesOrder: SalesOrder,\n lineConfigs: CpqOrderLineConfiguration[],\n scope: TenantScope,\n ): Promise<OrderResult> {\n const lines: OrderLineResult[] = []\n\n // XD-250 ARC: batch-load source subscription items so we can render the\n // before/after diff per line on the order detail page.\n const arcItemIds = new Set<string>()\n for (const lc of lineConfigs) {\n const m = (lc.configuration as Record<string, unknown> | null)?._arcMirroredFromItemId\n if (typeof m === 'string') arcItemIds.add(m)\n }\n const arcItemMap = new Map<string, CpqInventorySubscriptionItem>()\n if (arcItemIds.size > 0) {\n const items = await em.find(CpqInventorySubscriptionItem, {\n id: { $in: Array.from(arcItemIds) },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n })\n for (const it of items) arcItemMap.set(it.id, it)\n }\n\n for (const lc of lineConfigs) {\n const offeringInfo = await this.resolveOfferingInfo(\n em,\n lc.offeringId,\n scope,\n lc.configuration as Record<string, unknown> | null,\n )\n const arcSource = pickArcSourceFromConfig(lc.configuration as Record<string, unknown> | null, arcItemMap)\n lines.push({\n lineId: lc.orderLineId,\n offeringId: lc.offeringId ?? null,\n offeringName: offeringInfo.name,\n offeringType: offeringInfo.type,\n productId: lc.productId ?? null,\n specId: lc.specId ?? null,\n action: lc.action,\n parentLineId: lc.parentLineId ?? null,\n quantity: lc.quantity,\n configuration: stripQuoteOnlyArcMarkers(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 charges: (lc.charges ?? []) as Array<Record<string, unknown>>,\n sourceQuoteLineId: lc.sourceQuoteLineId ?? null,\n arcSource,\n })\n }\n\n // Source quote's quoteType \u2014 surfaced to the order header so the UI can\n // render an AMEND / RENEW / CANCEL badge alongside the order number.\n // CpqOrderConfiguration.sourceQuoteId stores CpqQuoteConfiguration.id\n // (see convertFromConfig \u2014 sourceQuoteId: cpqConfig.id), NOT the\n // SalesQuote.id, so we look it up by `id` rather than by `quoteId`.\n let quoteType = 'new'\n if (orderConfig.sourceQuoteId) {\n const sourceCfg = await em.findOne(CpqQuoteConfiguration, {\n id: orderConfig.sourceQuoteId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n if (sourceCfg?.quoteType) quoteType = sourceCfg.quoteType\n }\n\n const pricing = orderConfig.pricingSummary ?? {}\n\n return {\n id: orderConfig.id,\n orderId: orderConfig.orderId,\n orderNumber: salesOrder.orderNumber ?? '',\n customerId: orderConfig.customerId,\n cpqStatus: orderConfig.cpqStatus,\n sourceQuoteId: orderConfig.sourceQuoteId ?? null,\n quoteType,\n currencyCode: orderConfig.currencyCode,\n pricingSummary: {\n nrcTotal: Number((pricing as Record<string, unknown>).nrcTotal ?? 0),\n mrcTotal: Number((pricing as Record<string, unknown>).mrcTotal ?? 0),\n currencyCode: orderConfig.currencyCode,\n ...summarizeOrderPricing(lines, quoteType, orderConfig.currencyCode),\n },\n activatedAt: orderConfig.activatedAt?.toISOString() ?? null,\n createdAt: orderConfig.createdAt.toISOString(),\n lines,\n }\n }\n}\n\nfunction pickArcSourceFromConfig(\n cfg: Record<string, unknown> | null,\n map: Map<string, CpqInventorySubscriptionItem>,\n): OrderLineResult['arcSource'] {\n const m = cfg?._arcMirroredFromItemId\n if (typeof m !== 'string') return null\n const item = map.get(m)\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// \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 \u2014 see QUOTING_ERROR_BRAND in cpqQuotingService.ts for why\n// route handlers must not rely on `instanceof`. Use `isOrderError`.\nconst ORDER_ERROR_BRAND = Symbol.for('@dainamite/cpq/OrderError')\n\nexport class OrderError extends Error {\n readonly [ORDER_ERROR_BRAND] = true\n\n constructor(\n public status: number,\n message: string,\n public details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'OrderError'\n }\n}\n\nexport function isOrderError(err: unknown): err is OrderError {\n return !!err && typeof err === 'object' && (err as Record<symbol, unknown>)[ORDER_ERROR_BRAND] === true\n}\n\n// \u2500\u2500\u2500 ARC 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Build a service-layer ArcLineChange from a CpqQuoteLineConfiguration.\n * For 'add' actions, materializes the itemInput from line + spec data.\n */\nfunction buildArcLineChange(\n line: CpqQuoteLineConfiguration,\n specMap: Map<string, CpqProductSpecification>,\n): ArcLineChange {\n const action = line.action as 'add' | 'modify' | 'cancel'\n if (action === 'add') {\n const itemInput: Omit<CreateSubscriptionItemInput, 'name'> & { name: string } = {\n productId: line.productId ?? undefined,\n offeringId: line.offeringId ?? undefined,\n specId: line.specId ?? undefined,\n name: resolveLineName(line, specMap),\n configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? {},\n charges: (line.charges ?? null) as Array<Record<string, unknown>> | undefined,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n quantity: line.quantity,\n sourceQuoteLineId: line.quoteLineId,\n }\n return {\n quoteLineId: line.quoteLineId,\n action,\n itemInput,\n parentQuoteLineId: line.parentLineId ?? null,\n }\n }\n if (action === 'cancel') {\n return {\n quoteLineId: line.quoteLineId,\n action,\n sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,\n }\n }\n // modify\n return {\n quoteLineId: line.quoteLineId,\n action,\n sourceSubscriptionItemId: line.sourceSubscriptionItemId ?? null,\n modifyPatch: {\n configuration: stripQuoteOnlyArcMarkers(line.configuration) ?? undefined,\n charges: (line.charges ?? undefined) as Array<Record<string, unknown>> | undefined,\n mrcAmount: Number(line.mrcTotal),\n nrcAmount: Number(line.nrcTotal),\n quantity: line.quantity,\n },\n }\n}\n\nfunction resolveLineName(\n line: CpqQuoteLineConfiguration,\n specMap: Map<string, CpqProductSpecification>,\n): string {\n const cfg = line.configuration as Record<string, unknown> | null\n const cfgName = (cfg?._arcMirroredName as string | undefined) ?? null\n if (cfgName) return cfgName\n if (line.specId) {\n const spec = specMap.get(line.specId)\n if (spec?.name) return spec.name\n }\n return 'Configured Item'\n}\n\ninterface ArcEventEnvelope {\n organizationId: string\n tenantId: string\n sourceQuoteId: string\n sourceOrderId: string\n}\n\n// \u2500\u2500\u2500 Subscription-activated event (new-sale billing onboarding) \u2500\u2500\n\ntype ActivatedInventory = {\n subscriptionId: string\n items: Array<{\n subscriptionItemId: string\n productName: string\n /** Line totals \u2014 CPQ pricing has already applied line quantity. */\n mrcTotal: number\n nrcTotal: number\n }>\n}\n\n/**\n * Emit `cpq.subscription.activated` after a new-sale order activation.\n *\n * Payload matches the `@dainamite/cpq-billing-connector`\n * `cpq-subscription-activated` subscriber contract: one CPQ charge per\n * non-zero MRC / NRC total on each subscription item. The connector\n * get-or-creates the Billing Account (keyed on `customerId`) and turns\n * each charge into a Billing Item.\n */\nasync function emitActivatedEvent(\n orderConfig: CpqOrderConfiguration,\n inventory: ActivatedInventory,\n scope: TenantScope,\n): Promise<void> {\n const items = inventory.items.map((it) => ({\n subscriptionItemId: it.subscriptionItemId,\n productName: it.productName,\n // `mrcTotal` / `nrcTotal` are line totals \u2014 CPQ pricing already\n // applied the line quantity. Quantity is therefore 1 here so\n // `unitPrice \u00D7 quantity` stays internally consistent no matter\n // how the connector treats the multiplier.\n quantity: 1,\n charges: [\n ...(it.mrcTotal > 0\n ? [{ type: 'recurring', unitPrice: it.mrcTotal, description: 'Recurring charge' }]\n : []),\n ...(it.nrcTotal > 0\n ? [{ type: 'one_time', amount: it.nrcTotal, description: 'One-time charge' }]\n : []),\n ],\n }))\n await emitCpqEvent('cpq.subscription.activated' as never, {\n subscriptionId: inventory.subscriptionId,\n customerId: orderConfig.customerId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n currencyCode: orderConfig.currencyCode,\n timestamp: new Date().toISOString(),\n activationDate: new Date().toISOString().slice(0, 10),\n sourceQuoteId: orderConfig.sourceQuoteId ?? null,\n sourceOrderId: orderConfig.id,\n items,\n } as never)\n}\n\n/** Coerce a Date or `date`-column string to a `YYYY-MM-DD` string. */\nfunction iso10(value: Date | string | null | undefined): string | null {\n if (!value) return null\n if (value instanceof Date) return value.toISOString().slice(0, 10)\n return String(value).slice(0, 10)\n}\n\ntype ArcChargeItem = {\n subscriptionItemId: string\n productName: string\n quantity: number\n charges: Array<Record<string, unknown>>\n}\n\n/**\n * Build the connector's `addedItems` from a change log's `add` line\n * changes. `mrcAmount` / `nrcAmount` are line totals (CPQ pricing has\n * already applied quantity) \u2192 emit `quantity: 1` with the totals as the\n * charge rate, exactly as `emitActivatedEvent`.\n */\nfunction buildArcAddedItems(changeLog: ApplyArcResult['changeLog']): ArcChargeItem[] {\n const after = changeLog.afterSnapshot as\n | { items?: Array<{ id?: string; name?: string }> }\n | null\n const nameById = new Map(\n (after?.items ?? []).map((i) => [String(i.id), i.name ?? '']),\n )\n const summary = (changeLog.lineChanges ?? []) as Array<{\n action?: string\n itemId?: string\n mrcAmount?: unknown\n nrcAmount?: unknown\n }>\n const out: ArcChargeItem[] = []\n for (const change of summary) {\n if (change.action !== 'add' || typeof change.itemId !== 'string') continue\n const mrc = Number(change.mrcAmount)\n const nrc = Number(change.nrcAmount)\n out.push({\n subscriptionItemId: change.itemId,\n productName: nameById.get(change.itemId) || 'Configured item',\n quantity: 1,\n charges: [\n ...(mrc > 0\n ? [{ type: 'recurring', unitPrice: mrc, description: 'Recurring charge' }]\n : []),\n ...(nrc > 0\n ? [{ type: 'one_time', amount: nrc, description: 'One-time charge' }]\n : []),\n ],\n })\n }\n return out\n}\n\n/** Subscription-item ids removed by a change log's `cancel` line changes. */\nfunction buildArcRemovedItemIds(changeLog: ApplyArcResult['changeLog']): string[] {\n const summary = (changeLog.lineChanges ?? []) as Array<{\n action?: string\n itemId?: string\n }>\n return summary\n .filter((c) => c.action === 'cancel' && typeof c.itemId === 'string')\n .map((c) => c.itemId as string)\n}\n\nasync function emitAmendedEvent(\n result: ApplyArcResult,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.amended' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: result.subscription.id,\n customerId: result.subscription.customerId,\n // No operator-chosen amend date today \u2014 the activation moment is\n // the effective date. The billing connector computes the mid-cycle\n // proration from this date + the account's billing cycle.\n effectiveDate: iso10(result.changeLog.effectiveAt),\n addedItems: buildArcAddedItems(result.changeLog),\n removedSubscriptionItemIds: buildArcRemovedItemIds(result.changeLog),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitRenewedEvent(\n result: ApplyArcResult,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.renewed' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: result.subscription.id,\n customerId: result.subscription.customerId,\n newTermStart: iso10(result.subscription.currentTermStart),\n newTermEnd: iso10(result.subscription.currentTermEnd),\n addedItems: buildArcAddedItems(result.changeLog),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitCancelledEvent(\n result: ApplyArcResult,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.cancelled' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: result.subscription.id,\n customerId: result.subscription.customerId,\n effectiveDate: iso10(result.changeLog.effectiveAt),\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitMergedEvent(\n merge: ApplyMergeRenewalResult,\n envelope: ArcEventEnvelope,\n sourceSubscriptionIds: string[],\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.merged' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n mergedSubscriptionId: merge.mergedSubscription.id,\n sourceSubscriptionIds,\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n\nasync function emitSupersededEvent(\n sourceLog: { id: string; subscriptionId: string },\n effectiveDate: string | null,\n envelope: ArcEventEnvelope,\n): Promise<void> {\n await emitCpqEvent('cpq.subscription.superseded' as never, {\n tenantId: envelope.tenantId,\n organizationId: envelope.organizationId,\n subscriptionId: sourceLog.subscriptionId,\n effectiveDate,\n sourceQuoteId: envelope.sourceQuoteId,\n sourceOrderId: envelope.sourceOrderId,\n timestamp: new Date().toISOString(),\n } as never)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -63,6 +63,8 @@ class DefaultCpqPricingService {
63
63
  if (currencyCode) {
64
64
  resolved.currencyCode = currencyCode;
65
65
  }
66
+ resolved.listUnitPrice = resolved.unitPrice;
67
+ resolved.listTotalPrice = resolved.totalPrice;
66
68
  resolved.adjustments = [];
67
69
  results.push(resolved);
68
70
  }
@@ -74,6 +76,10 @@ class DefaultCpqPricingService {
74
76
  if (rules.length > 0) {
75
77
  this.applyPriceRules(results, rules, configuration);
76
78
  }
79
+ for (const resolved of results) {
80
+ resolved.standardUnitPrice = resolved.unitPrice;
81
+ resolved.standardTotalPrice = resolved.totalPrice;
82
+ }
77
83
  return results;
78
84
  }
79
85
  async loadPriceRules(params) {
@@ -141,6 +147,7 @@ class DefaultCpqPricingService {
141
147
  charge.totalPrice = unitPriceAfter;
142
148
  }
143
149
  const adjustment = {
150
+ origin: "rule",
144
151
  ruleCode: rule.code,
145
152
  ruleName: rule.name,
146
153
  ruleType: rule.ruleType,