@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
@@ -44,7 +44,7 @@ function PricingTableDetailPage(props) {
44
44
  const load = React.useCallback(async () => {
45
45
  if (isNew) return;
46
46
  if (!id || !UUID_RE.test(id)) {
47
- setError("Invalid pricing table ID");
47
+ setError(t("cpq.pricing.detail.errors.invalidId", "Invalid pricing table ID"));
48
48
  setLoading(false);
49
49
  return;
50
50
  }
@@ -52,7 +52,7 @@ function PricingTableDetailPage(props) {
52
52
  try {
53
53
  const res = await fetch(`/api/cpq/pricing-tables?id=${encodeURIComponent(id)}`);
54
54
  if (!res.ok) {
55
- setError("Pricing table not found");
55
+ setError(t("cpq.pricing.detail.errors.notFound", "Pricing table not found"));
56
56
  return;
57
57
  }
58
58
  const data = await res.json();
@@ -70,11 +70,11 @@ function PricingTableDetailPage(props) {
70
70
  setEntries(data.entries ?? []);
71
71
  } catch (err) {
72
72
  console.error("Failed to load pricing table", err);
73
- setError("Failed to load");
73
+ setError(t("cpq.pricing.detail.errors.loadFailed", "Failed to load"));
74
74
  } finally {
75
75
  setLoading(false);
76
76
  }
77
- }, [id, isNew]);
77
+ }, [id, isNew, t]);
78
78
  React.useEffect(() => {
79
79
  void load();
80
80
  }, [load]);
@@ -93,22 +93,32 @@ function PricingTableDetailPage(props) {
93
93
  setError(null);
94
94
  };
95
95
  const configValidationError = React.useMemo(() => {
96
- if (!draft.code.trim()) return "Code is required";
97
- if (!draft.name.trim()) return "Name is required";
98
- if (draft.currencyCodeList.length === 0) return "At least one currency is required";
99
- const checkList = (items, label) => {
96
+ if (!draft.code.trim()) return t("cpq.pricing.validation.codeRequired", "Code is required");
97
+ if (!draft.name.trim()) return t("cpq.pricing.validation.nameRequired", "Name is required");
98
+ if (draft.currencyCodeList.length === 0) {
99
+ return t("cpq.pricing.validation.currencyRequired", "At least one currency is required");
100
+ }
101
+ const checkList = (items, messages) => {
100
102
  const seen = /* @__PURE__ */ new Set();
101
103
  for (let i = 0; i < items.length; i++) {
102
104
  const item = items[i];
103
- if (!item.key.trim()) return `${label} #${i + 1}: key is required`;
104
- if (!item.label.trim()) return `${label} #${i + 1}: label is required`;
105
- if (seen.has(item.key)) return `${label}: duplicate key "${item.key}"`;
105
+ if (!item.key.trim()) return messages.keyRequired(i + 1);
106
+ if (!item.label.trim()) return messages.labelRequired(i + 1);
107
+ if (seen.has(item.key)) return messages.duplicateKey(item.key);
106
108
  seen.add(item.key);
107
109
  }
108
110
  return null;
109
111
  };
110
- return checkList(draft.dimensions, "Dimension") ?? checkList(draft.priceColumns, "Price Column");
111
- }, [draft]);
112
+ return checkList(draft.dimensions, {
113
+ keyRequired: (index) => t("cpq.pricing.validation.dimensionKeyRequired", "Dimension #{index}: key is required", { index }),
114
+ labelRequired: (index) => t("cpq.pricing.validation.dimensionLabelRequired", "Dimension #{index}: label is required", { index }),
115
+ duplicateKey: (key) => t("cpq.pricing.validation.dimensionDuplicateKey", 'Dimension: duplicate key "{key}"', { key })
116
+ }) ?? checkList(draft.priceColumns, {
117
+ keyRequired: (index) => t("cpq.pricing.validation.priceColumnKeyRequired", "Price Column #{index}: key is required", { index }),
118
+ labelRequired: (index) => t("cpq.pricing.validation.priceColumnLabelRequired", "Price Column #{index}: label is required", { index }),
119
+ duplicateKey: (key) => t("cpq.pricing.validation.priceColumnDuplicateKey", 'Price Column: duplicate key "{key}"', { key })
120
+ });
121
+ }, [draft, t]);
112
122
  const saveConfig = async () => {
113
123
  if (configValidationError) {
114
124
  setError(configValidationError);
@@ -132,7 +142,9 @@ function PricingTableDetailPage(props) {
132
142
  });
133
143
  if (!res.ok) {
134
144
  const body = await res.json().catch(() => ({}));
135
- setError(body.error ?? `Failed to ${isNew ? "create" : "save"} pricing table`);
145
+ setError(
146
+ body.error ?? (isNew ? t("cpq.pricing.detail.errors.createFailed", "Failed to create pricing table") : t("cpq.pricing.detail.errors.saveFailed", "Failed to save pricing table"))
147
+ );
136
148
  return;
137
149
  }
138
150
  const saved = await res.json();
@@ -144,7 +156,7 @@ function PricingTableDetailPage(props) {
144
156
  }
145
157
  } catch (err) {
146
158
  console.error("Failed to save", err);
147
- setError("Failed to save");
159
+ setError(t("cpq.pricing.detail.errors.saveFailedGeneric", "Failed to save"));
148
160
  } finally {
149
161
  setSaving(false);
150
162
  }
@@ -158,7 +170,8 @@ function PricingTableDetailPage(props) {
158
170
  priceColumns: table.priceColumns,
159
171
  currencyCodeList: table.currencyCodeList
160
172
  },
161
- entries
173
+ entries,
174
+ t
162
175
  );
163
176
  if (!r.ok) {
164
177
  setError(r.error);
@@ -171,7 +184,7 @@ function PricingTableDetailPage(props) {
171
184
  setImportApplying(true);
172
185
  setError(null);
173
186
  try {
174
- const r = await commitImportDiff(table.id, importDiff);
187
+ const r = await commitImportDiff(table.id, importDiff, t);
175
188
  if (!r.ok) {
176
189
  setError(r.error);
177
190
  return;
@@ -198,14 +211,14 @@ function PricingTableDetailPage(props) {
198
211
  router.push("/backend/cpq/pricing");
199
212
  } else {
200
213
  const body = await res.json().catch(() => ({}));
201
- setError(body.error ?? "Failed to delete");
214
+ setError(body.error ?? t("cpq.pricing.detail.errors.deleteFailed", "Failed to delete"));
202
215
  }
203
216
  } catch {
204
- setError("Failed to delete");
217
+ setError(t("cpq.pricing.detail.errors.deleteFailed", "Failed to delete"));
205
218
  }
206
219
  };
207
220
  if (loading) {
208
- return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("common.loading", "Loading...") });
221
+ return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("cpq.common.loading", "Loading...") });
209
222
  }
210
223
  if (error && !isNew && !table.id) {
211
224
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
@@ -216,7 +229,7 @@ function PricingTableDetailPage(props) {
216
229
  className: "text-sm text-muted-foreground hover:text-foreground",
217
230
  children: [
218
231
  "\u2190 ",
219
- t("common.back", "Back")
232
+ t("cpq.common.back", "Back")
220
233
  ]
221
234
  }
222
235
  ),
@@ -235,12 +248,12 @@ function PricingTableDetailPage(props) {
235
248
  className: "text-sm text-muted-foreground hover:text-foreground",
236
249
  children: [
237
250
  "\u2190 ",
238
- t("common.back", "Back")
251
+ t("cpq.common.back", "Back")
239
252
  ]
240
253
  }
241
254
  ),
242
255
  /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold", children: isNew ? t("cpq.pricing.new", "New Pricing Table") : table.name }),
243
- !isNew && /* @__PURE__ */ jsx(Tag, { variant: table.isActive ? "success" : "neutral", dot: true, children: table.isActive ? t("common.active", "Active") : t("common.inactive", "Inactive") })
256
+ !isNew && /* @__PURE__ */ jsx(Tag, { variant: table.isActive ? "success" : "neutral", dot: true, children: table.isActive ? t("cpq.common.active", "Active") : t("cpq.common.inactive", "Inactive") })
244
257
  ] }),
245
258
  !isNew && mode === "view" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
246
259
  /* @__PURE__ */ jsxs(
@@ -284,8 +297,8 @@ function PricingTableDetailPage(props) {
284
297
  }
285
298
  }
286
299
  ),
287
- /* @__PURE__ */ jsx(Button, { type: "button", onClick: startEdit, children: t("common.edit", "Edit") }),
288
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: deleteTable, children: t("common.delete", "Delete") })
300
+ /* @__PURE__ */ jsx(Button, { type: "button", onClick: startEdit, children: t("cpq.common.edit", "Edit") }),
301
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: deleteTable, children: t("cpq.common.delete", "Delete") })
289
302
  ] })
290
303
  ] }),
291
304
  error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: error }),
@@ -299,25 +312,25 @@ function PricingTableDetailPage(props) {
299
312
  }
300
313
  ),
301
314
  /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6 space-y-4", children: [
302
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Configuration" }),
315
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: t("cpq.pricing.detail.configuration", "Configuration") }),
303
316
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
304
- /* @__PURE__ */ jsx(ConfigField, { label: "Code", required: true, children: editing ? /* @__PURE__ */ jsx(
317
+ /* @__PURE__ */ jsx(ConfigField, { label: t("cpq.pricing.code", "Code"), required: true, children: editing ? /* @__PURE__ */ jsx(
305
318
  Input,
306
319
  {
307
320
  value: view.code,
308
321
  onChange: (e) => setDraft({ ...draft, code: e.target.value }),
309
- placeholder: "e.g. cloud-connect-pricing"
322
+ placeholder: t("cpq.pricing.detail.codePlaceholder", "e.g. cloud-connect-pricing")
310
323
  }
311
324
  ) : /* @__PURE__ */ jsx("span", { className: "font-mono text-sm", children: view.code }) }),
312
- /* @__PURE__ */ jsx(ConfigField, { label: "Name", required: true, children: editing ? /* @__PURE__ */ jsx(
325
+ /* @__PURE__ */ jsx(ConfigField, { label: t("cpq.pricing.name", "Name"), required: true, children: editing ? /* @__PURE__ */ jsx(
313
326
  Input,
314
327
  {
315
328
  value: view.name,
316
329
  onChange: (e) => setDraft({ ...draft, name: e.target.value }),
317
- placeholder: "Cloud Connect Pricing"
330
+ placeholder: t("cpq.pricing.detail.namePlaceholder", "Cloud Connect Pricing")
318
331
  }
319
332
  ) : /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: view.name }) }),
320
- /* @__PURE__ */ jsx(ConfigField, { label: "Currencies (comma-separated)", required: true, children: editing ? /* @__PURE__ */ jsx(
333
+ /* @__PURE__ */ jsx(ConfigField, { label: t("cpq.pricing.detail.currenciesCommaSeparated", "Currencies (comma-separated)"), required: true, children: editing ? /* @__PURE__ */ jsx(
321
334
  Input,
322
335
  {
323
336
  value: view.currencyCodeList.join(", "),
@@ -325,10 +338,10 @@ function PricingTableDetailPage(props) {
325
338
  ...draft,
326
339
  currencyCodeList: e.target.value.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean)
327
340
  }),
328
- placeholder: "USD, EUR"
341
+ placeholder: t("cpq.pricing.detail.currenciesPlaceholder", "USD, EUR")
329
342
  }
330
343
  ) : /* @__PURE__ */ jsx("span", { className: "text-sm", children: view.currencyCodeList.join(", ") || "\u2014" }) }),
331
- /* @__PURE__ */ jsx(ConfigField, { label: "Active", children: editing ? /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
344
+ /* @__PURE__ */ jsx(ConfigField, { label: t("cpq.common.active", "Active"), children: editing ? /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
332
345
  /* @__PURE__ */ jsx(
333
346
  "input",
334
347
  {
@@ -338,14 +351,18 @@ function PricingTableDetailPage(props) {
338
351
  className: "rounded border"
339
352
  }
340
353
  ),
341
- view.isActive ? "Yes" : "No"
342
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-sm", children: view.isActive ? "Yes" : "No" }) })
354
+ view.isActive ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No")
355
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-sm", children: view.isActive ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No") }) })
343
356
  ] }),
344
357
  /* @__PURE__ */ jsx(
345
358
  KeyLabelListEditor,
346
359
  {
347
- title: "Dimensions",
348
- description: "Lookup keys for matching entries (e.g. region, tier). Leave empty if you use tier ranges only.",
360
+ title: t("cpq.pricing.detail.dimensions.title", "Dimensions"),
361
+ description: t(
362
+ "cpq.pricing.detail.dimensions.description",
363
+ "Lookup keys for matching entries (e.g. region, tier). Leave empty if you use tier ranges only."
364
+ ),
365
+ addLabel: t("cpq.pricing.detail.dimensions.add", "+ Add Dimension"),
349
366
  items: view.dimensions,
350
367
  editing,
351
368
  onChange: (dimensions) => setDraft({ ...draft, dimensions })
@@ -354,8 +371,12 @@ function PricingTableDetailPage(props) {
354
371
  /* @__PURE__ */ jsx(
355
372
  KeyLabelListEditor,
356
373
  {
357
- title: "Price Columns",
358
- description: "Each price column becomes a numeric field on every entry. Charges reference one column by its key.",
374
+ title: t("cpq.pricing.priceColumns", "Price Columns"),
375
+ description: t(
376
+ "cpq.pricing.detail.priceColumns.description",
377
+ "Each price column becomes a numeric field on every entry. Charges reference one column by its key."
378
+ ),
379
+ addLabel: t("cpq.pricing.detail.priceColumns.add", "+ Add Price Column"),
359
380
  items: view.priceColumns,
360
381
  editing,
361
382
  onChange: (priceColumns) => setDraft({ ...draft, priceColumns })
@@ -370,10 +391,10 @@ function PricingTableDetailPage(props) {
370
391
  type: "button",
371
392
  onClick: saveConfig,
372
393
  disabled: saving || configValidationError !== null,
373
- children: saving ? "Saving..." : isNew ? "Create Pricing Table" : "Save"
394
+ children: saving ? t("cpq.common.saving", "Saving...") : isNew ? t("cpq.pricing.detail.create", "Create Pricing Table") : t("cpq.common.save", "Save")
374
395
  }
375
396
  ),
376
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: cancelEdit, disabled: saving, children: "Cancel" })
397
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: cancelEdit, disabled: saving, children: t("cpq.common.cancel", "Cancel") })
377
398
  ] })
378
399
  ] })
379
400
  ] }),
@@ -410,10 +431,12 @@ function ConfigField({
410
431
  function KeyLabelListEditor({
411
432
  title,
412
433
  description,
434
+ addLabel,
413
435
  items,
414
436
  editing,
415
437
  onChange
416
438
  }) {
439
+ const t = useT();
417
440
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
418
441
  /* @__PURE__ */ jsxs("div", { children: [
419
442
  /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: title }),
@@ -423,14 +446,16 @@ function KeyLabelListEditor({
423
446
  items.length > 0 && /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
424
447
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/30 text-xs", children: [
425
448
  /* @__PURE__ */ jsxs("th", { className: "px-3 py-2 text-left font-medium", children: [
426
- "Key ",
449
+ t("cpq.pricing.detail.keyLabelList.key", "Key"),
450
+ " ",
427
451
  editing && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
428
452
  ] }),
429
453
  /* @__PURE__ */ jsxs("th", { className: "px-3 py-2 text-left font-medium", children: [
430
- "Label ",
454
+ t("cpq.pricing.detail.keyLabelList.label", "Label"),
455
+ " ",
431
456
  editing && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
432
457
  ] }),
433
- editing && /* @__PURE__ */ jsx("th", { className: "px-3 py-2 w-8", "aria-label": "Actions" })
458
+ editing && /* @__PURE__ */ jsx("th", { className: "px-3 py-2 w-8", "aria-label": t("cpq.pricing.detail.keyLabelList.actions", "Actions") })
434
459
  ] }) }),
435
460
  /* @__PURE__ */ jsx("tbody", { children: items.map((item, idx) => /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0", children: [
436
461
  /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: editing ? /* @__PURE__ */ jsx(
@@ -442,7 +467,7 @@ function KeyLabelListEditor({
442
467
  next[idx] = { ...item, key: e.target.value };
443
468
  onChange(next);
444
469
  },
445
- placeholder: "e.g. region",
470
+ placeholder: t("cpq.pricing.detail.keyLabelList.keyPlaceholder", "e.g. region"),
446
471
  className: "h-8"
447
472
  }
448
473
  ) : /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: item.key }) }),
@@ -455,7 +480,7 @@ function KeyLabelListEditor({
455
480
  next[idx] = { ...item, label: e.target.value };
456
481
  onChange(next);
457
482
  },
458
- placeholder: "Region",
483
+ placeholder: t("cpq.pricing.detail.keyLabelList.labelPlaceholder", "Region"),
459
484
  className: "h-8"
460
485
  }
461
486
  ) : /* @__PURE__ */ jsx("span", { children: item.label }) }),
@@ -465,23 +490,20 @@ function KeyLabelListEditor({
465
490
  type: "button",
466
491
  onClick: () => onChange(items.filter((_, i) => i !== idx)),
467
492
  className: "text-destructive hover:bg-destructive/10 rounded p-1",
468
- "aria-label": "Remove",
493
+ "aria-label": t("cpq.pricing.detail.keyLabelList.remove", "Remove"),
469
494
  children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
470
495
  }
471
496
  ) })
472
497
  ] }, idx)) })
473
498
  ] }) }),
