@dainamite/billing 0.20.0 → 0.22.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 (604) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/dist/modules/billing/acl.js +13 -1
  3. package/dist/modules/billing/acl.js.map +2 -2
  4. package/dist/modules/billing/api/accounts/[id]/summary/route.js +52 -0
  5. package/dist/modules/billing/api/accounts/[id]/summary/route.js.map +7 -0
  6. package/dist/modules/billing/api/accounts/route.js +47 -4
  7. package/dist/modules/billing/api/accounts/route.js.map +2 -2
  8. package/dist/modules/billing/api/export/account/[id]/route.js +11 -7
  9. package/dist/modules/billing/api/export/account/[id]/route.js.map +2 -2
  10. package/dist/modules/billing/api/invoices/[id]/memos/route.js +54 -0
  11. package/dist/modules/billing/api/invoices/[id]/memos/route.js.map +7 -0
  12. package/dist/modules/billing/api/invoices/[id]/pdf/route.js +70 -0
  13. package/dist/modules/billing/api/invoices/[id]/pdf/route.js.map +7 -0
  14. package/dist/modules/billing/api/invoices/[id]/route.js +44 -24
  15. package/dist/modules/billing/api/invoices/[id]/route.js.map +2 -2
  16. package/dist/modules/billing/api/invoices/[id]/send/route.js +107 -0
  17. package/dist/modules/billing/api/invoices/[id]/send/route.js.map +7 -0
  18. package/dist/modules/billing/api/invoices/add-line/route.js +2 -2
  19. package/dist/modules/billing/api/invoices/add-line/route.js.map +2 -2
  20. package/dist/modules/billing/api/invoices/delete-draft/route.js +33 -0
  21. package/dist/modules/billing/api/invoices/delete-draft/route.js.map +7 -0
  22. package/dist/modules/billing/api/invoices/edit-line/route.js +2 -2
  23. package/dist/modules/billing/api/invoices/edit-line/route.js.map +2 -2
  24. package/dist/modules/billing/api/invoices/post/route.js +2 -2
  25. package/dist/modules/billing/api/invoices/post/route.js.map +2 -2
  26. package/dist/modules/billing/api/invoices/remove-line/route.js +2 -2
  27. package/dist/modules/billing/api/invoices/remove-line/route.js.map +2 -2
  28. package/dist/modules/billing/api/invoices/route.js +45 -46
  29. package/dist/modules/billing/api/invoices/route.js.map +2 -2
  30. package/dist/modules/billing/api/items/bulk/route.js +1 -1
  31. package/dist/modules/billing/api/items/bulk/route.js.map +2 -2
  32. package/dist/modules/billing/api/items/change-price/route.js +44 -0
  33. package/dist/modules/billing/api/items/change-price/route.js.map +7 -0
  34. package/dist/modules/billing/api/items/route.js +19 -7
  35. package/dist/modules/billing/api/items/route.js.map +2 -2
  36. package/dist/modules/billing/api/payment-imports/[id]/route.js +49 -0
  37. package/dist/modules/billing/api/payment-imports/[id]/route.js.map +7 -0
  38. package/dist/modules/billing/api/payment-imports/route.js +57 -0
  39. package/dist/modules/billing/api/payment-imports/route.js.map +7 -0
  40. package/dist/modules/billing/api/payments/[id]/route.js +60 -0
  41. package/dist/modules/billing/api/payments/[id]/route.js.map +7 -0
  42. package/dist/modules/billing/api/payments/allocate/route.js +35 -0
  43. package/dist/modules/billing/api/payments/allocate/route.js.map +7 -0
  44. package/dist/modules/billing/api/payments/assign/route.js +36 -0
  45. package/dist/modules/billing/api/payments/assign/route.js.map +7 -0
  46. package/dist/modules/billing/api/payments/convert-to-topup/route.js +35 -0
  47. package/dist/modules/billing/api/payments/convert-to-topup/route.js.map +7 -0
  48. package/dist/modules/billing/api/payments/ignore/route.js +35 -0
  49. package/dist/modules/billing/api/payments/ignore/route.js.map +7 -0
  50. package/dist/modules/billing/api/payments/import/route.js +63 -0
  51. package/dist/modules/billing/api/payments/import/route.js.map +7 -0
  52. package/dist/modules/billing/api/payments/restore/route.js +35 -0
  53. package/dist/modules/billing/api/payments/restore/route.js.map +7 -0
  54. package/dist/modules/billing/api/payments/route.js +114 -0
  55. package/dist/modules/billing/api/payments/route.js.map +7 -0
  56. package/dist/modules/billing/api/payments/unallocate/route.js +35 -0
  57. package/dist/modules/billing/api/payments/unallocate/route.js.map +7 -0
  58. package/dist/modules/billing/api/payments/unassign/route.js +35 -0
  59. package/dist/modules/billing/api/payments/unassign/route.js.map +7 -0
  60. package/dist/modules/billing/api/run-outcomes/route.js +43 -6
  61. package/dist/modules/billing/api/run-outcomes/route.js.map +2 -2
  62. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js +61 -0
  63. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js.map +7 -0
  64. package/dist/modules/billing/api/runs/[id]/route.js +53 -0
  65. package/dist/modules/billing/api/runs/[id]/route.js.map +7 -0
  66. package/dist/modules/billing/api/runs/retry-failed/route.js +1 -1
  67. package/dist/modules/billing/api/runs/retry-failed/route.js.map +2 -2
  68. package/dist/modules/billing/api/runs/route.js +9 -3
  69. package/dist/modules/billing/api/runs/route.js.map +2 -2
  70. package/dist/modules/billing/api/settings/number-preview/route.js +42 -0
  71. package/dist/modules/billing/api/settings/number-preview/route.js.map +7 -0
  72. package/dist/modules/billing/api/settings/route.js +92 -0
  73. package/dist/modules/billing/api/settings/route.js.map +7 -0
  74. package/dist/modules/billing/api/statements/route.js +3 -0
  75. package/dist/modules/billing/api/statements/route.js.map +2 -2
  76. package/dist/modules/billing/api/test-invoices/wipe/route.js +2 -2
  77. package/dist/modules/billing/api/test-invoices/wipe/route.js.map +2 -2
  78. package/dist/modules/billing/backend/billing/accounts/[id]/page.js +121 -232
  79. package/dist/modules/billing/backend/billing/accounts/[id]/page.js.map +2 -2
  80. package/dist/modules/billing/backend/billing/accounts/create/page.js +6 -0
  81. package/dist/modules/billing/backend/billing/accounts/create/page.js.map +2 -2
  82. package/dist/modules/billing/backend/billing/accounts/page.js +63 -4
  83. package/dist/modules/billing/backend/billing/accounts/page.js.map +2 -2
  84. package/dist/modules/billing/backend/billing/invoices/[id]/page.js +297 -65
  85. package/dist/modules/billing/backend/billing/invoices/[id]/page.js.map +3 -3
  86. package/dist/modules/billing/backend/billing/invoices/page.js +6 -172
  87. package/dist/modules/billing/backend/billing/invoices/page.js.map +2 -2
  88. package/dist/modules/billing/backend/billing/items/[id]/page.js +51 -7
  89. package/dist/modules/billing/backend/billing/items/[id]/page.js.map +2 -2
  90. package/dist/modules/billing/backend/billing/items/create/page.js +9 -6
  91. package/dist/modules/billing/backend/billing/items/create/page.js.map +2 -2
  92. package/dist/modules/billing/backend/billing/items/page.js +8 -2
  93. package/dist/modules/billing/backend/billing/items/page.js.map +2 -2
  94. package/dist/modules/billing/backend/billing/payments/[id]/page.js +297 -0
  95. package/dist/modules/billing/backend/billing/payments/[id]/page.js.map +7 -0
  96. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js +21 -0
  97. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js.map +7 -0
  98. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js +74 -0
  99. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js.map +7 -0
  100. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js +21 -0
  101. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js.map +7 -0
  102. package/dist/modules/billing/backend/billing/payments/page.js +58 -0
  103. package/dist/modules/billing/backend/billing/payments/page.js.map +7 -0
  104. package/dist/modules/billing/backend/billing/payments/page.meta.js +18 -0
  105. package/dist/modules/billing/backend/billing/payments/page.meta.js.map +7 -0
  106. package/dist/modules/billing/backend/billing/runs/[id]/page.js +49 -14
  107. package/dist/modules/billing/backend/billing/runs/[id]/page.js.map +2 -2
  108. package/dist/modules/billing/backend/billing/runs/page.js +58 -7
  109. package/dist/modules/billing/backend/billing/runs/page.js.map +2 -2
  110. package/dist/modules/billing/backend/billing/statements/[id]/page.js +61 -6
  111. package/dist/modules/billing/backend/billing/statements/[id]/page.js.map +2 -2
  112. package/dist/modules/billing/backend/billing/statements/page.js +1 -1
  113. package/dist/modules/billing/backend/billing/statements/page.js.map +2 -2
  114. package/dist/modules/billing/backend/billing/topups/page.js +1 -1
  115. package/dist/modules/billing/backend/billing/topups/page.js.map +2 -2
  116. package/dist/modules/billing/backend/billing/transactions/page.js +1 -1
  117. package/dist/modules/billing/backend/billing/transactions/page.js.map +2 -2
  118. package/dist/modules/billing/backend/billing/usage/create/page.js +3 -2
  119. package/dist/modules/billing/backend/billing/usage/create/page.js.map +2 -2
  120. package/dist/modules/billing/backend/config/billing/page.js +472 -0
  121. package/dist/modules/billing/backend/config/billing/page.js.map +7 -0
  122. package/dist/modules/billing/backend/config/billing/page.meta.js +19 -0
  123. package/dist/modules/billing/backend/config/billing/page.meta.js.map +7 -0
  124. package/dist/modules/billing/cli.js +22 -1
  125. package/dist/modules/billing/cli.js.map +2 -2
  126. package/dist/modules/billing/commands/accounts.js +6 -0
  127. package/dist/modules/billing/commands/accounts.js.map +2 -2
  128. package/dist/modules/billing/commands/index.js +3 -0
  129. package/dist/modules/billing/commands/index.js.map +2 -2
  130. package/dist/modules/billing/commands/invoices.js +269 -167
  131. package/dist/modules/billing/commands/invoices.js.map +2 -2
  132. package/dist/modules/billing/commands/items.js +108 -0
  133. package/dist/modules/billing/commands/items.js.map +2 -2
  134. package/dist/modules/billing/commands/memos.js +179 -0
  135. package/dist/modules/billing/commands/memos.js.map +7 -0
  136. package/dist/modules/billing/commands/payments.js +379 -0
  137. package/dist/modules/billing/commands/payments.js.map +7 -0
  138. package/dist/modules/billing/commands/runs.js +151 -4
  139. package/dist/modules/billing/commands/runs.js.map +2 -2
  140. package/dist/modules/billing/commands/settings.js +59 -0
  141. package/dist/modules/billing/commands/settings.js.map +7 -0
  142. package/dist/modules/billing/commands/topups.js +9 -2
  143. package/dist/modules/billing/commands/topups.js.map +2 -2
  144. package/dist/modules/billing/commands/transactions.js +2 -2
  145. package/dist/modules/billing/commands/transactions.js.map +2 -2
  146. package/dist/modules/billing/components/AccountForm.js +149 -42
  147. package/dist/modules/billing/components/AccountForm.js.map +2 -2
  148. package/dist/modules/billing/components/AccountInvoicesSection.js +64 -0
  149. package/dist/modules/billing/components/AccountInvoicesSection.js.map +7 -0
  150. package/dist/modules/billing/components/AccountPaymentsSection.js +43 -0
  151. package/dist/modules/billing/components/AccountPaymentsSection.js.map +7 -0
  152. package/dist/modules/billing/components/AccountPicker.js +56 -0
  153. package/dist/modules/billing/components/AccountPicker.js.map +7 -0
  154. package/dist/modules/billing/components/AllocatePaymentDialog.js +134 -0
  155. package/dist/modules/billing/components/AllocatePaymentDialog.js.map +7 -0
  156. package/dist/modules/billing/components/BillingDataTable.js +21 -0
  157. package/dist/modules/billing/components/BillingDataTable.js.map +7 -0
  158. package/dist/modules/billing/components/BillingSettingsLink.js +19 -0
  159. package/dist/modules/billing/components/BillingSettingsLink.js.map +7 -0
  160. package/dist/modules/billing/components/ChangeItemPriceDialog.js +158 -0
  161. package/dist/modules/billing/components/ChangeItemPriceDialog.js.map +7 -0
  162. package/dist/modules/billing/components/CreateMemoDialog.js +200 -0
  163. package/dist/modules/billing/components/CreateMemoDialog.js.map +7 -0
  164. package/dist/modules/billing/components/CustomerLabel.js +33 -0
  165. package/dist/modules/billing/components/CustomerLabel.js.map +7 -0
  166. package/dist/modules/billing/components/InvoicesTable.js +270 -0
  167. package/dist/modules/billing/components/InvoicesTable.js.map +7 -0
  168. package/dist/modules/billing/components/ItemForm.js +176 -44
  169. package/dist/modules/billing/components/ItemForm.js.map +2 -2
  170. package/dist/modules/billing/components/ItemPriceField.js +46 -0
  171. package/dist/modules/billing/components/ItemPriceField.js.map +7 -0
  172. package/dist/modules/billing/components/LineFormDialog.js +25 -2
  173. package/dist/modules/billing/components/LineFormDialog.js.map +2 -2
  174. package/dist/modules/billing/components/ManualPaymentDialog.js +122 -0
  175. package/dist/modules/billing/components/ManualPaymentDialog.js.map +7 -0
  176. package/dist/modules/billing/components/MoneyInput.js +14 -0
  177. package/dist/modules/billing/components/MoneyInput.js.map +7 -0
  178. package/dist/modules/billing/components/PaymentUploadDialog.js +115 -0
  179. package/dist/modules/billing/components/PaymentUploadDialog.js.map +7 -0
  180. package/dist/modules/billing/components/PaymentsTable.js +171 -0
  181. package/dist/modules/billing/components/PaymentsTable.js.map +7 -0
  182. package/dist/modules/billing/components/PostRunDraftsButton.js +105 -0
  183. package/dist/modules/billing/components/PostRunDraftsButton.js.map +7 -0
  184. package/dist/modules/billing/components/PrepaidPanel.js +14 -4
  185. package/dist/modules/billing/components/PrepaidPanel.js.map +2 -2
  186. package/dist/modules/billing/components/RunCyclesSection.js +209 -0
  187. package/dist/modules/billing/components/RunCyclesSection.js.map +7 -0
  188. package/dist/modules/billing/components/TestRunActions.js +127 -0
  189. package/dist/modules/billing/components/TestRunActions.js.map +7 -0
  190. package/dist/modules/billing/components/account/AccountItemsTab.js +157 -0
  191. package/dist/modules/billing/components/account/AccountItemsTab.js.map +7 -0
  192. package/dist/modules/billing/components/account/AccountRunBillingDialog.js +122 -0
  193. package/dist/modules/billing/components/account/AccountRunBillingDialog.js.map +7 -0
  194. package/dist/modules/billing/components/account/AccountRunsTab.js +152 -0
  195. package/dist/modules/billing/components/account/AccountRunsTab.js.map +7 -0
  196. package/dist/modules/billing/components/account/AccountStatementsTab.js +98 -0
  197. package/dist/modules/billing/components/account/AccountStatementsTab.js.map +7 -0
  198. package/dist/modules/billing/components/account/AccountSummaryCards.js +125 -0
  199. package/dist/modules/billing/components/account/AccountSummaryCards.js.map +7 -0
  200. package/dist/modules/billing/components/account/AccountUsageTab.js +91 -0
  201. package/dist/modules/billing/components/account/AccountUsageTab.js.map +7 -0
  202. package/dist/modules/billing/components/account/AccountView.js +73 -0
  203. package/dist/modules/billing/components/account/AccountView.js.map +7 -0
  204. package/dist/modules/billing/components/account/accountRow.js +39 -0
  205. package/dist/modules/billing/components/account/accountRow.js.map +7 -0
  206. package/dist/modules/billing/components/customerNames.js +42 -0
  207. package/dist/modules/billing/components/customerNames.js.map +7 -0
  208. package/dist/modules/billing/data/entities.js +560 -4
  209. package/dist/modules/billing/data/entities.js.map +2 -2
  210. package/dist/modules/billing/data/entityIds.js +10 -1
  211. package/dist/modules/billing/data/entityIds.js.map +2 -2
  212. package/dist/modules/billing/data/validators.js +269 -15
  213. package/dist/modules/billing/data/validators.js.map +2 -2
  214. package/dist/modules/billing/events.js +50 -0
  215. package/dist/modules/billing/events.js.map +2 -2
  216. package/dist/modules/billing/i18n/de.json +880 -0
  217. package/dist/modules/billing/i18n/en.json +457 -21
  218. package/dist/modules/billing/i18n/es.json +880 -0
  219. package/dist/modules/billing/i18n/pl.json +458 -22
  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 +237 -102
  237. package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
  238. package/dist/modules/billing/lib/billingSettings.js +116 -0
  239. package/dist/modules/billing/lib/billingSettings.js.map +7 -0
  240. package/dist/modules/billing/lib/commandRoute.js +81 -0
  241. package/dist/modules/billing/lib/commandRoute.js.map +7 -0
  242. package/dist/modules/billing/lib/customerLookup.js +97 -0
  243. package/dist/modules/billing/lib/customerLookup.js.map +7 -0
  244. package/dist/modules/billing/lib/dateOnly.js +13 -0
  245. package/dist/modules/billing/lib/dateOnly.js.map +7 -0
  246. package/dist/modules/billing/lib/documentParties.js +16 -0
  247. package/dist/modules/billing/lib/documentParties.js.map +7 -0
  248. package/dist/modules/billing/lib/documentTypes.js +27 -0
  249. package/dist/modules/billing/lib/documentTypes.js.map +7 -0
  250. package/dist/modules/billing/lib/dueDate.js +18 -0
  251. package/dist/modules/billing/lib/dueDate.js.map +7 -0
  252. package/dist/modules/billing/lib/iban.js +29 -0
  253. package/dist/modules/billing/lib/iban.js.map +7 -0
  254. package/dist/modules/billing/lib/invoiceDelivery.js +133 -0
  255. package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
  256. package/dist/modules/billing/lib/invoiceLanguages.js +28 -0
  257. package/dist/modules/billing/lib/invoiceLanguages.js.map +7 -0
  258. package/dist/modules/billing/lib/invoiceWriter.js +107 -99
  259. package/dist/modules/billing/lib/invoiceWriter.js.map +2 -2
  260. package/dist/modules/billing/lib/itemBillingState.js +27 -0
  261. package/dist/modules/billing/lib/itemBillingState.js.map +7 -0
  262. package/dist/modules/billing/lib/itemPriceChange.js +18 -0
  263. package/dist/modules/billing/lib/itemPriceChange.js.map +7 -0
  264. package/dist/modules/billing/lib/itemSelector.js.map +2 -2
  265. package/dist/modules/billing/lib/lineAmounts.js +32 -0
  266. package/dist/modules/billing/lib/lineAmounts.js.map +7 -0
  267. package/dist/modules/billing/lib/memoGuards.js +25 -0
  268. package/dist/modules/billing/lib/memoGuards.js.map +7 -0
  269. package/dist/modules/billing/lib/navigation.js +48 -0
  270. package/dist/modules/billing/lib/navigation.js.map +7 -0
  271. package/dist/modules/billing/lib/numbering.js +120 -0
  272. package/dist/modules/billing/lib/numbering.js.map +7 -0
  273. package/dist/modules/billing/lib/overdue.js +36 -0
  274. package/dist/modules/billing/lib/overdue.js.map +7 -0
  275. package/dist/modules/billing/lib/paymentCsv.js +125 -0
  276. package/dist/modules/billing/lib/paymentCsv.js.map +7 -0
  277. package/dist/modules/billing/lib/paymentGateway.js +15 -0
  278. package/dist/modules/billing/lib/paymentGateway.js.map +7 -0
  279. package/dist/modules/billing/lib/paymentImport.js +164 -0
  280. package/dist/modules/billing/lib/paymentImport.js.map +7 -0
  281. package/dist/modules/billing/lib/paymentMatcher.js +36 -0
  282. package/dist/modules/billing/lib/paymentMatcher.js.map +7 -0
  283. package/dist/modules/billing/lib/pdf/attachmentStore.js +46 -0
  284. package/dist/modules/billing/lib/pdf/attachmentStore.js.map +7 -0
  285. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js +7 -0
  286. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js.map +7 -0
  287. package/dist/modules/billing/lib/pdf/invoiceModel.js +194 -0
  288. package/dist/modules/billing/lib/pdf/invoiceModel.js.map +7 -0
  289. package/dist/modules/billing/lib/pdf/invoicePdf.js +165 -0
  290. package/dist/modules/billing/lib/pdf/invoicePdf.js.map +7 -0
  291. package/dist/modules/billing/lib/pdf/invoiceTemplate.js +276 -0
  292. package/dist/modules/billing/lib/pdf/invoiceTemplate.js.map +7 -0
  293. package/dist/modules/billing/lib/prepaidConfig.js +17 -25
  294. package/dist/modules/billing/lib/prepaidConfig.js.map +2 -2
  295. package/dist/modules/billing/lib/prepaidConsume.js +26 -7
  296. package/dist/modules/billing/lib/prepaidConsume.js.map +2 -2
  297. package/dist/modules/billing/lib/prepaidPeriodClose.js +277 -158
  298. package/dist/modules/billing/lib/prepaidPeriodClose.js.map +2 -2
  299. package/dist/modules/billing/lib/prepaidTaxPoint.js +37 -0
  300. package/dist/modules/billing/lib/prepaidTaxPoint.js.map +7 -0
  301. package/dist/modules/billing/lib/seeds/demo.js +51 -3
  302. package/dist/modules/billing/lib/seeds/demo.js.map +2 -2
  303. package/dist/modules/billing/lib/seeds/paymentsSample.js +93 -0
  304. package/dist/modules/billing/lib/seeds/paymentsSample.js.map +7 -0
  305. package/dist/modules/billing/lib/seeds/sellerSettings.js +41 -0
  306. package/dist/modules/billing/lib/seeds/sellerSettings.js.map +7 -0
  307. package/dist/modules/billing/lib/servicePeriods.js +121 -0
  308. package/dist/modules/billing/lib/servicePeriods.js.map +7 -0
  309. package/dist/modules/billing/lib/testRunCleanup.js +24 -0
  310. package/dist/modules/billing/lib/testRunCleanup.js.map +7 -0
  311. package/dist/modules/billing/lib/topupCapture.js +2 -2
  312. package/dist/modules/billing/lib/topupCapture.js.map +2 -2
  313. package/dist/modules/billing/lib/topupReceipt.js +58 -79
  314. package/dist/modules/billing/lib/topupReceipt.js.map +2 -2
  315. package/dist/modules/billing/lib/usageRater.js.map +1 -1
  316. package/dist/modules/billing/lib/usageRunner.js +14 -6
  317. package/dist/modules/billing/lib/usageRunner.js.map +2 -2
  318. package/dist/modules/billing/lib/vat.js +39 -0
  319. package/dist/modules/billing/lib/vat.js.map +7 -0
  320. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js +15 -0
  321. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js.map +7 -0
  322. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js +25 -0
  323. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js.map +7 -0
  324. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js +115 -0
  325. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js.map +7 -0
  326. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js +47 -0
  327. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js.map +7 -0
  328. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js +89 -0
  329. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js.map +7 -0
  330. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js +17 -0
  331. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js.map +7 -0
  332. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js +27 -0
  333. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js.map +7 -0
  334. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js +29 -0
  335. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js.map +7 -0
  336. package/dist/modules/billing/setup.js +7 -184
  337. package/dist/modules/billing/setup.js.map +2 -2
  338. package/dist/modules/billing/subscribers/credit-memo-auto-send.js +16 -0
  339. package/dist/modules/billing/subscribers/credit-memo-auto-send.js.map +7 -0
  340. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js +16 -0
  341. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js.map +7 -0
  342. package/dist/modules/billing/subscribers/debit-memo-auto-send.js +16 -0
  343. package/dist/modules/billing/subscribers/debit-memo-auto-send.js.map +7 -0
  344. package/dist/modules/billing/subscribers/invoice-apply-credit.js +34 -0
  345. package/dist/modules/billing/subscribers/invoice-apply-credit.js.map +7 -0
  346. package/dist/modules/billing/subscribers/invoice-auto-send.js +30 -0
  347. package/dist/modules/billing/subscribers/invoice-auto-send.js.map +7 -0
  348. package/dist/modules/billing/subscribers/payment-captured-to-paid.js +69 -33
  349. package/dist/modules/billing/subscribers/payment-captured-to-paid.js.map +2 -2
  350. package/dist/modules/billing/subscribers/prepaid-topup-captured.js +4 -6
  351. package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +2 -2
  352. package/generated/entities/billing_account/index.ts +3 -0
  353. package/generated/entities/billing_allocation/index.ts +18 -0
  354. package/generated/entities/billing_document_sequence/index.ts +11 -0
  355. package/generated/entities/billing_invoice/index.ts +38 -0
  356. package/generated/entities/billing_invoice_line/index.ts +24 -0
  357. package/generated/entities/billing_item/index.ts +4 -0
  358. package/generated/entities/billing_payment/index.ts +25 -0
  359. package/generated/entities/billing_payment_import/index.ts +14 -0
  360. package/generated/entities/billing_run/index.ts +0 -1
  361. package/generated/entities/billing_run_outcome/index.ts +1 -0
  362. package/generated/entities/billing_settings/index.ts +26 -0
  363. package/generated/entities/billing_statement/index.ts +1 -0
  364. package/generated/entities.ids.generated.ts +7 -0
  365. package/package.json +5 -1
  366. package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +171 -0
  367. package/src/modules/billing/__integration__/TC-BILL-005.spec.ts +134 -0
  368. package/src/modules/billing/__integration__/TC-BILL-006.spec.ts +101 -0
  369. package/src/modules/billing/__integration__/TC-BILL-007.spec.ts +140 -0
  370. package/src/modules/billing/__integration__/TC-BILL-008.spec.ts +108 -0
  371. package/src/modules/billing/__integration__/TC-BILL-009.spec.ts +113 -0
  372. package/src/modules/billing/__integration__/TC-BILL-010.spec.ts +118 -0
  373. package/src/modules/billing/__integration__/TC-BILL-011.spec.ts +142 -0
  374. package/src/modules/billing/__integration__/TC-BILL-012.spec.ts +115 -0
  375. package/src/modules/billing/__integration__/TC-BILL-013.spec.ts +118 -0
  376. package/src/modules/billing/__integration__/sellerSettings.ts +24 -0
  377. package/src/modules/billing/__tests__/commands/invoices.test.ts +436 -354
  378. package/src/modules/billing/__tests__/commands/itemsBulk.test.ts +33 -0
  379. package/src/modules/billing/__tests__/commands/memos.test.ts +205 -0
  380. package/src/modules/billing/__tests__/commands/payments.test.ts +241 -0
  381. package/src/modules/billing/__tests__/commands/runsDelete.test.ts +146 -0
  382. package/src/modules/billing/__tests__/commands/runsPostDrafts.test.ts +106 -0
  383. package/src/modules/billing/__tests__/commands/topups.test.ts +11 -0
  384. package/src/modules/billing/__tests__/entityRegistry.test.ts +8 -1
  385. package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
  386. package/src/modules/billing/__tests__/i18n/dictionaries.test.ts +64 -0
  387. package/src/modules/billing/__tests__/lib/accountFinancials.test.ts +53 -0
  388. package/src/modules/billing/__tests__/lib/accountSummary.test.ts +97 -0
  389. package/src/modules/billing/__tests__/lib/allocation.test.ts +319 -0
  390. package/src/modules/billing/__tests__/lib/billRunEngine.test.ts +228 -17
  391. package/src/modules/billing/__tests__/lib/billingSettings.test.ts +109 -0
  392. package/src/modules/billing/__tests__/lib/customerLookup.test.ts +156 -0
  393. package/src/modules/billing/__tests__/lib/dueDate.test.ts +35 -0
  394. package/src/modules/billing/__tests__/lib/iban.test.ts +38 -0
  395. package/src/modules/billing/__tests__/lib/invoiceDelivery.test.ts +206 -0
  396. package/src/modules/billing/__tests__/lib/invoiceLanguages.test.ts +49 -0
  397. package/src/modules/billing/__tests__/lib/invoiceWriter.test.ts +212 -10
  398. package/src/modules/billing/__tests__/lib/itemBillingState.test.ts +42 -0
  399. package/src/modules/billing/__tests__/lib/itemPriceChange.test.ts +165 -0
  400. package/src/modules/billing/__tests__/lib/lineAmounts.test.ts +86 -0
  401. package/src/modules/billing/__tests__/lib/navigation.test.ts +71 -0
  402. package/src/modules/billing/__tests__/lib/numbering.test.ts +91 -0
  403. package/src/modules/billing/__tests__/lib/overdue.test.ts +36 -0
  404. package/src/modules/billing/__tests__/lib/paymentCsv.test.ts +148 -0
  405. package/src/modules/billing/__tests__/lib/paymentImport.test.ts +113 -0
  406. package/src/modules/billing/__tests__/lib/paymentsSample.test.ts +73 -0
  407. package/src/modules/billing/__tests__/lib/pdf/invoicePdf.test.ts +269 -0
  408. package/src/modules/billing/__tests__/lib/pdf/invoicePdfService.test.ts +147 -0
  409. package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +374 -98
  410. package/src/modules/billing/__tests__/lib/prepaidTaxPoint.test.ts +118 -0
  411. package/src/modules/billing/__tests__/lib/seedsDemo.test.ts +53 -2
  412. package/src/modules/billing/__tests__/lib/sellerSettings.test.ts +28 -0
  413. package/src/modules/billing/__tests__/lib/servicePeriods.test.ts +190 -0
  414. package/src/modules/billing/__tests__/lib/topupCapture.test.ts +6 -28
  415. package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +21 -52
  416. package/src/modules/billing/__tests__/lib/vat.test.ts +51 -0
  417. package/src/modules/billing/__tests__/package-isolation.test.ts +22 -8
  418. package/src/modules/billing/__tests__/setup.test.ts +13 -4
  419. package/src/modules/billing/__tests__/validators.test.ts +197 -3
  420. package/src/modules/billing/acl.ts +12 -0
  421. package/src/modules/billing/api/accounts/[id]/summary/route.ts +62 -0
  422. package/src/modules/billing/api/accounts/route.ts +59 -4
  423. package/src/modules/billing/api/export/account/[id]/route.ts +13 -11
  424. package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
  425. package/src/modules/billing/api/invoices/[id]/pdf/route.ts +80 -0
  426. package/src/modules/billing/api/invoices/[id]/route.ts +57 -70
  427. package/src/modules/billing/api/invoices/[id]/send/route.ts +127 -0
  428. package/src/modules/billing/api/invoices/add-line/route.ts +2 -2
  429. package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
  430. package/src/modules/billing/api/invoices/edit-line/route.ts +2 -2
  431. package/src/modules/billing/api/invoices/post/route.ts +7 -6
  432. package/src/modules/billing/api/invoices/remove-line/route.ts +2 -2
  433. package/src/modules/billing/api/invoices/route.ts +81 -86
  434. package/src/modules/billing/api/items/bulk/route.ts +2 -1
  435. package/src/modules/billing/api/items/change-price/route.ts +54 -0
  436. package/src/modules/billing/api/items/route.ts +23 -7
  437. package/src/modules/billing/api/payment-imports/[id]/route.ts +49 -0
  438. package/src/modules/billing/api/payment-imports/route.ts +57 -0
  439. package/src/modules/billing/api/payments/[id]/route.ts +63 -0
  440. package/src/modules/billing/api/payments/allocate/route.ts +35 -0
  441. package/src/modules/billing/api/payments/assign/route.ts +36 -0
  442. package/src/modules/billing/api/payments/convert-to-topup/route.ts +35 -0
  443. package/src/modules/billing/api/payments/ignore/route.ts +35 -0
  444. package/src/modules/billing/api/payments/import/route.ts +72 -0
  445. package/src/modules/billing/api/payments/restore/route.ts +35 -0
  446. package/src/modules/billing/api/payments/route.ts +147 -0
  447. package/src/modules/billing/api/payments/unallocate/route.ts +35 -0
  448. package/src/modules/billing/api/payments/unassign/route.ts +35 -0
  449. package/src/modules/billing/api/run-outcomes/route.ts +49 -6
  450. package/src/modules/billing/api/runs/[id]/post-drafts/route.ts +71 -0
  451. package/src/modules/billing/api/runs/[id]/route.ts +59 -0
  452. package/src/modules/billing/api/runs/retry-failed/route.ts +2 -1
  453. package/src/modules/billing/api/runs/route.ts +15 -7
  454. package/src/modules/billing/api/settings/number-preview/route.ts +46 -0
  455. package/src/modules/billing/api/settings/route.ts +116 -0
  456. package/src/modules/billing/api/statements/route.ts +5 -0
  457. package/src/modules/billing/api/test-invoices/wipe/route.ts +2 -2
  458. package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +151 -372
  459. package/src/modules/billing/backend/billing/accounts/create/page.tsx +6 -0
  460. package/src/modules/billing/backend/billing/accounts/page.tsx +70 -4
  461. package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +444 -95
  462. package/src/modules/billing/backend/billing/invoices/page.tsx +8 -227
  463. package/src/modules/billing/backend/billing/items/[id]/page.tsx +75 -6
  464. package/src/modules/billing/backend/billing/items/create/page.tsx +13 -8
  465. package/src/modules/billing/backend/billing/items/page.tsx +18 -2
  466. package/src/modules/billing/backend/billing/payments/[id]/page.meta.ts +19 -0
  467. package/src/modules/billing/backend/billing/payments/[id]/page.tsx +415 -0
  468. package/src/modules/billing/backend/billing/payments/imports/[id]/page.meta.ts +19 -0
  469. package/src/modules/billing/backend/billing/payments/imports/[id]/page.tsx +106 -0
  470. package/src/modules/billing/backend/billing/payments/page.meta.ts +16 -0
  471. package/src/modules/billing/backend/billing/payments/page.tsx +56 -0
  472. package/src/modules/billing/backend/billing/runs/[id]/page.tsx +49 -18
  473. package/src/modules/billing/backend/billing/runs/page.tsx +59 -8
  474. package/src/modules/billing/backend/billing/statements/[id]/page.tsx +86 -5
  475. package/src/modules/billing/backend/billing/statements/page.tsx +1 -1
  476. package/src/modules/billing/backend/billing/topups/page.tsx +1 -1
  477. package/src/modules/billing/backend/billing/transactions/page.tsx +1 -1
  478. package/src/modules/billing/backend/billing/usage/create/page.tsx +3 -2
  479. package/src/modules/billing/backend/config/billing/page.meta.ts +21 -0
  480. package/src/modules/billing/backend/config/billing/page.tsx +549 -0
  481. package/src/modules/billing/cli.ts +31 -1
  482. package/src/modules/billing/commands/accounts.ts +6 -0
  483. package/src/modules/billing/commands/index.ts +3 -0
  484. package/src/modules/billing/commands/invoices.ts +364 -231
  485. package/src/modules/billing/commands/items.ts +143 -0
  486. package/src/modules/billing/commands/memos.ts +218 -0
  487. package/src/modules/billing/commands/payments.ts +428 -0
  488. package/src/modules/billing/commands/runs.ts +205 -3
  489. package/src/modules/billing/commands/settings.ts +77 -0
  490. package/src/modules/billing/commands/topups.ts +12 -3
  491. package/src/modules/billing/commands/transactions.ts +2 -2
  492. package/src/modules/billing/components/AccountForm.tsx +199 -53
  493. package/src/modules/billing/components/AccountInvoicesSection.tsx +75 -0
  494. package/src/modules/billing/components/AccountPaymentsSection.tsx +42 -0
  495. package/src/modules/billing/components/AccountPicker.tsx +70 -0
  496. package/src/modules/billing/components/AllocatePaymentDialog.tsx +167 -0
  497. package/src/modules/billing/components/BillingDataTable.tsx +34 -0
  498. package/src/modules/billing/components/BillingSettingsLink.tsx +25 -0
  499. package/src/modules/billing/components/ChangeItemPriceDialog.tsx +180 -0
  500. package/src/modules/billing/components/CreateMemoDialog.tsx +232 -0
  501. package/src/modules/billing/components/CustomerLabel.tsx +53 -0
  502. package/src/modules/billing/components/InvoicesTable.tsx +344 -0
  503. package/src/modules/billing/components/ItemForm.tsx +233 -44
  504. package/src/modules/billing/components/ItemPriceField.tsx +81 -0
  505. package/src/modules/billing/components/LineFormDialog.tsx +25 -1
  506. package/src/modules/billing/components/ManualPaymentDialog.tsx +140 -0
  507. package/src/modules/billing/components/MoneyInput.tsx +26 -0
  508. package/src/modules/billing/components/PaymentUploadDialog.tsx +148 -0
  509. package/src/modules/billing/components/PaymentsTable.tsx +213 -0
  510. package/src/modules/billing/components/PostRunDraftsButton.tsx +129 -0
  511. package/src/modules/billing/components/PrepaidPanel.tsx +19 -6
  512. package/src/modules/billing/components/RunCyclesSection.tsx +298 -0
  513. package/src/modules/billing/components/TestRunActions.tsx +152 -0
  514. package/src/modules/billing/components/account/AccountItemsTab.tsx +192 -0
  515. package/src/modules/billing/components/account/AccountRunBillingDialog.tsx +147 -0
  516. package/src/modules/billing/components/account/AccountRunsTab.tsx +201 -0
  517. package/src/modules/billing/components/account/AccountStatementsTab.tsx +120 -0
  518. package/src/modules/billing/components/account/AccountSummaryCards.tsx +153 -0
  519. package/src/modules/billing/components/account/AccountUsageTab.tsx +122 -0
  520. package/src/modules/billing/components/account/AccountView.tsx +101 -0
  521. package/src/modules/billing/components/account/accountRow.ts +70 -0
  522. package/src/modules/billing/components/customerNames.ts +62 -0
  523. package/src/modules/billing/data/entities.ts +656 -6
  524. package/src/modules/billing/data/entityIds.ts +9 -0
  525. package/src/modules/billing/data/validators.ts +388 -8
  526. package/src/modules/billing/events.ts +56 -3
  527. package/src/modules/billing/i18n/de.json +880 -0
  528. package/src/modules/billing/i18n/en.json +457 -21
  529. package/src/modules/billing/i18n/es.json +880 -0
  530. package/src/modules/billing/i18n/pl.json +458 -22
  531. package/src/modules/billing/index.ts +6 -2
  532. package/src/modules/billing/lib/accountFinancials.ts +84 -0
  533. package/src/modules/billing/lib/accountLock.ts +32 -0
  534. package/src/modules/billing/lib/accountStatus.ts +11 -9
  535. package/src/modules/billing/lib/accountSummary.ts +172 -0
  536. package/src/modules/billing/lib/allocation.ts +515 -0
  537. package/src/modules/billing/lib/allocationEvents.ts +26 -0
  538. package/src/modules/billing/lib/billPeriod.ts +19 -0
  539. package/src/modules/billing/lib/billRunEngine.ts +350 -150
  540. package/src/modules/billing/lib/billingSettings.ts +145 -0
  541. package/src/modules/billing/lib/commandRoute.ts +112 -0
  542. package/src/modules/billing/lib/customerLookup.ts +157 -0
  543. package/src/modules/billing/lib/dateOnly.ts +22 -0
  544. package/src/modules/billing/lib/documentParties.ts +23 -0
  545. package/src/modules/billing/lib/documentTypes.ts +37 -0
  546. package/src/modules/billing/lib/dueDate.ts +26 -0
  547. package/src/modules/billing/lib/iban.ts +36 -0
  548. package/src/modules/billing/lib/invoiceDelivery.ts +196 -0
  549. package/src/modules/billing/lib/invoiceLanguages.ts +57 -0
  550. package/src/modules/billing/lib/invoiceWriter.ts +162 -148
  551. package/src/modules/billing/lib/itemBillingState.ts +67 -0
  552. package/src/modules/billing/lib/itemPriceChange.ts +56 -0
  553. package/src/modules/billing/lib/itemSelector.ts +4 -1
  554. package/src/modules/billing/lib/lineAmounts.ts +61 -0
  555. package/src/modules/billing/lib/memoGuards.ts +41 -0
  556. package/src/modules/billing/lib/navigation.ts +64 -0
  557. package/src/modules/billing/lib/numbering.ts +174 -0
  558. package/src/modules/billing/lib/overdue.ts +60 -0
  559. package/src/modules/billing/lib/paymentCsv.ts +171 -0
  560. package/src/modules/billing/lib/paymentGateway.ts +52 -0
  561. package/src/modules/billing/lib/paymentImport.ts +228 -0
  562. package/src/modules/billing/lib/paymentMatcher.ts +88 -0
  563. package/src/modules/billing/lib/pdf/attachmentStore.ts +60 -0
  564. package/src/modules/billing/lib/pdf/fonts/NotoSans-Bold.ttf +0 -0
  565. package/src/modules/billing/lib/pdf/fonts/NotoSans-Regular.ttf +0 -0
  566. package/src/modules/billing/lib/pdf/fonts/OFL.txt +93 -0
  567. package/src/modules/billing/lib/pdf/fonts/embeddedFonts.ts +9 -0
  568. package/src/modules/billing/lib/pdf/invoiceModel.ts +329 -0
  569. package/src/modules/billing/lib/pdf/invoicePdf.ts +220 -0
  570. package/src/modules/billing/lib/pdf/invoiceTemplate.ts +338 -0
  571. package/src/modules/billing/lib/prepaidConfig.ts +27 -36
  572. package/src/modules/billing/lib/prepaidConsume.ts +29 -6
  573. package/src/modules/billing/lib/prepaidPeriodClose.ts +407 -239
  574. package/src/modules/billing/lib/prepaidTaxPoint.ts +76 -0
  575. package/src/modules/billing/lib/seeds/demo.ts +79 -6
  576. package/src/modules/billing/lib/seeds/paymentsSample.ts +136 -0
  577. package/src/modules/billing/lib/seeds/sellerSettings.ts +78 -0
  578. package/src/modules/billing/lib/servicePeriods.ts +226 -0
  579. package/src/modules/billing/lib/testRunCleanup.ts +42 -0
  580. package/src/modules/billing/lib/topupCapture.ts +3 -4
  581. package/src/modules/billing/lib/topupReceipt.ts +70 -103
  582. package/src/modules/billing/lib/usageRater.ts +1 -1
  583. package/src/modules/billing/lib/usageRunner.ts +17 -5
  584. package/src/modules/billing/lib/vat.ts +56 -0
  585. package/src/modules/billing/migrations/Migration20261114000000_billing_customer_kind.ts +25 -0
  586. package/src/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.ts +37 -0
  587. package/src/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.ts +132 -0
  588. package/src/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.ts +58 -0
  589. package/src/modules/billing/migrations/Migration20261117000000_billing_payments.ts +97 -0
  590. package/src/modules/billing/migrations/Migration20261118000000_billing_memos.ts +21 -0
  591. package/src/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.ts +39 -0
  592. package/src/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.ts +35 -0
  593. package/src/modules/billing/setup.ts +11 -237
  594. package/src/modules/billing/subscribers/credit-memo-auto-send.ts +15 -0
  595. package/src/modules/billing/subscribers/debit-memo-apply-credit.ts +15 -0
  596. package/src/modules/billing/subscribers/debit-memo-auto-send.ts +15 -0
  597. package/src/modules/billing/subscribers/invoice-apply-credit.ts +39 -0
  598. package/src/modules/billing/subscribers/invoice-auto-send.ts +46 -0
  599. package/src/modules/billing/subscribers/payment-captured-to-paid.ts +84 -62
  600. package/src/modules/billing/subscribers/prepaid-topup-captured.ts +4 -8
  601. package/dist/modules/billing/lib/invoiceStatus.js +0 -38
  602. package/dist/modules/billing/lib/invoiceStatus.js.map +0 -7
  603. package/src/modules/billing/__tests__/lib/invoiceStatus.test.ts +0 -97
  604. package/src/modules/billing/lib/invoiceStatus.ts +0 -61
@@ -0,0 +1,77 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import type { CommandHandler, CommandRuntimeContext } from '@open-mercato/shared/lib/commands/types'
3
+ import { registerCommand } from '@open-mercato/shared/lib/commands'
4
+ import { ensureOrganizationScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'
5
+ import { billingSettingsUpdateSchema, type BillingSettingsUpdateInput } from '../data/validators'
6
+ import { getBillingSettings, serializeBillingSettings, taxRateColumn } from '../lib/billingSettings'
7
+
8
+ /**
9
+ * `billing.settings.update` — edits the organization's billing settings
10
+ * (Spec 0: prepaid defaults + document number masks; Spec B: seller,
11
+ * payment and document fields). The row always exists (lazily created), so this is a partial
12
+ * update of one row per organization. Masks are validated by the schema.
13
+ */
14
+
15
+ function getEm(ctx: CommandRuntimeContext): EntityManager {
16
+ return (ctx.container.resolve('em') as EntityManager).fork()
17
+ }
18
+
19
+ function money4(value: number): string {
20
+ return (Math.round(value * 10000) / 10000).toFixed(4)
21
+ }
22
+
23
+ const updateSettingsCommand: CommandHandler<
24
+ BillingSettingsUpdateInput,
25
+ ReturnType<typeof serializeBillingSettings>
26
+ > = {
27
+ id: 'billing.settings.update',
28
+
29
+ async execute(rawInput, ctx) {
30
+ const parsed = billingSettingsUpdateSchema.parse(rawInput)
31
+ ensureTenantScope(ctx, parsed.tenantId)
32
+ ensureOrganizationScope(ctx, parsed.organizationId)
33
+
34
+ const em = getEm(ctx)
35
+ const settings = await getBillingSettings(em, {
36
+ tenantId: parsed.tenantId,
37
+ organizationId: parsed.organizationId,
38
+ })
39
+ if (parsed.lowBalanceThresholdDefault !== undefined) {
40
+ settings.lowBalanceThresholdDefault = money4(parsed.lowBalanceThresholdDefault)
41
+ }
42
+ if (parsed.nearLimitBufferDefault !== undefined) {
43
+ settings.nearLimitBufferDefault = money4(parsed.nearLimitBufferDefault)
44
+ }
45
+ if (parsed.statementEnabled !== undefined) settings.statementEnabled = parsed.statementEnabled
46
+ if (parsed.topupTaxRate !== undefined) settings.topupTaxRate = parsed.topupTaxRate.toFixed(4)
47
+ if (parsed.topupProvider !== undefined) settings.topupProvider = parsed.topupProvider
48
+ if (parsed.prepaidTaxPoint !== undefined) settings.prepaidTaxPoint = parsed.prepaidTaxPoint
49
+ if (parsed.numberMasks !== undefined) {
50
+ settings.numberMasks = { ...(settings.numberMasks ?? {}), ...stripUndefined(parsed.numberMasks) }
51
+ }
52
+ // Spec B — seller / payment / document fields. `null` clears a field.
53
+ if (parsed.legalName !== undefined) settings.legalName = parsed.legalName
54
+ if (parsed.sellerAddress !== undefined) settings.sellerAddress = parsed.sellerAddress
55
+ if (parsed.taxId !== undefined) settings.taxId = parsed.taxId
56
+ if (parsed.bankName !== undefined) settings.bankName = parsed.bankName
57
+ if (parsed.iban !== undefined) settings.iban = parsed.iban
58
+ if (parsed.bic !== undefined) settings.bic = parsed.bic
59
+ if (parsed.invoiceFooter !== undefined) settings.invoiceFooter = parsed.invoiceFooter
60
+ if (parsed.logoAttachmentId !== undefined) settings.logoAttachmentId = parsed.logoAttachmentId
61
+ if (parsed.defaultPaymentTermsDays !== undefined) settings.defaultPaymentTermsDays = parsed.defaultPaymentTermsDays
62
+ if (parsed.defaultTaxRate !== undefined) settings.defaultTaxRate = taxRateColumn(parsed.defaultTaxRate)
63
+ settings.updatedAt = new Date()
64
+ await em.flush()
65
+ return serializeBillingSettings(settings)
66
+ },
67
+ }
68
+
69
+ function stripUndefined(masks: Record<string, string | undefined>): Record<string, string> {
70
+ const out: Record<string, string> = {}
71
+ for (const [key, value] of Object.entries(masks)) if (value !== undefined) out[key] = value
72
+ return out
73
+ }
74
+
75
+ registerCommand(updateSettingsCommand)
76
+
77
+ export { updateSettingsCommand }
@@ -9,7 +9,7 @@ import {
9
9
  import { emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'
10
10
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
11
11
  import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
12
- import type { PaymentGatewayService } from '@open-mercato/core/modules/payment_gateways/lib/gateway-service'
12
+ import { resolvePaymentGateway } from '../lib/paymentGateway'
13
13
  import { BillingAccount, BillingTopup } from '../data/entities'
14
14
  import { billingEntityIds } from '../data/entityIds'
15
15
  import {
@@ -98,7 +98,17 @@ const createTopupCommand: CommandHandler<BillingTopupCreateInput, CreateTopupRes
98
98
  }
99
99
  }
100
100
 
101
- const providerKey = parsed.providerKey ?? (await getTopupProvider(em))
101
+ // E-D1: the gateway is optional. Check before persisting anything so an
102
+ // install without `payment_gateways` never leaves a dangling pending top-up.
103
+ const gateway = resolvePaymentGateway(ctx.container as never)
104
+ if (!gateway) {
105
+ throw new CrudHttpError(501, {
106
+ error: 'Online top-ups need the payment gateways module, which is not installed',
107
+ code: 'billing.topup.gateway_unavailable',
108
+ })
109
+ }
110
+
111
+ const providerKey = parsed.providerKey ?? (await getTopupProvider(em, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }))
102
112
  const paymentId = randomUUID()
103
113
  const now = new Date()
104
114
  const topup = em.create(BillingTopup, {
@@ -124,7 +134,6 @@ const createTopupCommand: CommandHandler<BillingTopupCreateInput, CreateTopupRes
124
134
  // Open the gateway session. captureMethod 'automatic' so a successful
125
135
  // checkout fires `payment.captured` directly (our capture subscriber
126
136
  // credits the balance + issues the receipt).
127
- const gateway = ctx.container.resolve('paymentGatewayService') as PaymentGatewayService
128
137
  const { transaction, session } = await gateway.createPaymentSession({
129
138
  providerKey,
130
139
  paymentId,
@@ -84,9 +84,9 @@ const adjustTransactionCommand: CommandHandler<BillingTransactionAdjustInput, Ad
84
84
  })
85
85
  const threshold = resolveLowBalanceThreshold(
86
86
  balanceRow?.lowBalanceThreshold ?? null,
87
- await getLowBalanceThresholdDefault(em),
87
+ await getLowBalanceThresholdDefault(em, { tenantId: account.tenantId, organizationId: account.organizationId }),
88
88
  )
89
- const nearLimitBuffer = await getNearLimitBufferDefault(em)
89
+ const nearLimitBuffer = await getNearLimitBufferDefault(em, { tenantId: account.tenantId, organizationId: account.organizationId })
90
90
  const userId = (ctx.auth?.sub as string | undefined) ?? null
91
91
 
92
92
  const outcome = await em.transactional(async (tem) =>
@@ -10,10 +10,24 @@ import {
10
10
  SelectValue,
11
11
  } from '@open-mercato/ui/primitives/select'
12
12
  import { Switch } from '@open-mercato/ui/primitives/switch'
13
+ import { SegmentedControl, SegmentedControlItem } from '@open-mercato/ui/primitives/segmented-control'
14
+ import { Building2, User } from 'lucide-react'
13
15
  import { Kbd, KbdShortcut } from '@open-mercato/ui/primitives/kbd'
14
16
  import { ComboboxInput, type ComboboxOption } from '@open-mercato/ui/backend/inputs'
15
17
  import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
16
18
  import { useT } from '@open-mercato/shared/lib/i18n/context'
19
+ import type { CustomerKind } from '../data/validators'
20
+ import {
21
+ applyCustomerPrefill,
22
+ customerEndpoint,
23
+ extractItems,
24
+ mapPrimaryAddress,
25
+ toCustomerSummary,
26
+ type CustomerSummary,
27
+ type PrefillAddress,
28
+ } from '../lib/customerLookup'
29
+ import { DEFAULT_INVOICE_LANGUAGE, SUPPORTED_INVOICE_LANGUAGES } from '../lib/invoiceLanguages'
30
+ import { fetchCustomerAddressRows } from './customerNames'
17
31
 
18
32
  /**
19
33
  * Shared form for Billing Account create + edit.
@@ -33,10 +47,17 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
33
47
  * disables `customerId` and `currencyCode` per the spec
34
48
  * ("immutable per spec — create a new account if the customer FK
35
49
  * changes" — see `billingAccountUpdateSchema`).
50
+ *
51
+ * Spec E (B2C): the customer can be a company or a person
52
+ * (`customerKind`, immutable after create). Picking a customer prefills
53
+ * name / invoice email / invoice address — only into empty fields, and a
54
+ * prefill that the operator has not touched is rolled back when they pick a
55
+ * different customer or switch kind.
36
56
  */
37
57
 
38
58
  export type AccountFormValues = {
39
59
  customerId: string
60
+ customerKind: CustomerKind
40
61
  name: string
41
62
  currencyCode: string
42
63
  billCycle: 'weekly' | 'monthly' | 'quarterly' | 'annually'
@@ -58,6 +79,9 @@ export type AccountFormValues = {
58
79
  creditLimit: string
59
80
  // Prepaid-only initial low-balance threshold for the balance row.
60
81
  lowBalanceThreshold: string
82
+ // Spec B — blank = organization default terms.
83
+ paymentTermsDays: string
84
+ autoSendInvoice: boolean
61
85
  }
62
86
 
63
87
  export type AccountFormProps = {
@@ -70,12 +94,13 @@ export type AccountFormProps = {
70
94
 
71
95
  const EMPTY_VALUES: AccountFormValues = {
72
96
  customerId: '',
97
+ customerKind: 'company',
73
98
  name: '',
74
99
  currencyCode: 'EUR',
75
100
  billCycle: 'monthly',
76
101
  billCycleAnchor: '1',
77
102
  invoiceEmail: '',
78
- invoiceLanguage: 'en',
103
+ invoiceLanguage: DEFAULT_INVOICE_LANGUAGE,
79
104
  taxId: '',
80
105
  invoiceAddress: {
81
106
  line1: '',
@@ -89,6 +114,8 @@ const EMPTY_VALUES: AccountFormValues = {
89
114
  billingMode: 'postpaid',
90
115
  creditLimit: '0',
91
116
  lowBalanceThreshold: '',
117
+ paymentTermsDays: '',
118
+ autoSendInvoice: false,
92
119
  }
93
120
 
94
121
  function todayIso(): string {
@@ -120,49 +147,95 @@ export function AccountForm({
120
147
  const [error, setError] = React.useState<string | null>(null)
121
148
  const isEdit = mode === 'edit'
122
149
 
123
- // Label cache for the customer combobox — populated as the user searches,
124
- // so the picker can render "Acme Telecom" after selection instead of the
125
- // raw UUID we send to the API.
126
- const customerLabelCacheRef = React.useRef<Map<string, ComboboxOption>>(new Map())
150
+ // Customer cache for the combobox — populated as the user searches, so the
151
+ // picker can render "Acme Telecom" after selection instead of the raw UUID
152
+ // we send to the API, and so prefill has the name + email at hand.
153
+ const customerCacheRef = React.useRef<Map<string, CustomerSummary>>(new Map())
154
+ // What the last prefill wrote — used to roll it back (only where the
155
+ // operator has not edited it since) when the customer or kind changes.
156
+ const prefilledRef = React.useRef<{ name?: string; invoiceEmail?: string; address?: PrefillAddress }>({})
127
157
 
128
158
  const loadCustomerOptions = React.useCallback(
129
159
  async (query?: string): Promise<ComboboxOption[]> => {
130
160
  const params = new URLSearchParams({ page: '1', pageSize: '20' })
131
161
  const q = (query ?? '').trim()
132
162
  if (q) params.set('search', q)
133
- const call = await apiCall<unknown>(`/api/customers/companies?${params.toString()}`)
163
+ const call = await apiCall<unknown>(`${customerEndpoint(values.customerKind)}?${params.toString()}`)
134
164
  if (!call.ok || call.result == null) return []
135
- const raw = call.result as { items?: unknown } | unknown[]
136
- const items: Array<Record<string, unknown>> = Array.isArray(raw)
137
- ? (raw as Array<Record<string, unknown>>)
138
- : Array.isArray((raw as { items?: unknown }).items)
139
- ? ((raw as { items: unknown[] }).items as Array<Record<string, unknown>>)
140
- : []
141
165
  const options: ComboboxOption[] = []
142
- for (const c of items) {
143
- const id = typeof c.id === 'string' ? c.id : c.id != null ? String(c.id) : ''
144
- if (!id) continue
145
- const label = String(c.display_name ?? c.displayName ?? c.name ?? id)
146
- const emailRaw = c.primary_email ?? c.email
147
- const description = typeof emailRaw === 'string' && emailRaw ? emailRaw : null
148
- const opt: ComboboxOption = { value: id, label, description }
149
- customerLabelCacheRef.current.set(id, opt)
150
- options.push(opt)
166
+ for (const raw of extractItems(call.result)) {
167
+ const summary = toCustomerSummary(raw)
168
+ if (!summary) continue
169
+ customerCacheRef.current.set(summary.id, summary)
170
+ options.push({ value: summary.id, label: summary.name, description: summary.email })
151
171
  }
152
172
  return options
153
173
  },
154
- [],
174
+ [values.customerKind],
155
175
  )
156
176
 
157
177
  const resolveCustomerLabel = React.useCallback(
158
- (id: string) => customerLabelCacheRef.current.get(id)?.label ?? id,
178
+ (id: string) => customerCacheRef.current.get(id)?.name ?? id,
159
179
  [],
160
180
  )
161
181
  const resolveCustomerDescription = React.useCallback(
162
- (id: string) => customerLabelCacheRef.current.get(id)?.description ?? null,
182
+ (id: string) => customerCacheRef.current.get(id)?.email ?? null,
163
183
  [],
164
184
  )
165
185
 
186
+ // Pure: strip fields that still hold the last prefill (untouched by the
187
+ // operator). Kept free of side effects so it is safe inside state updaters.
188
+ const withoutUntouchedPrefill = React.useCallback((prev: AccountFormValues): AccountFormValues => {
189
+ const filled = prefilledRef.current
190
+ let next = prev
191
+ if (filled.name !== undefined && prev.name === filled.name) next = { ...next, name: '' }
192
+ if (filled.invoiceEmail !== undefined && prev.invoiceEmail === filled.invoiceEmail) {
193
+ next = { ...next, invoiceEmail: '' }
194
+ }
195
+ if (filled.address && JSON.stringify(prev.invoiceAddress) === JSON.stringify(filled.address)) {
196
+ next = { ...next, invoiceAddress: { ...EMPTY_VALUES.invoiceAddress } }
197
+ }
198
+ return next
199
+ }, [])
200
+
201
+ const handleKindChange = React.useCallback(
202
+ (next: string) => {
203
+ const kind: CustomerKind = next === 'person' ? 'person' : 'company'
204
+ if (values.customerKind === kind) return
205
+ const reset = { ...withoutUntouchedPrefill(values), customerKind: kind, customerId: '' }
206
+ prefilledRef.current = {}
207
+ setValues(reset)
208
+ },
209
+ [values, withoutUntouchedPrefill],
210
+ )
211
+
212
+ const handleCustomerChange = React.useCallback(
213
+ (customerId: string) => {
214
+ const summary = customerCacheRef.current.get(customerId) ?? null
215
+ const base = { ...withoutUntouchedPrefill(values), customerId }
216
+ const filled = applyCustomerPrefill(base, summary, null)
217
+ prefilledRef.current = {
218
+ ...(filled.name !== base.name ? { name: filled.name } : {}),
219
+ ...(filled.invoiceEmail !== base.invoiceEmail ? { invoiceEmail: filled.invoiceEmail } : {}),
220
+ }
221
+ setValues(filled)
222
+ if (!customerId) return
223
+ void fetchCustomerAddressRows(customerId).then((rows) => {
224
+ const address = mapPrimaryAddress(rows)
225
+ if (!address) return
226
+ setValues((prev) => {
227
+ // Ignore a late response for a customer the operator already left.
228
+ if (prev.customerId !== customerId) return prev
229
+ return applyCustomerPrefill(prev, null, address)
230
+ })
231
+ // Record what we wrote; harmless if the updater above skipped (the
232
+ // rollback compares values, so a non-matching address is kept).
233
+ prefilledRef.current = { ...prefilledRef.current, address }
234
+ })
235
+ },
236
+ [values, withoutUntouchedPrefill],
237
+ )
238
+
166
239
  // Reset when the parent swaps `initial` (e.g. after loading the edit row).
167
240
  const initialKey = React.useMemo(
168
241
  () => JSON.stringify(initial ?? null),
@@ -245,48 +318,73 @@ export function AccountForm({
245
318
  if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
246
319
  event.preventDefault()
247
320
  void handleSubmit()
321
+ } else if (event.key === 'Escape') {
322
+ event.preventDefault()
323
+ onCancel()
248
324
  }
249
325
  },
250
- [handleSubmit],
326
+ [handleSubmit, onCancel],
251
327
  )
252
328
 
253
329
  return (
254
330
  <div className="rounded-lg border border-border bg-card p-6" onKeyDown={handleKeyDown}>
255
331
  <div className="grid grid-cols-2 gap-4">
332
+ <div className="flex flex-col gap-1 text-sm col-span-2">
333
+ <span className="text-muted-foreground">
334
+ {t('billing.accounts.form.customer_kind', 'Customer type')}
335
+ </span>
336
+ {isEdit ? (
337
+ <span className="inline-flex items-center gap-2">
338
+ {values.customerKind === 'person' ? <User size={16} /> : <Building2 size={16} />}
339
+ {values.customerKind === 'person'
340
+ ? t('billing.accounts.kind.person', 'Person')
341
+ : t('billing.accounts.kind.company', 'Company')}
342
+ </span>
343
+ ) : (
344
+ <SegmentedControl
345
+ value={values.customerKind}
346
+ onValueChange={handleKindChange}
347
+ aria-label={t('billing.accounts.form.customer_kind', 'Customer type')}
348
+ className="self-start"
349
+ >
350
+ <SegmentedControlItem value="company">
351
+ <Building2 size={14} />
352
+ {t('billing.accounts.kind.company', 'Company')}
353
+ </SegmentedControlItem>
354
+ <SegmentedControlItem value="person">
355
+ <User size={14} />
356
+ {t('billing.accounts.kind.person', 'Person')}
357
+ </SegmentedControlItem>
358
+ </SegmentedControl>
359
+ )}
360
+ </div>
361
+
256
362
  <label className="flex flex-col gap-1 text-sm">
257
363
  <span className="text-muted-foreground">
258
364
  {isEdit
259
365
  ? t('billing.accounts.form.customer_id', 'Customer ID')
260
- : t('billing.accounts.form.customer', 'Customer')}
366
+ : values.customerKind === 'person'
367
+ ? t('billing.accounts.form.customer.person', 'Person')
368
+ : t('billing.accounts.form.customer.company', 'Company')}
261
369
  {!isEdit ? <span className="text-destructive"> *</span> : null}
262
370
  </span>
263
371
  {isEdit ? (
264
372
  <Input value={values.customerId} disabled />
265
373
  ) : (
266
374
  <ComboboxInput
375
+ // Re-mount on kind switch so cached suggestions from the other
376
+ // collection never leak into this one.
377
+ key={values.customerKind}
267
378
  value={values.customerId}
268
- onChange={(next) => {
269
- setValues((prev) => {
270
- const customerLabel = customerLabelCacheRef.current.get(next)?.label ?? ''
271
- // Auto-fill Name with the customer's display name on the first
272
- // pick. We leave it alone if the operator has already typed
273
- // something — one customer can have multiple billing accounts
274
- // (e.g. "Acme — production" / "Acme — staging").
275
- const shouldFillName = customerLabel && !prev.name.trim()
276
- return {
277
- ...prev,
278
- customerId: next,
279
- name: shouldFillName ? customerLabel : prev.name,
280
- }
281
- })
282
- }}
379
+ onChange={handleCustomerChange}
283
380
  loadSuggestions={loadCustomerOptions}
284
381
  resolveLabel={resolveCustomerLabel}
285
382
  resolveDescription={resolveCustomerDescription}
286
- placeholder={t(
287
- 'billing.accounts.form.customer.placeholder',
288
- 'Search customers by name or email…',
289
- )}
383
+ placeholder={
384
+ values.customerKind === 'person'
385
+ ? t('billing.accounts.form.customer.placeholder_person', 'Search people by name or email…')
386
+ : t('billing.accounts.form.customer.placeholder', 'Search customers by name or email…')
387
+ }
290
388
  allowCustomValues={false}
291
389
  />
292
390
  )}
@@ -294,7 +392,14 @@ export function AccountForm({
294
392
  <span className="text-xs text-muted-foreground">
295
393
  {t('billing.accounts.form.customer_id.locked', 'Immutable — create a new account to re-link the customer.')}
296
394
  </span>
297
- ) : null}
395
+ ) : (
396
+ <span className="text-xs text-muted-foreground">
397
+ {t(
398
+ 'billing.accounts.form.customer.prefill_hint',
399
+ 'Name, invoice email and address are prefilled from the customer record when empty.',
400
+ )}
401
+ </span>
402
+ )}
298
403
  </label>
299
404
 
300
405
  <label className="flex flex-col gap-1 text-sm">
@@ -399,15 +504,23 @@ export function AccountForm({
399
504
 
400
505
  <label className="flex flex-col gap-1 text-sm">
401
506
  <span className="text-muted-foreground">
402
- {t('billing.accounts.form.invoice_language', 'Invoice language (ISO 639-1)')}
507
+ {t('billing.accounts.form.invoice_language', 'Invoice language')}
403
508
  </span>
404
- <Input
509
+ <Select
405
510
  value={values.invoiceLanguage}
406
- maxLength={5}
407
- onChange={(event) =>
408
- set('invoiceLanguage', event.currentTarget.value.toLowerCase())
409
- }
410
- />
511
+ onValueChange={(next) => set('invoiceLanguage', next)}
512
+ >
513
+ <SelectTrigger>
514
+ <SelectValue />
515
+ </SelectTrigger>
516
+ <SelectContent>
517
+ {SUPPORTED_INVOICE_LANGUAGES.map((language) => (
518
+ <SelectItem key={language.code} value={language.code}>
519
+ {language.label}
520
+ </SelectItem>
521
+ ))}
522
+ </SelectContent>
523
+ </Select>
411
524
  </label>
412
525
 
413
526
  <label className="flex flex-col gap-1 text-sm col-span-2">
@@ -520,6 +633,39 @@ export function AccountForm({
520
633
  />
521
634
  </label>
522
635
 
636
+ <label className="flex flex-col gap-1 text-sm">
637
+ <span className="text-muted-foreground">
638
+ {t('billing.accounts.form.payment_terms', 'Payment terms (days)')}
639
+ </span>
640
+ <Input
641
+ type="number"
642
+ min="0"
643
+ max="365"
644
+ step="1"
645
+ value={values.paymentTermsDays}
646
+ placeholder={t('billing.accounts.form.payment_terms.hint', 'Blank = organization default')}
647
+ onChange={(event) => set('paymentTermsDays', event.currentTarget.value)}
648
+ />
649
+ </label>
650
+
651
+ <div className="flex items-center justify-between gap-3 col-span-2">
652
+ <div>
653
+ <div className="text-sm font-medium">
654
+ {t('billing.accounts.form.auto_send', 'Email invoices automatically')}
655
+ </div>
656
+ <div className="text-xs text-muted-foreground">
657
+ {t(
658
+ 'billing.accounts.form.auto_send.help',
659
+ 'Each posted invoice is emailed as a PDF to the invoice email.',
660
+ )}
661
+ </div>
662
+ </div>
663
+ <Switch
664
+ checked={values.autoSendInvoice}
665
+ onCheckedChange={(next) => set('autoSendInvoice', next)}
666
+ />
667
+ </div>
668
+
523
669
  {values.billingMode === 'prepaid' ? (
524
670
  <label className="flex flex-col gap-1 text-sm">
525
671
  <span className="text-muted-foreground">
@@ -0,0 +1,75 @@
1
+ "use client"
2
+ import * as React from 'react'
3
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
4
+ import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
5
+ import { Stat, StatCard } from './DetailFields'
6
+ import { InvoicesTable, formatMoney } from './InvoicesTable'
7
+
8
+ /**
9
+ * Account Invoices section (Spec B): receivables summary cards + the
10
+ * account's billing documents. Self-contained so Spec E's account workspace
11
+ * can drop it into its Invoices tab unchanged.
12
+ */
13
+
14
+ type AccountSummary = {
15
+ currency_code: string
16
+ open_amount: string
17
+ overdue_amount: string
18
+ overdue_count: number
19
+ credit_amount: string
20
+ }
21
+
22
+ export function AccountInvoicesSection({
23
+ accountId,
24
+ showSummary = true,
25
+ }: {
26
+ accountId: string
27
+ /** False inside the account workspace, whose header already shows these figures. */
28
+ showSummary?: boolean
29
+ }) {
30
+ const t = useT()
31
+ const [summary, setSummary] = React.useState<AccountSummary | null>(null)
32
+
33
+ React.useEffect(() => {
34
+ if (!showSummary) return
35
+ let cancelled = false
36
+ readApiResultOrThrow<AccountSummary>(`/api/billing/accounts/${encodeURIComponent(accountId)}/summary`)
37
+ .then((result) => {
38
+ if (!cancelled) setSummary(result)
39
+ })
40
+ .catch(() => {
41
+ // Summary is informational; the invoices table reports its own errors.
42
+ if (!cancelled) setSummary(null)
43
+ })
44
+ return () => {
45
+ cancelled = true
46
+ }
47
+ }, [accountId, showSummary])
48
+
49
+ return (
50
+ <div className={showSummary ? 'mt-6 space-y-3' : 'space-y-3'}>
51
+ {showSummary && summary ? (
52
+ <StatCard>
53
+ <Stat
54
+ label={t('billing.accounts.summary.open', 'Open receivables')}
55
+ value={formatMoney(summary.open_amount, summary.currency_code)}
56
+ />
57
+ <Stat
58
+ label={t('billing.accounts.summary.overdue', 'Overdue')}
59
+ value={`${formatMoney(summary.overdue_amount, summary.currency_code)} (${summary.overdue_count})`}
60
+ />
61
+ <Stat
62
+ label={t('billing.accounts.summary.credit', 'Unapplied credit')}
63
+ value={formatMoney(summary.credit_amount, summary.currency_code)}
64
+ />
65
+ </StatCard>
66
+ ) : null}
67
+ <InvoicesTable
68
+ title={t('billing.accounts.detail.invoices', 'Invoices')}
69
+ billAccountId={accountId}
70
+ tableId="billing-account-invoices"
71
+ pageSize={10}
72
+ />
73
+ </div>
74
+ )
75
+ }
@@ -0,0 +1,42 @@
1
+ "use client"
2
+ import * as React from 'react'
3
+ import { useRouter } from 'next/navigation'
4
+ import { Plus } from 'lucide-react'
5
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { Button } from '@open-mercato/ui/primitives/button'
7
+ import { PaymentsTable } from './PaymentsTable'
8
+ import { ManualPaymentDialog } from './ManualPaymentDialog'
9
+
10
+ /**
11
+ * Account Payments section (Spec C): the account's payments plus "Record
12
+ * payment" (pre-filled account and currency). Self-contained so Spec E's
13
+ * Payments tab can reuse it.
14
+ */
15
+ export function AccountPaymentsSection({ accountId, currencyCode }: { accountId: string; currencyCode: string }) {
16
+ const t = useT()
17
+ const router = useRouter()
18
+ const [open, setOpen] = React.useState(false)
19
+ return (
20
+ <div className="mt-6">
21
+ <PaymentsTable
22
+ title={t('billing.accounts.detail.payments', 'Payments')}
23
+ tableId="billing-account-payments"
24
+ billAccountId={accountId}
25
+ pageSize={10}
26
+ actions={
27
+ <Button type="button" variant="outline" onClick={() => setOpen(true)}>
28
+ <Plus size={16} />
29
+ {t('billing.payments.manual.action', 'Record payment')}
30
+ </Button>
31
+ }
32
+ />
33
+ <ManualPaymentDialog
34
+ open={open}
35
+ onClose={() => setOpen(false)}
36
+ billAccountId={accountId}
37
+ currencyCode={currencyCode}
38
+ onCreated={(paymentId) => router.push(`/backend/billing/payments/${encodeURIComponent(paymentId)}`)}
39
+ />
40
+ </div>
41
+ )
42
+ }