@dainamite/billing 0.19.0 → 0.21.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 (614) hide show
  1. package/CHANGELOG.md +172 -0
  2. package/README.md +14 -0
  3. package/dist/modules/billing/acl.js +13 -1
  4. package/dist/modules/billing/acl.js.map +2 -2
  5. package/dist/modules/billing/api/accounts/[id]/summary/route.js +52 -0
  6. package/dist/modules/billing/api/accounts/[id]/summary/route.js.map +7 -0
  7. package/dist/modules/billing/api/accounts/route.js +46 -4
  8. package/dist/modules/billing/api/accounts/route.js.map +2 -2
  9. package/dist/modules/billing/api/export/account/[id]/route.js +16 -12
  10. package/dist/modules/billing/api/export/account/[id]/route.js.map +2 -2
  11. package/dist/modules/billing/api/invoices/[id]/memos/route.js +54 -0
  12. package/dist/modules/billing/api/invoices/[id]/memos/route.js.map +7 -0
  13. package/dist/modules/billing/api/invoices/[id]/pdf/route.js +69 -0
  14. package/dist/modules/billing/api/invoices/[id]/pdf/route.js.map +7 -0
  15. package/dist/modules/billing/api/invoices/[id]/route.js +44 -24
  16. package/dist/modules/billing/api/invoices/[id]/route.js.map +2 -2
  17. package/dist/modules/billing/api/invoices/[id]/send/route.js +107 -0
  18. package/dist/modules/billing/api/invoices/[id]/send/route.js.map +7 -0
  19. package/dist/modules/billing/api/invoices/add-line/route.js +3 -3
  20. package/dist/modules/billing/api/invoices/add-line/route.js.map +2 -2
  21. package/dist/modules/billing/api/invoices/delete-draft/route.js +33 -0
  22. package/dist/modules/billing/api/invoices/delete-draft/route.js.map +7 -0
  23. package/dist/modules/billing/api/invoices/edit-line/route.js +3 -3
  24. package/dist/modules/billing/api/invoices/edit-line/route.js.map +2 -2
  25. package/dist/modules/billing/api/invoices/post/route.js +2 -2
  26. package/dist/modules/billing/api/invoices/post/route.js.map +2 -2
  27. package/dist/modules/billing/api/invoices/remove-line/route.js +3 -3
  28. package/dist/modules/billing/api/invoices/remove-line/route.js.map +2 -2
  29. package/dist/modules/billing/api/invoices/route.js +45 -46
  30. package/dist/modules/billing/api/invoices/route.js.map +2 -2
  31. package/dist/modules/billing/api/items/bulk/route.js +1 -1
  32. package/dist/modules/billing/api/items/bulk/route.js.map +2 -2
  33. package/dist/modules/billing/api/items/change-price/route.js +44 -0
  34. package/dist/modules/billing/api/items/change-price/route.js.map +7 -0
  35. package/dist/modules/billing/api/items/route.js +19 -7
  36. package/dist/modules/billing/api/items/route.js.map +2 -2
  37. package/dist/modules/billing/api/payment-imports/[id]/route.js +49 -0
  38. package/dist/modules/billing/api/payment-imports/[id]/route.js.map +7 -0
  39. package/dist/modules/billing/api/payment-imports/route.js +57 -0
  40. package/dist/modules/billing/api/payment-imports/route.js.map +7 -0
  41. package/dist/modules/billing/api/payments/[id]/route.js +60 -0
  42. package/dist/modules/billing/api/payments/[id]/route.js.map +7 -0
  43. package/dist/modules/billing/api/payments/allocate/route.js +35 -0
  44. package/dist/modules/billing/api/payments/allocate/route.js.map +7 -0
  45. package/dist/modules/billing/api/payments/assign/route.js +36 -0
  46. package/dist/modules/billing/api/payments/assign/route.js.map +7 -0
  47. package/dist/modules/billing/api/payments/convert-to-topup/route.js +35 -0
  48. package/dist/modules/billing/api/payments/convert-to-topup/route.js.map +7 -0
  49. package/dist/modules/billing/api/payments/ignore/route.js +35 -0
  50. package/dist/modules/billing/api/payments/ignore/route.js.map +7 -0
  51. package/dist/modules/billing/api/payments/import/route.js +63 -0
  52. package/dist/modules/billing/api/payments/import/route.js.map +7 -0
  53. package/dist/modules/billing/api/payments/restore/route.js +35 -0
  54. package/dist/modules/billing/api/payments/restore/route.js.map +7 -0
  55. package/dist/modules/billing/api/payments/route.js +114 -0
  56. package/dist/modules/billing/api/payments/route.js.map +7 -0
  57. package/dist/modules/billing/api/payments/unallocate/route.js +35 -0
  58. package/dist/modules/billing/api/payments/unallocate/route.js.map +7 -0
  59. package/dist/modules/billing/api/payments/unassign/route.js +35 -0
  60. package/dist/modules/billing/api/payments/unassign/route.js.map +7 -0
  61. package/dist/modules/billing/api/run-outcomes/route.js +44 -7
  62. package/dist/modules/billing/api/run-outcomes/route.js.map +2 -2
  63. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js +61 -0
  64. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js.map +7 -0
  65. package/dist/modules/billing/api/runs/[id]/route.js +53 -0
  66. package/dist/modules/billing/api/runs/[id]/route.js.map +7 -0
  67. package/dist/modules/billing/api/runs/retry-failed/route.js +3 -3
  68. package/dist/modules/billing/api/runs/retry-failed/route.js.map +2 -2
  69. package/dist/modules/billing/api/runs/route.js +11 -5
  70. package/dist/modules/billing/api/runs/route.js.map +2 -2
  71. package/dist/modules/billing/api/settings/number-preview/route.js +42 -0
  72. package/dist/modules/billing/api/settings/number-preview/route.js.map +7 -0
  73. package/dist/modules/billing/api/settings/route.js +92 -0
  74. package/dist/modules/billing/api/settings/route.js.map +7 -0
  75. package/dist/modules/billing/api/statements/route.js +3 -0
  76. package/dist/modules/billing/api/statements/route.js.map +2 -2
  77. package/dist/modules/billing/api/test-invoices/wipe/route.js +2 -2
  78. package/dist/modules/billing/api/test-invoices/wipe/route.js.map +2 -2
  79. package/dist/modules/billing/backend/billing/accounts/[id]/page.js +121 -232
  80. package/dist/modules/billing/backend/billing/accounts/[id]/page.js.map +2 -2
  81. package/dist/modules/billing/backend/billing/accounts/create/page.js +6 -0
  82. package/dist/modules/billing/backend/billing/accounts/create/page.js.map +2 -2
  83. package/dist/modules/billing/backend/billing/accounts/page.js +63 -4
  84. package/dist/modules/billing/backend/billing/accounts/page.js.map +2 -2
  85. package/dist/modules/billing/backend/billing/invoices/[id]/page.js +297 -65
  86. package/dist/modules/billing/backend/billing/invoices/[id]/page.js.map +3 -3
  87. package/dist/modules/billing/backend/billing/invoices/page.js +6 -172
  88. package/dist/modules/billing/backend/billing/invoices/page.js.map +2 -2
  89. package/dist/modules/billing/backend/billing/items/[id]/page.js +51 -7
  90. package/dist/modules/billing/backend/billing/items/[id]/page.js.map +2 -2
  91. package/dist/modules/billing/backend/billing/items/create/page.js +9 -6
  92. package/dist/modules/billing/backend/billing/items/create/page.js.map +2 -2
  93. package/dist/modules/billing/backend/billing/items/page.js +8 -2
  94. package/dist/modules/billing/backend/billing/items/page.js.map +2 -2
  95. package/dist/modules/billing/backend/billing/payments/[id]/page.js +297 -0
  96. package/dist/modules/billing/backend/billing/payments/[id]/page.js.map +7 -0
  97. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js +21 -0
  98. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js.map +7 -0
  99. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js +74 -0
  100. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js.map +7 -0
  101. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js +21 -0
  102. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js.map +7 -0
  103. package/dist/modules/billing/backend/billing/payments/page.js +58 -0
  104. package/dist/modules/billing/backend/billing/payments/page.js.map +7 -0
  105. package/dist/modules/billing/backend/billing/payments/page.meta.js +18 -0
  106. package/dist/modules/billing/backend/billing/payments/page.meta.js.map +7 -0
  107. package/dist/modules/billing/backend/billing/runs/[id]/page.js +49 -14
  108. package/dist/modules/billing/backend/billing/runs/[id]/page.js.map +2 -2
  109. package/dist/modules/billing/backend/billing/runs/page.js +58 -7
  110. package/dist/modules/billing/backend/billing/runs/page.js.map +2 -2
  111. package/dist/modules/billing/backend/billing/statements/[id]/page.js +61 -6
  112. package/dist/modules/billing/backend/billing/statements/[id]/page.js.map +2 -2
  113. package/dist/modules/billing/backend/billing/statements/page.js +1 -1
  114. package/dist/modules/billing/backend/billing/statements/page.js.map +2 -2
  115. package/dist/modules/billing/backend/billing/topups/page.js +1 -1
  116. package/dist/modules/billing/backend/billing/topups/page.js.map +2 -2
  117. package/dist/modules/billing/backend/billing/transactions/page.js +1 -1
  118. package/dist/modules/billing/backend/billing/transactions/page.js.map +2 -2
  119. package/dist/modules/billing/backend/billing/usage/create/page.js +3 -2
  120. package/dist/modules/billing/backend/billing/usage/create/page.js.map +2 -2
  121. package/dist/modules/billing/backend/config/billing/page.js +472 -0
  122. package/dist/modules/billing/backend/config/billing/page.js.map +7 -0
  123. package/dist/modules/billing/backend/config/billing/page.meta.js +19 -0
  124. package/dist/modules/billing/backend/config/billing/page.meta.js.map +7 -0
  125. package/dist/modules/billing/ce.js.map +2 -2
  126. package/dist/modules/billing/cli.js +22 -1
  127. package/dist/modules/billing/cli.js.map +2 -2
  128. package/dist/modules/billing/commands/accounts.js +6 -0
  129. package/dist/modules/billing/commands/accounts.js.map +2 -2
  130. package/dist/modules/billing/commands/index.js +3 -0
  131. package/dist/modules/billing/commands/index.js.map +2 -2
  132. package/dist/modules/billing/commands/invoices.js +272 -170
  133. package/dist/modules/billing/commands/invoices.js.map +2 -2
  134. package/dist/modules/billing/commands/items.js +108 -0
  135. package/dist/modules/billing/commands/items.js.map +2 -2
  136. package/dist/modules/billing/commands/memos.js +179 -0
  137. package/dist/modules/billing/commands/memos.js.map +7 -0
  138. package/dist/modules/billing/commands/payments.js +379 -0
  139. package/dist/modules/billing/commands/payments.js.map +7 -0
  140. package/dist/modules/billing/commands/runs.js +154 -7
  141. package/dist/modules/billing/commands/runs.js.map +2 -2
  142. package/dist/modules/billing/commands/settings.js +59 -0
  143. package/dist/modules/billing/commands/settings.js.map +7 -0
  144. package/dist/modules/billing/commands/topups.js +9 -2
  145. package/dist/modules/billing/commands/topups.js.map +2 -2
  146. package/dist/modules/billing/commands/transactions.js +2 -2
  147. package/dist/modules/billing/commands/transactions.js.map +2 -2
  148. package/dist/modules/billing/components/AccountForm.js +149 -42
  149. package/dist/modules/billing/components/AccountForm.js.map +2 -2
  150. package/dist/modules/billing/components/AccountInvoicesSection.js +64 -0
  151. package/dist/modules/billing/components/AccountInvoicesSection.js.map +7 -0
  152. package/dist/modules/billing/components/AccountPaymentsSection.js +43 -0
  153. package/dist/modules/billing/components/AccountPaymentsSection.js.map +7 -0
  154. package/dist/modules/billing/components/AccountPicker.js +56 -0
  155. package/dist/modules/billing/components/AccountPicker.js.map +7 -0
  156. package/dist/modules/billing/components/AllocatePaymentDialog.js +134 -0
  157. package/dist/modules/billing/components/AllocatePaymentDialog.js.map +7 -0
  158. package/dist/modules/billing/components/BillingDataTable.js +21 -0
  159. package/dist/modules/billing/components/BillingDataTable.js.map +7 -0
  160. package/dist/modules/billing/components/BillingSettingsLink.js +19 -0
  161. package/dist/modules/billing/components/BillingSettingsLink.js.map +7 -0
  162. package/dist/modules/billing/components/ChangeItemPriceDialog.js +158 -0
  163. package/dist/modules/billing/components/ChangeItemPriceDialog.js.map +7 -0
  164. package/dist/modules/billing/components/CreateMemoDialog.js +200 -0
  165. package/dist/modules/billing/components/CreateMemoDialog.js.map +7 -0
  166. package/dist/modules/billing/components/CustomerLabel.js +33 -0
  167. package/dist/modules/billing/components/CustomerLabel.js.map +7 -0
  168. package/dist/modules/billing/components/InvoicesTable.js +270 -0
  169. package/dist/modules/billing/components/InvoicesTable.js.map +7 -0
  170. package/dist/modules/billing/components/ItemForm.js +176 -44
  171. package/dist/modules/billing/components/ItemForm.js.map +2 -2
  172. package/dist/modules/billing/components/ItemPriceField.js +46 -0
  173. package/dist/modules/billing/components/ItemPriceField.js.map +7 -0
  174. package/dist/modules/billing/components/LineFormDialog.js +25 -2
  175. package/dist/modules/billing/components/LineFormDialog.js.map +2 -2
  176. package/dist/modules/billing/components/ManualPaymentDialog.js +122 -0
  177. package/dist/modules/billing/components/ManualPaymentDialog.js.map +7 -0
  178. package/dist/modules/billing/components/MoneyInput.js +14 -0
  179. package/dist/modules/billing/components/MoneyInput.js.map +7 -0
  180. package/dist/modules/billing/components/PaymentUploadDialog.js +115 -0
  181. package/dist/modules/billing/components/PaymentUploadDialog.js.map +7 -0
  182. package/dist/modules/billing/components/PaymentsTable.js +171 -0
  183. package/dist/modules/billing/components/PaymentsTable.js.map +7 -0
  184. package/dist/modules/billing/components/PostRunDraftsButton.js +105 -0
  185. package/dist/modules/billing/components/PostRunDraftsButton.js.map +7 -0
  186. package/dist/modules/billing/components/PrepaidPanel.js +14 -4
  187. package/dist/modules/billing/components/PrepaidPanel.js.map +2 -2
  188. package/dist/modules/billing/components/RunCyclesSection.js +209 -0
  189. package/dist/modules/billing/components/RunCyclesSection.js.map +7 -0
  190. package/dist/modules/billing/components/TestRunActions.js +127 -0
  191. package/dist/modules/billing/components/TestRunActions.js.map +7 -0
  192. package/dist/modules/billing/components/account/AccountItemsTab.js +157 -0
  193. package/dist/modules/billing/components/account/AccountItemsTab.js.map +7 -0
  194. package/dist/modules/billing/components/account/AccountRunBillingDialog.js +122 -0
  195. package/dist/modules/billing/components/account/AccountRunBillingDialog.js.map +7 -0
  196. package/dist/modules/billing/components/account/AccountRunsTab.js +152 -0
  197. package/dist/modules/billing/components/account/AccountRunsTab.js.map +7 -0
  198. package/dist/modules/billing/components/account/AccountStatementsTab.js +98 -0
  199. package/dist/modules/billing/components/account/AccountStatementsTab.js.map +7 -0
  200. package/dist/modules/billing/components/account/AccountSummaryCards.js +125 -0
  201. package/dist/modules/billing/components/account/AccountSummaryCards.js.map +7 -0
  202. package/dist/modules/billing/components/account/AccountUsageTab.js +91 -0
  203. package/dist/modules/billing/components/account/AccountUsageTab.js.map +7 -0
  204. package/dist/modules/billing/components/account/AccountView.js +73 -0
  205. package/dist/modules/billing/components/account/AccountView.js.map +7 -0
  206. package/dist/modules/billing/components/account/accountRow.js +39 -0
  207. package/dist/modules/billing/components/account/accountRow.js.map +7 -0
  208. package/dist/modules/billing/components/customerNames.js +42 -0
  209. package/dist/modules/billing/components/customerNames.js.map +7 -0
  210. package/dist/modules/billing/data/entities.js +615 -59
  211. package/dist/modules/billing/data/entities.js.map +2 -2
  212. package/dist/modules/billing/data/entityIds.js +10 -1
  213. package/dist/modules/billing/data/entityIds.js.map +2 -2
  214. package/dist/modules/billing/data/validators.js +269 -15
  215. package/dist/modules/billing/data/validators.js.map +2 -2
  216. package/dist/modules/billing/events.js +70 -0
  217. package/dist/modules/billing/events.js.map +2 -2
  218. package/dist/modules/billing/i18n/en.json +457 -21
  219. package/dist/modules/billing/i18n/pl.json +457 -21
  220. package/dist/modules/billing/index.js +6 -2
  221. package/dist/modules/billing/index.js.map +2 -2
  222. package/dist/modules/billing/lib/accountFinancials.js +58 -0
  223. package/dist/modules/billing/lib/accountFinancials.js.map +7 -0
  224. package/dist/modules/billing/lib/accountLock.js +14 -0
  225. package/dist/modules/billing/lib/accountLock.js.map +7 -0
  226. package/dist/modules/billing/lib/accountStatus.js +9 -7
  227. package/dist/modules/billing/lib/accountStatus.js.map +2 -2
  228. package/dist/modules/billing/lib/accountSummary.js +106 -0
  229. package/dist/modules/billing/lib/accountSummary.js.map +7 -0
  230. package/dist/modules/billing/lib/allocation.js +356 -0
  231. package/dist/modules/billing/lib/allocation.js.map +7 -0
  232. package/dist/modules/billing/lib/allocationEvents.js +22 -0
  233. package/dist/modules/billing/lib/allocationEvents.js.map +7 -0
  234. package/dist/modules/billing/lib/billPeriod.js +15 -1
  235. package/dist/modules/billing/lib/billPeriod.js.map +2 -2
  236. package/dist/modules/billing/lib/billRunEngine.js +241 -106
  237. package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
  238. package/dist/modules/billing/lib/billRunLabel.js.map +1 -1
  239. package/dist/modules/billing/lib/billingSettings.js +116 -0
  240. package/dist/modules/billing/lib/billingSettings.js.map +7 -0
  241. package/dist/modules/billing/lib/commandRoute.js +81 -0
  242. package/dist/modules/billing/lib/commandRoute.js.map +7 -0
  243. package/dist/modules/billing/lib/customerLookup.js +97 -0
  244. package/dist/modules/billing/lib/customerLookup.js.map +7 -0
  245. package/dist/modules/billing/lib/dateOnly.js +13 -0
  246. package/dist/modules/billing/lib/dateOnly.js.map +7 -0
  247. package/dist/modules/billing/lib/documentParties.js +16 -0
  248. package/dist/modules/billing/lib/documentParties.js.map +7 -0
  249. package/dist/modules/billing/lib/documentTypes.js +27 -0
  250. package/dist/modules/billing/lib/documentTypes.js.map +7 -0
  251. package/dist/modules/billing/lib/dueDate.js +18 -0
  252. package/dist/modules/billing/lib/dueDate.js.map +7 -0
  253. package/dist/modules/billing/lib/iban.js +29 -0
  254. package/dist/modules/billing/lib/iban.js.map +7 -0
  255. package/dist/modules/billing/lib/invoiceDelivery.js +131 -0
  256. package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
  257. package/dist/modules/billing/lib/invoiceLanguages.js +16 -0
  258. package/dist/modules/billing/lib/invoiceLanguages.js.map +7 -0
  259. package/dist/modules/billing/lib/invoiceWriter.js +107 -99
  260. package/dist/modules/billing/lib/invoiceWriter.js.map +2 -2
  261. package/dist/modules/billing/lib/itemBillingState.js +27 -0
  262. package/dist/modules/billing/lib/itemBillingState.js.map +7 -0
  263. package/dist/modules/billing/lib/itemPriceChange.js +18 -0
  264. package/dist/modules/billing/lib/itemPriceChange.js.map +7 -0
  265. package/dist/modules/billing/lib/itemSelector.js.map +2 -2
  266. package/dist/modules/billing/lib/lineAmounts.js +32 -0
  267. package/dist/modules/billing/lib/lineAmounts.js.map +7 -0
  268. package/dist/modules/billing/lib/memoGuards.js +25 -0
  269. package/dist/modules/billing/lib/memoGuards.js.map +7 -0
  270. package/dist/modules/billing/lib/navigation.js +48 -0
  271. package/dist/modules/billing/lib/navigation.js.map +7 -0
  272. package/dist/modules/billing/lib/numbering.js +120 -0
  273. package/dist/modules/billing/lib/numbering.js.map +7 -0
  274. package/dist/modules/billing/lib/overdue.js +36 -0
  275. package/dist/modules/billing/lib/overdue.js.map +7 -0
  276. package/dist/modules/billing/lib/paymentCsv.js +125 -0
  277. package/dist/modules/billing/lib/paymentCsv.js.map +7 -0
  278. package/dist/modules/billing/lib/paymentGateway.js +15 -0
  279. package/dist/modules/billing/lib/paymentGateway.js.map +7 -0
  280. package/dist/modules/billing/lib/paymentImport.js +164 -0
  281. package/dist/modules/billing/lib/paymentImport.js.map +7 -0
  282. package/dist/modules/billing/lib/paymentMatcher.js +36 -0
  283. package/dist/modules/billing/lib/paymentMatcher.js.map +7 -0
  284. package/dist/modules/billing/lib/pdf/attachmentStore.js +46 -0
  285. package/dist/modules/billing/lib/pdf/attachmentStore.js.map +7 -0
  286. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js +7 -0
  287. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js.map +7 -0
  288. package/dist/modules/billing/lib/pdf/invoiceModel.js +194 -0
  289. package/dist/modules/billing/lib/pdf/invoiceModel.js.map +7 -0
  290. package/dist/modules/billing/lib/pdf/invoicePdf.js +165 -0
  291. package/dist/modules/billing/lib/pdf/invoicePdf.js.map +7 -0
  292. package/dist/modules/billing/lib/pdf/invoiceTemplate.js +274 -0
  293. package/dist/modules/billing/lib/pdf/invoiceTemplate.js.map +7 -0
  294. package/dist/modules/billing/lib/prepaidConfig.js +17 -25
  295. package/dist/modules/billing/lib/prepaidConfig.js.map +2 -2
  296. package/dist/modules/billing/lib/prepaidConsume.js +26 -7
  297. package/dist/modules/billing/lib/prepaidConsume.js.map +2 -2
  298. package/dist/modules/billing/lib/prepaidPeriodClose.js +277 -158
  299. package/dist/modules/billing/lib/prepaidPeriodClose.js.map +2 -2
  300. package/dist/modules/billing/lib/prepaidTaxPoint.js +37 -0
  301. package/dist/modules/billing/lib/prepaidTaxPoint.js.map +7 -0
  302. package/dist/modules/billing/lib/seeds/demo.js +51 -3
  303. package/dist/modules/billing/lib/seeds/demo.js.map +2 -2
  304. package/dist/modules/billing/lib/seeds/paymentsSample.js +93 -0
  305. package/dist/modules/billing/lib/seeds/paymentsSample.js.map +7 -0
  306. package/dist/modules/billing/lib/seeds/sellerSettings.js +41 -0
  307. package/dist/modules/billing/lib/seeds/sellerSettings.js.map +7 -0
  308. package/dist/modules/billing/lib/servicePeriods.js +121 -0
  309. package/dist/modules/billing/lib/servicePeriods.js.map +7 -0
  310. package/dist/modules/billing/lib/tenantLock.js.map +1 -1
  311. package/dist/modules/billing/lib/testRunCleanup.js +24 -0
  312. package/dist/modules/billing/lib/testRunCleanup.js.map +7 -0
  313. package/dist/modules/billing/lib/topupCapture.js +2 -2
  314. package/dist/modules/billing/lib/topupCapture.js.map +2 -2
  315. package/dist/modules/billing/lib/topupReceipt.js +58 -79
  316. package/dist/modules/billing/lib/topupReceipt.js.map +2 -2
  317. package/dist/modules/billing/lib/usageRater.js.map +1 -1
  318. package/dist/modules/billing/lib/usageRunner.js +14 -6
  319. package/dist/modules/billing/lib/usageRunner.js.map +2 -2
  320. package/dist/modules/billing/lib/vat.js +39 -0
  321. package/dist/modules/billing/lib/vat.js.map +7 -0
  322. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js +15 -0
  323. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js.map +7 -0
  324. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js +25 -0
  325. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js.map +7 -0
  326. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js +115 -0
  327. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js.map +7 -0
  328. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js +47 -0
  329. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js.map +7 -0
  330. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js +89 -0
  331. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js.map +7 -0
  332. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js +17 -0
  333. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js.map +7 -0
  334. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js +27 -0
  335. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js.map +7 -0
  336. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js +29 -0
  337. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js.map +7 -0
  338. package/dist/modules/billing/setup.js +7 -184
  339. package/dist/modules/billing/setup.js.map +2 -2
  340. package/dist/modules/billing/subscribers/credit-memo-auto-send.js +16 -0
  341. package/dist/modules/billing/subscribers/credit-memo-auto-send.js.map +7 -0
  342. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js +16 -0
  343. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js.map +7 -0
  344. package/dist/modules/billing/subscribers/debit-memo-auto-send.js +16 -0
  345. package/dist/modules/billing/subscribers/debit-memo-auto-send.js.map +7 -0
  346. package/dist/modules/billing/subscribers/invoice-apply-credit.js +34 -0
  347. package/dist/modules/billing/subscribers/invoice-apply-credit.js.map +7 -0
  348. package/dist/modules/billing/subscribers/invoice-auto-send.js +30 -0
  349. package/dist/modules/billing/subscribers/invoice-auto-send.js.map +7 -0
  350. package/dist/modules/billing/subscribers/payment-captured-to-paid.js +69 -33
  351. package/dist/modules/billing/subscribers/payment-captured-to-paid.js.map +2 -2
  352. package/dist/modules/billing/subscribers/prepaid-topup-captured.js +4 -6
  353. package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +2 -2
  354. package/dist/modules/billing/workers/reap-stale-bill-runs.js +2 -2
  355. package/dist/modules/billing/workers/reap-stale-bill-runs.js.map +2 -2
  356. package/generated/entities/billing_account/index.ts +26 -0
  357. package/generated/entities/billing_account_balance/index.ts +13 -0
  358. package/generated/entities/billing_account_transaction/index.ts +21 -0
  359. package/generated/entities/billing_account_usage/index.ts +18 -0
  360. package/generated/entities/billing_allocation/index.ts +18 -0
  361. package/generated/entities/billing_document_sequence/index.ts +11 -0
  362. package/generated/entities/billing_draft_invoice_edit/index.ts +14 -0
  363. package/generated/entities/billing_invoice/index.ts +38 -0
  364. package/generated/entities/billing_invoice_line/index.ts +24 -0
  365. package/generated/entities/billing_item/index.ts +26 -0
  366. package/generated/entities/billing_payment/index.ts +25 -0
  367. package/generated/entities/billing_payment_import/index.ts +14 -0
  368. package/generated/entities/billing_run/index.ts +20 -0
  369. package/generated/entities/billing_run_outcome/index.ts +18 -0
  370. package/generated/entities/billing_settings/index.ts +26 -0
  371. package/generated/entities/billing_statement/index.ts +22 -0
  372. package/generated/entities/billing_topup/index.ts +20 -0
  373. package/generated/entities.ids.generated.ts +35 -0
  374. package/package.json +15 -10
  375. package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +170 -0
  376. package/src/modules/billing/__integration__/TC-BILL-005.spec.ts +134 -0
  377. package/src/modules/billing/__integration__/TC-BILL-006.spec.ts +101 -0
  378. package/src/modules/billing/__integration__/TC-BILL-007.spec.ts +140 -0
  379. package/src/modules/billing/__integration__/TC-BILL-008.spec.ts +108 -0
  380. package/src/modules/billing/__integration__/TC-BILL-009.spec.ts +113 -0
  381. package/src/modules/billing/__integration__/TC-BILL-010.spec.ts +118 -0
  382. package/src/modules/billing/__integration__/TC-BILL-011.spec.ts +142 -0
  383. package/src/modules/billing/__integration__/TC-BILL-012.spec.ts +115 -0
  384. package/src/modules/billing/__integration__/TC-BILL-013.spec.ts +118 -0
  385. package/src/modules/billing/__integration__/sellerSettings.ts +24 -0
  386. package/src/modules/billing/__tests__/commands/invoices.test.ts +437 -355
  387. package/src/modules/billing/__tests__/commands/itemsBulk.test.ts +33 -0
  388. package/src/modules/billing/__tests__/commands/memos.test.ts +205 -0
  389. package/src/modules/billing/__tests__/commands/payments.test.ts +241 -0
  390. package/src/modules/billing/__tests__/commands/runsDelete.test.ts +146 -0
  391. package/src/modules/billing/__tests__/commands/runsPostDrafts.test.ts +106 -0
  392. package/src/modules/billing/__tests__/commands/topups.test.ts +11 -0
  393. package/src/modules/billing/__tests__/entityRegistry.test.ts +326 -0
  394. package/src/modules/billing/__tests__/events.test.ts +142 -0
  395. package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
  396. package/src/modules/billing/__tests__/lib/accountFinancials.test.ts +53 -0
  397. package/src/modules/billing/__tests__/lib/accountSummary.test.ts +97 -0
  398. package/src/modules/billing/__tests__/lib/allocation.test.ts +319 -0
  399. package/src/modules/billing/__tests__/lib/billRunEngine.test.ts +231 -20
  400. package/src/modules/billing/__tests__/lib/billingSettings.test.ts +109 -0
  401. package/src/modules/billing/__tests__/lib/customerLookup.test.ts +156 -0
  402. package/src/modules/billing/__tests__/lib/dueDate.test.ts +35 -0
  403. package/src/modules/billing/__tests__/lib/iban.test.ts +38 -0
  404. package/src/modules/billing/__tests__/lib/invoiceDelivery.test.ts +189 -0
  405. package/src/modules/billing/__tests__/lib/invoiceWriter.test.ts +212 -10
  406. package/src/modules/billing/__tests__/lib/itemBillingState.test.ts +42 -0
  407. package/src/modules/billing/__tests__/lib/itemPriceChange.test.ts +165 -0
  408. package/src/modules/billing/__tests__/lib/lineAmounts.test.ts +86 -0
  409. package/src/modules/billing/__tests__/lib/navigation.test.ts +71 -0
  410. package/src/modules/billing/__tests__/lib/numbering.test.ts +91 -0
  411. package/src/modules/billing/__tests__/lib/overdue.test.ts +36 -0
  412. package/src/modules/billing/__tests__/lib/paymentCsv.test.ts +148 -0
  413. package/src/modules/billing/__tests__/lib/paymentImport.test.ts +113 -0
  414. package/src/modules/billing/__tests__/lib/paymentsSample.test.ts +73 -0
  415. package/src/modules/billing/__tests__/lib/pdf/invoicePdf.test.ts +199 -0
  416. package/src/modules/billing/__tests__/lib/pdf/invoicePdfService.test.ts +147 -0
  417. package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +374 -98
  418. package/src/modules/billing/__tests__/lib/prepaidTaxPoint.test.ts +118 -0
  419. package/src/modules/billing/__tests__/lib/seedsDemo.test.ts +53 -2
  420. package/src/modules/billing/__tests__/lib/sellerSettings.test.ts +28 -0
  421. package/src/modules/billing/__tests__/lib/servicePeriods.test.ts +190 -0
  422. package/src/modules/billing/__tests__/lib/topupCapture.test.ts +6 -28
  423. package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +21 -52
  424. package/src/modules/billing/__tests__/lib/vat.test.ts +51 -0
  425. package/src/modules/billing/__tests__/package-isolation.test.ts +22 -8
  426. package/src/modules/billing/__tests__/setup.test.ts +13 -4
  427. package/src/modules/billing/__tests__/validators.test.ts +193 -3
  428. package/src/modules/billing/acl.ts +12 -0
  429. package/src/modules/billing/api/accounts/[id]/summary/route.ts +62 -0
  430. package/src/modules/billing/api/accounts/route.ts +58 -4
  431. package/src/modules/billing/api/export/account/[id]/route.ts +20 -18
  432. package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
  433. package/src/modules/billing/api/invoices/[id]/pdf/route.ts +79 -0
  434. package/src/modules/billing/api/invoices/[id]/route.ts +57 -70
  435. package/src/modules/billing/api/invoices/[id]/send/route.ts +127 -0
  436. package/src/modules/billing/api/invoices/add-line/route.ts +3 -3
  437. package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
  438. package/src/modules/billing/api/invoices/edit-line/route.ts +4 -4
  439. package/src/modules/billing/api/invoices/post/route.ts +7 -6
  440. package/src/modules/billing/api/invoices/remove-line/route.ts +3 -3
  441. package/src/modules/billing/api/invoices/route.ts +81 -86
  442. package/src/modules/billing/api/items/bulk/route.ts +2 -1
  443. package/src/modules/billing/api/items/change-price/route.ts +54 -0
  444. package/src/modules/billing/api/items/route.ts +23 -7
  445. package/src/modules/billing/api/payment-imports/[id]/route.ts +49 -0
  446. package/src/modules/billing/api/payment-imports/route.ts +57 -0
  447. package/src/modules/billing/api/payments/[id]/route.ts +63 -0
  448. package/src/modules/billing/api/payments/allocate/route.ts +35 -0
  449. package/src/modules/billing/api/payments/assign/route.ts +36 -0
  450. package/src/modules/billing/api/payments/convert-to-topup/route.ts +35 -0
  451. package/src/modules/billing/api/payments/ignore/route.ts +35 -0
  452. package/src/modules/billing/api/payments/import/route.ts +72 -0
  453. package/src/modules/billing/api/payments/restore/route.ts +35 -0
  454. package/src/modules/billing/api/payments/route.ts +147 -0
  455. package/src/modules/billing/api/payments/unallocate/route.ts +35 -0
  456. package/src/modules/billing/api/payments/unassign/route.ts +35 -0
  457. package/src/modules/billing/api/run-outcomes/route.ts +50 -7
  458. package/src/modules/billing/api/runs/[id]/post-drafts/route.ts +71 -0
  459. package/src/modules/billing/api/runs/[id]/route.ts +59 -0
  460. package/src/modules/billing/api/runs/retry-failed/route.ts +4 -3
  461. package/src/modules/billing/api/runs/route.ts +17 -9
  462. package/src/modules/billing/api/settings/number-preview/route.ts +46 -0
  463. package/src/modules/billing/api/settings/route.ts +116 -0
  464. package/src/modules/billing/api/statements/route.ts +5 -0
  465. package/src/modules/billing/api/test-invoices/wipe/route.ts +2 -2
  466. package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +151 -372
  467. package/src/modules/billing/backend/billing/accounts/create/page.tsx +6 -0
  468. package/src/modules/billing/backend/billing/accounts/page.tsx +71 -5
  469. package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +445 -96
  470. package/src/modules/billing/backend/billing/invoices/page.tsx +8 -227
  471. package/src/modules/billing/backend/billing/items/[id]/page.tsx +75 -6
  472. package/src/modules/billing/backend/billing/items/create/page.tsx +13 -8
  473. package/src/modules/billing/backend/billing/items/page.tsx +19 -3
  474. package/src/modules/billing/backend/billing/payments/[id]/page.meta.ts +19 -0
  475. package/src/modules/billing/backend/billing/payments/[id]/page.tsx +415 -0
  476. package/src/modules/billing/backend/billing/payments/imports/[id]/page.meta.ts +19 -0
  477. package/src/modules/billing/backend/billing/payments/imports/[id]/page.tsx +106 -0
  478. package/src/modules/billing/backend/billing/payments/page.meta.ts +16 -0
  479. package/src/modules/billing/backend/billing/payments/page.tsx +56 -0
  480. package/src/modules/billing/backend/billing/runs/[id]/page.tsx +50 -19
  481. package/src/modules/billing/backend/billing/runs/page.tsx +60 -9
  482. package/src/modules/billing/backend/billing/statements/[id]/page.tsx +87 -6
  483. package/src/modules/billing/backend/billing/statements/page.tsx +2 -2
  484. package/src/modules/billing/backend/billing/topups/page.tsx +2 -2
  485. package/src/modules/billing/backend/billing/transactions/page.tsx +2 -2
  486. package/src/modules/billing/backend/billing/usage/create/page.tsx +3 -2
  487. package/src/modules/billing/backend/config/billing/page.meta.ts +21 -0
  488. package/src/modules/billing/backend/config/billing/page.tsx +549 -0
  489. package/src/modules/billing/ce.ts +8 -7
  490. package/src/modules/billing/cli.ts +31 -1
  491. package/src/modules/billing/commands/accounts.ts +6 -0
  492. package/src/modules/billing/commands/index.ts +3 -0
  493. package/src/modules/billing/commands/invoices.ts +371 -238
  494. package/src/modules/billing/commands/items.ts +143 -0
  495. package/src/modules/billing/commands/memos.ts +218 -0
  496. package/src/modules/billing/commands/payments.ts +428 -0
  497. package/src/modules/billing/commands/runs.ts +208 -6
  498. package/src/modules/billing/commands/settings.ts +77 -0
  499. package/src/modules/billing/commands/topups.ts +12 -3
  500. package/src/modules/billing/commands/transactions.ts +2 -2
  501. package/src/modules/billing/components/AccountForm.tsx +199 -53
  502. package/src/modules/billing/components/AccountInvoicesSection.tsx +75 -0
  503. package/src/modules/billing/components/AccountPaymentsSection.tsx +42 -0
  504. package/src/modules/billing/components/AccountPicker.tsx +70 -0
  505. package/src/modules/billing/components/AllocatePaymentDialog.tsx +167 -0
  506. package/src/modules/billing/components/BillingDataTable.tsx +34 -0
  507. package/src/modules/billing/components/BillingSettingsLink.tsx +25 -0
  508. package/src/modules/billing/components/ChangeItemPriceDialog.tsx +180 -0
  509. package/src/modules/billing/components/CreateMemoDialog.tsx +232 -0
  510. package/src/modules/billing/components/CustomerLabel.tsx +53 -0
  511. package/src/modules/billing/components/InvoicesTable.tsx +344 -0
  512. package/src/modules/billing/components/ItemForm.tsx +233 -44
  513. package/src/modules/billing/components/ItemPriceField.tsx +81 -0
  514. package/src/modules/billing/components/LineFormDialog.tsx +25 -1
  515. package/src/modules/billing/components/ManualPaymentDialog.tsx +140 -0
  516. package/src/modules/billing/components/MoneyInput.tsx +26 -0
  517. package/src/modules/billing/components/PaymentUploadDialog.tsx +148 -0
  518. package/src/modules/billing/components/PaymentsTable.tsx +213 -0
  519. package/src/modules/billing/components/PostRunDraftsButton.tsx +129 -0
  520. package/src/modules/billing/components/PrepaidPanel.tsx +20 -7
  521. package/src/modules/billing/components/RunCyclesSection.tsx +298 -0
  522. package/src/modules/billing/components/TestRunActions.tsx +152 -0
  523. package/src/modules/billing/components/account/AccountItemsTab.tsx +192 -0
  524. package/src/modules/billing/components/account/AccountRunBillingDialog.tsx +147 -0
  525. package/src/modules/billing/components/account/AccountRunsTab.tsx +201 -0
  526. package/src/modules/billing/components/account/AccountStatementsTab.tsx +120 -0
  527. package/src/modules/billing/components/account/AccountSummaryCards.tsx +153 -0
  528. package/src/modules/billing/components/account/AccountUsageTab.tsx +122 -0
  529. package/src/modules/billing/components/account/AccountView.tsx +101 -0
  530. package/src/modules/billing/components/account/accountRow.ts +70 -0
  531. package/src/modules/billing/components/customerNames.ts +62 -0
  532. package/src/modules/billing/data/entities.ts +685 -15
  533. package/src/modules/billing/data/entityIds.ts +25 -11
  534. package/src/modules/billing/data/validators.ts +388 -8
  535. package/src/modules/billing/events.ts +82 -3
  536. package/src/modules/billing/i18n/en.json +457 -21
  537. package/src/modules/billing/i18n/pl.json +457 -21
  538. package/src/modules/billing/index.ts +6 -2
  539. package/src/modules/billing/lib/accountFinancials.ts +84 -0
  540. package/src/modules/billing/lib/accountLock.ts +32 -0
  541. package/src/modules/billing/lib/accountStatus.ts +11 -9
  542. package/src/modules/billing/lib/accountSummary.ts +172 -0
  543. package/src/modules/billing/lib/allocation.ts +515 -0
  544. package/src/modules/billing/lib/allocationEvents.ts +26 -0
  545. package/src/modules/billing/lib/billPeriod.ts +19 -0
  546. package/src/modules/billing/lib/billRunEngine.ts +362 -162
  547. package/src/modules/billing/lib/billRunLabel.ts +1 -1
  548. package/src/modules/billing/lib/billingSettings.ts +145 -0
  549. package/src/modules/billing/lib/commandRoute.ts +112 -0
  550. package/src/modules/billing/lib/customerLookup.ts +157 -0
  551. package/src/modules/billing/lib/dateOnly.ts +22 -0
  552. package/src/modules/billing/lib/documentParties.ts +23 -0
  553. package/src/modules/billing/lib/documentTypes.ts +37 -0
  554. package/src/modules/billing/lib/dueDate.ts +26 -0
  555. package/src/modules/billing/lib/iban.ts +36 -0
  556. package/src/modules/billing/lib/invoiceDelivery.ts +197 -0
  557. package/src/modules/billing/lib/invoiceLanguages.ts +34 -0
  558. package/src/modules/billing/lib/invoiceWriter.ts +162 -148
  559. package/src/modules/billing/lib/itemBillingState.ts +67 -0
  560. package/src/modules/billing/lib/itemPriceChange.ts +56 -0
  561. package/src/modules/billing/lib/itemSelector.ts +4 -1
  562. package/src/modules/billing/lib/lineAmounts.ts +61 -0
  563. package/src/modules/billing/lib/memoGuards.ts +41 -0
  564. package/src/modules/billing/lib/navigation.ts +64 -0
  565. package/src/modules/billing/lib/numbering.ts +174 -0
  566. package/src/modules/billing/lib/overdue.ts +60 -0
  567. package/src/modules/billing/lib/paymentCsv.ts +171 -0
  568. package/src/modules/billing/lib/paymentGateway.ts +52 -0
  569. package/src/modules/billing/lib/paymentImport.ts +228 -0
  570. package/src/modules/billing/lib/paymentMatcher.ts +88 -0
  571. package/src/modules/billing/lib/pdf/attachmentStore.ts +60 -0
  572. package/src/modules/billing/lib/pdf/fonts/NotoSans-Bold.ttf +0 -0
  573. package/src/modules/billing/lib/pdf/fonts/NotoSans-Regular.ttf +0 -0
  574. package/src/modules/billing/lib/pdf/fonts/OFL.txt +93 -0
  575. package/src/modules/billing/lib/pdf/fonts/embeddedFonts.ts +9 -0
  576. package/src/modules/billing/lib/pdf/invoiceModel.ts +328 -0
  577. package/src/modules/billing/lib/pdf/invoicePdf.ts +216 -0
  578. package/src/modules/billing/lib/pdf/invoiceTemplate.ts +338 -0
  579. package/src/modules/billing/lib/prepaidConfig.ts +27 -36
  580. package/src/modules/billing/lib/prepaidConsume.ts +29 -6
  581. package/src/modules/billing/lib/prepaidPeriodClose.ts +410 -242
  582. package/src/modules/billing/lib/prepaidTaxPoint.ts +76 -0
  583. package/src/modules/billing/lib/seeds/demo.ts +79 -6
  584. package/src/modules/billing/lib/seeds/paymentsSample.ts +136 -0
  585. package/src/modules/billing/lib/seeds/sellerSettings.ts +78 -0
  586. package/src/modules/billing/lib/servicePeriods.ts +226 -0
  587. package/src/modules/billing/lib/tenantLock.ts +1 -1
  588. package/src/modules/billing/lib/testRunCleanup.ts +42 -0
  589. package/src/modules/billing/lib/topupCapture.ts +3 -4
  590. package/src/modules/billing/lib/topupReceipt.ts +70 -103
  591. package/src/modules/billing/lib/usageRater.ts +1 -1
  592. package/src/modules/billing/lib/usageRunner.ts +17 -5
  593. package/src/modules/billing/lib/vat.ts +56 -0
  594. package/src/modules/billing/migrations/Migration20261114000000_billing_customer_kind.ts +25 -0
  595. package/src/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.ts +37 -0
  596. package/src/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.ts +132 -0
  597. package/src/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.ts +58 -0
  598. package/src/modules/billing/migrations/Migration20261117000000_billing_payments.ts +97 -0
  599. package/src/modules/billing/migrations/Migration20261118000000_billing_memos.ts +21 -0
  600. package/src/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.ts +39 -0
  601. package/src/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.ts +35 -0
  602. package/src/modules/billing/setup.ts +11 -237
  603. package/src/modules/billing/subscribers/credit-memo-auto-send.ts +15 -0
  604. package/src/modules/billing/subscribers/debit-memo-apply-credit.ts +15 -0
  605. package/src/modules/billing/subscribers/debit-memo-auto-send.ts +15 -0
  606. package/src/modules/billing/subscribers/invoice-apply-credit.ts +39 -0
  607. package/src/modules/billing/subscribers/invoice-auto-send.ts +46 -0
  608. package/src/modules/billing/subscribers/payment-captured-to-paid.ts +84 -62
  609. package/src/modules/billing/subscribers/prepaid-topup-captured.ts +4 -8
  610. package/src/modules/billing/workers/reap-stale-bill-runs.ts +4 -4
  611. package/dist/modules/billing/lib/invoiceStatus.js +0 -38
  612. package/dist/modules/billing/lib/invoiceStatus.js.map +0 -7
  613. package/src/modules/billing/__tests__/lib/invoiceStatus.test.ts +0 -97
  614. package/src/modules/billing/lib/invoiceStatus.ts +0 -61
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation";
5
5
  import { Play } from "lucide-react";