474
- editing && /* @__PURE__ */ jsxs(
499
+ editing && /* @__PURE__ */ jsx(
475
500
  Button,
476
501
  {
477
502
  type: "button",
478
503
  variant: "outline",
479
504
  size: "sm",
480
505
  onClick: () => onChange([...items, { key: "", label: "" }]),
481
- children: [
482
- "+ Add ",
483
- title.slice(0, -1)
484
- ]
506
+ children: addLabel
485
507
  }
486
508
  )
487
509
  ] });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/cpq/backend/cpq/pricing/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Download, Trash2, Upload } from 'lucide-react'\nimport { EntriesEditor, type Entry } from './EntriesEditor'\nimport { exportPricingTableToXlsx } from './xlsxExport'\nimport {\n commitImportDiff,\n parsePricingTableXlsx,\n type ImportDiff,\n} from './xlsxImport'\nimport { ImportPreview } from './ImportPreview'\n\ntype Dimension = { key: string; label: string }\ntype PriceColumn = { key: string; label: string }\n\ntype PricingTable = {\n id: string\n code: string\n name: string\n dimensions: Dimension[]\n priceColumns: PriceColumn[]\n currencyCodeList: string[]\n isActive: boolean\n}\n\nconst EMPTY_TABLE: PricingTable = {\n id: '',\n code: '',\n name: '',\n dimensions: [],\n priceColumns: [],\n currencyCodeList: ['USD'],\n isActive: true,\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nexport default function PricingTableDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const id = (props.params?.id ?? urlParams?.id) as string\n const isNew = id === 'new'\n\n const [table, setTable] = React.useState<PricingTable>(EMPTY_TABLE)\n const [entries, setEntries] = React.useState<Entry[]>([])\n const [loading, setLoading] = React.useState(!isNew)\n const [error, setError] = React.useState<string | null>(null)\n const [mode, setMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [draft, setDraft] = React.useState<PricingTable>(EMPTY_TABLE)\n const [saving, setSaving] = React.useState(false)\n\n // Import state\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n const [importDiff, setImportDiff] = React.useState<ImportDiff | null>(null)\n const [importApplying, setImportApplying] = React.useState(false)\n\n // \u2500\u2500\u2500 Load \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const load = React.useCallback(async () => {\n if (isNew) return\n if (!id || !UUID_RE.test(id)) {\n setError('Invalid pricing table ID')\n setLoading(false)\n return\n }\n setLoading(true)\n try {\n const res = await fetch(`/api/cpq/pricing-tables?id=${encodeURIComponent(id)}`)\n if (!res.ok) {\n setError('Pricing table not found')\n return\n }\n const data = await res.json()\n const loaded: PricingTable = {\n id: data.id,\n code: data.code,\n name: data.name,\n dimensions: data.dimensions ?? [],\n priceColumns: data.priceColumns ?? [],\n currencyCodeList: data.currencyCodeList ?? ['USD'],\n isActive: data.isActive,\n }\n setTable(loaded)\n setDraft(loaded)\n setEntries(data.entries ?? [])\n } catch (err) {\n console.error('Failed to load pricing table', err)\n setError('Failed to load')\n } finally {\n setLoading(false)\n }\n }, [id, isNew])\n\n React.useEffect(() => {\n void load()\n }, [load])\n\n // \u2500\u2500\u2500 Config CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const startEdit = () => {\n setDraft(table)\n setMode('edit')\n setError(null)\n }\n\n const cancelEdit = () => {\n if (isNew) {\n router.push('/backend/cpq/pricing')\n return\n }\n setDraft(table)\n setMode('view')\n setError(null)\n }\n\n // Mirror V-PT-1 from validators.ts so the user gets feedback before the\n // server rejects the payload.\n const configValidationError = React.useMemo(() => {\n if (!draft.code.trim()) return 'Code is required'\n if (!draft.name.trim()) return 'Name is required'\n if (draft.currencyCodeList.length === 0) return 'At least one currency is required'\n const checkList = (items: Array<{ key: string; label: string }>, label: string): string | null => {\n const seen = new Set<string>()\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n if (!item.key.trim()) return `${label} #${i + 1}: key is required`\n if (!item.label.trim()) return `${label} #${i + 1}: label is required`\n if (seen.has(item.key)) return `${label}: duplicate key \"${item.key}\"`\n seen.add(item.key)\n }\n return null\n }\n return checkList(draft.dimensions, 'Dimension') ?? checkList(draft.priceColumns, 'Price Column')\n }, [draft])\n\n const saveConfig = async () => {\n if (configValidationError) {\n setError(configValidationError)\n return\n }\n setSaving(true)\n setError(null)\n try {\n const payload = {\n code: draft.code,\n name: draft.name,\n dimensions: draft.dimensions,\n priceColumns: draft.priceColumns,\n currencyCodeList: draft.currencyCodeList,\n isActive: draft.isActive,\n }\n const res = await fetch('/api/cpq/pricing-tables', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(isNew ? payload : { id, ...payload }),\n })\n if (!res.ok) {\n const body = await res.json().catch(() => ({}))\n setError(body.error ?? `Failed to ${isNew ? 'create' : 'save'} pricing table`)\n return\n }\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/pricing/${saved.id}`)\n } else {\n setTable({ ...draft, id })\n setMode('view')\n }\n } catch (err) {\n console.error('Failed to save', err)\n setError('Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n // \u2500\u2500\u2500 Excel import \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const handleImportFile = async (file: File) => {\n setError(null)\n const r = await parsePricingTableXlsx(\n file,\n {\n dimensions: table.dimensions,\n priceColumns: table.priceColumns,\n currencyCodeList: table.currencyCodeList,\n },\n entries,\n )\n if (!r.ok) {\n setError(r.error)\n return\n }\n setImportDiff(r.diff)\n }\n\n const applyImportDiff = async () => {\n if (!importDiff) return\n setImportApplying(true)\n setError(null)\n try {\n const r = await commitImportDiff(table.id, importDiff)\n if (!r.ok) {\n setError(r.error)\n return\n }\n setImportDiff(null)\n await load()\n } finally {\n setImportApplying(false)\n }\n }\n\n const cancelImport = () => {\n setImportDiff(null)\n if (fileInputRef.current) fileInputRef.current.value = ''\n }\n\n const deleteTable = async () => {\n if (!window.confirm(t('cpq.pricing.confirmDelete', 'Delete this pricing table and all its entries?'))) return\n try {\n const res = await fetch('/api/cpq/pricing-tables', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n if (res.ok) {\n router.push('/backend/cpq/pricing')\n } else {\n const body = await res.json().catch(() => ({}))\n setError(body.error ?? 'Failed to delete')\n }\n } catch {\n setError('Failed to delete')\n }\n }\n\n // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('common.loading', 'Loading...')}</div>\n }\n\n if (error && !isNew && !table.id) {\n return (\n <div className=\"space-y-4\">\n <button\n onClick={() => router.push('/backend/cpq/pricing')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('common.back', 'Back')}\n </button>\n <Alert variant=\"destructive\">{error}</Alert>\n </div>\n )\n }\n\n const editing = mode === 'edit'\n const view = editing ? draft : table\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/pricing')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.pricing.new', 'New Pricing Table') : table.name}\n </h1>\n {!isNew && (\n <Tag variant={table.isActive ? 'success' : 'neutral'} dot>\n {table.isActive ? t('common.active', 'Active') : t('common.inactive', 'Inactive')}\n </Tag>\n )}\n </div>\n {!isNew && mode === 'view' && (\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => exportPricingTableToXlsx(table, entries)}\n title={t('cpq.pricing.export.tooltip', 'Download this pricing table as an Excel file')}\n >\n <Download className=\"h-4 w-4 mr-1.5\" />\n {t('cpq.pricing.export.button', 'Export to Excel')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => fileInputRef.current?.click()}\n title={t('cpq.pricing.import.tooltip', 'Upload an Excel file to add / update / delete entries')}\n disabled={importDiff !== null}\n >\n <Upload className=\"h-4 w-4 mr-1.5\" />\n {t('cpq.pricing.import.button', 'Import from Excel')}\n </Button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".xlsx,.xls,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) void handleImportFile(file)\n // reset so re-uploading the same file fires onChange again\n e.target.value = ''\n }}\n />\n <Button type=\"button\" onClick={startEdit}>{t('common.edit', 'Edit')}</Button>\n <Button type=\"button\" variant=\"destructive\" onClick={deleteTable}>\n {t('common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && <Alert variant=\"destructive\">{error}</Alert>}\n\n {/* Excel import preview \u2014 shown after a file is parsed, hides until user confirms / cancels */}\n {importDiff && (\n <ImportPreview\n diff={importDiff}\n saving={importApplying}\n onConfirm={applyImportDiff}\n onCancel={cancelImport}\n />\n )}\n\n {/* Configuration section */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold\">Configuration</h2>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <ConfigField label=\"Code\" required>\n {editing ? (\n <Input\n value={view.code}\n onChange={(e) => setDraft({ ...draft, code: e.target.value })}\n placeholder=\"e.g. cloud-connect-pricing\"\n />\n ) : (\n <span className=\"font-mono text-sm\">{view.code}</span>\n )}\n </ConfigField>\n <ConfigField label=\"Name\" required>\n {editing ? (\n <Input\n value={view.name}\n onChange={(e) => setDraft({ ...draft, name: e.target.value })}\n placeholder=\"Cloud Connect Pricing\"\n />\n ) : (\n <span className=\"font-medium text-sm\">{view.name}</span>\n )}\n </ConfigField>\n <ConfigField label=\"Currencies (comma-separated)\" required>\n {editing ? (\n <Input\n value={view.currencyCodeList.join(', ')}\n onChange={(e) =>\n setDraft({\n ...draft,\n currencyCodeList: e.target.value\n .split(',')\n .map((s) => s.trim().toUpperCase())\n .filter(Boolean),\n })\n }\n placeholder=\"USD, EUR\"\n />\n ) : (\n <span className=\"text-sm\">{view.currencyCodeList.join(', ') || '\u2014'}</span>\n )}\n </ConfigField>\n <ConfigField label=\"Active\">\n {editing ? (\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={view.isActive}\n onChange={(e) => setDraft({ ...draft, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n {view.isActive ? 'Yes' : 'No'}\n </label>\n ) : (\n <span className=\"text-sm\">{view.isActive ? 'Yes' : 'No'}</span>\n )}\n </ConfigField>\n </div>\n\n <KeyLabelListEditor\n title=\"Dimensions\"\n description=\"Lookup keys for matching entries (e.g. region, tier). Leave empty if you use tier ranges only.\"\n items={view.dimensions}\n editing={editing}\n onChange={(dimensions) => setDraft({ ...draft, dimensions })}\n />\n\n <KeyLabelListEditor\n title=\"Price Columns\"\n description=\"Each price column becomes a numeric field on every entry. Charges reference one column by its key.\"\n items={view.priceColumns}\n editing={editing}\n onChange={(priceColumns) => setDraft({ ...draft, priceColumns })}\n />\n\n {editing && (\n <>\n {configValidationError && (\n <Alert variant=\"destructive\">{configValidationError}</Alert>\n )}\n <div className=\"flex gap-2 pt-2 border-t\">\n <Button\n type=\"button\"\n onClick={saveConfig}\n disabled={saving || configValidationError !== null}\n >\n {saving ? 'Saving...' : (isNew ? 'Create Pricing Table' : 'Save')}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={cancelEdit} disabled={saving}>\n Cancel\n </Button>\n </div>\n </>\n )}\n </div>\n\n {/* Entries section \u2014 only when table exists */}\n {!isNew && (\n <EntriesEditor\n table={{\n id: table.id,\n dimensions: table.dimensions,\n priceColumns: table.priceColumns,\n currencyCodeList: table.currencyCodeList,\n }}\n initialEntries={entries}\n onSaved={() => {\n void load()\n }}\n />\n )}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 ConfigField \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction ConfigField({\n label,\n required,\n children,\n}: {\n label: string\n required?: boolean\n children: React.ReactNode\n}) {\n return (\n <div>\n <div className=\"text-muted-foreground text-xs mb-1\">\n {label}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </div>\n <div>{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 KeyLabelListEditor (dimensions / price columns) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction KeyLabelListEditor({\n title,\n description,\n items,\n editing,\n onChange,\n}: {\n title: string\n description: string\n items: Array<{ key: string; label: string }>\n editing: boolean\n onChange: (next: Array<{ key: string; label: string }>) => void\n}) {\n return (\n <div className=\"space-y-2\">\n <div>\n <div className=\"text-sm font-medium\">{title}</div>\n <p className=\"text-xs text-muted-foreground\">{description}</p>\n </div>\n\n {items.length === 0 && !editing && (\n <div className=\"text-xs text-muted-foreground italic\">\u2014</div>\n )}\n\n {items.length > 0 && (\n <div className=\"rounded-md border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30 text-xs\">\n <th className=\"px-3 py-2 text-left font-medium\">\n Key {editing && <span className=\"text-destructive\">*</span>}\n </th>\n <th className=\"px-3 py-2 text-left font-medium\">\n Label {editing && <span className=\"text-destructive\">*</span>}\n </th>\n {editing && <th className=\"px-3 py-2 w-8\" aria-label=\"Actions\" />}\n </tr>\n </thead>\n <tbody>\n {items.map((item, idx) => (\n <tr key={idx} className=\"border-b last:border-0\">\n <td className=\"px-3 py-2\">\n {editing ? (\n <Input\n value={item.key}\n onChange={(e) => {\n const next = [...items]\n next[idx] = { ...item, key: e.target.value }\n onChange(next)\n }}\n placeholder=\"e.g. region\"\n className=\"h-8\"\n />\n ) : (\n <span className=\"font-mono text-xs\">{item.key}</span>\n )}\n </td>\n <td className=\"px-3 py-2\">\n {editing ? (\n <Input\n value={item.label}\n onChange={(e) => {\n const next = [...items]\n next[idx] = { ...item, label: e.target.value }\n onChange(next)\n }}\n placeholder=\"Region\"\n className=\"h-8\"\n />\n ) : (\n <span>{item.label}</span>\n )}\n </td>\n {editing && (\n <td className=\"px-3 py-2\">\n <button\n type=\"button\"\n onClick={() => onChange(items.filter((_, i) => i !== idx))}\n className=\"text-destructive hover:bg-destructive/10 rounded p-1\"\n aria-label=\"Remove\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {editing && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onChange([...items, { key: '', label: '' }])}\n >\n + Add {title.slice(0, -1)}\n </Button>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Download, Trash2, Upload } from 'lucide-react'\nimport { EntriesEditor, type Entry } from './EntriesEditor'\nimport { exportPricingTableToXlsx } from './xlsxExport'\nimport {\n commitImportDiff,\n parsePricingTableXlsx,\n type ImportDiff,\n} from './xlsxImport'\nimport { ImportPreview } from './ImportPreview'\n\ntype Dimension = { key: string; label: string }\ntype PriceColumn = { key: string; label: string }\n\ntype PricingTable = {\n id: string\n code: string\n name: string\n dimensions: Dimension[]\n priceColumns: PriceColumn[]\n currencyCodeList: string[]\n isActive: boolean\n}\n\nconst EMPTY_TABLE: PricingTable = {\n id: '',\n code: '',\n name: '',\n dimensions: [],\n priceColumns: [],\n currencyCodeList: ['USD'],\n isActive: true,\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nexport default function PricingTableDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const id = (props.params?.id ?? urlParams?.id) as string\n const isNew = id === 'new'\n\n const [table, setTable] = React.useState<PricingTable>(EMPTY_TABLE)\n const [entries, setEntries] = React.useState<Entry[]>([])\n const [loading, setLoading] = React.useState(!isNew)\n const [error, setError] = React.useState<string | null>(null)\n const [mode, setMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [draft, setDraft] = React.useState<PricingTable>(EMPTY_TABLE)\n const [saving, setSaving] = React.useState(false)\n\n // Import state\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n const [importDiff, setImportDiff] = React.useState<ImportDiff | null>(null)\n const [importApplying, setImportApplying] = React.useState(false)\n\n // \u2500\u2500\u2500 Load \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const load = React.useCallback(async () => {\n if (isNew) return\n if (!id || !UUID_RE.test(id)) {\n setError(t('cpq.pricing.detail.errors.invalidId', 'Invalid pricing table ID'))\n setLoading(false)\n return\n }\n setLoading(true)\n try {\n const res = await fetch(`/api/cpq/pricing-tables?id=${encodeURIComponent(id)}`)\n if (!res.ok) {\n setError(t('cpq.pricing.detail.errors.notFound', 'Pricing table not found'))\n return\n }\n const data = await res.json()\n const loaded: PricingTable = {\n id: data.id,\n code: data.code,\n name: data.name,\n dimensions: data.dimensions ?? [],\n priceColumns: data.priceColumns ?? [],\n currencyCodeList: data.currencyCodeList ?? ['USD'],\n isActive: data.isActive,\n }\n setTable(loaded)\n setDraft(loaded)\n setEntries(data.entries ?? [])\n } catch (err) {\n console.error('Failed to load pricing table', err)\n setError(t('cpq.pricing.detail.errors.loadFailed', 'Failed to load'))\n } finally {\n setLoading(false)\n }\n }, [id, isNew, t])\n\n React.useEffect(() => {\n void load()\n }, [load])\n\n // \u2500\u2500\u2500 Config CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const startEdit = () => {\n setDraft(table)\n setMode('edit')\n setError(null)\n }\n\n const cancelEdit = () => {\n if (isNew) {\n router.push('/backend/cpq/pricing')\n return\n }\n setDraft(table)\n setMode('view')\n setError(null)\n }\n\n // Mirror V-PT-1 from validators.ts so the user gets feedback before the\n // server rejects the payload.\n const configValidationError = React.useMemo(() => {\n if (!draft.code.trim()) return t('cpq.pricing.validation.codeRequired', 'Code is required')\n if (!draft.name.trim()) return t('cpq.pricing.validation.nameRequired', 'Name is required')\n if (draft.currencyCodeList.length === 0) {\n return t('cpq.pricing.validation.currencyRequired', 'At least one currency is required')\n }\n type ListMessages = {\n keyRequired: (index: number) => string\n labelRequired: (index: number) => string\n duplicateKey: (key: string) => string\n }\n const checkList = (items: Array<{ key: string; label: string }>, messages: ListMessages): string | null => {\n const seen = new Set<string>()\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n if (!item.key.trim()) return messages.keyRequired(i + 1)\n if (!item.label.trim()) return messages.labelRequired(i + 1)\n if (seen.has(item.key)) return messages.duplicateKey(item.key)\n seen.add(item.key)\n }\n return null\n }\n return (\n checkList(draft.dimensions, {\n keyRequired: (index) =>\n t('cpq.pricing.validation.dimensionKeyRequired', 'Dimension #{index}: key is required', { index }),\n labelRequired: (index) =>\n t('cpq.pricing.validation.dimensionLabelRequired', 'Dimension #{index}: label is required', { index }),\n duplicateKey: (key) =>\n t('cpq.pricing.validation.dimensionDuplicateKey', 'Dimension: duplicate key \"{key}\"', { key }),\n }) ??\n checkList(draft.priceColumns, {\n keyRequired: (index) =>\n t('cpq.pricing.validation.priceColumnKeyRequired', 'Price Column #{index}: key is required', { index }),\n labelRequired: (index) =>\n t('cpq.pricing.validation.priceColumnLabelRequired', 'Price Column #{index}: label is required', { index }),\n duplicateKey: (key) =>\n t('cpq.pricing.validation.priceColumnDuplicateKey', 'Price Column: duplicate key \"{key}\"', { key }),\n })\n )\n }, [draft, t])\n\n const saveConfig = async () => {\n if (configValidationError) {\n setError(configValidationError)\n return\n }\n setSaving(true)\n setError(null)\n try {\n const payload = {\n code: draft.code,\n name: draft.name,\n dimensions: draft.dimensions,\n priceColumns: draft.priceColumns,\n currencyCodeList: draft.currencyCodeList,\n isActive: draft.isActive,\n }\n const res = await fetch('/api/cpq/pricing-tables', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(isNew ? payload : { id, ...payload }),\n })\n if (!res.ok) {\n const body = await res.json().catch(() => ({}))\n setError(\n body.error ??\n (isNew\n ? t('cpq.pricing.detail.errors.createFailed', 'Failed to create pricing table')\n : t('cpq.pricing.detail.errors.saveFailed', 'Failed to save pricing table')),\n )\n return\n }\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/pricing/${saved.id}`)\n } else {\n setTable({ ...draft, id })\n setMode('view')\n }\n } catch (err) {\n console.error('Failed to save', err)\n setError(t('cpq.pricing.detail.errors.saveFailedGeneric', 'Failed to save'))\n } finally {\n setSaving(false)\n }\n }\n\n // \u2500\u2500\u2500 Excel import \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const handleImportFile = async (file: File) => {\n setError(null)\n const r = await parsePricingTableXlsx(\n file,\n {\n dimensions: table.dimensions,\n priceColumns: table.priceColumns,\n currencyCodeList: table.currencyCodeList,\n },\n entries,\n t,\n )\n if (!r.ok) {\n setError(r.error)\n return\n }\n setImportDiff(r.diff)\n }\n\n const applyImportDiff = async () => {\n if (!importDiff) return\n setImportApplying(true)\n setError(null)\n try {\n const r = await commitImportDiff(table.id, importDiff, t)\n if (!r.ok) {\n setError(r.error)\n return\n }\n setImportDiff(null)\n await load()\n } finally {\n setImportApplying(false)\n }\n }\n\n const cancelImport = () => {\n setImportDiff(null)\n if (fileInputRef.current) fileInputRef.current.value = ''\n }\n\n const deleteTable = async () => {\n if (!window.confirm(t('cpq.pricing.confirmDelete', 'Delete this pricing table and all its entries?'))) return\n try {\n const res = await fetch('/api/cpq/pricing-tables', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n if (res.ok) {\n router.push('/backend/cpq/pricing')\n } else {\n const body = await res.json().catch(() => ({}))\n setError(body.error ?? t('cpq.pricing.detail.errors.deleteFailed', 'Failed to delete'))\n }\n } catch {\n setError(t('cpq.pricing.detail.errors.deleteFailed', 'Failed to delete'))\n }\n }\n\n // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('cpq.common.loading', 'Loading...')}</div>\n }\n\n if (error && !isNew && !table.id) {\n return (\n <div className=\"space-y-4\">\n <button\n onClick={() => router.push('/backend/cpq/pricing')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('cpq.common.back', 'Back')}\n </button>\n <Alert variant=\"destructive\">{error}</Alert>\n </div>\n )\n }\n\n const editing = mode === 'edit'\n const view = editing ? draft : table\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/pricing')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('cpq.common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.pricing.new', 'New Pricing Table') : table.name}\n </h1>\n {!isNew && (\n <Tag variant={table.isActive ? 'success' : 'neutral'} dot>\n {table.isActive ? t('cpq.common.active', 'Active') : t('cpq.common.inactive', 'Inactive')}\n </Tag>\n )}\n </div>\n {!isNew && mode === 'view' && (\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => exportPricingTableToXlsx(table, entries)}\n title={t('cpq.pricing.export.tooltip', 'Download this pricing table as an Excel file')}\n >\n <Download className=\"h-4 w-4 mr-1.5\" />\n {t('cpq.pricing.export.button', 'Export to Excel')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => fileInputRef.current?.click()}\n title={t('cpq.pricing.import.tooltip', 'Upload an Excel file to add / update / delete entries')}\n disabled={importDiff !== null}\n >\n <Upload className=\"h-4 w-4 mr-1.5\" />\n {t('cpq.pricing.import.button', 'Import from Excel')}\n </Button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".xlsx,.xls,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) void handleImportFile(file)\n // reset so re-uploading the same file fires onChange again\n e.target.value = ''\n }}\n />\n <Button type=\"button\" onClick={startEdit}>{t('cpq.common.edit', 'Edit')}</Button>\n <Button type=\"button\" variant=\"destructive\" onClick={deleteTable}>\n {t('cpq.common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && <Alert variant=\"destructive\">{error}</Alert>}\n\n {/* Excel import preview \u2014 shown after a file is parsed, hides until user confirms / cancels */}\n {importDiff && (\n <ImportPreview\n diff={importDiff}\n saving={importApplying}\n onConfirm={applyImportDiff}\n onCancel={cancelImport}\n />\n )}\n\n {/* Configuration section */}\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold\">{t('cpq.pricing.detail.configuration', 'Configuration')}</h2>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <ConfigField label={t('cpq.pricing.code', 'Code')} required>\n {editing ? (\n <Input\n value={view.code}\n onChange={(e) => setDraft({ ...draft, code: e.target.value })}\n placeholder={t('cpq.pricing.detail.codePlaceholder', 'e.g. cloud-connect-pricing')}\n />\n ) : (\n <span className=\"font-mono text-sm\">{view.code}</span>\n )}\n </ConfigField>\n <ConfigField label={t('cpq.pricing.name', 'Name')} required>\n {editing ? (\n <Input\n value={view.name}\n onChange={(e) => setDraft({ ...draft, name: e.target.value })}\n placeholder={t('cpq.pricing.detail.namePlaceholder', 'Cloud Connect Pricing')}\n />\n ) : (\n <span className=\"font-medium text-sm\">{view.name}</span>\n )}\n </ConfigField>\n <ConfigField label={t('cpq.pricing.detail.currenciesCommaSeparated', 'Currencies (comma-separated)')} required>\n {editing ? (\n <Input\n value={view.currencyCodeList.join(', ')}\n onChange={(e) =>\n setDraft({\n ...draft,\n currencyCodeList: e.target.value\n .split(',')\n .map((s) => s.trim().toUpperCase())\n .filter(Boolean),\n })\n }\n placeholder={t('cpq.pricing.detail.currenciesPlaceholder', 'USD, EUR')}\n />\n ) : (\n <span className=\"text-sm\">{view.currencyCodeList.join(', ') || '\u2014'}</span>\n )}\n </ConfigField>\n <ConfigField label={t('cpq.common.active', 'Active')}>\n {editing ? (\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={view.isActive}\n onChange={(e) => setDraft({ ...draft, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n {view.isActive ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}\n </label>\n ) : (\n <span className=\"text-sm\">{view.isActive ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}</span>\n )}\n </ConfigField>\n </div>\n\n <KeyLabelListEditor\n title={t('cpq.pricing.detail.dimensions.title', 'Dimensions')}\n description={t(\n 'cpq.pricing.detail.dimensions.description',\n 'Lookup keys for matching entries (e.g. region, tier). Leave empty if you use tier ranges only.',\n )}\n addLabel={t('cpq.pricing.detail.dimensions.add', '+ Add Dimension')}\n items={view.dimensions}\n editing={editing}\n onChange={(dimensions) => setDraft({ ...draft, dimensions })}\n />\n\n <KeyLabelListEditor\n title={t('cpq.pricing.priceColumns', 'Price Columns')}\n description={t(\n 'cpq.pricing.detail.priceColumns.description',\n 'Each price column becomes a numeric field on every entry. Charges reference one column by its key.',\n )}\n addLabel={t('cpq.pricing.detail.priceColumns.add', '+ Add Price Column')}\n items={view.priceColumns}\n editing={editing}\n onChange={(priceColumns) => setDraft({ ...draft, priceColumns })}\n />\n\n {editing && (\n <>\n {configValidationError && (\n <Alert variant=\"destructive\">{configValidationError}</Alert>\n )}\n <div className=\"flex gap-2 pt-2 border-t\">\n <Button\n type=\"button\"\n onClick={saveConfig}\n disabled={saving || configValidationError !== null}\n >\n {saving\n ? t('cpq.common.saving', 'Saving...')\n : isNew\n ? t('cpq.pricing.detail.create', 'Create Pricing Table')\n : t('cpq.common.save', 'Save')}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={cancelEdit} disabled={saving}>\n {t('cpq.common.cancel', 'Cancel')}\n </Button>\n </div>\n </>\n )}\n </div>\n\n {/* Entries section \u2014 only when table exists */}\n {!isNew && (\n <EntriesEditor\n table={{\n id: table.id,\n dimensions: table.dimensions,\n priceColumns: table.priceColumns,\n currencyCodeList: table.currencyCodeList,\n }}\n initialEntries={entries}\n onSaved={() => {\n void load()\n }}\n />\n )}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 ConfigField \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction ConfigField({\n label,\n required,\n children,\n}: {\n label: string\n required?: boolean\n children: React.ReactNode\n}) {\n return (\n <div>\n <div className=\"text-muted-foreground text-xs mb-1\">\n {label}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </div>\n <div>{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 KeyLabelListEditor (dimensions / price columns) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction KeyLabelListEditor({\n title,\n description,\n addLabel,\n items,\n editing,\n onChange,\n}: {\n title: string\n description: string\n /** Translated \"+ Add \u2026\" button text, supplied by the caller. */\n addLabel: string\n items: Array<{ key: string; label: string }>\n editing: boolean\n onChange: (next: Array<{ key: string; label: string }>) => void\n}) {\n const t = useT()\n return (\n <div className=\"space-y-2\">\n <div>\n <div className=\"text-sm font-medium\">{title}</div>\n <p className=\"text-xs text-muted-foreground\">{description}</p>\n </div>\n\n {items.length === 0 && !editing && (\n <div className=\"text-xs text-muted-foreground italic\">\u2014</div>\n )}\n\n {items.length > 0 && (\n <div className=\"rounded-md border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30 text-xs\">\n <th className=\"px-3 py-2 text-left font-medium\">\n {t('cpq.pricing.detail.keyLabelList.key', 'Key')}{' '}\n {editing && <span className=\"text-destructive\">*</span>}\n </th>\n <th className=\"px-3 py-2 text-left font-medium\">\n {t('cpq.pricing.detail.keyLabelList.label', 'Label')}{' '}\n {editing && <span className=\"text-destructive\">*</span>}\n </th>\n {editing && <th className=\"px-3 py-2 w-8\" aria-label={t('cpq.pricing.detail.keyLabelList.actions', 'Actions')} />}\n </tr>\n </thead>\n <tbody>\n {items.map((item, idx) => (\n <tr key={idx} className=\"border-b last:border-0\">\n <td className=\"px-3 py-2\">\n {editing ? (\n <Input\n value={item.key}\n onChange={(e) => {\n const next = [...items]\n next[idx] = { ...item, key: e.target.value }\n onChange(next)\n }}\n placeholder={t('cpq.pricing.detail.keyLabelList.keyPlaceholder', 'e.g. region')}\n className=\"h-8\"\n />\n ) : (\n <span className=\"font-mono text-xs\">{item.key}</span>\n )}\n </td>\n <td className=\"px-3 py-2\">\n {editing ? (\n <Input\n value={item.label}\n onChange={(e) => {\n const next = [...items]\n next[idx] = { ...item, label: e.target.value }\n onChange(next)\n }}\n placeholder={t('cpq.pricing.detail.keyLabelList.labelPlaceholder', 'Region')}\n className=\"h-8\"\n />\n ) : (\n <span>{item.label}</span>\n )}\n </td>\n {editing && (\n <td className=\"px-3 py-2\">\n <button\n type=\"button\"\n onClick={() => onChange(items.filter((_, i) => i !== idx))}\n className=\"text-destructive hover:bg-destructive/10 rounded p-1\"\n aria-label={t('cpq.pricing.detail.keyLabelList.remove', 'Remove')}\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {editing && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onChange([...items, { key: '', label: '' }])}\n >\n {addLabel}\n </Button>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }