@dainamite/cpq 0.2.2

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 (504) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/LICENSE +21 -0
  3. package/MIGRATION.md +236 -0
  4. package/README.md +108 -0
  5. package/dist/modules/cpq/acl.js +30 -0
  6. package/dist/modules/cpq/acl.js.map +7 -0
  7. package/dist/modules/cpq/api/_helpers/handleArcError.js +37 -0
  8. package/dist/modules/cpq/api/_helpers/handleArcError.js.map +7 -0
  9. package/dist/modules/cpq/api/attribute-options/route.js +47 -0
  10. package/dist/modules/cpq/api/attribute-options/route.js.map +7 -0
  11. package/dist/modules/cpq/api/bundle-slots/route.js +101 -0
  12. package/dist/modules/cpq/api/bundle-slots/route.js.map +7 -0
  13. package/dist/modules/cpq/api/bundle-tree/route.js +28 -0
  14. package/dist/modules/cpq/api/bundle-tree/route.js.map +7 -0
  15. package/dist/modules/cpq/api/context.js +29 -0
  16. package/dist/modules/cpq/api/context.js.map +7 -0
  17. package/dist/modules/cpq/api/inventory/assets/route.js +113 -0
  18. package/dist/modules/cpq/api/inventory/assets/route.js.map +7 -0
  19. package/dist/modules/cpq/api/inventory/assets/status/route.js +35 -0
  20. package/dist/modules/cpq/api/inventory/assets/status/route.js.map +7 -0
  21. package/dist/modules/cpq/api/inventory/customer/[customerId]/parent-items/route.js +30 -0
  22. package/dist/modules/cpq/api/inventory/customer/[customerId]/parent-items/route.js.map +7 -0
  23. package/dist/modules/cpq/api/inventory/customer/[customerId]/route.js +31 -0
  24. package/dist/modules/cpq/api/inventory/customer/[customerId]/route.js.map +7 -0
  25. package/dist/modules/cpq/api/inventory/subscription-items/route.js +99 -0
  26. package/dist/modules/cpq/api/inventory/subscription-items/route.js.map +7 -0
  27. package/dist/modules/cpq/api/inventory/subscriptions/[subscriptionId]/change-log/route.js +57 -0
  28. package/dist/modules/cpq/api/inventory/subscriptions/[subscriptionId]/change-log/route.js.map +7 -0
  29. package/dist/modules/cpq/api/inventory/subscriptions/expiring/route.js +62 -0
  30. package/dist/modules/cpq/api/inventory/subscriptions/expiring/route.js.map +7 -0
  31. package/dist/modules/cpq/api/inventory/subscriptions/route.js +116 -0
  32. package/dist/modules/cpq/api/inventory/subscriptions/route.js.map +7 -0
  33. package/dist/modules/cpq/api/inventory/subscriptions/status/route.js +35 -0
  34. package/dist/modules/cpq/api/inventory/subscriptions/status/route.js.map +7 -0
  35. package/dist/modules/cpq/api/offering-components/route.js +91 -0
  36. package/dist/modules/cpq/api/offering-components/route.js.map +7 -0
  37. package/dist/modules/cpq/api/orders/[orderId]/activate/route.js +39 -0
  38. package/dist/modules/cpq/api/orders/[orderId]/activate/route.js.map +7 -0
  39. package/dist/modules/cpq/api/orders/[orderId]/route.js +28 -0
  40. package/dist/modules/cpq/api/orders/[orderId]/route.js.map +7 -0
  41. package/dist/modules/cpq/api/orders/[orderId]/status/route.js +38 -0
  42. package/dist/modules/cpq/api/orders/[orderId]/status/route.js.map +7 -0
  43. package/dist/modules/cpq/api/orders/route.js +71 -0
  44. package/dist/modules/cpq/api/orders/route.js.map +7 -0
  45. package/dist/modules/cpq/api/price-rules/route.js +180 -0
  46. package/dist/modules/cpq/api/price-rules/route.js.map +7 -0
  47. package/dist/modules/cpq/api/pricing-table-entries/route.js +142 -0
  48. package/dist/modules/cpq/api/pricing-table-entries/route.js.map +7 -0
  49. package/dist/modules/cpq/api/pricing-tables/route.js +179 -0
  50. package/dist/modules/cpq/api/pricing-tables/route.js.map +7 -0
  51. package/dist/modules/cpq/api/product-attributes/route.js +160 -0
  52. package/dist/modules/cpq/api/product-attributes/route.js.map +7 -0
  53. package/dist/modules/cpq/api/product-charges/route.js +166 -0
  54. package/dist/modules/cpq/api/product-charges/route.js.map +7 -0
  55. package/dist/modules/cpq/api/product-offerings/route.js +294 -0
  56. package/dist/modules/cpq/api/product-offerings/route.js.map +7 -0
  57. package/dist/modules/cpq/api/product-relationships/route.js +144 -0
  58. package/dist/modules/cpq/api/product-relationships/route.js.map +7 -0
  59. package/dist/modules/cpq/api/product-specifications/route.js +292 -0
  60. package/dist/modules/cpq/api/product-specifications/route.js.map +7 -0
  61. package/dist/modules/cpq/api/quotes/[quoteId]/cancel-meta/route.js +71 -0
  62. package/dist/modules/cpq/api/quotes/[quoteId]/cancel-meta/route.js.map +7 -0
  63. package/dist/modules/cpq/api/quotes/[quoteId]/clone/route.js +29 -0
  64. package/dist/modules/cpq/api/quotes/[quoteId]/clone/route.js.map +7 -0
  65. package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js +54 -0
  66. package/dist/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.js.map +7 -0
  67. package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js +27 -0
  68. package/dist/modules/cpq/api/quotes/[quoteId]/items/route.js.map +7 -0
  69. package/dist/modules/cpq/api/quotes/[quoteId]/merge-meta/route.js +72 -0
  70. package/dist/modules/cpq/api/quotes/[quoteId]/merge-meta/route.js.map +7 -0
  71. package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js +35 -0
  72. package/dist/modules/cpq/api/quotes/[quoteId]/recalculate/route.js.map +7 -0
  73. package/dist/modules/cpq/api/quotes/[quoteId]/route.js +102 -0
  74. package/dist/modules/cpq/api/quotes/[quoteId]/route.js.map +7 -0
  75. package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js +27 -0
  76. package/dist/modules/cpq/api/quotes/[quoteId]/status/route.js.map +7 -0
  77. package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/[targetId]/route.js +79 -0
  78. package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/[targetId]/route.js.map +7 -0
  79. package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/route.js +95 -0
  80. package/dist/modules/cpq/api/quotes/[quoteId]/target-subscriptions/route.js.map +7 -0
  81. package/dist/modules/cpq/api/quotes/attributes/route.js +52 -0
  82. package/dist/modules/cpq/api/quotes/attributes/route.js.map +7 -0
  83. package/dist/modules/cpq/api/quotes/from-subscription/route.js +72 -0
  84. package/dist/modules/cpq/api/quotes/from-subscription/route.js.map +7 -0
  85. package/dist/modules/cpq/api/quotes/price/route.js +69 -0
  86. package/dist/modules/cpq/api/quotes/price/route.js.map +7 -0
  87. package/dist/modules/cpq/api/quotes/route.js +97 -0
  88. package/dist/modules/cpq/api/quotes/route.js.map +7 -0
  89. package/dist/modules/cpq/api/quotes/validate-relationships/route.js +86 -0
  90. package/dist/modules/cpq/api/quotes/validate-relationships/route.js.map +7 -0
  91. package/dist/modules/cpq/api/resolveQuotingService.js +7 -0
  92. package/dist/modules/cpq/api/resolveQuotingService.js.map +7 -0
  93. package/dist/modules/cpq/api/wizards/resolve/route.js +38 -0
  94. package/dist/modules/cpq/api/wizards/resolve/route.js.map +7 -0
  95. package/dist/modules/cpq/api/wizards/route.js +111 -0
  96. package/dist/modules/cpq/api/wizards/route.js.map +7 -0
  97. package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +136 -0
  98. package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +7 -0
  99. package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +185 -0
  100. package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +7 -0
  101. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +343 -0
  102. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +7 -0
  103. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +13 -0
  104. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +7 -0
  105. package/dist/modules/cpq/backend/cpq/inventory/page.js +35 -0
  106. package/dist/modules/cpq/backend/cpq/inventory/page.js.map +7 -0
  107. package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +18 -0
  108. package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +7 -0
  109. package/dist/modules/cpq/backend/cpq/inventory/shared.js +20 -0
  110. package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +7 -0
  111. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +794 -0
  112. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +7 -0
  113. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +13 -0
  114. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +7 -0
  115. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +917 -0
  116. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +7 -0
  117. package/dist/modules/cpq/backend/cpq/offerings/page.js +405 -0
  118. package/dist/modules/cpq/backend/cpq/offerings/page.js.map +7 -0
  119. package/dist/modules/cpq/backend/cpq/offerings/page.meta.js +18 -0
  120. package/dist/modules/cpq/backend/cpq/offerings/page.meta.js.map +7 -0
  121. package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +677 -0
  122. package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +7 -0
  123. package/dist/modules/cpq/backend/cpq/orders/page.js +134 -0
  124. package/dist/modules/cpq/backend/cpq/orders/page.js.map +7 -0
  125. package/dist/modules/cpq/backend/cpq/orders/page.meta.js +18 -0
  126. package/dist/modules/cpq/backend/cpq/orders/page.meta.js.map +7 -0
  127. package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +272 -0
  128. package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +7 -0
  129. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +407 -0
  130. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +7 -0
  131. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +13 -0
  132. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +7 -0
  133. package/dist/modules/cpq/backend/cpq/price-rules/page.js +211 -0
  134. package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +7 -0
  135. package/dist/modules/cpq/backend/cpq/price-rules/page.meta.js +18 -0
  136. package/dist/modules/cpq/backend/cpq/price-rules/page.meta.js.map +7 -0
  137. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +275 -0
  138. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +7 -0
  139. package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +112 -0
  140. package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +7 -0
  141. package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +492 -0
  142. package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +7 -0
  143. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxExport.js +50 -0
  144. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxExport.js.map +7 -0
  145. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +249 -0
  146. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +7 -0
  147. package/dist/modules/cpq/backend/cpq/pricing/page.js +87 -0
  148. package/dist/modules/cpq/backend/cpq/pricing/page.js.map +7 -0
  149. package/dist/modules/cpq/backend/cpq/pricing/page.meta.js +18 -0
  150. package/dist/modules/cpq/backend/cpq/pricing/page.meta.js.map +7 -0
  151. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +652 -0
  152. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +7 -0
  153. package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +1289 -0
  154. package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +7 -0
  155. package/dist/modules/cpq/backend/cpq/quotes/page.js +283 -0
  156. package/dist/modules/cpq/backend/cpq/quotes/page.js.map +7 -0
  157. package/dist/modules/cpq/backend/cpq/quotes/page.meta.js +18 -0
  158. package/dist/modules/cpq/backend/cpq/quotes/page.meta.js.map +7 -0
  159. package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +214 -0
  160. package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +7 -0
  161. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +1399 -0
  162. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +7 -0
  163. package/dist/modules/cpq/backend/cpq/specifications/page.js +148 -0
  164. package/dist/modules/cpq/backend/cpq/specifications/page.js.map +7 -0
  165. package/dist/modules/cpq/backend/cpq/specifications/page.meta.js +18 -0
  166. package/dist/modules/cpq/backend/cpq/specifications/page.meta.js.map +7 -0
  167. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +204 -0
  168. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +7 -0
  169. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +191 -0
  170. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +7 -0
  171. package/dist/modules/cpq/backend/cpq/wizards/page.js +119 -0
  172. package/dist/modules/cpq/backend/cpq/wizards/page.js.map +7 -0
  173. package/dist/modules/cpq/backend/cpq/wizards/page.meta.js +18 -0
  174. package/dist/modules/cpq/backend/cpq/wizards/page.meta.js.map +7 -0
  175. package/dist/modules/cpq/ce.js +151 -0
  176. package/dist/modules/cpq/ce.js.map +7 -0
  177. package/dist/modules/cpq/cli.js +11 -0
  178. package/dist/modules/cpq/cli.js.map +7 -0
  179. package/dist/modules/cpq/components/CpqListView.js +265 -0
  180. package/dist/modules/cpq/components/CpqListView.js.map +7 -0
  181. package/dist/modules/cpq/components/NumberInput.js +95 -0
  182. package/dist/modules/cpq/components/NumberInput.js.map +7 -0
  183. package/dist/modules/cpq/components/StatusPath.js +60 -0
  184. package/dist/modules/cpq/components/StatusPath.js.map +7 -0
  185. package/dist/modules/cpq/components/statusMaps.js +66 -0
  186. package/dist/modules/cpq/components/statusMaps.js.map +7 -0
  187. package/dist/modules/cpq/components/useCpqRowActions.js +125 -0
  188. package/dist/modules/cpq/components/useCpqRowActions.js.map +7 -0
  189. package/dist/modules/cpq/data/entities.js +1556 -0
  190. package/dist/modules/cpq/data/entities.js.map +7 -0
  191. package/dist/modules/cpq/data/validators.js +575 -0
  192. package/dist/modules/cpq/data/validators.js.map +7 -0
  193. package/dist/modules/cpq/di.js +57 -0
  194. package/dist/modules/cpq/di.js.map +7 -0
  195. package/dist/modules/cpq/events.js +50 -0
  196. package/dist/modules/cpq/events.js.map +7 -0
  197. package/dist/modules/cpq/index.js +16 -0
  198. package/dist/modules/cpq/index.js.map +7 -0
  199. package/dist/modules/cpq/lib/seeds/api.js +32 -0
  200. package/dist/modules/cpq/lib/seeds/api.js.map +7 -0
  201. package/dist/modules/cpq/lib/seeds/tenant-provisioning.js +158 -0
  202. package/dist/modules/cpq/lib/seeds/tenant-provisioning.js.map +7 -0
  203. package/dist/modules/cpq/lib/seeds.js +6 -0
  204. package/dist/modules/cpq/lib/seeds.js.map +7 -0
  205. package/dist/modules/cpq/migrations/Migration20260220220000_cpq.js +40 -0
  206. package/dist/modules/cpq/migrations/Migration20260220220000_cpq.js.map +7 -0
  207. package/dist/modules/cpq/migrations/Migration20260330000000_cpq_product_domain.js +54 -0
  208. package/dist/modules/cpq/migrations/Migration20260330000000_cpq_product_domain.js.map +7 -0
  209. package/dist/modules/cpq/migrations/Migration20260331000000_cpq_charge_unique_per_offering.js +15 -0
  210. package/dist/modules/cpq/migrations/Migration20260331000000_cpq_charge_unique_per_offering.js.map +7 -0
  211. package/dist/modules/cpq/migrations/Migration20260401000000_cpq_quoting_v2.js +62 -0
  212. package/dist/modules/cpq/migrations/Migration20260401000000_cpq_quoting_v2.js.map +7 -0
  213. package/dist/modules/cpq/migrations/Migration20260402000000_cpq_workflows.js +56 -0
  214. package/dist/modules/cpq/migrations/Migration20260402000000_cpq_workflows.js.map +7 -0
  215. package/dist/modules/cpq/migrations/Migration20260407000000_cpq_pricing_tables_v2.js +26 -0
  216. package/dist/modules/cpq/migrations/Migration20260407000000_cpq_pricing_tables_v2.js.map +7 -0
  217. package/dist/modules/cpq/migrations/Migration20260407100000_cpq_price_rules.js +37 -0
  218. package/dist/modules/cpq/migrations/Migration20260407100000_cpq_price_rules.js.map +7 -0
  219. package/dist/modules/cpq/migrations/Migration20260408000000_cpq_price_rules.js +35 -0
  220. package/dist/modules/cpq/migrations/Migration20260408000000_cpq_price_rules.js.map +7 -0
  221. package/dist/modules/cpq/migrations/Migration20260410000000_cpq_drop_datacentres_inventory.js +21 -0
  222. package/dist/modules/cpq/migrations/Migration20260410000000_cpq_drop_datacentres_inventory.js.map +7 -0
  223. package/dist/modules/cpq/migrations/Migration20260410000000_cpq_wizard_rename.js +46 -0
  224. package/dist/modules/cpq/migrations/Migration20260410000000_cpq_wizard_rename.js.map +7 -0
  225. package/dist/modules/cpq/migrations/Migration20260410100000_cpq_inventory.js +118 -0
  226. package/dist/modules/cpq/migrations/Migration20260410100000_cpq_inventory.js.map +7 -0
  227. package/dist/modules/cpq/migrations/Migration20260411000000_cpq_orders.js +63 -0
  228. package/dist/modules/cpq/migrations/Migration20260411000000_cpq_orders.js.map +7 -0
  229. package/dist/modules/cpq/migrations/Migration20260412000000_cpq_bundled_offerings.js +28 -0
  230. package/dist/modules/cpq/migrations/Migration20260412000000_cpq_bundled_offerings.js.map +7 -0
  231. package/dist/modules/cpq/migrations/Migration20260504064621_cpq_arc.js +36 -0
  232. package/dist/modules/cpq/migrations/Migration20260504064621_cpq_arc.js.map +7 -0
  233. package/dist/modules/cpq/migrations/Migration20260514000000_cpq_spec_merge_retired_deprecated.js +14 -0
  234. package/dist/modules/cpq/migrations/Migration20260514000000_cpq_spec_merge_retired_deprecated.js.map +7 -0
  235. package/dist/modules/cpq/migrations/Migration20260514100000_cpq_offering_merge_retired_deprecated.js +14 -0
  236. package/dist/modules/cpq/migrations/Migration20260514100000_cpq_offering_merge_retired_deprecated.js.map +7 -0
  237. package/dist/modules/cpq/migrations/Migration20260514110000_cpq_list_search_indexes.js +58 -0
  238. package/dist/modules/cpq/migrations/Migration20260514110000_cpq_list_search_indexes.js.map +7 -0
  239. package/dist/modules/cpq/migrations/Migration20260515000000_cpq_inventory_subscriptions_search_indexes.js +29 -0
  240. package/dist/modules/cpq/migrations/Migration20260515000000_cpq_inventory_subscriptions_search_indexes.js.map +7 -0
  241. package/dist/modules/cpq/services/cpqBundleService.js +447 -0
  242. package/dist/modules/cpq/services/cpqBundleService.js.map +7 -0
  243. package/dist/modules/cpq/services/cpqInventoryService.js +1371 -0
  244. package/dist/modules/cpq/services/cpqInventoryService.js.map +7 -0
  245. package/dist/modules/cpq/services/cpqOrderService.js +901 -0
  246. package/dist/modules/cpq/services/cpqOrderService.js.map +7 -0
  247. package/dist/modules/cpq/services/cpqPricingService.js +289 -0
  248. package/dist/modules/cpq/services/cpqPricingService.js.map +7 -0
  249. package/dist/modules/cpq/services/cpqProductService.js +204 -0
  250. package/dist/modules/cpq/services/cpqProductService.js.map +7 -0
  251. package/dist/modules/cpq/services/cpqQuotingService.js +1867 -0
  252. package/dist/modules/cpq/services/cpqQuotingService.js.map +7 -0
  253. package/dist/modules/cpq/services/cpqValidationService.js +234 -0
  254. package/dist/modules/cpq/services/cpqValidationService.js.map +7 -0
  255. package/dist/modules/cpq/services/cpqWizardService.js +137 -0
  256. package/dist/modules/cpq/services/cpqWizardService.js.map +7 -0
  257. package/dist/modules/cpq/services/types.js +114 -0
  258. package/dist/modules/cpq/services/types.js.map +7 -0
  259. package/dist/modules/cpq/setup.js +49 -0
  260. package/dist/modules/cpq/setup.js.map +7 -0
  261. package/dist/modules/cpq/subscribers/subscription-amended-log.js +18 -0
  262. package/dist/modules/cpq/subscribers/subscription-amended-log.js.map +7 -0
  263. package/dist/modules/cpq/subscribers/subscription-cancelled-log.js +19 -0
  264. package/dist/modules/cpq/subscribers/subscription-cancelled-log.js.map +7 -0
  265. package/dist/modules/cpq/subscribers/subscription-merged-log.js +20 -0
  266. package/dist/modules/cpq/subscribers/subscription-merged-log.js.map +7 -0
  267. package/dist/modules/cpq/subscribers/subscription-renewed-log.js +18 -0
  268. package/dist/modules/cpq/subscribers/subscription-renewed-log.js.map +7 -0
  269. package/dist/modules/cpq/subscribers/subscription-superseded-log.js +18 -0
  270. package/dist/modules/cpq/subscribers/subscription-superseded-log.js.map +7 -0
  271. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +192 -0
  272. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +7 -0
  273. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.js +17 -0
  274. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.js.map +7 -0
  275. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +79 -0
  276. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +7 -0
  277. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.js +17 -0
  278. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.js.map +7 -0
  279. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +181 -0
  280. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +7 -0
  281. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.js +17 -0
  282. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.js.map +7 -0
  283. package/dist/modules/cpq/widgets/injection-table.js +44 -0
  284. package/dist/modules/cpq/widgets/injection-table.js.map +7 -0
  285. package/dist/modules/cpq/workflows/WizardRunner.js +113 -0
  286. package/dist/modules/cpq/workflows/WizardRunner.js.map +7 -0
  287. package/dist/modules/cpq/workflows/WizardTrigger.js +116 -0
  288. package/dist/modules/cpq/workflows/WizardTrigger.js.map +7 -0
  289. package/dist/modules/cpq/workflows/engine.js +188 -0
  290. package/dist/modules/cpq/workflows/engine.js.map +7 -0
  291. package/dist/modules/cpq/workflows/registry.js +16 -0
  292. package/dist/modules/cpq/workflows/registry.js.map +7 -0
  293. package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +119 -0
  294. package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +7 -0
  295. package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +24 -0
  296. package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +7 -0
  297. package/dist/modules/cpq/workflows/steps/ItemListStep.js +115 -0
  298. package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +7 -0
  299. package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +327 -0
  300. package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +7 -0
  301. package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +231 -0
  302. package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +7 -0
  303. package/dist/modules/cpq/workflows/steps/ReviewStep.js +152 -0
  304. package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +7 -0
  305. package/dist/modules/cpq/workflows/steps/index.js +49 -0
  306. package/dist/modules/cpq/workflows/steps/index.js.map +7 -0
  307. package/dist/modules/cpq/workflows/types.js +1 -0
  308. package/dist/modules/cpq/workflows/types.js.map +7 -0
  309. package/package.json +150 -0
  310. package/src/modules/cpq/__integration__/TC-CPQ-001.spec.ts +177 -0
  311. package/src/modules/cpq/__integration__/TC-CPQ-002.spec.ts +123 -0
  312. package/src/modules/cpq/__integration__/TC-CPQ-003.spec.ts +115 -0
  313. package/src/modules/cpq/__integration__/TC-CPQ-004.spec.ts +184 -0
  314. package/src/modules/cpq/__integration__/TC-CPQ-005.spec.ts +43 -0
  315. package/src/modules/cpq/__integration__/TC-CPQ-006.spec.ts +87 -0
  316. package/src/modules/cpq/__integration__/TC-CPQ-007.spec.ts +79 -0
  317. package/src/modules/cpq/__integration__/TC-CPQ-008.spec.ts +55 -0
  318. package/src/modules/cpq/__integration__/TC-CPQ-009.spec.ts +45 -0
  319. package/src/modules/cpq/__integration__/TC-CPQ-010.spec.ts +54 -0
  320. package/src/modules/cpq/__integration__/TC-CPQ-011.spec.ts +24 -0
  321. package/src/modules/cpq/__integration__/TC-CPQ-012.spec.ts +62 -0
  322. package/src/modules/cpq/__integration__/TC-CPQ-ARC-001.spec.ts +52 -0
  323. package/src/modules/cpq/__integration__/TC-CPQ-ARC-002.spec.ts +65 -0
  324. package/src/modules/cpq/__integration__/TC-CPQ-ARC-003.spec.ts +107 -0
  325. package/src/modules/cpq/__integration__/TC-CPQ-ARC-004.spec.ts +74 -0
  326. package/src/modules/cpq/__integration__/TC-CPQ-ARC-005.spec.ts +86 -0
  327. package/src/modules/cpq/__integration__/TC-CPQ-ARC-006.spec.ts +79 -0
  328. package/src/modules/cpq/__integration__/TC-CPQ-ARC-007.spec.ts +63 -0
  329. package/src/modules/cpq/__integration__/TC-CPQ-ARC-008.spec.ts +62 -0
  330. package/src/modules/cpq/__integration__/TC-CPQ-ARC-009.spec.ts +62 -0
  331. package/src/modules/cpq/__integration__/TC-CPQ-ARC-010.spec.ts +59 -0
  332. package/src/modules/cpq/__integration__/TC-CPQ-ARC-011.spec.ts +128 -0
  333. package/src/modules/cpq/__integration__/_helpers/cpqArcFixtures.ts +208 -0
  334. package/src/modules/cpq/__tests__/package-isolation.test.ts +232 -0
  335. package/src/modules/cpq/acl.ts +26 -0
  336. package/src/modules/cpq/api/_helpers/__tests__/handleArcError.test.ts +117 -0
  337. package/src/modules/cpq/api/_helpers/handleArcError.ts +81 -0
  338. package/src/modules/cpq/api/attribute-options/route.ts +55 -0
  339. package/src/modules/cpq/api/bundle-slots/route.ts +112 -0
  340. package/src/modules/cpq/api/bundle-tree/route.ts +31 -0
  341. package/src/modules/cpq/api/context.ts +39 -0
  342. package/src/modules/cpq/api/inventory/assets/route.ts +123 -0
  343. package/src/modules/cpq/api/inventory/assets/status/route.ts +34 -0
  344. package/src/modules/cpq/api/inventory/customer/[customerId]/parent-items/route.ts +30 -0
  345. package/src/modules/cpq/api/inventory/customer/[customerId]/route.ts +31 -0
  346. package/src/modules/cpq/api/inventory/subscription-items/route.ts +107 -0
  347. package/src/modules/cpq/api/inventory/subscriptions/[subscriptionId]/change-log/route.ts +64 -0
  348. package/src/modules/cpq/api/inventory/subscriptions/expiring/route.ts +66 -0
  349. package/src/modules/cpq/api/inventory/subscriptions/route.ts +126 -0
  350. package/src/modules/cpq/api/inventory/subscriptions/status/route.ts +34 -0
  351. package/src/modules/cpq/api/offering-components/route.ts +103 -0
  352. package/src/modules/cpq/api/orders/[orderId]/activate/route.ts +48 -0
  353. package/src/modules/cpq/api/orders/[orderId]/route.ts +28 -0
  354. package/src/modules/cpq/api/orders/[orderId]/status/route.ts +38 -0
  355. package/src/modules/cpq/api/orders/route.ts +77 -0
  356. package/src/modules/cpq/api/price-rules/route.ts +210 -0
  357. package/src/modules/cpq/api/pricing-table-entries/route.ts +159 -0
  358. package/src/modules/cpq/api/pricing-tables/route.ts +202 -0
  359. package/src/modules/cpq/api/product-attributes/route.ts +175 -0
  360. package/src/modules/cpq/api/product-charges/route.ts +181 -0
  361. package/src/modules/cpq/api/product-offerings/route.ts +329 -0
  362. package/src/modules/cpq/api/product-relationships/route.ts +156 -0
  363. package/src/modules/cpq/api/product-specifications/route.ts +325 -0
  364. package/src/modules/cpq/api/quotes/[quoteId]/cancel-meta/route.ts +77 -0
  365. package/src/modules/cpq/api/quotes/[quoteId]/clone/route.ts +28 -0
  366. package/src/modules/cpq/api/quotes/[quoteId]/items/[lineId]/route.ts +55 -0
  367. package/src/modules/cpq/api/quotes/[quoteId]/items/route.ts +26 -0
  368. package/src/modules/cpq/api/quotes/[quoteId]/merge-meta/route.ts +78 -0
  369. package/src/modules/cpq/api/quotes/[quoteId]/recalculate/route.ts +34 -0
  370. package/src/modules/cpq/api/quotes/[quoteId]/route.ts +109 -0
  371. package/src/modules/cpq/api/quotes/[quoteId]/status/route.ts +26 -0
  372. package/src/modules/cpq/api/quotes/[quoteId]/target-subscriptions/[targetId]/route.ts +91 -0
  373. package/src/modules/cpq/api/quotes/[quoteId]/target-subscriptions/route.ts +107 -0
  374. package/src/modules/cpq/api/quotes/attributes/route.ts +61 -0
  375. package/src/modules/cpq/api/quotes/from-subscription/route.ts +85 -0
  376. package/src/modules/cpq/api/quotes/price/route.ts +81 -0
  377. package/src/modules/cpq/api/quotes/route.ts +114 -0
  378. package/src/modules/cpq/api/quotes/validate-relationships/route.ts +100 -0
  379. package/src/modules/cpq/api/resolveQuotingService.ts +11 -0
  380. package/src/modules/cpq/api/wizards/resolve/route.ts +39 -0
  381. package/src/modules/cpq/api/wizards/route.ts +127 -0
  382. package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +166 -0
  383. package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +251 -0
  384. package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +9 -0
  385. package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +440 -0
  386. package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +16 -0
  387. package/src/modules/cpq/backend/cpq/inventory/page.tsx +49 -0
  388. package/src/modules/cpq/backend/cpq/inventory/shared.tsx +32 -0
  389. package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +9 -0
  390. package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +1085 -0
  391. package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +1165 -0
  392. package/src/modules/cpq/backend/cpq/offerings/page.meta.ts +16 -0
  393. package/src/modules/cpq/backend/cpq/offerings/page.tsx +468 -0
  394. package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +921 -0
  395. package/src/modules/cpq/backend/cpq/orders/page.meta.ts +16 -0
  396. package/src/modules/cpq/backend/cpq/orders/page.tsx +182 -0
  397. package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +310 -0
  398. package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +9 -0
  399. package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +472 -0
  400. package/src/modules/cpq/backend/cpq/price-rules/page.meta.ts +16 -0
  401. package/src/modules/cpq/backend/cpq/price-rules/page.tsx +253 -0
  402. package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +431 -0
  403. package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +122 -0
  404. package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +588 -0
  405. package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxExport.ts +90 -0
  406. package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +338 -0
  407. package/src/modules/cpq/backend/cpq/pricing/page.meta.ts +16 -0
  408. package/src/modules/cpq/backend/cpq/pricing/page.tsx +111 -0
  409. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +737 -0
  410. package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +1721 -0
  411. package/src/modules/cpq/backend/cpq/quotes/page.meta.ts +16 -0
  412. package/src/modules/cpq/backend/cpq/quotes/page.tsx +370 -0
  413. package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +300 -0
  414. package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +1722 -0
  415. package/src/modules/cpq/backend/cpq/specifications/page.meta.ts +16 -0
  416. package/src/modules/cpq/backend/cpq/specifications/page.tsx +191 -0
  417. package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +319 -0
  418. package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +234 -0
  419. package/src/modules/cpq/backend/cpq/wizards/page.meta.ts +16 -0
  420. package/src/modules/cpq/backend/cpq/wizards/page.tsx +141 -0
  421. package/src/modules/cpq/ce.ts +150 -0
  422. package/src/modules/cpq/cli.ts +10 -0
  423. package/src/modules/cpq/components/CpqListView.tsx +431 -0
  424. package/src/modules/cpq/components/NumberInput.tsx +166 -0
  425. package/src/modules/cpq/components/StatusPath.tsx +116 -0
  426. package/src/modules/cpq/components/statusMaps.ts +148 -0
  427. package/src/modules/cpq/components/useCpqRowActions.tsx +183 -0
  428. package/src/modules/cpq/data/__tests__/validators.arc.test.ts +271 -0
  429. package/src/modules/cpq/data/__tests__/validators.test.ts +782 -0
  430. package/src/modules/cpq/data/entities.ts +1467 -0
  431. package/src/modules/cpq/data/validators.ts +663 -0
  432. package/src/modules/cpq/di.ts +70 -0
  433. package/src/modules/cpq/events.ts +62 -0
  434. package/src/modules/cpq/index.ts +15 -0
  435. package/src/modules/cpq/lib/seeds/__tests__/api.test.ts +86 -0
  436. package/src/modules/cpq/lib/seeds/__tests__/tenant-provisioning.test.ts +349 -0
  437. package/src/modules/cpq/lib/seeds/api.ts +119 -0
  438. package/src/modules/cpq/lib/seeds/tenant-provisioning.ts +239 -0
  439. package/src/modules/cpq/lib/seeds.ts +18 -0
  440. package/src/modules/cpq/migrations/.snapshot-open-mercato.json +7473 -0
  441. package/src/modules/cpq/migrations/Migration20260220220000_cpq.ts +51 -0
  442. package/src/modules/cpq/migrations/Migration20260330000000_cpq_product_domain.ts +70 -0
  443. package/src/modules/cpq/migrations/Migration20260331000000_cpq_charge_unique_per_offering.ts +15 -0
  444. package/src/modules/cpq/migrations/Migration20260401000000_cpq_quoting_v2.ts +73 -0
  445. package/src/modules/cpq/migrations/Migration20260402000000_cpq_workflows.ts +59 -0
  446. package/src/modules/cpq/migrations/Migration20260407000000_cpq_pricing_tables_v2.ts +30 -0
  447. package/src/modules/cpq/migrations/Migration20260407100000_cpq_price_rules.ts +36 -0
  448. package/src/modules/cpq/migrations/Migration20260408000000_cpq_price_rules.ts +33 -0
  449. package/src/modules/cpq/migrations/Migration20260410000000_cpq_drop_datacentres_inventory.ts +22 -0
  450. package/src/modules/cpq/migrations/Migration20260410000000_cpq_wizard_rename.ts +56 -0
  451. package/src/modules/cpq/migrations/Migration20260410100000_cpq_inventory.ts +118 -0
  452. package/src/modules/cpq/migrations/Migration20260411000000_cpq_orders.ts +62 -0
  453. package/src/modules/cpq/migrations/Migration20260412000000_cpq_bundled_offerings.ts +33 -0
  454. package/src/modules/cpq/migrations/Migration20260504064621_cpq_arc.ts +68 -0
  455. package/src/modules/cpq/migrations/Migration20260514000000_cpq_spec_merge_retired_deprecated.ts +30 -0
  456. package/src/modules/cpq/migrations/Migration20260514100000_cpq_offering_merge_retired_deprecated.ts +27 -0
  457. package/src/modules/cpq/migrations/Migration20260514110000_cpq_list_search_indexes.ts +82 -0
  458. package/src/modules/cpq/migrations/Migration20260515000000_cpq_inventory_subscriptions_search_indexes.ts +52 -0
  459. package/src/modules/cpq/services/__tests__/_helpers/mockEm.ts +59 -0
  460. package/src/modules/cpq/services/__tests__/cpqBundleService.test.ts +661 -0
  461. package/src/modules/cpq/services/__tests__/cpqInventoryService.arc.test.ts +357 -0
  462. package/src/modules/cpq/services/__tests__/cpqInventoryService.test.ts +718 -0
  463. package/src/modules/cpq/services/__tests__/cpqOrderService.test.ts +603 -0
  464. package/src/modules/cpq/services/__tests__/cpqPricingService.test.ts +1012 -0
  465. package/src/modules/cpq/services/__tests__/cpqProductService.test.ts +603 -0
  466. package/src/modules/cpq/services/__tests__/cpqQuotingService.arc.test.ts +143 -0
  467. package/src/modules/cpq/services/__tests__/cpqQuotingService.test.ts +658 -0
  468. package/src/modules/cpq/services/__tests__/cpqValidationService.test.ts +811 -0
  469. package/src/modules/cpq/services/__tests__/cpqWizardService.test.ts +389 -0
  470. package/src/modules/cpq/services/__tests__/types.test.ts +359 -0
  471. package/src/modules/cpq/services/cpqBundleService.ts +671 -0
  472. package/src/modules/cpq/services/cpqInventoryService.ts +1929 -0
  473. package/src/modules/cpq/services/cpqOrderService.ts +1230 -0
  474. package/src/modules/cpq/services/cpqPricingService.ts +412 -0
  475. package/src/modules/cpq/services/cpqProductService.ts +311 -0
  476. package/src/modules/cpq/services/cpqQuotingService.ts +2638 -0
  477. package/src/modules/cpq/services/cpqValidationService.ts +323 -0
  478. package/src/modules/cpq/services/cpqWizardService.ts +204 -0
  479. package/src/modules/cpq/services/types.ts +303 -0
  480. package/src/modules/cpq/setup.ts +63 -0
  481. package/src/modules/cpq/subscribers/subscription-amended-log.ts +20 -0
  482. package/src/modules/cpq/subscribers/subscription-cancelled-log.ts +19 -0
  483. package/src/modules/cpq/subscribers/subscription-merged-log.ts +22 -0
  484. package/src/modules/cpq/subscribers/subscription-renewed-log.ts +18 -0
  485. package/src/modules/cpq/subscribers/subscription-superseded-log.ts +19 -0
  486. package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +339 -0
  487. package/src/modules/cpq/widgets/injection/customer-inventory/widget.ts +16 -0
  488. package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +96 -0
  489. package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.ts +16 -0
  490. package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +265 -0
  491. package/src/modules/cpq/widgets/injection/quote-configurator/widget.ts +16 -0
  492. package/src/modules/cpq/widgets/injection-table.ts +42 -0
  493. package/src/modules/cpq/workflows/WizardRunner.tsx +158 -0
  494. package/src/modules/cpq/workflows/WizardTrigger.tsx +142 -0
  495. package/src/modules/cpq/workflows/engine.tsx +278 -0
  496. package/src/modules/cpq/workflows/registry.ts +15 -0
  497. package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +136 -0
  498. package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +34 -0
  499. package/src/modules/cpq/workflows/steps/ItemListStep.tsx +146 -0
  500. package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +438 -0
  501. package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +287 -0
  502. package/src/modules/cpq/workflows/steps/ReviewStep.tsx +219 -0
  503. package/src/modules/cpq/workflows/steps/index.ts +51 -0
  504. package/src/modules/cpq/workflows/types.ts +102 -0
@@ -0,0 +1,192 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import { Tag } from "@open-mercato/ui/primitives/tag";
6
+ import {
7
+ assetStatusMap,
8
+ formatStatusLabel,
9
+ subscriptionStatusMap
10
+ } from "../../../components/statusMaps.js";
11
+ function fmt(amount, currency) {
12
+ return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
13
+ }
14
+ function StatusBadge({ status }) {
15
+ const variant = subscriptionStatusMap[status] ?? assetStatusMap[status] ?? "neutral";
16
+ return /* @__PURE__ */ jsx(Tag, { variant, dot: true, children: formatStatusLabel(status) });
17
+ }
18
+ function CustomerInventoryWidget({ data, context }) {
19
+ const router = useRouter();
20
+ const record = data;
21
+ const companyRecord = record?.company;
22
+ const customerId = context?.companyId ?? context?.resourceId ?? companyRecord?.id ?? record?.id ?? null;
23
+ const [inventory, setInventory] = React.useState(null);
24
+ const [loading, setLoading] = React.useState(true);
25
+ const [activeTab, setActiveTab] = React.useState("subscriptions");
26
+ React.useEffect(() => {
27
+ if (!customerId) {
28
+ setLoading(false);
29
+ return;
30
+ }
31
+ let cancelled = false;
32
+ async function load() {
33
+ try {
34
+ const res = await fetch(`/api/cpq/inventory/customer/${customerId}`);
35
+ if (res.ok && !cancelled) setInventory(await res.json());
36
+ } catch {
37
+ } finally {
38
+ if (!cancelled) setLoading(false);
39
+ }
40
+ }
41
+ load();
42
+ return () => {
43
+ cancelled = true;
44
+ };
45
+ }, [customerId]);
46
+ if (!customerId) return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-muted-foreground", children: "No customer context available." });
47
+ if (loading) {
48
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-6 text-sm text-muted-foreground", children: [
49
+ /* @__PURE__ */ jsx(Spinner, {}),
50
+ " Loading inventory\u2026"
51
+ ] });
52
+ }
53
+ if (!inventory || inventory.subscriptions.length === 0 && inventory.assets.length === 0) {
54
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 px-4", children: [
55
+ /* @__PURE__ */ jsx("div", { className: "rounded-full bg-primary/10 p-3 mb-3", children: /* @__PURE__ */ jsx("svg", { className: "h-6 w-6 text-primary", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" }) }) }),
56
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No inventory records found." })
57
+ ] });
58
+ }
59
+ const { summary } = inventory;
60
+ const currency = summary.currencyCode || "USD";
61
+ const tabs = [
62
+ { key: "subscriptions", label: "Subscriptions", count: inventory.subscriptions.length },
63
+ { key: "items", label: "Subscription Items", count: inventory.subscriptionItems.length },
64
+ { key: "assets", label: "Assets", count: inventory.assets.length }
65
+ ];
66
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
67
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-3", children: [
68
+ /* @__PURE__ */ jsx(SummaryCard, { label: "Active Subscriptions", value: String(summary.activeSubscriptions) }),
69
+ /* @__PURE__ */ jsx(SummaryCard, { label: "Total MRC", value: fmt(summary.totalMrc, currency), mono: true }),
70
+ /* @__PURE__ */ jsx(SummaryCard, { label: "Active Assets", value: String(summary.activeAssets) }),
71
+ /* @__PURE__ */ jsx(SummaryCard, { label: "Pending Items", value: String(summary.pendingItems) })
72
+ ] }),
73
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1 border-b", children: tabs.map((tab) => /* @__PURE__ */ jsxs(
74
+ "button",
75
+ {
76
+ onClick: () => setActiveTab(tab.key),
77
+ className: `px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${activeTab === tab.key ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
78
+ children: [
79
+ tab.label,
80
+ /* @__PURE__ */ jsx("span", { className: "ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs", children: tab.count })
81
+ ]
82
+ },
83
+ tab.key
84
+ )) }),
85
+ activeTab === "subscriptions" && /* @__PURE__ */ jsx(SubscriptionsTable, { items: inventory.subscriptions, currency, onOpen: (id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`) }),
86
+ activeTab === "items" && /* @__PURE__ */ jsx(SubscriptionItemsTable, { items: inventory.subscriptionItems, currency, onOpen: (id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`) }),
87
+ activeTab === "assets" && /* @__PURE__ */ jsx(AssetsTable, { items: inventory.assets, currency, onOpen: (id) => router.push(`/backend/cpq/inventory/assets/${id}`) }),
88
+ /* @__PURE__ */ jsx("div", { className: "pt-2 text-right", children: /* @__PURE__ */ jsx("a", { href: "/backend/cpq/inventory", className: "text-sm text-primary hover:underline", children: "View full inventory \u2192" }) })
89
+ ] });
90
+ }
91
+ function SummaryCard({ label, value, mono }) {
92
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-3", children: [
93
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: label }),
94
+ /* @__PURE__ */ jsx("p", { className: `text-lg font-semibold ${mono ? "font-mono" : ""}`, children: value })
95
+ ] });
96
+ }
97
+ function SubscriptionsTable({ items, currency, onOpen }) {
98
+ if (items.length === 0) return /* @__PURE__ */ jsx(EmptyTab, {});
99
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
100
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-muted-foreground", children: [
101
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Name" }),
102
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Status" }),
103
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "MRC" }),
104
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Billing" }),
105
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Start Date" }),
106
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Term End" })
107
+ ] }) }),
108
+ /* @__PURE__ */ jsx("tbody", { children: items.map((s) => /* @__PURE__ */ jsxs(
109
+ "tr",
110
+ {
111
+ onClick: () => onOpen(s.id),
112
+ className: "border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors",
113
+ children: [
114
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-medium", children: s.name }),
115
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(StatusBadge, { status: s.status }) }),
116
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right font-mono", children: fmt(s.mrcAmount, s.currencyCode || currency) }),
117
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 capitalize", children: s.billingCycle }),
118
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-muted-foreground", children: s.startDate ? new Date(s.startDate).toLocaleDateString() : "\u2014" }),
119
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-muted-foreground", children: s.currentTermEnd ? new Date(s.currentTermEnd).toLocaleDateString() : "\u2014" })
120
+ ]
121
+ },
122
+ s.id
123
+ )) })
124
+ ] }) });
125
+ }
126
+ function SubscriptionItemsTable({ items, currency, onOpen }) {
127
+ if (items.length === 0) return /* @__PURE__ */ jsx(EmptyTab, {});
128
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
129
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-muted-foreground", children: [
130
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Name" }),
131
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Status" }),
132
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "MRC" }),
133
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "NRC" }),
134
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "Qty" })
135
+ ] }) }),
136
+ /* @__PURE__ */ jsx("tbody", { children: items.map((item) => /* @__PURE__ */ jsxs(
137
+ "tr",
138
+ {
139
+ onClick: () => onOpen(item.subscriptionId),
140
+ className: "border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors",
141
+ children: [
142
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-medium", children: item.name }),
143
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(StatusBadge, { status: item.status }) }),
144
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right font-mono", children: fmt(item.mrcAmount, item.currencyCode || currency) }),
145
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right font-mono", children: fmt(item.nrcAmount, item.currencyCode || currency) }),
146
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right font-mono", children: item.quantity })
147
+ ]
148
+ },
149
+ item.id
150
+ )) })
151
+ ] }) });
152
+ }
153
+ function AssetsTable({ items, currency, onOpen }) {
154
+ if (items.length === 0) return /* @__PURE__ */ jsx(EmptyTab, {});
155
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
156
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-muted-foreground", children: [
157
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Name" }),
158
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Type" }),
159
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Status" }),
160
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "Price" }),
161
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Linked To" })
162
+ ] }) }),
163
+ /* @__PURE__ */ jsx("tbody", { children: items.map((a) => /* @__PURE__ */ jsxs(
164
+ "tr",
165
+ {
166
+ onClick: () => onOpen(a.id),
167
+ className: "border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors",
168
+ children: [
169
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-medium", children: a.name }),
170
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 capitalize", children: a.assetType.replace(/_/g, " ") }),
171
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(StatusBadge, { status: a.status }) }),
172
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right font-mono", children: fmt(a.purchasePrice, a.currencyCode || currency) }),
173
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-muted-foreground", children: a.subscriptionId ? `Sub ${a.subscriptionId.slice(0, 8)}\u2026` : "\u2014" })
174
+ ]
175
+ },
176
+ a.id
177
+ )) })
178
+ ] }) });
179
+ }
180
+ function EmptyTab() {
181
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: "No records in this category." });
182
+ }
183
+ function Spinner() {
184
+ return /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
185
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
186
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
187
+ ] });
188
+ }
189
+ export {
190
+ CustomerInventoryWidget as default
191
+ };
192
+ //# sourceMappingURL=widget.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx"],
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useRouter } from 'next/navigation'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport {\n assetStatusMap,\n formatStatusLabel,\n subscriptionStatusMap,\n type AssetStatus,\n type SubscriptionStatus,\n} from '../../../components/statusMaps'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype Subscription = {\n id: string\n code: string\n name: string\n status: string\n mrcAmount: number\n nrcAmount: number\n billingCycle: string\n currencyCode: string\n startDate: string\n currentTermEnd: string | null\n autoRenew: boolean\n createdAt: string\n}\n\ntype SubscriptionItem = {\n id: string\n subscriptionId: string\n parentItemId: string | null\n productId: string | null\n name: string\n status: string\n mrcAmount: number\n nrcAmount: number\n currencyCode: string\n quantity: number\n}\n\ntype Asset = {\n id: string\n code: string\n name: string\n status: string\n assetType: string\n purchasePrice: number\n currencyCode: string\n subscriptionId: string | null\n subscriptionItemId: string | null\n createdAt: string\n}\n\ntype InventorySummary = {\n activeSubscriptions: number\n totalMrc: number\n activeAssets: number\n pendingItems: number\n currencyCode: string\n}\n\ntype InventoryResponse = {\n customerId: string\n subscriptions: Subscription[]\n subscriptionItems: SubscriptionItem[]\n assets: Asset[]\n summary: InventorySummary\n}\n\ntype TabKey = 'subscriptions' | 'items' | 'assets'\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction fmt(amount: number, currency: string): string {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const variant =\n subscriptionStatusMap[status as SubscriptionStatus] ??\n assetStatusMap[status as AssetStatus] ??\n 'neutral'\n return (\n <Tag variant={variant} dot>\n {formatStatusLabel(status)}\n </Tag>\n )\n}\n\n// \u2500\u2500\u2500 Main Widget \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function CustomerInventoryWidget({ data, context }: InjectionWidgetComponentProps & { context?: Record<string, unknown> }) {\n const router = useRouter()\n const record = data as Record<string, unknown> | null\n const companyRecord = record?.company as Record<string, unknown> | undefined\n const customerId =\n (context?.companyId as string) ??\n (context?.resourceId as string) ??\n (companyRecord?.id as string) ??\n (record?.id as string) ??\n null\n\n const [inventory, setInventory] = React.useState<InventoryResponse | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [activeTab, setActiveTab] = React.useState<TabKey>('subscriptions')\n\n React.useEffect(() => {\n if (!customerId) { setLoading(false); return }\n let cancelled = false\n async function load() {\n try {\n const res = await fetch(`/api/cpq/inventory/customer/${customerId}`)\n if (res.ok && !cancelled) setInventory(await res.json())\n } catch { /* no inventory data */ }\n finally { if (!cancelled) setLoading(false) }\n }\n load()\n return () => { cancelled = true }\n }, [customerId])\n\n if (!customerId) return <div className=\"p-4 text-sm text-muted-foreground\">No customer context available.</div>\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 p-6 text-sm text-muted-foreground\">\n <Spinner /> Loading inventory\u2026\n </div>\n )\n }\n\n if (!inventory || (inventory.subscriptions.length === 0 && inventory.assets.length === 0)) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 px-4\">\n <div className=\"rounded-full bg-primary/10 p-3 mb-3\">\n <svg className=\"h-6 w-6 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth=\"1.5\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z\" />\n </svg>\n </div>\n <p className=\"text-sm text-muted-foreground\">No inventory records found.</p>\n </div>\n )\n }\n\n const { summary } = inventory\n const currency = summary.currencyCode || 'USD'\n\n const tabs: { key: TabKey; label: string; count: number }[] = [\n { key: 'subscriptions', label: 'Subscriptions', count: inventory.subscriptions.length },\n { key: 'items', label: 'Subscription Items', count: inventory.subscriptionItems.length },\n { key: 'assets', label: 'Assets', count: inventory.assets.length },\n ]\n\n return (\n <div className=\"space-y-4\">\n {/* Summary Cards */}\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-3\">\n <SummaryCard label=\"Active Subscriptions\" value={String(summary.activeSubscriptions)} />\n <SummaryCard label=\"Total MRC\" value={fmt(summary.totalMrc, currency)} mono />\n <SummaryCard label=\"Active Assets\" value={String(summary.activeAssets)} />\n <SummaryCard label=\"Pending Items\" value={String(summary.pendingItems)} />\n </div>\n\n {/* Tab Switcher */}\n <div className=\"flex gap-1 border-b\">\n {tabs.map((tab) => (\n <button\n key={tab.key}\n onClick={() => setActiveTab(tab.key)}\n className={`px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${\n activeTab === tab.key\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {tab.label}\n <span className=\"ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs\">{tab.count}</span>\n </button>\n ))}\n </div>\n\n {/* Tab Content */}\n {activeTab === 'subscriptions' && <SubscriptionsTable items={inventory.subscriptions} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`)} />}\n {activeTab === 'items' && <SubscriptionItemsTable items={inventory.subscriptionItems} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`)} />}\n {activeTab === 'assets' && <AssetsTable items={inventory.assets} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/assets/${id}`)} />}\n\n {/* Link to full page */}\n <div className=\"pt-2 text-right\">\n <a href=\"/backend/cpq/inventory\" className=\"text-sm text-primary hover:underline\">\n View full inventory \u2192\n </a>\n </div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Summary Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 SummaryCard({ label, value, mono }: { label: string; value: string; mono?: boolean }) {\n return (\n <div className=\"rounded-lg border bg-card p-3\">\n <p className=\"text-xs text-muted-foreground\">{label}</p>\n <p className={`text-lg font-semibold ${mono ? 'font-mono' : ''}`}>{value}</p>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Subscriptions Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 SubscriptionsTable({ items, currency, onOpen }: { items: Subscription[]; currency: string; onOpen: (id: string) => void }) {\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Name</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Status</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">MRC</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Billing</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Start Date</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Term End</th>\n </tr>\n </thead>\n <tbody>\n {items.map((s) => (\n <tr\n key={s.id}\n onClick={() => onOpen(s.id)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{s.name}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={s.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(s.mrcAmount, s.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 capitalize\">{s.billingCycle}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{s.startDate ? new Date(s.startDate).toLocaleDateString() : '\u2014'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{s.currentTermEnd ? new Date(s.currentTermEnd).toLocaleDateString() : '\u2014'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Subscription Items Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 SubscriptionItemsTable({ items, currency, onOpen }: { items: SubscriptionItem[]; currency: string; onOpen: (subscriptionId: string) => void }) {\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Name</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Status</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">MRC</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">NRC</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">Qty</th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => (\n <tr\n key={item.id}\n onClick={() => onOpen(item.subscriptionId)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{item.name}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={item.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(item.mrcAmount, item.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(item.nrcAmount, item.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-right font-mono\">{item.quantity}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Assets Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 AssetsTable({ items, currency, onOpen }: { items: Asset[]; currency: string; onOpen: (id: string) => void }) {\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Name</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Type</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Status</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">Price</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Linked To</th>\n </tr>\n </thead>\n <tbody>\n {items.map((a) => (\n <tr\n key={a.id}\n onClick={() => onOpen(a.id)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{a.name}</td>\n <td className=\"px-4 py-3 capitalize\">{a.assetType.replace(/_/g, ' ')}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={a.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(a.purchasePrice, a.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {a.subscriptionId ? `Sub ${a.subscriptionId.slice(0, 8)}\u2026` : '\u2014'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Shared \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 EmptyTab() {\n return (\n <div className=\"rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground\">\n No records in this category.\n </div>\n )\n}\n\nfunction Spinner() {\n return (\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import CustomerInventoryWidget from "./widget.client.js";
2
+ const widget = {
3
+ metadata: {
4
+ id: "cpq.injection.customer-inventory",
5
+ title: "Customer Inventory",
6
+ description: "Products and services purchased by this customer",
7
+ features: ["cpq.inventory.view"],
8
+ priority: 60,
9
+ enabled: true
10
+ },
11
+ Widget: CustomerInventoryWidget
12
+ };
13
+ var widget_default = widget;
14
+ export {
15
+ widget_default as default
16
+ };
17
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/cpq/widgets/injection/customer-inventory/widget.ts"],
4
+ "sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport CustomerInventoryWidget from './widget.client'\n\nconst widget: InjectionWidgetModule<any, any> = {\n metadata: {\n id: 'cpq.injection.customer-inventory',\n title: 'Customer Inventory',\n description: 'Products and services purchased by this customer',\n features: ['cpq.inventory.view'],\n priority: 60,\n enabled: true,\n },\n Widget: CustomerInventoryWidget,\n}\n\nexport default widget\n"],
5
+ "mappings": "AACA,OAAO,6BAA6B;AAEpC,MAAM,SAA0C;AAAA,EAC9C,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU,CAAC,oBAAoB;AAAA,IAC/B,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import { Tag } from "@open-mercato/ui/primitives/tag";
6
+ import {
7
+ formatStatusLabel,
8
+ orderCpqStatusMap
9
+ } from "../../../components/statusMaps.js";
10
+ function fmt(amount, currency) {
11
+ if (amount == null) return "\u2014";
12
+ return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
13
+ }
14
+ function OrderCpqTabWidget({ data }) {
15
+ const router = useRouter();
16
+ const salesOrderId = data?.id;
17
+ const [cpqOrders, setCpqOrders] = React.useState([]);
18
+ const [loading, setLoading] = React.useState(true);
19
+ React.useEffect(() => {
20
+ if (!salesOrderId) {
21
+ setLoading(false);
22
+ return;
23
+ }
24
+ let cancelled = false;
25
+ fetch(`/api/cpq/orders?salesOrderId=${salesOrderId}&pageSize=50`).then((r) => r.json()).then((result) => {
26
+ if (!cancelled) setCpqOrders(result.items ?? []);
27
+ }).catch(() => {
28
+ }).finally(() => {
29
+ if (!cancelled) setLoading(false);
30
+ });
31
+ return () => {
32
+ cancelled = true;
33
+ };
34
+ }, [salesOrderId]);
35
+ if (loading) {
36
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-8 justify-center text-sm text-muted-foreground", children: [
37
+ /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
38
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
39
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
40
+ ] }),
41
+ "Loading CPQ orders\u2026"
42
+ ] });
43
+ }
44
+ if (cpqOrders.length === 0) {
45
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground", children: "No CPQ orders linked to this sales order." });
46
+ }
47
+ return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: cpqOrders.map((o) => /* @__PURE__ */ jsxs(
48
+ "div",
49
+ {
50
+ onClick: () => router.push(`/backend/cpq/orders/${o.id}`),
51
+ className: "flex items-center justify-between rounded-lg border p-3 hover:bg-muted/30 cursor-pointer transition-colors",
52
+ children: [
53
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
54
+ /* @__PURE__ */ jsx(Tag, { variant: orderCpqStatusMap[o.cpqStatus] ?? "neutral", dot: true, children: formatStatusLabel(o.cpqStatus) }),
55
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: o.currencyCode })
56
+ ] }),
57
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-xs", children: [
58
+ o.pricingSummary && /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ /* @__PURE__ */ jsxs("span", { children: [
60
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "NRC " }),
61
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(o.pricingSummary.nrcTotal, o.currencyCode) })
62
+ ] }),
63
+ /* @__PURE__ */ jsxs("span", { children: [
64
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "MRC " }),
65
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(o.pricingSummary.mrcTotal, o.currencyCode) })
66
+ ] })
67
+ ] }),
68
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: new Date(o.createdAt).toLocaleDateString() }),
69
+ /* @__PURE__ */ jsx("span", { className: "text-primary font-medium", children: "Open \u2192" })
70
+ ] })
71
+ ]
72
+ },
73
+ o.id
74
+ )) });
75
+ }
76
+ export {
77
+ OrderCpqTabWidget as default
78
+ };
79
+ //# sourceMappingURL=widget.client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx"],
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useRouter } from 'next/navigation'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../components/statusMaps'\n\ntype CpqOrderSummary = {\n id: string\n orderId: string\n orderNumber?: string\n cpqStatus: string\n sourceQuoteId: string | null\n currencyCode: string\n pricingSummary: { nrcTotal: number; mrcTotal: number } | null\n activatedAt: string | null\n createdAt: string\n}\n\nfunction fmt(amount: number | undefined | null, currency: string): string {\n if (amount == null) return '\u2014'\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nexport default function OrderCpqTabWidget({ data }: InjectionWidgetComponentProps<any, any>) {\n const router = useRouter()\n const salesOrderId = data?.id as string | undefined\n const [cpqOrders, setCpqOrders] = React.useState<CpqOrderSummary[]>([])\n const [loading, setLoading] = React.useState(true)\n\n React.useEffect(() => {\n if (!salesOrderId) { setLoading(false); return }\n let cancelled = false\n fetch(`/api/cpq/orders?salesOrderId=${salesOrderId}&pageSize=50`)\n .then((r) => r.json())\n .then((result) => {\n if (!cancelled) setCpqOrders(result.items ?? [])\n })\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [salesOrderId])\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 py-8 justify-center text-sm text-muted-foreground\">\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n Loading CPQ orders\u2026\n </div>\n )\n }\n\n if (cpqOrders.length === 0) {\n return (\n <div className=\"py-8 text-center text-sm text-muted-foreground\">\n No CPQ orders linked to this sales order.\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n {cpqOrders.map((o) => (\n <div\n key={o.id}\n onClick={() => router.push(`/backend/cpq/orders/${o.id}`)}\n className=\"flex items-center justify-between rounded-lg border p-3 hover:bg-muted/30 cursor-pointer transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <Tag variant={orderCpqStatusMap[o.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(o.cpqStatus)}\n </Tag>\n <span className=\"text-sm font-medium\">{o.currencyCode}</span>\n </div>\n <div className=\"flex items-center gap-4 text-xs\">\n {o.pricingSummary && (\n <>\n <span><span className=\"text-muted-foreground\">NRC </span><span className=\"font-mono font-medium\">{fmt(o.pricingSummary.nrcTotal, o.currencyCode)}</span></span>\n <span><span className=\"text-muted-foreground\">MRC </span><span className=\"font-mono font-medium\">{fmt(o.pricingSummary.mrcTotal, o.currencyCode)}</span></span>\n </>\n )}\n <span className=\"text-muted-foreground\">{new Date(o.createdAt).toLocaleDateString()}</span>\n <span className=\"text-primary font-medium\">Open \u2192</span>\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAkDQ,SAiCM,UAhCJ,KADF;AAjDR,YAAY,WAAW;AAEvB,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAcP,SAAS,IAAI,QAAmC,UAA0B;AACxE,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO,IAAI,KAAK,aAAa,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,MAAM;AACtF;AAEe,SAAR,kBAAmC,EAAE,KAAK,GAA4C;AAC3F,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,MAAM;AAC3B,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAA4B,CAAC,CAAC;AACtE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AAEjD,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,cAAc;AAAE,iBAAW,KAAK;AAAG;AAAA,IAAO;AAC/C,QAAI,YAAY;AAChB,UAAM,gCAAgC,YAAY,cAAc,EAC7D,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,EACpB,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,UAAW,cAAa,OAAO,SAAS,CAAC,CAAC;AAAA,IACjD,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC,EACd,QAAQ,MAAM;AAAE,UAAI,CAAC,UAAW,YAAW,KAAK;AAAA,IAAE,CAAC;AACtD,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,YAAY,CAAC;AAEjB,MAAI,SAAS;AACX,WACE,qBAAC,SAAI,WAAU,6EACb;AAAA,2BAAC,SAAI,WAAU,wBAAuB,SAAQ,aAAY,MAAK,QAC7D;AAAA,4BAAC,YAAO,WAAU,cAAa,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,QAAO,gBAAe,aAAY,KAAI;AAAA,QAC5F,oBAAC,UAAK,WAAU,cAAa,MAAK,gBAAe,GAAE,uCAAsC;AAAA,SAC3F;AAAA,MAAM;AAAA,OAER;AAAA,EAEJ;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WACE,oBAAC,SAAI,WAAU,kDAAiD,uDAEhE;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,aACZ,oBAAU,IAAI,CAAC,MACd;AAAA,IAAC;AAAA;AAAA,MAEC,SAAS,MAAM,OAAO,KAAK,uBAAuB,EAAE,EAAE,EAAE;AAAA,MACxD,WAAU;AAAA,MAEV;AAAA,6BAAC,SAAI,WAAU,2BACb;AAAA,8BAAC,OAAI,SAAS,kBAAkB,EAAE,SAA2B,KAAK,WAAW,KAAG,MAC7E,4BAAkB,EAAE,SAAS,GAChC;AAAA,UACA,oBAAC,UAAK,WAAU,uBAAuB,YAAE,cAAa;AAAA,WACxD;AAAA,QACA,qBAAC,SAAI,WAAU,mCACZ;AAAA,YAAE,kBACD,iCACE;AAAA,iCAAC,UAAK;AAAA,kCAAC,UAAK,WAAU,yBAAwB,kBAAI;AAAA,cAAO,oBAAC,UAAK,WAAU,yBAAyB,cAAI,EAAE,eAAe,UAAU,EAAE,YAAY,GAAE;AAAA,eAAO;AAAA,YACxJ,qBAAC,UAAK;AAAA,kCAAC,UAAK,WAAU,yBAAwB,kBAAI;AAAA,cAAO,oBAAC,UAAK,WAAU,yBAAyB,cAAI,EAAE,eAAe,UAAU,EAAE,YAAY,GAAE;AAAA,eAAO;AAAA,aAC1J;AAAA,UAEF,oBAAC,UAAK,WAAU,yBAAyB,cAAI,KAAK,EAAE,SAAS,EAAE,mBAAmB,GAAE;AAAA,UACpF,oBAAC,UAAK,WAAU,4BAA2B,yBAAM;AAAA,WACnD;AAAA;AAAA;AAAA,IAnBK,EAAE;AAAA,EAoBT,CACD,GACH;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import OrderCpqTabWidget from "./widget.client.js";
2
+ const widget = {
3
+ metadata: {
4
+ id: "cpq.injection.order-cpq-tab",
5
+ title: "CPQ Order",
6
+ description: "View the CPQ order associated with this sales order",
7
+ features: ["cpq.orders.view"],
8
+ priority: 60,
9
+ enabled: true
10
+ },
11
+ Widget: OrderCpqTabWidget
12
+ };
13
+ var widget_default = widget;
14
+ export {
15
+ widget_default as default
16
+ };
17
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/cpq/widgets/injection/order-cpq-tab/widget.ts"],
4
+ "sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport OrderCpqTabWidget from './widget.client'\n\nconst widget: InjectionWidgetModule<any, any> = {\n metadata: {\n id: 'cpq.injection.order-cpq-tab',\n title: 'CPQ Order',\n description: 'View the CPQ order associated with this sales order',\n features: ['cpq.orders.view'],\n priority: 60,\n enabled: true,\n },\n Widget: OrderCpqTabWidget,\n}\n\nexport default widget\n"],
5
+ "mappings": "AACA,OAAO,uBAAuB;AAE9B,MAAM,SAA0C;AAAA,EAC9C,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU,CAAC,iBAAiB;AAAA,IAC5B,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,181 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import { Tag } from "@open-mercato/ui/primitives/tag";
6
+ import {
7
+ formatStatusLabel,
8
+ quoteCpqStatusMap
9
+ } from "../../../components/statusMaps.js";
10
+ function fmt(amount, currency) {
11
+ return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
12
+ }
13
+ function QuoteConfiguratorWidget({ data }) {
14
+ const router = useRouter();
15
+ const record = data;
16
+ const quoteId = record?.id ?? null;
17
+ const [cpqQuote, setCpqQuote] = React.useState(null);
18
+ const [loading, setLoading] = React.useState(true);
19
+ const [expandedLines, setExpandedLines] = React.useState(/* @__PURE__ */ new Set());
20
+ React.useEffect(() => {
21
+ if (!quoteId) {
22
+ setLoading(false);
23
+ return;
24
+ }
25
+ let cancelled = false;
26
+ async function load() {
27
+ try {
28
+ const res = await fetch(`/api/cpq/quotes/${quoteId}`);
29
+ if (res.ok && !cancelled) setCpqQuote(await res.json());
30
+ } catch {
31
+ } finally {
32
+ if (!cancelled) setLoading(false);
33
+ }
34
+ }
35
+ load();
36
+ return () => {
37
+ cancelled = true;
38
+ };
39
+ }, [quoteId]);
40
+ if (!quoteId) return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-muted-foreground", children: "No quote context available." });
41
+ if (loading) {
42
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-6 text-sm text-muted-foreground", children: [
43
+ /* @__PURE__ */ jsx(Spinner, {}),
44
+ " Loading CPQ configuration\u2026"
45
+ ] });
46
+ }
47
+ if (!cpqQuote) {
48
+ const custId = record?.customerEntityId ?? record?.customer_entity_id ?? "";
49
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 px-4", children: [
50
+ /* @__PURE__ */ jsx("div", { className: "rounded-full bg-primary/10 p-3 mb-3", children: /* @__PURE__ */ jsxs("svg", { className: "h-6 w-6 text-primary", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: [
51
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 010 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 010-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28z" }),
52
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
53
+ ] }) }),
54
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: "This quote has no CPQ configuration yet." }),
55
+ /* @__PURE__ */ jsxs(
56
+ "button",
57
+ {
58
+ onClick: () => router.push(`/backend/cpq/quotes/new?quoteId=${quoteId}&customerId=${custId}`),
59
+ className: "inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm hover:bg-primary/90 transition-colors",
60
+ children: [
61
+ /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4.5v15m7.5-7.5h-15" }) }),
62
+ "Create CPQ Quote"
63
+ ]
64
+ }
65
+ ),
66
+ !custId && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-status-warning-text", children: "Assign a customer to this quote first." })
67
+ ] });
68
+ }
69
+ const { pricingSummary: summary, currencyCode: currency } = cpqQuote;
70
+ const toggleLine = (id) => {
71
+ setExpandedLines((prev) => {
72
+ const next = new Set(prev);
73
+ next.has(id) ? next.delete(id) : next.add(id);
74
+ return next;
75
+ });
76
+ };
77
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
78
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-1", children: [
79
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
80
+ /* @__PURE__ */ jsx(Tag, { variant: quoteCpqStatusMap[cpqQuote.cpqStatus] ?? "neutral", dot: true, children: formatStatusLabel(cpqQuote.cpqStatus) }),
81
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
82
+ "v",
83
+ cpqQuote.version
84
+ ] }),
85
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: currency })
86
+ ] }),
87
+ /* @__PURE__ */ jsxs(
88
+ "button",
89
+ {
90
+ onClick: () => router.push(`/backend/cpq/quotes/${cpqQuote.id}`),
91
+ className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground shadow-sm hover:bg-primary/90 transition-colors",
92
+ children: [
93
+ "Open CPQ Configurator",
94
+ /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" }) })
95
+ ]
96
+ }
97
+ )
98
+ ] }),
99
+ cpqQuote.lines.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: "No items configured yet." }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card divide-y", children: cpqQuote.lines.map((line) => {
100
+ const isExpanded = expandedLines.has(line.lineId);
101
+ return /* @__PURE__ */ jsxs("div", { children: [
102
+ /* @__PURE__ */ jsxs(
103
+ "div",
104
+ {
105
+ className: "flex items-center gap-3 px-4 py-3 hover:bg-muted/30 transition-colors cursor-pointer",
106
+ onClick: () => toggleLine(line.lineId),
107
+ children: [
108
+ /* @__PURE__ */ jsx("button", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground", children: /* @__PURE__ */ jsx("svg", { className: `h-4 w-4 transition-transform ${isExpanded ? "rotate-90" : ""}`, fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) }) }),
109
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
110
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
111
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: line.offeringName }),
112
+ line.quantity > 1 && /* @__PURE__ */ jsxs("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs font-medium", children: [
113
+ "\xD7",
114
+ line.quantity
115
+ ] }),
116
+ line.isConfigured ? /* @__PURE__ */ jsx(Tag, { variant: "success", className: "px-1.5 text-xs", children: "configured" }) : /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "px-1.5 text-xs", children: "incomplete" })
117
+ ] }),
118
+ line.validationErrors && line.validationErrors.length > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-0.5", children: line.validationErrors[0].message })
119
+ ] }),
120
+ /* @__PURE__ */ jsxs("div", { className: "shrink-0 text-right text-xs space-y-0.5", children: [
121
+ line.nrcTotal > 0 && /* @__PURE__ */ jsxs("div", { children: [
122
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "NRC " }),
123
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(line.nrcTotal, currency) })
124
+ ] }),
125
+ line.mrcTotal > 0 && /* @__PURE__ */ jsxs("div", { children: [
126
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "MRC " }),
127
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(line.mrcTotal, currency) })
128
+ ] })
129
+ ] })
130
+ ]
131
+ }
132
+ ),
133
+ isExpanded && line.charges.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t bg-muted/10 px-12 py-2", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-xs", children: [
134
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "text-muted-foreground", children: [
135
+ /* @__PURE__ */ jsx("th", { className: "text-left py-1 font-medium", children: "Charge" }),
136
+ /* @__PURE__ */ jsx("th", { className: "text-left py-1 font-medium", children: "Type" }),
137
+ /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: "Unit Price" }),
138
+ /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: "Qty" }),
139
+ /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: "Total" })
140
+ ] }) }),
141
+ /* @__PURE__ */ jsx("tbody", { children: line.charges.map((c, i) => /* @__PURE__ */ jsxs("tr", { className: "border-t border-dashed border-border/50", children: [
142
+ /* @__PURE__ */ jsx("td", { className: "py-1", children: c.chargeName }),
143
+ /* @__PURE__ */ jsx("td", { className: "py-1 uppercase", children: c.chargeType }),
144
+ /* @__PURE__ */ jsx("td", { className: "py-1 text-right font-mono", children: fmt(c.unitPrice, currency) }),
145
+ /* @__PURE__ */ jsx("td", { className: "py-1 text-right font-mono", children: c.quantity ?? "\u2014" }),
146
+ /* @__PURE__ */ jsx("td", { className: "py-1 text-right font-mono", children: c.totalPrice != null ? fmt(c.totalPrice, currency) : c.note ?? "\u2014" })
147
+ ] }, i)) })
148
+ ] }) })
149
+ ] }, line.lineId);
150
+ }) }),
151
+ cpqQuote.lines.length > 0 && /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-4", children: [
152
+ /* @__PURE__ */ jsxs("div", { children: [
153
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Non-Recurring (NRC)" }),
154
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold font-mono", children: fmt(summary.nrcTotal, currency) })
155
+ ] }),
156
+ /* @__PURE__ */ jsxs("div", { children: [
157
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Monthly Recurring (MRC)" }),
158
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold font-mono", children: fmt(summary.mrcTotal, currency) })
159
+ ] }),
160
+ summary.usageCharges.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
161
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Usage Charges" }),
162
+ /* @__PURE__ */ jsx("div", { className: "mt-1 space-y-0.5", children: summary.usageCharges.map((uc, i) => /* @__PURE__ */ jsxs("p", { className: "text-xs", children: [
163
+ uc.chargeName,
164
+ ": ",
165
+ fmt(uc.unitPrice, currency),
166
+ "/unit"
167
+ ] }, i)) })
168
+ ] })
169
+ ] }) })
170
+ ] });
171
+ }
172
+ function Spinner() {
173
+ return /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
174
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
175
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
176
+ ] });
177
+ }
178
+ export {
179
+ QuoteConfiguratorWidget as default
180
+ };
181
+ //# sourceMappingURL=widget.client.js.map