6
6
  import { useT } from "@open-mercato/shared/lib/i18n/context";
7
7
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
8
- import { DataTable } from "@open-mercato/ui/backend/DataTable";
8
+ import { BillingDataTable as DataTable } from "../../../components/BillingDataTable.js";
9
+ import { RowActions } from "@open-mercato/ui/backend/RowActions";
10
+ import { BillingSettingsLink } from "../../../components/BillingSettingsLink.js";
11
+ import { billRunMode, useTestRunCleanup } from "../../../components/TestRunActions.js";
9
12
  import { Tag } from "@open-mercato/ui/primitives/tag";
10
13
  import { Button } from "@open-mercato/ui/primitives/button";
11
14
  import { Input } from "@open-mercato/ui/primitives/input";
@@ -71,6 +74,7 @@ function BillRunsListPage() {
71
74
  const [totalPages, setTotalPages] = React.useState(1);
72
75
  const [loading, setLoading] = React.useState(true);
73
76
  const [search, setSearch] = React.useState("");
77
+ const cleanup = useTestRunCleanup();
74
78
  const [triggerOpen, setTriggerOpen] = React.useState(false);
75
79
  const [triggerMode, setTriggerMode] = React.useState("real");
76
80
  const [triggerAsOfDate, setTriggerAsOfDate] = React.useState(todayIso());
@@ -91,6 +95,16 @@ function BillRunsListPage() {
91
95
  { value: "failed", label: t("billing.runs.status.failed", "Failed") }
92
96
  ]
93
97
  },
98
+ {
99
+ id: "mode",
100
+ label: t("billing.runs.filters.mode", "Mode"),
101
+ type: "select",
102
+ options: [
103
+ { value: "real", label: t("billing.runs.mode.real", "Real") },
104
+ { value: "test", label: t("billing.runs.mode.test", "Test") },
105
+ { value: "dry", label: t("billing.runs.mode.dry_run", "Dry-run") }
106
+ ]
107
+ },
94
108
  {
95
109
  id: "triggeredBy",
96
110
  label: t("billing.runs.filters.triggered_by", "Trigger"),
@@ -119,6 +133,9 @@ function BillRunsListPage() {
119
133
  if (typeof filters.triggeredBy === "string" && filters.triggeredBy) {
120
134
  params.set("triggeredBy", filters.triggeredBy);
121
135
  }
136
+ if (typeof filters.mode === "string" && filters.mode) {
137
+ params.set("mode", filters.mode);
138
+ }
122
139
  const result = await readApiResultOrThrow(
123
140
  `/api/billing/runs?${params.toString()}`
124
141
  );
@@ -128,7 +145,7 @@ function BillRunsListPage() {
128
145
  } finally {
129
146
  setLoading(false);
130
147
  }
131
- }, [filters.status, filters.triggeredBy, page, pageSize, search]);
148
+ }, [filters.mode, filters.status, filters.triggeredBy, page, pageSize, search]);
132
149
  React.useEffect(() => {
133
150
  void loadRows();
134
151
  }, [loadRows]);
@@ -235,9 +252,12 @@ function BillRunsListPage() {
235
252
  DataTable,
236
253
  {
237
254
  title: t("billing.runs.title", "Bill Runs"),
238
- actions: /* @__PURE__ */ jsxs(Button, { onClick: () => setTriggerOpen(true), children: [
239
- /* @__PURE__ */ jsx(Play, { size: 16 }),
240
- t("billing.runs.trigger.action", "New run")
255
+ actions: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
256
+ /* @__PURE__ */ jsx(BillingSettingsLink, {}),
257
+ /* @__PURE__ */ jsxs(Button, { onClick: () => setTriggerOpen(true), children: [
258
+ /* @__PURE__ */ jsx(Play, { size: 16 }),
259
+ t("billing.runs.trigger.action", "New run")
260
+ ] })
241
261
  ] }),
242
262
  refreshButton: {
243
263
  label: t("billing.common.refresh", "Refresh"),
@@ -249,6 +269,36 @@ function BillRunsListPage() {
249
269
  columns,
250
270
  data: rows,
251
271
  onRowClick: (row) => router.push(`/backend/billing/runs/${row.id}`),
272
+ rowActions: (row) => {
273
+ const mode = billRunMode(row);
274
+ return /* @__PURE__ */ jsx(
275
+ RowActions,
276
+ {
277
+ items: [
278
+ {
279
+ id: "open",
280
+ label: t("billing.runs.actions.open", "Open"),
281
+ href: `/backend/billing/runs/${row.id}`
282
+ },
283
+ ...mode !== "real" && row.status !== "running" ? [
284
+ {
285
+ id: "delete",
286
+ label: t("billing.runs.delete.action", "Delete run"),
287
+ destructive: true,
288
+ onSelect: async () => {
289
+ const removed = await cleanup.remove({
290
+ runId: row.id,
291
+ mode,
292
+ draftsCount: row.summary?.drafts_created
293
+ });
294
+ if (removed !== null) void loadRows();
295
+ }
296
+ }
297
+ ] : []
298
+ ]
299
+ }
300
+ );
301
+ },
252
302
  isLoading: loading,
253
303
  pagination: {
254
304
  page,
@@ -304,7 +354,7 @@ function BillRunsListPage() {
304
354
  ),
305
355
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
306
356
  "billing.runs.trigger.dialog.as_of_date.help",
307
- "Accounts whose next bill date is on or before this date will be billed."
357
+ "Bills every due cycle up to this date \u2014 one draft per bill date. Test and dry-run simulate them without changing accounts."
308
358
  ) })
309
359
  ] })
310
360
  ] }),
@@ -332,7 +382,8 @@ function BillRunsListPage() {
332
382
  /* @__PURE__ */ jsx(Button, { type: "button", onClick: () => void handleTrigger(), disabled: triggering, children: triggering ? t("billing.runs.trigger.dialog.running", "Running\u2026") : t("billing.runs.trigger.dialog.submit", "Run now") })
333
383
  ] })
334
384
  ] })
335
- ] }) })
385
+ ] }) }),
386
+ cleanup.ConfirmDialogElement
336
387
  ] }) });
337
388
  }
338
389
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/backend/billing/runs/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Play } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Kbd, KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { normalizeCrudServerError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { billRunName } from '../../../lib/billRunLabel'\n\n/**\n * Bill Runs admin list page.\n *\n * Lists every Bill Run for the operator's tenant with status, mode,\n * summary stats, and a link into the detail page. The \"New run\" button\n * opens an inline trigger dialog that posts to `/api/billing/runs` \u2014\n * same endpoint operators previously had to curl by hand. Retry-failed\n * stays on the run detail page (scoped to a specific run's failures).\n */\n\ntype TriggerMode = 'real' | 'dry' | 'test'\n\nfunction todayIso(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\n// API list rows are snake_case (see `api/runs/route.ts` `fields`).\ntype BillRunRow = {\n id: string\n triggered_by: 'schedule' | 'manual'\n parent_run_id: string | null\n dry_run: boolean\n test_mode: boolean\n catch_up: boolean\n as_of_date: string\n started_at: string | null\n finished_at: string | null\n status: 'running' | 'completed' | 'partial_failure' | 'failed'\n summary: {\n accounts_processed?: number\n drafts_created?: number\n drafts_skipped_existing?: number\n accounts_failed?: number\n accounts_with_warnings?: number\n usage_records_rated?: number\n } | null\n created_at: string\n updated_at: string\n}\n\ntype ListResponse = {\n items: BillRunRow[]\n total: number\n totalPages: number\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n}\n\nfunction formatDateOnly(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleDateString()\n}\n\nfunction statusVariant(\n status: BillRunRow['status'],\n): 'default' | 'success' | 'warning' | 'error' {\n switch (status) {\n case 'completed':\n return 'success'\n case 'partial_failure':\n return 'warning'\n case 'failed':\n return 'error'\n case 'running':\n default:\n return 'default'\n }\n}\n\nfunction modeBadge(row: BillRunRow): { label: string; variant: 'default' | 'warning' } | null {\n if (row.dry_run) return { label: 'Dry-run', variant: 'warning' }\n if (row.test_mode) return { label: 'Test', variant: 'warning' }\n return null\n}\n\nexport default function BillRunsListPage() {\n const t = useT()\n const router = useRouter()\n const [rows, setRows] = React.useState<BillRunRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filters, setFilters] = React.useState<FilterValues>({})\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [search, setSearch] = React.useState('')\n\n // Trigger dialog \u2014 controls the New-run modal and its submit state.\n const [triggerOpen, setTriggerOpen] = React.useState(false)\n const [triggerMode, setTriggerMode] = React.useState<TriggerMode>('real')\n const [triggerAsOfDate, setTriggerAsOfDate] = React.useState<string>(todayIso())\n const [triggering, setTriggering] = React.useState(false)\n\n const filterDefs = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: t('billing.runs.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'running', label: t('billing.runs.status.running', 'Running') },\n { value: 'completed', label: t('billing.runs.status.completed', 'Completed') },\n {\n value: 'partial_failure',\n label: t('billing.runs.status.partial_failure', 'Partial failure'),\n },\n { value: 'failed', label: t('billing.runs.status.failed', 'Failed') },\n ],\n },\n {\n id: 'triggeredBy',\n label: t('billing.runs.filters.triggered_by', 'Trigger'),\n type: 'select',\n options: [\n { value: 'schedule', label: t('billing.runs.trigger.schedule', 'Schedule') },\n { value: 'manual', label: t('billing.runs.trigger.manual', 'Manual') },\n ],\n },\n ],\n [t],\n )\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'startedAt',\n sortDir: 'desc',\n })\n if (search.trim()) params.set('search', search.trim())\n if (typeof filters.status === 'string' && filters.status) {\n params.set('status', filters.status)\n }\n if (typeof filters.triggeredBy === 'string' && filters.triggeredBy) {\n params.set('triggeredBy', filters.triggeredBy)\n }\n const result = await readApiResultOrThrow<ListResponse>(\n `/api/billing/runs?${params.toString()}`,\n )\n setRows(result.items ?? [])\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n } finally {\n setLoading(false)\n }\n }, [filters.status, filters.triggeredBy, page, pageSize, search])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const handleTrigger = React.useCallback(async () => {\n setTriggering(true)\n try {\n const payload: Record<string, unknown> = { mode: triggerMode }\n if (triggerAsOfDate) payload.asOfDate = triggerAsOfDate\n const call = await apiCallOrThrow<{ billRunId: string | null }>(\n '/api/billing/runs',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n flash(t('billing.runs.trigger.success', 'Bill Run triggered'), 'success')\n setTriggerOpen(false)\n const newId = call.result?.billRunId\n if (newId) {\n router.push(`/backend/billing/runs/${newId}`)\n } else {\n void loadRows()\n }\n } catch (err) {\n const { message, fieldErrors } = normalizeCrudServerError(err)\n const fieldDetail =\n fieldErrors && Object.keys(fieldErrors).length\n ? Object.entries(fieldErrors)\n .map(([field, msg]) => `${field}: ${msg}`)\n .join('; ')\n : null\n const detailed =\n fieldDetail && message ? `${message} \u2014 ${fieldDetail}` : fieldDetail || message\n flash(detailed || t('billing.runs.trigger.error', 'Failed to trigger run'), 'error')\n } finally {\n setTriggering(false)\n }\n }, [loadRows, router, t, triggerAsOfDate, triggerMode])\n\n const handleTriggerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!triggering) void handleTrigger()\n }\n },\n [handleTrigger, triggering],\n )\n\n const columns = React.useMemo<ColumnDef<BillRunRow>[]>(\n () => [\n {\n id: 'name',\n header: t('billing.runs.columns.name', 'Bill Run'),\n cell: ({ row }) => (\n <span className=\"text-sm font-medium text-primary\">\n {billRunName(row.original.as_of_date)}\n </span>\n ),\n },\n {\n accessorKey: 'status',\n header: t('billing.runs.columns.status', 'Status'),\n cell: ({ row }) => {\n const mode = modeBadge(row.original)\n return (\n <div className=\"flex items-center gap-2\">\n <Tag variant={statusVariant(row.original.status)}>\n {row.original.status}\n </Tag>\n {mode ? <Tag variant={mode.variant}>{mode.label}</Tag> : null}\n </div>\n )\n },\n },\n {\n accessorKey: 'as_of_date',\n header: t('billing.runs.columns.as_of_date', 'As-of date'),\n cell: ({ row }) => formatDateOnly(row.original.as_of_date),\n },\n {\n accessorKey: 'triggered_by',\n header: t('billing.runs.columns.triggered_by', 'Trigger'),\n },\n {\n id: 'drafts_created',\n header: t('billing.runs.columns.drafts', 'Drafts'),\n cell: ({ row }) => row.original.summary?.drafts_created ?? '\u2014',\n },\n {\n id: 'accounts_processed',\n header: t('billing.runs.columns.accounts', 'Accounts'),\n cell: ({ row }) => row.original.summary?.accounts_processed ?? '\u2014',\n },\n {\n id: 'accounts_failed',\n header: t('billing.runs.columns.failed', 'Failed'),\n cell: ({ row }) => {\n const failed = row.original.summary?.accounts_failed ?? 0\n if (failed === 0) return '\u2014'\n return <Tag variant=\"error\">{failed}</Tag>\n },\n },\n {\n accessorKey: 'started_at',\n header: t('billing.runs.columns.started_at', 'Started'),\n cell: ({ row }) => formatDate(row.original.started_at),\n },\n {\n accessorKey: 'finished_at',\n header: t('billing.runs.columns.finished_at', 'Finished'),\n cell: ({ row }) => formatDate(row.original.finished_at),\n },\n ],\n [t],\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('billing.runs.title', 'Bill Runs')}\n actions={\n <Button onClick={() => setTriggerOpen(true)}>\n <Play size={16} />\n {t('billing.runs.trigger.action', 'New run')}\n </Button>\n }\n refreshButton={{\n label: t('billing.common.refresh', 'Refresh'),\n onRefresh: loadRows,\n isRefreshing: loading,\n }}\n columnChooser={{ auto: true }}\n perspective={{ tableId: 'billing-runs' }}\n columns={columns}\n data={rows}\n onRowClick={(row) => router.push(`/backend/billing/runs/${row.id}`)}\n isLoading={loading}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={setFilters}\n onFiltersClear={() => setFilters({})}\n searchValue={search}\n onSearchChange={setSearch}\n />\n\n <Dialog open={triggerOpen} onOpenChange={(next) => !triggering && setTriggerOpen(next)}>\n <DialogContent onKeyDown={handleTriggerKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('billing.runs.trigger.dialog.title', 'Trigger Bill Run')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'billing.runs.trigger.dialog.description',\n 'Runs the bill cycle for every account whose next bill date has passed. Dry-run / Test produce drafts without posting any invoices.',\n )}\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-4\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"text-muted-foreground\">\n {t('billing.runs.trigger.dialog.mode', 'Mode')}\n </span>\n <Select\n value={triggerMode}\n onValueChange={(next) => setTriggerMode(next as TriggerMode)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"real\">\n {t('billing.runs.trigger.dialog.mode.real', 'Real \u2014 create draft invoices')}\n </SelectItem>\n <SelectItem value=\"dry\">\n {t('billing.runs.trigger.dialog.mode.dry', 'Dry-run \u2014 no rows written')}\n </SelectItem>\n <SelectItem value=\"test\">\n {t('billing.runs.trigger.dialog.mode.test', 'Test \u2014 drafts tagged for cleanup')}\n </SelectItem>\n </SelectContent>\n </Select>\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"text-muted-foreground\">\n {t('billing.runs.trigger.dialog.as_of_date', 'As-of date')}\n </span>\n <Input\n type=\"date\"\n value={triggerAsOfDate}\n onChange={(event) => setTriggerAsOfDate(event.currentTarget.value)}\n />\n <span className=\"text-xs text-muted-foreground\">\n {t(\n 'billing.runs.trigger.dialog.as_of_date.help',\n 'Accounts whose next bill date is on or before this date will be billed.',\n )}\n </span>\n </label>\n </div>\n <DialogFooter className=\"flex items-center justify-between gap-3 sm:justify-between\">\n <span className=\"text-xs text-muted-foreground\">\n <KbdShortcut keys={['Ctrl/\u2318', 'Enter']} />{' '}\n {t('billing.runs.trigger.dialog.submit_hint', 'to run,')} <Kbd>Esc</Kbd>{' '}\n {t('billing.runs.trigger.dialog.cancel_hint', 'to cancel')}\n </span>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setTriggerOpen(false)}\n disabled={triggering}\n >\n {t('billing.common.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void handleTrigger()} disabled={triggering}>\n {triggering\n ? t('billing.runs.trigger.dialog.running', 'Running\u2026')\n : t('billing.runs.trigger.dialog.submit', 'Run now')}\n </Button>\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Play } from 'lucide-react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { BillingDataTable as DataTable } from '../../../components/BillingDataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { BillingSettingsLink } from '../../../components/BillingSettingsLink'\nimport { billRunMode, useTestRunCleanup } from '../../../components/TestRunActions'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Kbd, KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { normalizeCrudServerError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { billRunName } from '../../../lib/billRunLabel'\n\n/**\n * Bill Runs admin list page.\n *\n * Lists every Bill Run for the operator's tenant with status, mode,\n * summary stats, and a link into the detail page. The \"New run\" button\n * opens an inline trigger dialog that posts to `/api/billing/runs` \u2014\n * same endpoint operators previously had to curl by hand. Retry-failed\n * stays on the run detail page (scoped to a specific run's failures).\n */\n\ntype TriggerMode = 'real' | 'dry' | 'test'\n\nfunction todayIso(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\n// API list rows are snake_case (see `api/runs/route.ts` `fields`).\ntype BillRunRow = {\n id: string\n triggered_by: 'schedule' | 'manual'\n parent_run_id: string | null\n dry_run: boolean\n test_mode: boolean\n as_of_date: string\n started_at: string | null\n finished_at: string | null\n status: 'running' | 'completed' | 'partial_failure' | 'failed'\n summary: {\n accounts_processed?: number\n drafts_created?: number\n drafts_skipped_existing?: number\n accounts_failed?: number\n accounts_with_warnings?: number\n usage_records_rated?: number\n } | null\n created_at: string\n updated_at: string\n}\n\ntype ListResponse = {\n items: BillRunRow[]\n total: number\n totalPages: number\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n}\n\nfunction formatDateOnly(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const parsed = new Date(value)\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleDateString()\n}\n\nfunction statusVariant(\n status: BillRunRow['status'],\n): 'default' | 'success' | 'warning' | 'error' {\n switch (status) {\n case 'completed':\n return 'success'\n case 'partial_failure':\n return 'warning'\n case 'failed':\n return 'error'\n case 'running':\n default:\n return 'default'\n }\n}\n\nfunction modeBadge(row: BillRunRow): { label: string; variant: 'default' | 'warning' } | null {\n if (row.dry_run) return { label: 'Dry-run', variant: 'warning' }\n if (row.test_mode) return { label: 'Test', variant: 'warning' }\n return null\n}\n\nexport default function BillRunsListPage() {\n const t = useT()\n const router = useRouter()\n const [rows, setRows] = React.useState<BillRunRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filters, setFilters] = React.useState<FilterValues>({})\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [search, setSearch] = React.useState('')\n const cleanup = useTestRunCleanup()\n\n // Trigger dialog \u2014 controls the New-run modal and its submit state.\n const [triggerOpen, setTriggerOpen] = React.useState(false)\n const [triggerMode, setTriggerMode] = React.useState<TriggerMode>('real')\n const [triggerAsOfDate, setTriggerAsOfDate] = React.useState<string>(todayIso())\n const [triggering, setTriggering] = React.useState(false)\n\n const filterDefs = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: t('billing.runs.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'running', label: t('billing.runs.status.running', 'Running') },\n { value: 'completed', label: t('billing.runs.status.completed', 'Completed') },\n {\n value: 'partial_failure',\n label: t('billing.runs.status.partial_failure', 'Partial failure'),\n },\n { value: 'failed', label: t('billing.runs.status.failed', 'Failed') },\n ],\n },\n {\n id: 'mode',\n label: t('billing.runs.filters.mode', 'Mode'),\n type: 'select',\n options: [\n { value: 'real', label: t('billing.runs.mode.real', 'Real') },\n { value: 'test', label: t('billing.runs.mode.test', 'Test') },\n { value: 'dry', label: t('billing.runs.mode.dry_run', 'Dry-run') },\n ],\n },\n {\n id: 'triggeredBy',\n label: t('billing.runs.filters.triggered_by', 'Trigger'),\n type: 'select',\n options: [\n { value: 'schedule', label: t('billing.runs.trigger.schedule', 'Schedule') },\n { value: 'manual', label: t('billing.runs.trigger.manual', 'Manual') },\n ],\n },\n ],\n [t],\n )\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'startedAt',\n sortDir: 'desc',\n })\n if (search.trim()) params.set('search', search.trim())\n if (typeof filters.status === 'string' && filters.status) {\n params.set('status', filters.status)\n }\n if (typeof filters.triggeredBy === 'string' && filters.triggeredBy) {\n params.set('triggeredBy', filters.triggeredBy)\n }\n if (typeof filters.mode === 'string' && filters.mode) {\n params.set('mode', filters.mode)\n }\n const result = await readApiResultOrThrow<ListResponse>(\n `/api/billing/runs?${params.toString()}`,\n )\n setRows(result.items ?? [])\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n } finally {\n setLoading(false)\n }\n }, [filters.mode, filters.status, filters.triggeredBy, page, pageSize, search])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const handleTrigger = React.useCallback(async () => {\n setTriggering(true)\n try {\n const payload: Record<string, unknown> = { mode: triggerMode }\n if (triggerAsOfDate) payload.asOfDate = triggerAsOfDate\n const call = await apiCallOrThrow<{ billRunId: string | null }>(\n '/api/billing/runs',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n flash(t('billing.runs.trigger.success', 'Bill Run triggered'), 'success')\n setTriggerOpen(false)\n const newId = call.result?.billRunId\n if (newId) {\n router.push(`/backend/billing/runs/${newId}`)\n } else {\n void loadRows()\n }\n } catch (err) {\n const { message, fieldErrors } = normalizeCrudServerError(err)\n const fieldDetail =\n fieldErrors && Object.keys(fieldErrors).length\n ? Object.entries(fieldErrors)\n .map(([field, msg]) => `${field}: ${msg}`)\n .join('; ')\n : null\n const detailed =\n fieldDetail && message ? `${message} \u2014 ${fieldDetail}` : fieldDetail || message\n flash(detailed || t('billing.runs.trigger.error', 'Failed to trigger run'), 'error')\n } finally {\n setTriggering(false)\n }\n }, [loadRows, router, t, triggerAsOfDate, triggerMode])\n\n const handleTriggerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!triggering) void handleTrigger()\n }\n },\n [handleTrigger, triggering],\n )\n\n const columns = React.useMemo<ColumnDef<BillRunRow>[]>(\n () => [\n {\n id: 'name',\n header: t('billing.runs.columns.name', 'Bill Run'),\n cell: ({ row }) => (\n <span className=\"text-sm font-medium text-primary\">\n {billRunName(row.original.as_of_date)}\n </span>\n ),\n },\n {\n accessorKey: 'status',\n header: t('billing.runs.columns.status', 'Status'),\n cell: ({ row }) => {\n const mode = modeBadge(row.original)\n return (\n <div className=\"flex items-center gap-2\">\n <Tag variant={statusVariant(row.original.status)}>\n {row.original.status}\n </Tag>\n {mode ? <Tag variant={mode.variant}>{mode.label}</Tag> : null}\n </div>\n )\n },\n },\n {\n accessorKey: 'as_of_date',\n header: t('billing.runs.columns.as_of_date', 'As-of date'),\n cell: ({ row }) => formatDateOnly(row.original.as_of_date),\n },\n {\n accessorKey: 'triggered_by',\n header: t('billing.runs.columns.triggered_by', 'Trigger'),\n },\n {\n id: 'drafts_created',\n header: t('billing.runs.columns.drafts', 'Drafts'),\n cell: ({ row }) => row.original.summary?.drafts_created ?? '\u2014',\n },\n {\n id: 'accounts_processed',\n header: t('billing.runs.columns.accounts', 'Accounts'),\n cell: ({ row }) => row.original.summary?.accounts_processed ?? '\u2014',\n },\n {\n id: 'accounts_failed',\n header: t('billing.runs.columns.failed', 'Failed'),\n cell: ({ row }) => {\n const failed = row.original.summary?.accounts_failed ?? 0\n if (failed === 0) return '\u2014'\n return <Tag variant=\"error\">{failed}</Tag>\n },\n },\n {\n accessorKey: 'started_at',\n header: t('billing.runs.columns.started_at', 'Started'),\n cell: ({ row }) => formatDate(row.original.started_at),\n },\n {\n accessorKey: 'finished_at',\n header: t('billing.runs.columns.finished_at', 'Finished'),\n cell: ({ row }) => formatDate(row.original.finished_at),\n },\n ],\n [t],\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('billing.runs.title', 'Bill Runs')}\n actions={\n <div className=\"flex items-center gap-2\">\n <BillingSettingsLink />\n <Button onClick={() => setTriggerOpen(true)}>\n <Play size={16} />\n {t('billing.runs.trigger.action', 'New run')}\n </Button>\n </div>\n }\n refreshButton={{\n label: t('billing.common.refresh', 'Refresh'),\n onRefresh: loadRows,\n isRefreshing: loading,\n }}\n columnChooser={{ auto: true }}\n perspective={{ tableId: 'billing-runs' }}\n columns={columns}\n data={rows}\n onRowClick={(row) => router.push(`/backend/billing/runs/${row.id}`)}\n rowActions={(row) => {\n const mode = billRunMode(row)\n return (\n <RowActions\n items={[\n {\n id: 'open',\n label: t('billing.runs.actions.open', 'Open'),\n href: `/backend/billing/runs/${row.id}`,\n },\n ...(mode !== 'real' && row.status !== 'running'\n ? [\n {\n id: 'delete',\n label: t('billing.runs.delete.action', 'Delete run'),\n destructive: true,\n onSelect: async () => {\n const removed = await cleanup.remove({\n runId: row.id,\n mode,\n draftsCount: row.summary?.drafts_created,\n })\n if (removed !== null) void loadRows()\n },\n },\n ]\n : []),\n ]}\n />\n )\n }}\n isLoading={loading}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={setFilters}\n onFiltersClear={() => setFilters({})}\n searchValue={search}\n onSearchChange={setSearch}\n />\n\n <Dialog open={triggerOpen} onOpenChange={(next) => !triggering && setTriggerOpen(next)}>\n <DialogContent onKeyDown={handleTriggerKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('billing.runs.trigger.dialog.title', 'Trigger Bill Run')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'billing.runs.trigger.dialog.description',\n 'Runs the bill cycle for every account whose next bill date has passed. Dry-run / Test produce drafts without posting any invoices.',\n )}\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-4\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"text-muted-foreground\">\n {t('billing.runs.trigger.dialog.mode', 'Mode')}\n </span>\n <Select\n value={triggerMode}\n onValueChange={(next) => setTriggerMode(next as TriggerMode)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"real\">\n {t('billing.runs.trigger.dialog.mode.real', 'Real \u2014 create draft invoices')}\n </SelectItem>\n <SelectItem value=\"dry\">\n {t('billing.runs.trigger.dialog.mode.dry', 'Dry-run \u2014 no rows written')}\n </SelectItem>\n <SelectItem value=\"test\">\n {t('billing.runs.trigger.dialog.mode.test', 'Test \u2014 drafts tagged for cleanup')}\n </SelectItem>\n </SelectContent>\n </Select>\n </label>\n <label className=\"flex flex-col gap-1 text-sm\">\n <span className=\"text-muted-foreground\">\n {t('billing.runs.trigger.dialog.as_of_date', 'As-of date')}\n </span>\n <Input\n type=\"date\"\n value={triggerAsOfDate}\n onChange={(event) => setTriggerAsOfDate(event.currentTarget.value)}\n />\n <span className=\"text-xs text-muted-foreground\">\n {t(\n 'billing.runs.trigger.dialog.as_of_date.help',\n 'Bills every due cycle up to this date \u2014 one draft per bill date. Test and dry-run simulate them without changing accounts.',\n )}\n </span>\n </label>\n </div>\n <DialogFooter className=\"flex items-center justify-between gap-3 sm:justify-between\">\n <span className=\"text-xs text-muted-foreground\">\n <KbdShortcut keys={['Ctrl/\u2318', 'Enter']} />{' '}\n {t('billing.runs.trigger.dialog.submit_hint', 'to run,')} <Kbd>Esc</Kbd>{' '}\n {t('billing.runs.trigger.dialog.cancel_hint', 'to cancel')}\n </span>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setTriggerOpen(false)}\n disabled={triggering}\n >\n {t('billing.common.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void handleTrigger()} disabled={triggering}>\n {triggering\n ? t('billing.runs.trigger.dialog.running', 'Running\u2026')\n : t('billing.runs.trigger.dialog.submit', 'Run now')}\n </Button>\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n {cleanup.ConfirmDialogElement}\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -8,7 +8,7 @@ import { Page, PageBody } from "@open-mercato/ui/backend/Page";
8
8
  import { FormHeader } from "@open-mercato/ui/backend/forms";
9
9
  import { Tag } from "@open-mercato/ui/primitives/tag";
10
10
  import { Button } from "@open-mercato/ui/primitives/button";
11
- import { DataTable } from "@open-mercato/ui/backend/DataTable";
11
+ import { BillingDataTable as DataTable } from "../../../../components/BillingDataTable.js";
12
12
  import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
13
13
  import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
14
14
  import { DetailCard, DetailField } from "../../../../components/DetailFields.js";
@@ -47,6 +47,8 @@ function BillingStatementDetailPage(props) {
47
47
  };
48
48
  }, [statementId, t]);
49
49
  const breakdown = row?.debit_breakdown?.items ?? [];
50
+ const vatSummary = row?.vat_summary ?? [];
51
+ const showVat = vatSummary.length > 0;
50
52
  const columns = React.useMemo(
51
53
  () => [
52
54
  {
@@ -57,19 +59,62 @@ function BillingStatementDetailPage(props) {
57
59
  {
58
60
  accessorKey: "billing_item_id",
59
61
  header: t("billing.statements.breakdown.item", "Item"),
60
- cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: row2.original.billing_item_id })
62
+ cell: ({ row: row2 }) => /* @__PURE__ */ jsx(Link, { href: `/backend/billing/items/${row2.original.billing_item_id}`, className: "text-sm text-primary hover:underline", children: row2.original.description ?? row2.original.billing_item_id })
63
+ },
64
+ {
65
+ accessorKey: "service_period_start",
66
+ header: t("billing.statements.breakdown.service_period", "Service period"),
67
+ cell: ({ row: row2 }) => row2.original.service_period_start ? `${row2.original.service_period_start} \u2013 ${row2.original.service_period_end ?? "\u2026"}` : "\u2014"
61
68
  },
62
69
  {
63
70
  accessorKey: "quantity",
64
71
  header: t("billing.statements.breakdown.quantity", "Qty"),
65
72
  cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row2.original.quantity })
66
73
  },
74
+ ...showVat ? [
75
+ {
76
+ accessorKey: "net",
77
+ header: t("billing.statements.breakdown.net", "Net"),
78
+ cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row2.original.net ?? "\u2014" })
79
+ },
80
+ {
81
+ accessorKey: "tax",
82
+ header: t("billing.statements.breakdown.vat", "VAT"),
83
+ cell: ({ row: row2 }) => row2.original.tax !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "font-mono tabular-nums", children: [
84
+ row2.original.tax,
85
+ " (",
86
+ row2.original.tax_rate ?? "0",
87
+ " %)"
88
+ ] }) : "\u2014"
89
+ }
90
+ ] : [],
67
91
  {
68
92
  accessorKey: "amount",
69
- header: t("billing.statements.breakdown.amount", "Amount"),
93
+ header: t("billing.statements.breakdown.charged", "Charged to balance"),
70
94
  cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row2.original.amount })
71
95
  }
72
96
  ],
97
+ [showVat, t]
98
+ );
99
+ const vatColumns = React.useMemo(
100
+ () => [
101
+ { accessorKey: "rate", header: t("billing.statements.vat.rate", "VAT rate"), cell: ({ row: row2 }) => `${row2.original.rate} %` },
102
+ {
103
+ accessorKey: "net",
104
+ header: t("billing.statements.breakdown.net", "Net"),
105
+ cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row2.original.net })
106
+ },
107
+ {
108
+ accessorKey: "tax",
109
+ header: t("billing.statements.breakdown.vat", "VAT"),
110
+ cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row2.original.tax })
111
+ },
112
+ {
113
+ accessorKey: "gross",
114
+ header: t("billing.statements.vat.gross", "Gross"),
115
+ cell: ({ row: row2 }) => /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row2.original.gross })
116
+ }
117
+ ],
73
118
  [t]
74
119
  );
75
120
  if (error) {
@@ -95,7 +140,7 @@ function BillingStatementDetailPage(props) {
95
140
  /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.opening", "Opening"), children: /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row.opening_balance }) }),
96
141
  /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.topups", "Top-ups"), children: /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row.total_topups }) }),
97
142
  /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.usage", "Usage"), children: /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row.total_usage }) }),
98
- /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.recurring", "Recurring"), children: /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row.total_recurring }) }),
143
+ /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.charges", "Charges"), children: /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row.total_recurring }) }),
99
144
  /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.adjustments", "Adjustments"), children: /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: row.total_adjustments }) }),
100
145
  /* @__PURE__ */ jsx(DetailField, { label: t("billing.statements.columns.closing", "Closing"), children: /* @__PURE__ */ jsxs("span", { className: "font-mono tabular-nums", children: [
101
146
  row.closing_balance,
@@ -117,9 +162,19 @@ function BillingStatementDetailPage(props) {
117
162
  title: t("billing.statements.detail.breakdown", "Period-close charges"),
118
163
  columns,
119
164
  data: breakdown,
120
- emptyState: /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("billing.statements.detail.no_charges", "No recurring charges this period.") })
165
+ pagination: { page: 1, pageSize: 100, total: breakdown.length, totalPages: 1, onPageChange: () => void 0 },
166
+ emptyState: /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("billing.statements.detail.no_charges", "No charges at this bill date.") })
167
+ }
168
+ ) }),
169
+ showVat ? /* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsx(
170
+ DataTable,
171
+ {
172
+ title: t("billing.statements.detail.vat_summary", "VAT summary"),
173
+ columns: vatColumns,
174
+ data: vatSummary,
175
+ pagination: { page: 1, pageSize: 100, total: vatSummary.length, totalPages: 1, onPageChange: () => void 0 }
121
176
  }
122
- ) })
177
+ ) }) : null
123
178
  ] })
124
179
  ] });
125
180
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/billing/backend/billing/statements/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useParams } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { DetailCard, DetailField } from '../../../../components/DetailFields'\nimport { statementStatusVariant } from '../page'\n\ntype BreakdownEntry = {\n billing_item_id: string\n billing_type: string\n uom_code?: string\n quantity: string\n amount: string\n}\n\ntype StatementRow = {\n id: string\n bill_account_id: string\n bill_run_id: string | null\n period_start: string\n period_end: string\n currency_code: string\n opening_balance: string\n total_topups: string\n total_usage: string\n total_recurring: string\n total_adjustments: string\n closing_balance: string\n debit_breakdown: { items?: BreakdownEntry[] } | null\n status: string\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const d = new Date(value)\n return Number.isNaN(d.getTime()) ? value : d.toLocaleDateString()\n}\n\nexport default function BillingStatementDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const urlParams = useParams<{ id: string }>()\n const statementId = (props.params?.id ?? urlParams?.id ?? '') as string\n\n const [row, setRow] = React.useState<StatementRow | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n if (!statementId) return\n setLoading(true)\n readApiResultOrThrow<{ items: StatementRow[] }>(\n `/api/billing/statements?id=${statementId}&pageSize=1`,\n )\n .then((res) => {\n if (cancelled) return\n const found = res.items?.[0]\n if (!found) setError(t('billing.statements.detail.not_found', 'Statement not found'))\n else setRow(found)\n })\n .catch(() => {\n if (!cancelled)\n setError(t('billing.statements.detail.load_error', 'Failed to load statement'))\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [statementId, t])\n\n const breakdown = row?.debit_breakdown?.items ?? []\n const columns = React.useMemo<ColumnDef<BreakdownEntry>[]>(\n () => [\n {\n accessorKey: 'billing_type',\n header: t('billing.statements.breakdown.type', 'Type'),\n cell: ({ row }) => <Tag variant=\"info\">{row.original.billing_type}</Tag>,\n },\n {\n accessorKey: 'billing_item_id',\n header: t('billing.statements.breakdown.item', 'Item'),\n cell: ({ row }) => <span className=\"font-mono text-xs\">{row.original.billing_item_id}</span>,\n },\n {\n accessorKey: 'quantity',\n header: t('billing.statements.breakdown.quantity', 'Qty'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.quantity}</span>,\n },\n {\n accessorKey: 'amount',\n header: t('billing.statements.breakdown.amount', 'Amount'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.amount}</span>,\n },\n ],\n [t],\n )\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n if (loading || !row) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('billing.statements.detail.loading', 'Loading statement\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/billing/statements\"\n entityTypeLabel={t('billing.statements.detail.title', 'Statement')}\n title={`${formatDate(row.period_start)} \u2013 ${formatDate(row.period_end)}`}\n statusBadge={\n <Tag variant={statementStatusVariant(row.status)}>\n {t(`billing.statements.status.${row.status}`, row.status)}\n </Tag>\n }\n actionsContent={\n <Button asChild variant=\"outline\">\n <Link href={`/backend/billing/accounts/${row.bill_account_id}`}>\n {t('billing.statements.detail.view_account', 'View account')}\n </Link>\n </Button>\n }\n />\n <PageBody>\n <DetailCard>\n <DetailField label={t('billing.statements.columns.opening', 'Opening')}>\n <span className=\"font-mono tabular-nums\">{row.opening_balance}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.topups', 'Top-ups')}>\n <span className=\"font-mono tabular-nums\">{row.total_topups}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.usage', 'Usage')}>\n <span className=\"font-mono tabular-nums\">{row.total_usage}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.recurring', 'Recurring')}>\n <span className=\"font-mono tabular-nums\">{row.total_recurring}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.adjustments', 'Adjustments')}>\n <span className=\"font-mono tabular-nums\">{row.total_adjustments}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.closing', 'Closing')}>\n <span className=\"font-mono tabular-nums\">\n {row.closing_balance} {row.currency_code}\n </span>\n </DetailField>\n <DetailField label={t('billing.statements.detail.bill_run', 'Bill Run')}>\n {row.bill_run_id ? (\n <Link\n href={`/backend/billing/runs/${row.bill_run_id}`}\n className=\"font-mono text-xs hover:underline\"\n >\n {row.bill_run_id}\n </Link>\n ) : (\n '\u2014'\n )}\n </DetailField>\n </DetailCard>\n <div className=\"mt-6\">\n <DataTable\n title={t('billing.statements.detail.breakdown', 'Period-close charges')}\n columns={columns}\n data={breakdown}\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t('billing.statements.detail.no_charges', 'No recurring charges this period.')}\n </div>\n }\n />\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useParams } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BillingDataTable as DataTable } from '../../../../components/BillingDataTable'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { DetailCard, DetailField } from '../../../../components/DetailFields'\nimport { statementStatusVariant } from '../page'\n\ntype BreakdownEntry = {\n billing_item_id: string\n billing_type: string\n uom_code?: string\n quantity: string\n /** What left the balance. */\n amount: string\n // Spec F \u2014 older statements do not carry these.\n description?: string\n net?: string\n tax?: string\n tax_rate?: string\n service_period_start?: string | null\n service_period_end?: string | null\n}\n\ntype VatSummaryEntry = { rate: string; net: string; tax: string; gross: string }\n\ntype StatementRow = {\n id: string\n bill_account_id: string\n bill_run_id: string | null\n period_start: string\n period_end: string\n currency_code: string\n opening_balance: string\n total_topups: string\n total_usage: string\n total_recurring: string\n total_adjustments: string\n closing_balance: string\n debit_breakdown: { items?: BreakdownEntry[] } | null\n vat_summary?: VatSummaryEntry[] | null\n status: string\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const d = new Date(value)\n return Number.isNaN(d.getTime()) ? value : d.toLocaleDateString()\n}\n\nexport default function BillingStatementDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const urlParams = useParams<{ id: string }>()\n const statementId = (props.params?.id ?? urlParams?.id ?? '') as string\n\n const [row, setRow] = React.useState<StatementRow | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n if (!statementId) return\n setLoading(true)\n readApiResultOrThrow<{ items: StatementRow[] }>(\n `/api/billing/statements?id=${statementId}&pageSize=1`,\n )\n .then((res) => {\n if (cancelled) return\n const found = res.items?.[0]\n if (!found) setError(t('billing.statements.detail.not_found', 'Statement not found'))\n else setRow(found)\n })\n .catch(() => {\n if (!cancelled)\n setError(t('billing.statements.detail.load_error', 'Failed to load statement'))\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [statementId, t])\n\n const breakdown = row?.debit_breakdown?.items ?? []\n const vatSummary = row?.vat_summary ?? []\n // Spec F: VAT columns only when VAT was charged at consumption.\n const showVat = vatSummary.length > 0\n const columns = React.useMemo<ColumnDef<BreakdownEntry>[]>(\n () => [\n {\n accessorKey: 'billing_type',\n header: t('billing.statements.breakdown.type', 'Type'),\n cell: ({ row }) => <Tag variant=\"info\">{row.original.billing_type}</Tag>,\n },\n {\n accessorKey: 'billing_item_id',\n header: t('billing.statements.breakdown.item', 'Item'),\n cell: ({ row }) => (\n <Link href={`/backend/billing/items/${row.original.billing_item_id}`} className=\"text-sm text-primary hover:underline\">\n {row.original.description ?? row.original.billing_item_id}\n </Link>\n ),\n },\n {\n accessorKey: 'service_period_start',\n header: t('billing.statements.breakdown.service_period', 'Service period'),\n cell: ({ row }) =>\n row.original.service_period_start\n ? `${row.original.service_period_start} \u2013 ${row.original.service_period_end ?? '\u2026'}`\n : '\u2014',\n },\n {\n accessorKey: 'quantity',\n header: t('billing.statements.breakdown.quantity', 'Qty'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.quantity}</span>,\n },\n ...(showVat\n ? [\n {\n accessorKey: 'net',\n header: t('billing.statements.breakdown.net', 'Net'),\n cell: ({ row }: { row: { original: BreakdownEntry } }) => (\n <span className=\"font-mono tabular-nums\">{row.original.net ?? '\u2014'}</span>\n ),\n } satisfies ColumnDef<BreakdownEntry>,\n {\n accessorKey: 'tax',\n header: t('billing.statements.breakdown.vat', 'VAT'),\n cell: ({ row }: { row: { original: BreakdownEntry } }) =>\n row.original.tax !== undefined ? (\n <span className=\"font-mono tabular-nums\">\n {row.original.tax} ({row.original.tax_rate ?? '0'} %)\n </span>\n ) : (\n '\u2014'\n ),\n } satisfies ColumnDef<BreakdownEntry>,\n ]\n : []),\n {\n accessorKey: 'amount',\n header: t('billing.statements.breakdown.charged', 'Charged to balance'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.amount}</span>,\n },\n ],\n [showVat, t],\n )\n const vatColumns = React.useMemo<ColumnDef<VatSummaryEntry>[]>(\n () => [\n { accessorKey: 'rate', header: t('billing.statements.vat.rate', 'VAT rate'), cell: ({ row }) => `${row.original.rate} %` },\n {\n accessorKey: 'net',\n header: t('billing.statements.breakdown.net', 'Net'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.net}</span>,\n },\n {\n accessorKey: 'tax',\n header: t('billing.statements.breakdown.vat', 'VAT'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.tax}</span>,\n },\n {\n accessorKey: 'gross',\n header: t('billing.statements.vat.gross', 'Gross'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.gross}</span>,\n },\n ],\n [t],\n )\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n if (loading || !row) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('billing.statements.detail.loading', 'Loading statement\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/billing/statements\"\n entityTypeLabel={t('billing.statements.detail.title', 'Statement')}\n title={`${formatDate(row.period_start)} \u2013 ${formatDate(row.period_end)}`}\n statusBadge={\n <Tag variant={statementStatusVariant(row.status)}>\n {t(`billing.statements.status.${row.status}`, row.status)}\n </Tag>\n }\n actionsContent={\n <Button asChild variant=\"outline\">\n <Link href={`/backend/billing/accounts/${row.bill_account_id}`}>\n {t('billing.statements.detail.view_account', 'View account')}\n </Link>\n </Button>\n }\n />\n <PageBody>\n <DetailCard>\n <DetailField label={t('billing.statements.columns.opening', 'Opening')}>\n <span className=\"font-mono tabular-nums\">{row.opening_balance}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.topups', 'Top-ups')}>\n <span className=\"font-mono tabular-nums\">{row.total_topups}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.usage', 'Usage')}>\n <span className=\"font-mono tabular-nums\">{row.total_usage}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.charges', 'Charges')}>\n <span className=\"font-mono tabular-nums\">{row.total_recurring}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.adjustments', 'Adjustments')}>\n <span className=\"font-mono tabular-nums\">{row.total_adjustments}</span>\n </DetailField>\n <DetailField label={t('billing.statements.columns.closing', 'Closing')}>\n <span className=\"font-mono tabular-nums\">\n {row.closing_balance} {row.currency_code}\n </span>\n </DetailField>\n <DetailField label={t('billing.statements.detail.bill_run', 'Bill Run')}>\n {row.bill_run_id ? (\n <Link\n href={`/backend/billing/runs/${row.bill_run_id}`}\n className=\"font-mono text-xs hover:underline\"\n >\n {row.bill_run_id}\n </Link>\n ) : (\n '\u2014'\n )}\n </DetailField>\n </DetailCard>\n <div className=\"mt-6\">\n <DataTable\n title={t('billing.statements.detail.breakdown', 'Period-close charges')}\n columns={columns}\n data={breakdown}\n pagination={{ page: 1, pageSize: 100, total: breakdown.length, totalPages: 1, onPageChange: () => undefined }}\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t('billing.statements.detail.no_charges', 'No charges at this bill date.')}\n </div>\n }\n />\n </div>\n {showVat ? (\n <div className=\"mt-6\">\n <DataTable\n title={t('billing.statements.detail.vat_summary', 'VAT summary')}\n columns={vatColumns}\n data={vatSummary}\n pagination={{ page: 1, pageSize: 100, total: vatSummary.length, totalPages: 1, onPageChange: () => undefined }}\n />\n </div>\n ) : null}\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["row"]
7
7
  }
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
6
6
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
7
- import { DataTable } from "@open-mercato/ui/backend/DataTable";
7
+ import { BillingDataTable as DataTable } from "../../../components/BillingDataTable.js";
8
8
  import { Tag } from "@open-mercato/ui/primitives/tag";
9
9
  import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
10
10
  import { fetchAccountNames } from "../../../components/accountNames.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/backend/billing/statements/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { fetchAccountNames } from '../../../components/accountNames'\n\n/**\n * Consumption statements admin list (SPEC-002 P3). Non-fiscal period summaries\n * for prepaid accounts \u2014 opening / top-ups / usage / recurring / closing.\n */\n\ntype StatementRow = {\n id: string\n bill_account_id: string\n period_start: string\n period_end: string\n currency_code: string\n opening_balance: string\n total_topups: string\n total_usage: string\n total_recurring: string\n closing_balance: string\n status: string\n}\n\ntype ListResponse = { items: StatementRow[]; total: number; totalPages: number }\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const d = new Date(value)\n return Number.isNaN(d.getTime()) ? value : d.toLocaleDateString()\n}\n\nexport function statementStatusVariant(status: string): 'success' | 'info' {\n return status === 'sent' ? 'success' : 'info'\n}\n\nexport default function BillingStatementsListPage() {\n const t = useT()\n const router = useRouter()\n const [rows, setRows] = React.useState<StatementRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [filters, setFilters] = React.useState<FilterValues>({})\n const [accountNames, setAccountNames] = React.useState<Record<string, string>>({})\n\n const filterDefs = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: t('billing.statements.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'generated', label: t('billing.statements.status.generated', 'Generated') },\n { value: 'sent', label: t('billing.statements.status.sent', 'Sent') },\n ],\n },\n ],\n [t],\n )\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'periodEnd',\n sortDir: 'desc',\n })\n if (typeof filters.status === 'string' && filters.status) params.set('status', filters.status)\n const result = await readApiResultOrThrow<ListResponse>(\n `/api/billing/statements?${params.toString()}`,\n )\n const items = result.items ?? []\n setRows(items)\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n try {\n const names = await fetchAccountNames(items.map((r) => r.bill_account_id))\n setAccountNames((prev) => ({ ...prev, ...names }))\n } catch {\n // Name resolution is best-effort \u2014 fall back to the id in the cell.\n }\n } finally {\n setLoading(false)\n }\n }, [filters.status, page, pageSize])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const columns = React.useMemo<ColumnDef<StatementRow>[]>(\n () => [\n {\n accessorKey: 'period_end',\n header: t('billing.statements.columns.period', 'Period'),\n cell: ({ row }) =>\n `${formatDate(row.original.period_start)} \u2013 ${formatDate(row.original.period_end)}`,\n },\n {\n accessorKey: 'bill_account_id',\n header: t('billing.statements.columns.account', 'Account'),\n cell: ({ row }) => {\n const name = accountNames[row.original.bill_account_id]\n return name ? (\n <span className=\"text-sm\">{name}</span>\n ) : (\n <span className=\"font-mono text-xs\">{row.original.bill_account_id}</span>\n )\n },\n },\n {\n accessorKey: 'opening_balance',\n header: t('billing.statements.columns.opening', 'Opening'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.opening_balance}</span>,\n },\n {\n accessorKey: 'total_topups',\n header: t('billing.statements.columns.topups', 'Top-ups'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.total_topups}</span>,\n },\n {\n accessorKey: 'total_usage',\n header: t('billing.statements.columns.usage', 'Usage'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.total_usage}</span>,\n },\n {\n accessorKey: 'total_recurring',\n header: t('billing.statements.columns.recurring', 'Recurring'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.total_recurring}</span>,\n },\n {\n accessorKey: 'closing_balance',\n header: t('billing.statements.columns.closing', 'Closing'),\n cell: ({ row }) => (\n <span className=\"font-mono tabular-nums\">\n {row.original.closing_balance} {row.original.currency_code}\n </span>\n ),\n },\n {\n accessorKey: 'status',\n header: t('billing.statements.columns.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={statementStatusVariant(row.original.status)}>\n {t(`billing.statements.status.${row.original.status}`, row.original.status)}\n </Tag>\n ),\n },\n ],\n [t, accountNames],\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('billing.statements.title', 'Statements')}\n refreshButton={{\n label: t('billing.common.refresh', 'Refresh'),\n onRefresh: loadRows,\n isRefreshing: loading,\n }}\n columnChooser={{ auto: true }}\n perspective={{ tableId: 'billing-statements' }}\n columns={columns}\n data={rows}\n onRowClick={(row) => router.push(`/backend/billing/statements/${row.id}`)}\n isLoading={loading}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={setFilters}\n onFiltersClear={() => setFilters({})}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { BillingDataTable as DataTable } from '../../../components/BillingDataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { fetchAccountNames } from '../../../components/accountNames'\n\n/**\n * Consumption statements admin list (SPEC-002 P3). Non-fiscal period summaries\n * for prepaid accounts \u2014 opening / top-ups / usage / recurring / closing.\n */\n\ntype StatementRow = {\n id: string\n bill_account_id: string\n period_start: string\n period_end: string\n currency_code: string\n opening_balance: string\n total_topups: string\n total_usage: string\n total_recurring: string\n closing_balance: string\n status: string\n}\n\ntype ListResponse = { items: StatementRow[]; total: number; totalPages: number }\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const d = new Date(value)\n return Number.isNaN(d.getTime()) ? value : d.toLocaleDateString()\n}\n\nexport function statementStatusVariant(status: string): 'success' | 'info' {\n return status === 'sent' ? 'success' : 'info'\n}\n\nexport default function BillingStatementsListPage() {\n const t = useT()\n const router = useRouter()\n const [rows, setRows] = React.useState<StatementRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [filters, setFilters] = React.useState<FilterValues>({})\n const [accountNames, setAccountNames] = React.useState<Record<string, string>>({})\n\n const filterDefs = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: t('billing.statements.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'generated', label: t('billing.statements.status.generated', 'Generated') },\n { value: 'sent', label: t('billing.statements.status.sent', 'Sent') },\n ],\n },\n ],\n [t],\n )\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'periodEnd',\n sortDir: 'desc',\n })\n if (typeof filters.status === 'string' && filters.status) params.set('status', filters.status)\n const result = await readApiResultOrThrow<ListResponse>(\n `/api/billing/statements?${params.toString()}`,\n )\n const items = result.items ?? []\n setRows(items)\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n try {\n const names = await fetchAccountNames(items.map((r) => r.bill_account_id))\n setAccountNames((prev) => ({ ...prev, ...names }))\n } catch {\n // Name resolution is best-effort \u2014 fall back to the id in the cell.\n }\n } finally {\n setLoading(false)\n }\n }, [filters.status, page, pageSize])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const columns = React.useMemo<ColumnDef<StatementRow>[]>(\n () => [\n {\n accessorKey: 'period_end',\n header: t('billing.statements.columns.period', 'Period'),\n cell: ({ row }) =>\n `${formatDate(row.original.period_start)} \u2013 ${formatDate(row.original.period_end)}`,\n },\n {\n accessorKey: 'bill_account_id',\n header: t('billing.statements.columns.account', 'Account'),\n cell: ({ row }) => {\n const name = accountNames[row.original.bill_account_id]\n return name ? (\n <span className=\"text-sm\">{name}</span>\n ) : (\n <span className=\"font-mono text-xs\">{row.original.bill_account_id}</span>\n )\n },\n },\n {\n accessorKey: 'opening_balance',\n header: t('billing.statements.columns.opening', 'Opening'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.opening_balance}</span>,\n },\n {\n accessorKey: 'total_topups',\n header: t('billing.statements.columns.topups', 'Top-ups'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.total_topups}</span>,\n },\n {\n accessorKey: 'total_usage',\n header: t('billing.statements.columns.usage', 'Usage'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.total_usage}</span>,\n },\n {\n accessorKey: 'total_recurring',\n header: t('billing.statements.columns.recurring', 'Recurring'),\n cell: ({ row }) => <span className=\"font-mono tabular-nums\">{row.original.total_recurring}</span>,\n },\n {\n accessorKey: 'closing_balance',\n header: t('billing.statements.columns.closing', 'Closing'),\n cell: ({ row }) => (\n <span className=\"font-mono tabular-nums\">\n {row.original.closing_balance} {row.original.currency_code}\n </span>\n ),\n },\n {\n accessorKey: 'status',\n header: t('billing.statements.columns.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={statementStatusVariant(row.original.status)}>\n {t(`billing.statements.status.${row.original.status}`, row.original.status)}\n </Tag>\n ),\n },\n ],\n [t, accountNames],\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('billing.statements.title', 'Statements')}\n refreshButton={{\n label: t('billing.common.refresh', 'Refresh'),\n onRefresh: loadRows,\n isRefreshing: loading,\n }}\n columnChooser={{ auto: true }}\n perspective={{ tableId: 'billing-statements' }}\n columns={columns}\n data={rows}\n onRowClick={(row) => router.push(`/backend/billing/statements/${row.id}`)}\n isLoading={loading}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={setFilters}\n onFiltersClear={() => setFilters({})}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
6
6
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
7
- import { DataTable } from "@open-mercato/ui/backend/DataTable";
7
+ import { BillingDataTable as DataTable } from "../../../components/BillingDataTable.js";
8
8
  import { Tag } from "@open-mercato/ui/primitives/tag";
9
9
  import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
10
10
  import { fetchAccountNames } from "../../../components/accountNames.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/backend/billing/topups/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { fetchAccountNames } from '../../../components/accountNames'\n\n/**\n * Registered top-ups admin list (SPEC-002 P2). Read-only \u2014 top-ups are\n * initiated from a prepaid account's detail page and progress through the\n * gateway capture lifecycle.\n */\n\ntype TopupRow = {\n id: string\n bill_account_id: string\n status: string\n amount: string\n currency_code: string\n provider_key: string\n receipt_invoice_id: string | null\n created_at: string\n}\n\ntype ListResponse = { items: TopupRow[]; total: number; totalPages: number }\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const d = new Date(value)\n return Number.isNaN(d.getTime()) ? value : d.toLocaleString()\n}\n\nexport function statusVariant(status: string): 'success' | 'info' | 'error' | 'default' {\n if (status === 'captured') return 'success'\n if (status === 'pending') return 'info'\n if (status === 'failed') return 'error'\n return 'default' // cancelled / expired\n}\n\nexport default function BillingTopupsListPage() {\n const t = useT()\n const router = useRouter()\n const [rows, setRows] = React.useState<TopupRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filters, setFilters] = React.useState<FilterValues>({})\n const [search, setSearch] = React.useState('')\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [accountNames, setAccountNames] = React.useState<Record<string, string>>({})\n\n const filterDefs = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: t('billing.topups.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'pending', label: t('billing.topups.status.pending', 'Pending') },\n { value: 'captured', label: t('billing.topups.status.captured', 'Captured') },\n { value: 'failed', label: t('billing.topups.status.failed', 'Failed') },\n { value: 'cancelled', label: t('billing.topups.status.cancelled', 'Cancelled') },\n { value: 'expired', label: t('billing.topups.status.expired', 'Expired') },\n ],\n },\n ],\n [t],\n )\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'createdAt',\n sortDir: 'desc',\n })\n if (search.trim()) params.set('search', search.trim())\n if (typeof filters.status === 'string' && filters.status) params.set('status', filters.status)\n const result = await readApiResultOrThrow<ListResponse>(\n `/api/billing/topups?${params.toString()}`,\n )\n const items = result.items ?? []\n setRows(items)\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n try {\n const names = await fetchAccountNames(items.map((r) => r.bill_account_id))\n setAccountNames((prev) => ({ ...prev, ...names }))\n } catch {\n // Name resolution is best-effort \u2014 fall back to the id in the cell.\n }\n } finally {\n setLoading(false)\n }\n }, [filters.status, page, pageSize, search])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const columns = React.useMemo<ColumnDef<TopupRow>[]>(\n () => [\n {\n accessorKey: 'created_at',\n header: t('billing.topups.columns.created', 'Created'),\n cell: ({ row }) => formatDate(row.original.created_at),\n },\n {\n accessorKey: 'amount',\n header: t('billing.topups.columns.amount', 'Amount'),\n cell: ({ row }) => (\n <span className=\"font-mono tabular-nums\">\n {row.original.amount} {row.original.currency_code}\n </span>\n ),\n },\n {\n accessorKey: 'provider_key',\n header: t('billing.topups.columns.provider', 'Provider'),\n cell: ({ row }) => <span className=\"font-mono text-xs\">{row.original.provider_key}</span>,\n },\n {\n accessorKey: 'status',\n header: t('billing.topups.columns.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={statusVariant(row.original.status)}>\n {t(`billing.topups.status.${row.original.status}`, row.original.status)}\n </Tag>\n ),\n },\n {\n accessorKey: 'bill_account_id',\n header: t('billing.topups.columns.account', 'Account'),\n cell: ({ row }) => {\n const name = accountNames[row.original.bill_account_id]\n return name ? (\n <span className=\"text-sm\">{name}</span>\n ) : (\n <span className=\"font-mono text-xs\">{row.original.bill_account_id}</span>\n )\n },\n },\n ],\n [t, accountNames],\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('billing.topups.title', 'Top-ups')}\n refreshButton={{\n label: t('billing.common.refresh', 'Refresh'),\n onRefresh: loadRows,\n isRefreshing: loading,\n }}\n columnChooser={{ auto: true }}\n perspective={{ tableId: 'billing-topups' }}\n columns={columns}\n data={rows}\n onRowClick={(row) => router.push(`/backend/billing/topups/${row.id}`)}\n isLoading={loading}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={setFilters}\n onFiltersClear={() => setFilters({})}\n searchValue={search}\n onSearchChange={setSearch}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { BillingDataTable as DataTable } from '../../../components/BillingDataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { fetchAccountNames } from '../../../components/accountNames'\n\n/**\n * Registered top-ups admin list (SPEC-002 P2). Read-only \u2014 top-ups are\n * initiated from a prepaid account's detail page and progress through the\n * gateway capture lifecycle.\n */\n\ntype TopupRow = {\n id: string\n bill_account_id: string\n status: string\n amount: string\n currency_code: string\n provider_key: string\n receipt_invoice_id: string | null\n created_at: string\n}\n\ntype ListResponse = { items: TopupRow[]; total: number; totalPages: number }\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '\u2014'\n const d = new Date(value)\n return Number.isNaN(d.getTime()) ? value : d.toLocaleString()\n}\n\nexport function statusVariant(status: string): 'success' | 'info' | 'error' | 'default' {\n if (status === 'captured') return 'success'\n if (status === 'pending') return 'info'\n if (status === 'failed') return 'error'\n return 'default' // cancelled / expired\n}\n\nexport default function BillingTopupsListPage() {\n const t = useT()\n const router = useRouter()\n const [rows, setRows] = React.useState<TopupRow[]>([])\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filters, setFilters] = React.useState<FilterValues>({})\n const [search, setSearch] = React.useState('')\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(true)\n const [accountNames, setAccountNames] = React.useState<Record<string, string>>({})\n\n const filterDefs = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: t('billing.topups.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'pending', label: t('billing.topups.status.pending', 'Pending') },\n { value: 'captured', label: t('billing.topups.status.captured', 'Captured') },\n { value: 'failed', label: t('billing.topups.status.failed', 'Failed') },\n { value: 'cancelled', label: t('billing.topups.status.cancelled', 'Cancelled') },\n { value: 'expired', label: t('billing.topups.status.expired', 'Expired') },\n ],\n },\n ],\n [t],\n )\n\n const loadRows = React.useCallback(async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n sortField: 'createdAt',\n sortDir: 'desc',\n })\n if (search.trim()) params.set('search', search.trim())\n if (typeof filters.status === 'string' && filters.status) params.set('status', filters.status)\n const result = await readApiResultOrThrow<ListResponse>(\n `/api/billing/topups?${params.toString()}`,\n )\n const items = result.items ?? []\n setRows(items)\n setTotal(result.total ?? 0)\n setTotalPages(result.totalPages ?? 1)\n try {\n const names = await fetchAccountNames(items.map((r) => r.bill_account_id))\n setAccountNames((prev) => ({ ...prev, ...names }))\n } catch {\n // Name resolution is best-effort \u2014 fall back to the id in the cell.\n }\n } finally {\n setLoading(false)\n }\n }, [filters.status, page, pageSize, search])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows])\n\n const columns = React.useMemo<ColumnDef<TopupRow>[]>(\n () => [\n {\n accessorKey: 'created_at',\n header: t('billing.topups.columns.created', 'Created'),\n cell: ({ row }) => formatDate(row.original.created_at),\n },\n {\n accessorKey: 'amount',\n header: t('billing.topups.columns.amount', 'Amount'),\n cell: ({ row }) => (\n <span className=\"font-mono tabular-nums\">\n {row.original.amount} {row.original.currency_code}\n </span>\n ),\n },\n {\n accessorKey: 'provider_key',\n header: t('billing.topups.columns.provider', 'Provider'),\n cell: ({ row }) => <span className=\"font-mono text-xs\">{row.original.provider_key}</span>,\n },\n {\n accessorKey: 'status',\n header: t('billing.topups.columns.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={statusVariant(row.original.status)}>\n {t(`billing.topups.status.${row.original.status}`, row.original.status)}\n </Tag>\n ),\n },\n {\n accessorKey: 'bill_account_id',\n header: t('billing.topups.columns.account', 'Account'),\n cell: ({ row }) => {\n const name = accountNames[row.original.bill_account_id]\n return name ? (\n <span className=\"text-sm\">{name}</span>\n ) : (\n <span className=\"font-mono text-xs\">{row.original.bill_account_id}</span>\n )\n },\n },\n ],\n [t, accountNames],\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('billing.topups.title', 'Top-ups')}\n refreshButton={{\n label: t('billing.common.refresh', 'Refresh'),\n onRefresh: loadRows,\n isRefreshing: loading,\n }}\n columnChooser={{ auto: true }}\n perspective={{ tableId: 'billing-topups' }}\n columns={columns}\n data={rows}\n onRowClick={(row) => router.push(`/backend/billing/topups/${row.id}`)}\n isLoading={loading}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n filters={filterDefs}\n filterValues={filters}\n onFiltersApply={setFilters}\n onFiltersClear={() => setFilters({})}\n searchValue={search}\n onSearchChange={setSearch}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }