@dainamite/billing 0.20.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 (598) hide show
  1. package/CHANGELOG.md +90 -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 +46 -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 +69 -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/en.json +457 -21
  217. package/dist/modules/billing/i18n/pl.json +457 -21
  218. package/dist/modules/billing/index.js +6 -2
  219. package/dist/modules/billing/index.js.map +2 -2
  220. package/dist/modules/billing/lib/accountFinancials.js +58 -0
  221. package/dist/modules/billing/lib/accountFinancials.js.map +7 -0
  222. package/dist/modules/billing/lib/accountLock.js +14 -0
  223. package/dist/modules/billing/lib/accountLock.js.map +7 -0
  224. package/dist/modules/billing/lib/accountStatus.js +9 -7
  225. package/dist/modules/billing/lib/accountStatus.js.map +2 -2
  226. package/dist/modules/billing/lib/accountSummary.js +106 -0
  227. package/dist/modules/billing/lib/accountSummary.js.map +7 -0
  228. package/dist/modules/billing/lib/allocation.js +356 -0
  229. package/dist/modules/billing/lib/allocation.js.map +7 -0
  230. package/dist/modules/billing/lib/allocationEvents.js +22 -0
  231. package/dist/modules/billing/lib/allocationEvents.js.map +7 -0
  232. package/dist/modules/billing/lib/billPeriod.js +15 -1
  233. package/dist/modules/billing/lib/billPeriod.js.map +2 -2
  234. package/dist/modules/billing/lib/billRunEngine.js +237 -102
  235. package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
  236. package/dist/modules/billing/lib/billingSettings.js +116 -0
  237. package/dist/modules/billing/lib/billingSettings.js.map +7 -0
  238. package/dist/modules/billing/lib/commandRoute.js +81 -0
  239. package/dist/modules/billing/lib/commandRoute.js.map +7 -0
  240. package/dist/modules/billing/lib/customerLookup.js +97 -0
  241. package/dist/modules/billing/lib/customerLookup.js.map +7 -0
  242. package/dist/modules/billing/lib/dateOnly.js +13 -0
  243. package/dist/modules/billing/lib/dateOnly.js.map +7 -0
  244. package/dist/modules/billing/lib/documentParties.js +16 -0
  245. package/dist/modules/billing/lib/documentParties.js.map +7 -0
  246. package/dist/modules/billing/lib/documentTypes.js +27 -0
  247. package/dist/modules/billing/lib/documentTypes.js.map +7 -0
  248. package/dist/modules/billing/lib/dueDate.js +18 -0
  249. package/dist/modules/billing/lib/dueDate.js.map +7 -0
  250. package/dist/modules/billing/lib/iban.js +29 -0
  251. package/dist/modules/billing/lib/iban.js.map +7 -0
  252. package/dist/modules/billing/lib/invoiceDelivery.js +131 -0
  253. package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
  254. package/dist/modules/billing/lib/invoiceLanguages.js +16 -0
  255. package/dist/modules/billing/lib/invoiceLanguages.js.map +7 -0
  256. package/dist/modules/billing/lib/invoiceWriter.js +107 -99
  257. package/dist/modules/billing/lib/invoiceWriter.js.map +2 -2
  258. package/dist/modules/billing/lib/itemBillingState.js +27 -0
  259. package/dist/modules/billing/lib/itemBillingState.js.map +7 -0
  260. package/dist/modules/billing/lib/itemPriceChange.js +18 -0
  261. package/dist/modules/billing/lib/itemPriceChange.js.map +7 -0
  262. package/dist/modules/billing/lib/itemSelector.js.map +2 -2
  263. package/dist/modules/billing/lib/lineAmounts.js +32 -0
  264. package/dist/modules/billing/lib/lineAmounts.js.map +7 -0
  265. package/dist/modules/billing/lib/memoGuards.js +25 -0
  266. package/dist/modules/billing/lib/memoGuards.js.map +7 -0
  267. package/dist/modules/billing/lib/navigation.js +48 -0
  268. package/dist/modules/billing/lib/navigation.js.map +7 -0
  269. package/dist/modules/billing/lib/numbering.js +120 -0
  270. package/dist/modules/billing/lib/numbering.js.map +7 -0
  271. package/dist/modules/billing/lib/overdue.js +36 -0
  272. package/dist/modules/billing/lib/overdue.js.map +7 -0
  273. package/dist/modules/billing/lib/paymentCsv.js +125 -0
  274. package/dist/modules/billing/lib/paymentCsv.js.map +7 -0
  275. package/dist/modules/billing/lib/paymentGateway.js +15 -0
  276. package/dist/modules/billing/lib/paymentGateway.js.map +7 -0
  277. package/dist/modules/billing/lib/paymentImport.js +164 -0
  278. package/dist/modules/billing/lib/paymentImport.js.map +7 -0
  279. package/dist/modules/billing/lib/paymentMatcher.js +36 -0
  280. package/dist/modules/billing/lib/paymentMatcher.js.map +7 -0
  281. package/dist/modules/billing/lib/pdf/attachmentStore.js +46 -0
  282. package/dist/modules/billing/lib/pdf/attachmentStore.js.map +7 -0
  283. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js +7 -0
  284. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js.map +7 -0
  285. package/dist/modules/billing/lib/pdf/invoiceModel.js +194 -0
  286. package/dist/modules/billing/lib/pdf/invoiceModel.js.map +7 -0
  287. package/dist/modules/billing/lib/pdf/invoicePdf.js +165 -0
  288. package/dist/modules/billing/lib/pdf/invoicePdf.js.map +7 -0
  289. package/dist/modules/billing/lib/pdf/invoiceTemplate.js +274 -0
  290. package/dist/modules/billing/lib/pdf/invoiceTemplate.js.map +7 -0
  291. package/dist/modules/billing/lib/prepaidConfig.js +17 -25
  292. package/dist/modules/billing/lib/prepaidConfig.js.map +2 -2
  293. package/dist/modules/billing/lib/prepaidConsume.js +26 -7
  294. package/dist/modules/billing/lib/prepaidConsume.js.map +2 -2
  295. package/dist/modules/billing/lib/prepaidPeriodClose.js +277 -158
  296. package/dist/modules/billing/lib/prepaidPeriodClose.js.map +2 -2
  297. package/dist/modules/billing/lib/prepaidTaxPoint.js +37 -0
  298. package/dist/modules/billing/lib/prepaidTaxPoint.js.map +7 -0
  299. package/dist/modules/billing/lib/seeds/demo.js +51 -3
  300. package/dist/modules/billing/lib/seeds/demo.js.map +2 -2
  301. package/dist/modules/billing/lib/seeds/paymentsSample.js +93 -0
  302. package/dist/modules/billing/lib/seeds/paymentsSample.js.map +7 -0
  303. package/dist/modules/billing/lib/seeds/sellerSettings.js +41 -0
  304. package/dist/modules/billing/lib/seeds/sellerSettings.js.map +7 -0
  305. package/dist/modules/billing/lib/servicePeriods.js +121 -0
  306. package/dist/modules/billing/lib/servicePeriods.js.map +7 -0
  307. package/dist/modules/billing/lib/testRunCleanup.js +24 -0
  308. package/dist/modules/billing/lib/testRunCleanup.js.map +7 -0
  309. package/dist/modules/billing/lib/topupCapture.js +2 -2
  310. package/dist/modules/billing/lib/topupCapture.js.map +2 -2
  311. package/dist/modules/billing/lib/topupReceipt.js +58 -79
  312. package/dist/modules/billing/lib/topupReceipt.js.map +2 -2
  313. package/dist/modules/billing/lib/usageRater.js.map +1 -1
  314. package/dist/modules/billing/lib/usageRunner.js +14 -6
  315. package/dist/modules/billing/lib/usageRunner.js.map +2 -2
  316. package/dist/modules/billing/lib/vat.js +39 -0
  317. package/dist/modules/billing/lib/vat.js.map +7 -0
  318. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js +15 -0
  319. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js.map +7 -0
  320. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js +25 -0
  321. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js.map +7 -0
  322. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js +115 -0
  323. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js.map +7 -0
  324. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js +47 -0
  325. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js.map +7 -0
  326. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js +89 -0
  327. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js.map +7 -0
  328. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js +17 -0
  329. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js.map +7 -0
  330. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js +27 -0
  331. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js.map +7 -0
  332. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js +29 -0
  333. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js.map +7 -0
  334. package/dist/modules/billing/setup.js +7 -184
  335. package/dist/modules/billing/setup.js.map +2 -2
  336. package/dist/modules/billing/subscribers/credit-memo-auto-send.js +16 -0
  337. package/dist/modules/billing/subscribers/credit-memo-auto-send.js.map +7 -0
  338. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js +16 -0
  339. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js.map +7 -0
  340. package/dist/modules/billing/subscribers/debit-memo-auto-send.js +16 -0
  341. package/dist/modules/billing/subscribers/debit-memo-auto-send.js.map +7 -0
  342. package/dist/modules/billing/subscribers/invoice-apply-credit.js +34 -0
  343. package/dist/modules/billing/subscribers/invoice-apply-credit.js.map +7 -0
  344. package/dist/modules/billing/subscribers/invoice-auto-send.js +30 -0
  345. package/dist/modules/billing/subscribers/invoice-auto-send.js.map +7 -0
  346. package/dist/modules/billing/subscribers/payment-captured-to-paid.js +69 -33
  347. package/dist/modules/billing/subscribers/payment-captured-to-paid.js.map +2 -2
  348. package/dist/modules/billing/subscribers/prepaid-topup-captured.js +4 -6
  349. package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +2 -2
  350. package/generated/entities/billing_account/index.ts +3 -0
  351. package/generated/entities/billing_allocation/index.ts +18 -0
  352. package/generated/entities/billing_document_sequence/index.ts +11 -0
  353. package/generated/entities/billing_invoice/index.ts +38 -0
  354. package/generated/entities/billing_invoice_line/index.ts +24 -0
  355. package/generated/entities/billing_item/index.ts +4 -0
  356. package/generated/entities/billing_payment/index.ts +25 -0
  357. package/generated/entities/billing_payment_import/index.ts +14 -0
  358. package/generated/entities/billing_run/index.ts +0 -1
  359. package/generated/entities/billing_run_outcome/index.ts +1 -0
  360. package/generated/entities/billing_settings/index.ts +26 -0
  361. package/generated/entities/billing_statement/index.ts +1 -0
  362. package/generated/entities.ids.generated.ts +7 -0
  363. package/package.json +5 -1
  364. package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +170 -0
  365. package/src/modules/billing/__integration__/TC-BILL-005.spec.ts +134 -0
  366. package/src/modules/billing/__integration__/TC-BILL-006.spec.ts +101 -0
  367. package/src/modules/billing/__integration__/TC-BILL-007.spec.ts +140 -0
  368. package/src/modules/billing/__integration__/TC-BILL-008.spec.ts +108 -0
  369. package/src/modules/billing/__integration__/TC-BILL-009.spec.ts +113 -0
  370. package/src/modules/billing/__integration__/TC-BILL-010.spec.ts +118 -0
  371. package/src/modules/billing/__integration__/TC-BILL-011.spec.ts +142 -0
  372. package/src/modules/billing/__integration__/TC-BILL-012.spec.ts +115 -0
  373. package/src/modules/billing/__integration__/TC-BILL-013.spec.ts +118 -0
  374. package/src/modules/billing/__integration__/sellerSettings.ts +24 -0
  375. package/src/modules/billing/__tests__/commands/invoices.test.ts +436 -354
  376. package/src/modules/billing/__tests__/commands/itemsBulk.test.ts +33 -0
  377. package/src/modules/billing/__tests__/commands/memos.test.ts +205 -0
  378. package/src/modules/billing/__tests__/commands/payments.test.ts +241 -0
  379. package/src/modules/billing/__tests__/commands/runsDelete.test.ts +146 -0
  380. package/src/modules/billing/__tests__/commands/runsPostDrafts.test.ts +106 -0
  381. package/src/modules/billing/__tests__/commands/topups.test.ts +11 -0
  382. package/src/modules/billing/__tests__/entityRegistry.test.ts +8 -1
  383. package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
  384. package/src/modules/billing/__tests__/lib/accountFinancials.test.ts +53 -0
  385. package/src/modules/billing/__tests__/lib/accountSummary.test.ts +97 -0
  386. package/src/modules/billing/__tests__/lib/allocation.test.ts +319 -0
  387. package/src/modules/billing/__tests__/lib/billRunEngine.test.ts +228 -17
  388. package/src/modules/billing/__tests__/lib/billingSettings.test.ts +109 -0
  389. package/src/modules/billing/__tests__/lib/customerLookup.test.ts +156 -0
  390. package/src/modules/billing/__tests__/lib/dueDate.test.ts +35 -0
  391. package/src/modules/billing/__tests__/lib/iban.test.ts +38 -0
  392. package/src/modules/billing/__tests__/lib/invoiceDelivery.test.ts +189 -0
  393. package/src/modules/billing/__tests__/lib/invoiceWriter.test.ts +212 -10
  394. package/src/modules/billing/__tests__/lib/itemBillingState.test.ts +42 -0
  395. package/src/modules/billing/__tests__/lib/itemPriceChange.test.ts +165 -0
  396. package/src/modules/billing/__tests__/lib/lineAmounts.test.ts +86 -0
  397. package/src/modules/billing/__tests__/lib/navigation.test.ts +71 -0
  398. package/src/modules/billing/__tests__/lib/numbering.test.ts +91 -0
  399. package/src/modules/billing/__tests__/lib/overdue.test.ts +36 -0
  400. package/src/modules/billing/__tests__/lib/paymentCsv.test.ts +148 -0
  401. package/src/modules/billing/__tests__/lib/paymentImport.test.ts +113 -0
  402. package/src/modules/billing/__tests__/lib/paymentsSample.test.ts +73 -0
  403. package/src/modules/billing/__tests__/lib/pdf/invoicePdf.test.ts +199 -0
  404. package/src/modules/billing/__tests__/lib/pdf/invoicePdfService.test.ts +147 -0
  405. package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +374 -98
  406. package/src/modules/billing/__tests__/lib/prepaidTaxPoint.test.ts +118 -0
  407. package/src/modules/billing/__tests__/lib/seedsDemo.test.ts +53 -2
  408. package/src/modules/billing/__tests__/lib/sellerSettings.test.ts +28 -0
  409. package/src/modules/billing/__tests__/lib/servicePeriods.test.ts +190 -0
  410. package/src/modules/billing/__tests__/lib/topupCapture.test.ts +6 -28
  411. package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +21 -52
  412. package/src/modules/billing/__tests__/lib/vat.test.ts +51 -0
  413. package/src/modules/billing/__tests__/package-isolation.test.ts +22 -8
  414. package/src/modules/billing/__tests__/setup.test.ts +13 -4
  415. package/src/modules/billing/__tests__/validators.test.ts +193 -3
  416. package/src/modules/billing/acl.ts +12 -0
  417. package/src/modules/billing/api/accounts/[id]/summary/route.ts +62 -0
  418. package/src/modules/billing/api/accounts/route.ts +58 -4
  419. package/src/modules/billing/api/export/account/[id]/route.ts +13 -11
  420. package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
  421. package/src/modules/billing/api/invoices/[id]/pdf/route.ts +79 -0
  422. package/src/modules/billing/api/invoices/[id]/route.ts +57 -70
  423. package/src/modules/billing/api/invoices/[id]/send/route.ts +127 -0
  424. package/src/modules/billing/api/invoices/add-line/route.ts +2 -2
  425. package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
  426. package/src/modules/billing/api/invoices/edit-line/route.ts +2 -2
  427. package/src/modules/billing/api/invoices/post/route.ts +7 -6
  428. package/src/modules/billing/api/invoices/remove-line/route.ts +2 -2
  429. package/src/modules/billing/api/invoices/route.ts +81 -86
  430. package/src/modules/billing/api/items/bulk/route.ts +2 -1
  431. package/src/modules/billing/api/items/change-price/route.ts +54 -0
  432. package/src/modules/billing/api/items/route.ts +23 -7
  433. package/src/modules/billing/api/payment-imports/[id]/route.ts +49 -0
  434. package/src/modules/billing/api/payment-imports/route.ts +57 -0
  435. package/src/modules/billing/api/payments/[id]/route.ts +63 -0
  436. package/src/modules/billing/api/payments/allocate/route.ts +35 -0
  437. package/src/modules/billing/api/payments/assign/route.ts +36 -0
  438. package/src/modules/billing/api/payments/convert-to-topup/route.ts +35 -0
  439. package/src/modules/billing/api/payments/ignore/route.ts +35 -0
  440. package/src/modules/billing/api/payments/import/route.ts +72 -0
  441. package/src/modules/billing/api/payments/restore/route.ts +35 -0
  442. package/src/modules/billing/api/payments/route.ts +147 -0
  443. package/src/modules/billing/api/payments/unallocate/route.ts +35 -0
  444. package/src/modules/billing/api/payments/unassign/route.ts +35 -0
  445. package/src/modules/billing/api/run-outcomes/route.ts +49 -6
  446. package/src/modules/billing/api/runs/[id]/post-drafts/route.ts +71 -0
  447. package/src/modules/billing/api/runs/[id]/route.ts +59 -0
  448. package/src/modules/billing/api/runs/retry-failed/route.ts +2 -1
  449. package/src/modules/billing/api/runs/route.ts +15 -7
  450. package/src/modules/billing/api/settings/number-preview/route.ts +46 -0
  451. package/src/modules/billing/api/settings/route.ts +116 -0
  452. package/src/modules/billing/api/statements/route.ts +5 -0
  453. package/src/modules/billing/api/test-invoices/wipe/route.ts +2 -2
  454. package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +151 -372
  455. package/src/modules/billing/backend/billing/accounts/create/page.tsx +6 -0
  456. package/src/modules/billing/backend/billing/accounts/page.tsx +70 -4
  457. package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +444 -95
  458. package/src/modules/billing/backend/billing/invoices/page.tsx +8 -227
  459. package/src/modules/billing/backend/billing/items/[id]/page.tsx +75 -6
  460. package/src/modules/billing/backend/billing/items/create/page.tsx +13 -8
  461. package/src/modules/billing/backend/billing/items/page.tsx +18 -2
  462. package/src/modules/billing/backend/billing/payments/[id]/page.meta.ts +19 -0
  463. package/src/modules/billing/backend/billing/payments/[id]/page.tsx +415 -0
  464. package/src/modules/billing/backend/billing/payments/imports/[id]/page.meta.ts +19 -0
  465. package/src/modules/billing/backend/billing/payments/imports/[id]/page.tsx +106 -0
  466. package/src/modules/billing/backend/billing/payments/page.meta.ts +16 -0
  467. package/src/modules/billing/backend/billing/payments/page.tsx +56 -0
  468. package/src/modules/billing/backend/billing/runs/[id]/page.tsx +49 -18
  469. package/src/modules/billing/backend/billing/runs/page.tsx +59 -8
  470. package/src/modules/billing/backend/billing/statements/[id]/page.tsx +86 -5
  471. package/src/modules/billing/backend/billing/statements/page.tsx +1 -1
  472. package/src/modules/billing/backend/billing/topups/page.tsx +1 -1
  473. package/src/modules/billing/backend/billing/transactions/page.tsx +1 -1
  474. package/src/modules/billing/backend/billing/usage/create/page.tsx +3 -2
  475. package/src/modules/billing/backend/config/billing/page.meta.ts +21 -0
  476. package/src/modules/billing/backend/config/billing/page.tsx +549 -0
  477. package/src/modules/billing/cli.ts +31 -1
  478. package/src/modules/billing/commands/accounts.ts +6 -0
  479. package/src/modules/billing/commands/index.ts +3 -0
  480. package/src/modules/billing/commands/invoices.ts +364 -231
  481. package/src/modules/billing/commands/items.ts +143 -0
  482. package/src/modules/billing/commands/memos.ts +218 -0
  483. package/src/modules/billing/commands/payments.ts +428 -0
  484. package/src/modules/billing/commands/runs.ts +205 -3
  485. package/src/modules/billing/commands/settings.ts +77 -0
  486. package/src/modules/billing/commands/topups.ts +12 -3
  487. package/src/modules/billing/commands/transactions.ts +2 -2
  488. package/src/modules/billing/components/AccountForm.tsx +199 -53
  489. package/src/modules/billing/components/AccountInvoicesSection.tsx +75 -0
  490. package/src/modules/billing/components/AccountPaymentsSection.tsx +42 -0
  491. package/src/modules/billing/components/AccountPicker.tsx +70 -0
  492. package/src/modules/billing/components/AllocatePaymentDialog.tsx +167 -0
  493. package/src/modules/billing/components/BillingDataTable.tsx +34 -0
  494. package/src/modules/billing/components/BillingSettingsLink.tsx +25 -0
  495. package/src/modules/billing/components/ChangeItemPriceDialog.tsx +180 -0
  496. package/src/modules/billing/components/CreateMemoDialog.tsx +232 -0
  497. package/src/modules/billing/components/CustomerLabel.tsx +53 -0
  498. package/src/modules/billing/components/InvoicesTable.tsx +344 -0
  499. package/src/modules/billing/components/ItemForm.tsx +233 -44
  500. package/src/modules/billing/components/ItemPriceField.tsx +81 -0
  501. package/src/modules/billing/components/LineFormDialog.tsx +25 -1
  502. package/src/modules/billing/components/ManualPaymentDialog.tsx +140 -0
  503. package/src/modules/billing/components/MoneyInput.tsx +26 -0
  504. package/src/modules/billing/components/PaymentUploadDialog.tsx +148 -0
  505. package/src/modules/billing/components/PaymentsTable.tsx +213 -0
  506. package/src/modules/billing/components/PostRunDraftsButton.tsx +129 -0
  507. package/src/modules/billing/components/PrepaidPanel.tsx +19 -6
  508. package/src/modules/billing/components/RunCyclesSection.tsx +298 -0
  509. package/src/modules/billing/components/TestRunActions.tsx +152 -0
  510. package/src/modules/billing/components/account/AccountItemsTab.tsx +192 -0
  511. package/src/modules/billing/components/account/AccountRunBillingDialog.tsx +147 -0
  512. package/src/modules/billing/components/account/AccountRunsTab.tsx +201 -0
  513. package/src/modules/billing/components/account/AccountStatementsTab.tsx +120 -0
  514. package/src/modules/billing/components/account/AccountSummaryCards.tsx +153 -0
  515. package/src/modules/billing/components/account/AccountUsageTab.tsx +122 -0
  516. package/src/modules/billing/components/account/AccountView.tsx +101 -0
  517. package/src/modules/billing/components/account/accountRow.ts +70 -0
  518. package/src/modules/billing/components/customerNames.ts +62 -0
  519. package/src/modules/billing/data/entities.ts +654 -5
  520. package/src/modules/billing/data/entityIds.ts +9 -0
  521. package/src/modules/billing/data/validators.ts +388 -8
  522. package/src/modules/billing/events.ts +56 -3
  523. package/src/modules/billing/i18n/en.json +457 -21
  524. package/src/modules/billing/i18n/pl.json +457 -21
  525. package/src/modules/billing/index.ts +6 -2
  526. package/src/modules/billing/lib/accountFinancials.ts +84 -0
  527. package/src/modules/billing/lib/accountLock.ts +32 -0
  528. package/src/modules/billing/lib/accountStatus.ts +11 -9
  529. package/src/modules/billing/lib/accountSummary.ts +172 -0
  530. package/src/modules/billing/lib/allocation.ts +515 -0
  531. package/src/modules/billing/lib/allocationEvents.ts +26 -0
  532. package/src/modules/billing/lib/billPeriod.ts +19 -0
  533. package/src/modules/billing/lib/billRunEngine.ts +350 -150
  534. package/src/modules/billing/lib/billingSettings.ts +145 -0
  535. package/src/modules/billing/lib/commandRoute.ts +112 -0
  536. package/src/modules/billing/lib/customerLookup.ts +157 -0
  537. package/src/modules/billing/lib/dateOnly.ts +22 -0
  538. package/src/modules/billing/lib/documentParties.ts +23 -0
  539. package/src/modules/billing/lib/documentTypes.ts +37 -0
  540. package/src/modules/billing/lib/dueDate.ts +26 -0
  541. package/src/modules/billing/lib/iban.ts +36 -0
  542. package/src/modules/billing/lib/invoiceDelivery.ts +197 -0
  543. package/src/modules/billing/lib/invoiceLanguages.ts +34 -0
  544. package/src/modules/billing/lib/invoiceWriter.ts +162 -148
  545. package/src/modules/billing/lib/itemBillingState.ts +67 -0
  546. package/src/modules/billing/lib/itemPriceChange.ts +56 -0
  547. package/src/modules/billing/lib/itemSelector.ts +4 -1
  548. package/src/modules/billing/lib/lineAmounts.ts +61 -0
  549. package/src/modules/billing/lib/memoGuards.ts +41 -0
  550. package/src/modules/billing/lib/navigation.ts +64 -0
  551. package/src/modules/billing/lib/numbering.ts +174 -0
  552. package/src/modules/billing/lib/overdue.ts +60 -0
  553. package/src/modules/billing/lib/paymentCsv.ts +171 -0
  554. package/src/modules/billing/lib/paymentGateway.ts +52 -0
  555. package/src/modules/billing/lib/paymentImport.ts +228 -0
  556. package/src/modules/billing/lib/paymentMatcher.ts +88 -0
  557. package/src/modules/billing/lib/pdf/attachmentStore.ts +60 -0
  558. package/src/modules/billing/lib/pdf/fonts/NotoSans-Bold.ttf +0 -0
  559. package/src/modules/billing/lib/pdf/fonts/NotoSans-Regular.ttf +0 -0
  560. package/src/modules/billing/lib/pdf/fonts/OFL.txt +93 -0
  561. package/src/modules/billing/lib/pdf/fonts/embeddedFonts.ts +9 -0
  562. package/src/modules/billing/lib/pdf/invoiceModel.ts +328 -0
  563. package/src/modules/billing/lib/pdf/invoicePdf.ts +216 -0
  564. package/src/modules/billing/lib/pdf/invoiceTemplate.ts +338 -0
  565. package/src/modules/billing/lib/prepaidConfig.ts +27 -36
  566. package/src/modules/billing/lib/prepaidConsume.ts +29 -6
  567. package/src/modules/billing/lib/prepaidPeriodClose.ts +407 -239
  568. package/src/modules/billing/lib/prepaidTaxPoint.ts +76 -0
  569. package/src/modules/billing/lib/seeds/demo.ts +79 -6
  570. package/src/modules/billing/lib/seeds/paymentsSample.ts +136 -0
  571. package/src/modules/billing/lib/seeds/sellerSettings.ts +78 -0
  572. package/src/modules/billing/lib/servicePeriods.ts +226 -0
  573. package/src/modules/billing/lib/testRunCleanup.ts +42 -0
  574. package/src/modules/billing/lib/topupCapture.ts +3 -4
  575. package/src/modules/billing/lib/topupReceipt.ts +70 -103
  576. package/src/modules/billing/lib/usageRater.ts +1 -1
  577. package/src/modules/billing/lib/usageRunner.ts +17 -5
  578. package/src/modules/billing/lib/vat.ts +56 -0
  579. package/src/modules/billing/migrations/Migration20261114000000_billing_customer_kind.ts +25 -0
  580. package/src/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.ts +37 -0
  581. package/src/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.ts +132 -0
  582. package/src/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.ts +58 -0
  583. package/src/modules/billing/migrations/Migration20261117000000_billing_payments.ts +97 -0
  584. package/src/modules/billing/migrations/Migration20261118000000_billing_memos.ts +21 -0
  585. package/src/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.ts +39 -0
  586. package/src/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.ts +35 -0
  587. package/src/modules/billing/setup.ts +11 -237
  588. package/src/modules/billing/subscribers/credit-memo-auto-send.ts +15 -0
  589. package/src/modules/billing/subscribers/debit-memo-apply-credit.ts +15 -0
  590. package/src/modules/billing/subscribers/debit-memo-auto-send.ts +15 -0
  591. package/src/modules/billing/subscribers/invoice-apply-credit.ts +39 -0
  592. package/src/modules/billing/subscribers/invoice-auto-send.ts +46 -0
  593. package/src/modules/billing/subscribers/payment-captured-to-paid.ts +84 -62
  594. package/src/modules/billing/subscribers/prepaid-topup-captured.ts +4 -8
  595. package/dist/modules/billing/lib/invoiceStatus.js +0 -38
  596. package/dist/modules/billing/lib/invoiceStatus.js.map +0 -7
  597. package/src/modules/billing/__tests__/lib/invoiceStatus.test.ts +0 -97
  598. package/src/modules/billing/lib/invoiceStatus.ts +0 -61
@@ -1,175 +1,5 @@
1
1
  import { features as billingAclFeatures } from "./acl.js";
2
- import {
3
- Dictionary,
4
- DictionaryEntry
5
- } from "@open-mercato/core/modules/dictionaries/data/entities";
6
- import { ModuleConfig } from "@open-mercato/core/modules/configs/data/entities";
7
- const BILLING_UOM_DICTIONARY_KEY = "billing.uom";
8
- const SALES_INVOICE_STATUS_DICTIONARY_KEY = "sales.invoice_status";
9
- const BILLING_UOM_CODES = [
10
- // time
11
- { value: "hour", label: "Hour" },
12
- { value: "day", label: "Day" },
13
- { value: "week", label: "Week" },
14
- { value: "month", label: "Month" },
15
- // volume
16
- { value: "gb", label: "Gigabyte" },
17
- { value: "tb", label: "Terabyte" },
18
- { value: "mb", label: "Megabyte" },
19
- // requests / tokens
20
- { value: "request", label: "Request" },
21
- { value: "api_request", label: "API Request" },
22
- { value: "token", label: "Token" },
23
- { value: "input_token", label: "Input Token" },
24
- { value: "output_token", label: "Output Token" },
25
- // seats / devices
26
- { value: "seat", label: "Seat" },
27
- { value: "user", label: "User" },
28
- { value: "device", label: "Device" },
29
- { value: "active_user", label: "Active User" }
30
- ];
31
- const INVOICE_STATUS_ENTRIES = [
32
- // `posted` is the canonical "issued" state and is also the default a
33
- // freshly created invoice transitions to — but billing creates drafts,
34
- // so `draft` is the default DictionaryEntry for new rows.
35
- { value: "draft", label: "Draft", isDefault: true, color: "#9ca3af" },
36
- { value: "posted", label: "Posted", isDefault: false, color: "#2563eb" },
37
- { value: "paid", label: "Paid", isDefault: false, color: "#16a34a" },
38
- { value: "void", label: "Void", isDefault: false, color: "#dc2626" }
39
- ];
40
- async function ensureDictionary(em, scope, params) {
41
- const existing = await em.findOne(Dictionary, {
42
- tenantId: scope.tenantId,
43
- organizationId: scope.organizationId,
44
- key: params.key,
45
- deletedAt: null
46
- });
47
- if (existing) return existing;
48
- const dictionary = em.create(Dictionary, {
49
- tenantId: scope.tenantId,
50
- organizationId: scope.organizationId,
51
- key: params.key,
52
- name: params.name,
53
- description: params.description,
54
- isSystem: true,
55
- isActive: true,
56
- managerVisibility: "hidden",
57
- createdAt: /* @__PURE__ */ new Date(),
58
- updatedAt: /* @__PURE__ */ new Date()
59
- });
60
- em.persist(dictionary);
61
- await em.flush();
62
- return dictionary;
63
- }
64
- async function ensureDictionaryEntries(em, scope, dictionary, entries) {
65
- const existing = await em.find(DictionaryEntry, {
66
- dictionary,
67
- tenantId: scope.tenantId,
68
- organizationId: scope.organizationId
69
- });
70
- const existingValues = new Set(existing.map((e) => e.value));
71
- let position = existing.length;
72
- for (const entry of entries) {
73
- if (existingValues.has(entry.value)) continue;
74
- em.persist(
75
- em.create(DictionaryEntry, {
76
- dictionary,
77
- tenantId: scope.tenantId,
78
- organizationId: scope.organizationId,
79
- value: entry.value,
80
- normalizedValue: entry.value.trim().toLowerCase(),
81
- label: entry.label,
82
- color: entry.color ?? null,
83
- position,
84
- isDefault: entry.isDefault ?? false,
85
- createdAt: /* @__PURE__ */ new Date(),
86
- updatedAt: /* @__PURE__ */ new Date()
87
- })
88
- );
89
- position += 1;
90
- }
91
- await em.flush();
92
- }
93
- async function seedBillingUomDictionary(em, scope) {
94
- const dict = await ensureDictionary(em, scope, {
95
- key: BILLING_UOM_DICTIONARY_KEY,
96
- name: "Billing units of measure",
97
- description: "Units billing accepts on usage records (exact match \u2014 no conversion)."
98
- });
99
- await ensureDictionaryEntries(em, scope, dict, BILLING_UOM_CODES);
100
- }
101
- async function seedInvoiceStatusDictionary(em, scope) {
102
- const dict = await ensureDictionary(em, scope, {
103
- key: SALES_INVOICE_STATUS_DICTIONARY_KEY,
104
- name: "Sales invoice statuses",
105
- description: "draft \u2192 posted \u2192 paid (or void). Drives the billing draft/post lifecycle."
106
- });
107
- await ensureDictionaryEntries(em, scope, dict, INVOICE_STATUS_ENTRIES);
108
- }
109
- async function ensureModuleConfig(em, params) {
110
- const existing = await em.findOne(ModuleConfig, {
111
- moduleId: params.moduleId,
112
- name: params.name
113
- });
114
- if (existing) return;
115
- em.persist(
116
- em.create(ModuleConfig, {
117
- moduleId: params.moduleId,
118
- name: params.name,
119
- valueJson: params.value,
120
- createdAt: /* @__PURE__ */ new Date(),
121
- updatedAt: /* @__PURE__ */ new Date()
122
- })
123
- );
124
- await em.flush();
125
- }
126
- async function seedBillingConfigs(em) {
127
- await ensureModuleConfig(em, {
128
- moduleId: "billing",
129
- name: "cron_schedule",
130
- value: "0 2 * * *"
131
- });
132
- await ensureModuleConfig(em, {
133
- moduleId: "billing",
134
- name: "cron_enabled",
135
- value: true
136
- });
137
- await ensureModuleConfig(em, {
138
- moduleId: "billing",
139
- name: "invoice_number.format",
140
- value: "INV-{YYYY}-{0000001}"
141
- });
142
- await ensureModuleConfig(em, {
143
- moduleId: "billing",
144
- name: "invoice_number.reset_cycle",
145
- value: "yearly"
146
- });
147
- await ensureModuleConfig(em, {
148
- moduleId: "billing",
149
- name: "prepaid.low_balance_threshold_default",
150
- value: 0
151
- });
152
- await ensureModuleConfig(em, {
153
- moduleId: "billing",
154
- name: "prepaid.topup_provider",
155
- value: "stripe"
156
- });
157
- await ensureModuleConfig(em, {
158
- moduleId: "billing",
159
- name: "prepaid.statement_enabled",
160
- value: true
161
- });
162
- await ensureModuleConfig(em, {
163
- moduleId: "billing",
164
- name: "prepaid.topup_tax_rate",
165
- value: 0
166
- });
167
- await ensureModuleConfig(em, {
168
- moduleId: "billing",
169
- name: "credit.near_limit_buffer_default",
170
- value: 0
171
- });
172
- }
2
+ import { getBillingSettings } from "./lib/billingSettings.js";
173
3
  const ALL_BILLING_FEATURES = billingAclFeatures.map((f) => f.id);
174
4
  const setup = {
175
5
  defaultRoleFeatures: {
@@ -191,26 +21,19 @@ const setup = {
191
21
  "billing.balance.view",
192
22
  "billing.credit.view",
193
23
  "billing.topup.view",
194
- "billing.statement.view"
24
+ "billing.statement.view",
25
+ "billing.settings.view",
26
+ "billing.payment.view"
195
27
  ],
196
28
  // Narrow scope for external usage-ingestion API keys.
197
29
  billing_usage_writer: ["billing.usage.ingest"]
198
30
  },
199
31
  /**
200
- * Tenant init: per-tenant module configs (cron, invoice number defaults).
201
- * Runs inside `setupInitialTenant()`, always — no `--no-examples` gate.
202
- */
203
- async onTenantCreated({ em }) {
204
- await seedBillingConfigs(em);
205
- },
206
- /**
207
- * Reference data: dictionaries (UoM, invoice statuses). Always runs
208
- * during `mercato init`. Idempotent — re-seed is safe.
32
+ * Reference data: the organization's billing settings row (Spec 0).
33
+ * Always runs during `mercato init`. Idempotent (race-safe upsert).
209
34
  */
210
35
  async seedDefaults({ em, tenantId, organizationId }) {
211
- const scope = { tenantId, organizationId };
212
- await seedBillingUomDictionary(em, scope);
213
- await seedInvoiceStatusDictionary(em, scope);
36
+ await getBillingSettings(em, { tenantId, organizationId });
214
37
  }
215
38
  };
216
39
  var setup_default = setup;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/billing/setup.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { features as billingAclFeatures } from './acl'\nimport {\n Dictionary,\n DictionaryEntry,\n} from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { ModuleConfig } from '@open-mercato/core/modules/configs/data/entities'\n\n/**\n * Billing module setup \u2014 per-tenant defaults at module installation.\n *\n * Idempotency contract:\n * - All seed helpers below check for an existing row before inserting.\n * - Safe to re-run on every `mercato init` and on `auth sync-role-acls`.\n *\n * What this file seeds:\n * - `billing.uom` dictionary with 16 global codes (operators can add more).\n * - `sales.invoice_status` dictionary with `draft` / `posted` / `paid` /\n * `void` so the core/sales Invoice entity's dictionary-driven status\n * workflow has values to point at. (Core/sales does NOT seed these \u2014\n * billing owns them per Phase 0 validation.)\n * - `billing.cron_schedule` + `billing.cron_enabled` module configs.\n * - `billing.invoice_number.format` + `.reset_cycle` configs (per-tenant\n * defaults; the actual atomic numbering uses core/sales'\n * `SalesDocumentSequence` which is created by core/sales' own\n * `onTenantCreated`).\n *\n * Default role-feature grants:\n * - `admin` gets every `billing.*` feature.\n * - `billing_admin` is the day-to-day finance operator.\n * - `billing_finance_user` is read + dry-run (no posting / no real trigger).\n * - `billing_usage_writer` is the narrow scope for external system API keys.\n */\n\nconst BILLING_UOM_DICTIONARY_KEY = 'billing.uom'\nconst SALES_INVOICE_STATUS_DICTIONARY_KEY = 'sales.invoice_status'\n\nconst BILLING_UOM_CODES = [\n // time\n { value: 'hour', label: 'Hour' },\n { value: 'day', label: 'Day' },\n { value: 'week', label: 'Week' },\n { value: 'month', label: 'Month' },\n // volume\n { value: 'gb', label: 'Gigabyte' },\n { value: 'tb', label: 'Terabyte' },\n { value: 'mb', label: 'Megabyte' },\n // requests / tokens\n { value: 'request', label: 'Request' },\n { value: 'api_request', label: 'API Request' },\n { value: 'token', label: 'Token' },\n { value: 'input_token', label: 'Input Token' },\n { value: 'output_token', label: 'Output Token' },\n // seats / devices\n { value: 'seat', label: 'Seat' },\n { value: 'user', label: 'User' },\n { value: 'device', label: 'Device' },\n { value: 'active_user', label: 'Active User' },\n] as const\n\nconst INVOICE_STATUS_ENTRIES = [\n // `posted` is the canonical \"issued\" state and is also the default a\n // freshly created invoice transitions to \u2014 but billing creates drafts,\n // so `draft` is the default DictionaryEntry for new rows.\n { value: 'draft', label: 'Draft', isDefault: true, color: '#9ca3af' },\n { value: 'posted', label: 'Posted', isDefault: false, color: '#2563eb' },\n { value: 'paid', label: 'Paid', isDefault: false, color: '#16a34a' },\n { value: 'void', label: 'Void', isDefault: false, color: '#dc2626' },\n] as const\n\ntype SeedScope = { tenantId: string; organizationId: string }\n\nasync function ensureDictionary(\n em: EntityManager,\n scope: SeedScope,\n params: { key: string; name: string; description: string },\n): Promise<Dictionary> {\n const existing = await em.findOne(Dictionary, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n key: params.key,\n deletedAt: null,\n })\n if (existing) return existing\n const dictionary = em.create(Dictionary, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n key: params.key,\n name: params.name,\n description: params.description,\n isSystem: true,\n isActive: true,\n managerVisibility: 'hidden',\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(dictionary)\n await em.flush()\n return dictionary\n}\n\nasync function ensureDictionaryEntries(\n em: EntityManager,\n scope: SeedScope,\n dictionary: Dictionary,\n entries: ReadonlyArray<{\n value: string\n label: string\n isDefault?: boolean\n color?: string\n }>,\n): Promise<void> {\n const existing = await em.find(DictionaryEntry, {\n dictionary,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n const existingValues = new Set(existing.map((e) => e.value))\n let position = existing.length\n for (const entry of entries) {\n if (existingValues.has(entry.value)) continue\n em.persist(\n em.create(DictionaryEntry, {\n dictionary,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n value: entry.value,\n normalizedValue: entry.value.trim().toLowerCase(),\n label: entry.label,\n color: entry.color ?? null,\n position,\n isDefault: entry.isDefault ?? false,\n createdAt: new Date(),\n updatedAt: new Date(),\n }),\n )\n position += 1\n }\n await em.flush()\n}\n\nasync function seedBillingUomDictionary(em: EntityManager, scope: SeedScope): Promise<void> {\n const dict = await ensureDictionary(em, scope, {\n key: BILLING_UOM_DICTIONARY_KEY,\n name: 'Billing units of measure',\n description: 'Units billing accepts on usage records (exact match \u2014 no conversion).',\n })\n await ensureDictionaryEntries(em, scope, dict, BILLING_UOM_CODES)\n}\n\nasync function seedInvoiceStatusDictionary(em: EntityManager, scope: SeedScope): Promise<void> {\n const dict = await ensureDictionary(em, scope, {\n key: SALES_INVOICE_STATUS_DICTIONARY_KEY,\n name: 'Sales invoice statuses',\n description: 'draft \u2192 posted \u2192 paid (or void). Drives the billing draft/post lifecycle.',\n })\n await ensureDictionaryEntries(em, scope, dict, INVOICE_STATUS_ENTRIES)\n}\n\nasync function ensureModuleConfig(\n em: EntityManager,\n params: { moduleId: string; name: string; value: unknown },\n): Promise<void> {\n const existing = await em.findOne(ModuleConfig, {\n moduleId: params.moduleId,\n name: params.name,\n })\n if (existing) return\n em.persist(\n em.create(ModuleConfig, {\n moduleId: params.moduleId,\n name: params.name,\n valueJson: params.value as Record<string, unknown> | null,\n createdAt: new Date(),\n updatedAt: new Date(),\n }),\n )\n await em.flush()\n}\n\nasync function seedBillingConfigs(em: EntityManager): Promise<void> {\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'cron_schedule',\n value: '0 2 * * *',\n })\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'cron_enabled',\n value: true,\n })\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'invoice_number.format',\n value: 'INV-{YYYY}-{0000001}',\n })\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'invoice_number.reset_cycle',\n value: 'yearly',\n })\n\n // \u2500\u2500\u2500 Prepaid balance billing (SPEC-002) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Fallback low-balance threshold when a prepaid account leaves its own\n // `low_balance_threshold` null. 0 = off (status never flips to `low`\n // until an operator sets a per-account threshold).\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.low_balance_threshold_default',\n value: 0,\n })\n // Default gateway provider key for top-up sessions.\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.topup_provider',\n value: 'stripe',\n })\n // Master switch for period statements.\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.statement_enabled',\n value: true,\n })\n // VAT rate (percent) applied to top-up receipts. The top-up `amount` is\n // treated as GROSS (what the customer pays = what the balance is credited);\n // the core tax service computes net + VAT from this rate. 0 = no VAT until\n // an operator sets the jurisdiction's rate. (Deviation from xd-249, which\n // never resolves a rate \u2014 see CHANGELOG.)\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.topup_tax_rate',\n value: 0,\n })\n // Fallback buffer for the `near_limit` credit status. 0 = warn only at the\n // limit itself.\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'credit.near_limit_buffer_default',\n value: 0,\n })\n}\n\n// Derived from `acl.ts` so a new feature added there automatically lands\n// in every role that should get \"everything billing\" \u2014 no parallel list\n// to keep in sync.\nconst ALL_BILLING_FEATURES = billingAclFeatures.map((f) => f.id)\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n // Org admins get every billing feature \u2014 `billing.*` wildcard is matched\n // by the shared feature matcher (`hasFeature` is wildcard-aware).\n admin: ['billing.*'],\n\n // Day-to-day finance operator persona.\n billing_admin: [...ALL_BILLING_FEATURES],\n\n // Read-only + dry-run preview \u2014 auditor / finance-watcher persona.\n billing_finance_user: [\n 'billing.account.view',\n 'billing.item.view',\n 'billing.usage.view',\n 'billing.run.view',\n 'billing.run.dry_run',\n 'billing.invoice.view',\n // Prepaid read-only (SPEC-002): balances, transactions, top-ups,\n // statements, credit status \u2014 no adjust / no top-up initiation.\n 'billing.balance.view',\n 'billing.credit.view',\n 'billing.topup.view',\n 'billing.statement.view',\n ],\n\n // Narrow scope for external usage-ingestion API keys.\n billing_usage_writer: ['billing.usage.ingest'],\n },\n\n /**\n * Tenant init: per-tenant module configs (cron, invoice number defaults).\n * Runs inside `setupInitialTenant()`, always \u2014 no `--no-examples` gate.\n */\n async onTenantCreated({ em }) {\n await seedBillingConfigs(em)\n },\n\n /**\n * Reference data: dictionaries (UoM, invoice statuses). Always runs\n * during `mercato init`. Idempotent \u2014 re-seed is safe.\n */\n async seedDefaults({ em, tenantId, organizationId }) {\n const scope = { tenantId, organizationId }\n await seedBillingUomDictionary(em, scope)\n await seedInvoiceStatusDictionary(em, scope)\n },\n}\n\nexport default setup\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { features as billingAclFeatures } from './acl'\nimport { getBillingSettings } from './lib/billingSettings'\n\n/**\n * Billing module setup \u2014 per-tenant defaults at module installation.\n *\n * Idempotency contract:\n * - All seed helpers below check for an existing row before inserting.\n * - Safe to re-run on every `mercato init` and on `auth sync-role-acls`.\n *\n * What this file seeds (Spec 0 \u2014 no core `configs` / `dictionaries` /\n * `sales` rows any more):\n * - one `billing_settings` row per organization with the defaults\n * (prepaid defaults + number masks). `getBillingSettings` also creates\n * it lazily, so this is only a warm-up.\n *\n * Default role-feature grants:\n * - `admin` gets every `billing.*` feature.\n * - `billing_admin` is the day-to-day finance operator.\n * - `billing_finance_user` is read + dry-run (no posting / no real trigger).\n * - `billing_usage_writer` is the narrow scope for external system API keys.\n */\n\n// Derived from `acl.ts` so a new feature added there automatically lands\n// in every role that should get \"everything billing\" \u2014 no parallel list\n// to keep in sync.\nconst ALL_BILLING_FEATURES = billingAclFeatures.map((f) => f.id)\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n // Org admins get every billing feature \u2014 `billing.*` wildcard is matched\n // by the shared feature matcher (`hasFeature` is wildcard-aware).\n admin: ['billing.*'],\n\n // Day-to-day finance operator persona.\n billing_admin: [...ALL_BILLING_FEATURES],\n\n // Read-only + dry-run preview \u2014 auditor / finance-watcher persona.\n billing_finance_user: [\n 'billing.account.view',\n 'billing.item.view',\n 'billing.usage.view',\n 'billing.run.view',\n 'billing.run.dry_run',\n 'billing.invoice.view',\n // Prepaid read-only (SPEC-002): balances, transactions, top-ups,\n // statements, credit status \u2014 no adjust / no top-up initiation.\n 'billing.balance.view',\n 'billing.credit.view',\n 'billing.topup.view',\n 'billing.statement.view',\n 'billing.settings.view',\n 'billing.payment.view',\n ],\n\n // Narrow scope for external usage-ingestion API keys.\n billing_usage_writer: ['billing.usage.ingest'],\n },\n\n /**\n * Reference data: the organization's billing settings row (Spec 0).\n * Always runs during `mercato init`. Idempotent (race-safe upsert).\n */\n async seedDefaults({ em, tenantId, organizationId }) {\n await getBillingSettings(em as EntityManager, { tenantId, organizationId })\n },\n}\n\nexport default setup\n"],
5
+ "mappings": "AAEA,SAAS,YAAY,0BAA0B;AAC/C,SAAS,0BAA0B;AAyBnC,MAAM,uBAAuB,mBAAmB,IAAI,CAAC,MAAM,EAAE,EAAE;AAExD,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA;AAAA;AAAA,IAGnB,OAAO,CAAC,WAAW;AAAA;AAAA,IAGnB,eAAe,CAAC,GAAG,oBAAoB;AAAA;AAAA,IAGvC,sBAAsB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,sBAAsB,CAAC,sBAAsB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,EAAE,IAAI,UAAU,eAAe,GAAG;AACnD,UAAM,mBAAmB,IAAqB,EAAE,UAAU,eAAe,CAAC;AAAA,EAC5E;AACF;AAEA,IAAO,gBAAQ;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,16 @@
1
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
+ import { autoSendInvoice } from "./invoice-auto-send.js";
3
+ const metadata = {
4
+ event: "billing.credit_memo.posted",
5
+ persistent: true,
6
+ id: "billing-credit-memo-auto-send"
7
+ };
8
+ async function handle(payload) {
9
+ const container = await createRequestContainer();
10
+ await autoSendInvoice(container.resolve("em").fork(), payload);
11
+ }
12
+ export {
13
+ handle as default,
14
+ metadata
15
+ };
16
+ //# sourceMappingURL=credit-memo-auto-send.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/billing/subscribers/credit-memo-auto-send.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { autoSendInvoice } from './invoice-auto-send'\n\n/** Auto-send of posted credit memos for accounts with `auto_send_invoice` (Spec D, P-D9). */\nexport const metadata = {\n event: 'billing.credit_memo.posted',\n persistent: true,\n id: 'billing-credit-memo-auto-send',\n}\n\nexport default async function handle(payload: { invoiceId?: string; tenantId?: string; organizationId?: string }): Promise<void> {\n const container = await createRequestContainer()\n await autoSendInvoice((container.resolve('em') as EntityManager).fork(), payload)\n}\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAGzB,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,OAA8B,SAA4F;AAC/H,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,gBAAiB,UAAU,QAAQ,IAAI,EAAoB,KAAK,GAAG,OAAO;AAClF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { applyCreditForAccount } from "./invoice-apply-credit.js";
2
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
3
+ const metadata = {
4
+ event: "billing.debit_memo.posted",
5
+ persistent: true,
6
+ id: "billing-debit-memo-apply-credit"
7
+ };
8
+ async function handle(payload) {
9
+ const container = await createRequestContainer();
10
+ await applyCreditForAccount(container.resolve("em").fork(), payload);
11
+ }
12
+ export {
13
+ handle as default,
14
+ metadata
15
+ };
16
+ //# sourceMappingURL=debit-memo-apply-credit.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/billing/subscribers/debit-memo-apply-credit.ts"],
4
+ "sourcesContent": ["import { applyCreditForAccount, type PostedPayload } from './invoice-apply-credit'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\n\n/** Credit auto-apply when a debit memo is posted (Spec D, P-D6) \u2014 same handler as for invoices. */\nexport const metadata = {\n event: 'billing.debit_memo.posted',\n persistent: true,\n id: 'billing-debit-memo-apply-credit',\n}\n\nexport default async function handle(payload: PostedPayload): Promise<void> {\n const container = await createRequestContainer()\n await applyCreditForAccount((container.resolve('em') as EntityManager).fork(), payload)\n}\n"],
5
+ "mappings": "AAAA,SAAS,6BAAiD;AAC1D,SAAS,8BAA8B;AAIhC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,OAA8B,SAAuC;AAC1E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,sBAAuB,UAAU,QAAQ,IAAI,EAAoB,KAAK,GAAG,OAAO;AACxF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
+ import { autoSendInvoice } from "./invoice-auto-send.js";
3
+ const metadata = {
4
+ event: "billing.debit_memo.posted",
5
+ persistent: true,
6
+ id: "billing-debit-memo-auto-send"
7
+ };
8
+ async function handle(payload) {
9
+ const container = await createRequestContainer();
10
+ await autoSendInvoice(container.resolve("em").fork(), payload);
11
+ }
12
+ export {
13
+ handle as default,
14
+ metadata
15
+ };
16
+ //# sourceMappingURL=debit-memo-auto-send.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/billing/subscribers/debit-memo-auto-send.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { autoSendInvoice } from './invoice-auto-send'\n\n/** Auto-send of posted debit memos for accounts with `auto_send_invoice` (Spec D, P-D9). */\nexport const metadata = {\n event: 'billing.debit_memo.posted',\n persistent: true,\n id: 'billing-debit-memo-auto-send',\n}\n\nexport default async function handle(payload: { invoiceId?: string; tenantId?: string; organizationId?: string }): Promise<void> {\n const container = await createRequestContainer()\n await autoSendInvoice((container.resolve('em') as EntityManager).fork(), payload)\n}\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAGzB,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,OAA8B,SAA4F;AAC/H,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,gBAAiB,UAAU,QAAQ,IAAI,EAAoB,KAAK,GAAG,OAAO;AAClF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,34 @@
1
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
+ import { BillingAccount } from "../data/entities.js";
3
+ import { withAccountLock } from "../lib/accountLock.js";
4
+ import { applyAccountCredit } from "../lib/allocation.js";
5
+ import { emitAllocationEffects } from "../lib/allocationEvents.js";
6
+ const metadata = {
7
+ event: "billing.invoice.posted",
8
+ persistent: true,
9
+ id: "billing-invoice-apply-credit"
10
+ };
11
+ async function applyCreditForAccount(em, payload) {
12
+ if (!payload?.billAccountId || !payload.tenantId || !payload.organizationId) return 0;
13
+ const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId };
14
+ const account = await em.findOne(BillingAccount, { id: payload.billAccountId, ...scope });
15
+ if (!account || account.billingMode === "prepaid") return 0;
16
+ const effects = await withAccountLock(
17
+ em,
18
+ { tenantId: scope.tenantId, billAccountId: account.id },
19
+ (tem) => applyAccountCredit(tem, scope, { id: account.id, currencyCode: account.currencyCode })
20
+ );
21
+ await emitAllocationEffects(scope, effects);
22
+ return effects.created.length;
23
+ }
24
+ async function handle(payload) {
25
+ const container = await createRequestContainer();
26
+ const em = container.resolve("em").fork();
27
+ await applyCreditForAccount(em, payload);
28
+ }
29
+ export {
30
+ applyCreditForAccount,
31
+ handle as default,
32
+ metadata
33
+ };
34
+ //# sourceMappingURL=invoice-apply-credit.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/billing/subscribers/invoice-apply-credit.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { BillingAccount } from '../data/entities'\nimport { withAccountLock } from '../lib/accountLock'\nimport { applyAccountCredit } from '../lib/allocation'\nimport { emitAllocationEffects } from '../lib/allocationEvents'\n\n/**\n * Credit auto-apply on post (Spec C, D12): when an invoice is posted, any\n * unapplied credit of its account (overpayments, unallocated payments,\n * open credit memos) is spent on the account's open receivables, oldest due\n * date first. Persistent and safe to re-run (it only spends what is left).\n */\n\nexport const metadata = {\n event: 'billing.invoice.posted',\n persistent: true,\n id: 'billing-invoice-apply-credit',\n}\n\nexport type PostedPayload = { billAccountId?: string; tenantId?: string; organizationId?: string }\n\nexport async function applyCreditForAccount(em: EntityManager, payload: PostedPayload): Promise<number> {\n if (!payload?.billAccountId || !payload.tenantId || !payload.organizationId) return 0\n const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const account = await em.findOne(BillingAccount, { id: payload.billAccountId, ...scope } as never)\n if (!account || account.billingMode === 'prepaid') return 0\n const effects = await withAccountLock(em, { tenantId: scope.tenantId, billAccountId: account.id }, (tem) =>\n applyAccountCredit(tem, scope, { id: account.id, currencyCode: account.currencyCode }),\n )\n await emitAllocationEffects(scope, effects)\n return effects.created.length\n}\n\nexport default async function handle(payload: PostedPayload): Promise<void> {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await applyCreditForAccount(em, payload)\n}\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AAS/B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAIA,eAAsB,sBAAsB,IAAmB,SAAyC;AACtG,MAAI,CAAC,SAAS,iBAAiB,CAAC,QAAQ,YAAY,CAAC,QAAQ,eAAgB,QAAO;AACpF,QAAM,QAAQ,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AACnF,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,eAAe,GAAG,MAAM,CAAU;AACjG,MAAI,CAAC,WAAW,QAAQ,gBAAgB,UAAW,QAAO;AAC1D,QAAM,UAAU,MAAM;AAAA,IAAgB;AAAA,IAAI,EAAE,UAAU,MAAM,UAAU,eAAe,QAAQ,GAAG;AAAA,IAAG,CAAC,QAClG,mBAAmB,KAAK,OAAO,EAAE,IAAI,QAAQ,IAAI,cAAc,QAAQ,aAAa,CAAC;AAAA,EACvF;AACA,QAAM,sBAAsB,OAAO,OAAO;AAC1C,SAAO,QAAQ,QAAQ;AACzB;AAEA,eAAO,OAA8B,SAAuC;AAC1E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,sBAAsB,IAAI,OAAO;AACzC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,30 @@
1
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
+ import { BillingAccount, BillingInvoice } from "../data/entities.js";
3
+ import { hasSuccessfulDelivery, isDeliverableEmail, sendInvoice } from "../lib/invoiceDelivery.js";
4
+ const metadata = {
5
+ event: "billing.invoice.posted",
6
+ persistent: true,
7
+ id: "billing-invoice-auto-send"
8
+ };
9
+ async function autoSendInvoice(em, payload, deps = {}) {
10
+ if (!payload?.invoiceId || !payload.tenantId || !payload.organizationId) return "skipped";
11
+ const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId };
12
+ const invoice = await em.findOne(BillingInvoice, { id: payload.invoiceId, ...scope, deletedAt: null });
13
+ if (!invoice || invoice.testRun || invoice.status === "draft" || invoice.documentType === "receipt") return "skipped";
14
+ if (hasSuccessfulDelivery(invoice, "auto")) return "skipped";
15
+ const account = await em.findOne(BillingAccount, { id: invoice.billAccountId, ...scope });
16
+ if (!account?.autoSendInvoice || !isDeliverableEmail(account.invoiceEmail)) return "skipped";
17
+ const result = await sendInvoice(em, { invoiceId: invoice.id, ...scope, trigger: "auto" }, deps);
18
+ return result.status;
19
+ }
20
+ async function handle(payload) {
21
+ const container = await createRequestContainer();
22
+ const em = container.resolve("em").fork();
23
+ await autoSendInvoice(em, payload);
24
+ }
25
+ export {
26
+ autoSendInvoice,
27
+ handle as default,
28
+ metadata
29
+ };
30
+ //# sourceMappingURL=invoice-auto-send.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/billing/subscribers/invoice-auto-send.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { BillingAccount, BillingInvoice } from '../data/entities'\nimport { hasSuccessfulDelivery, isDeliverableEmail, sendInvoice, type SendInvoiceDeps } from '../lib/invoiceDelivery'\n\n/**\n * Auto-send (Spec B): `billing.invoice.posted` \u2192 email the document when the\n * account has `auto_send_invoice` on.\n *\n * Persistent and idempotent: a redelivered event finds a `sent` auto\n * delivery in `metadata.deliveries` and does nothing. Receipts, test\n * documents and accounts with a placeholder / missing email are skipped\n * without a delivery entry (the operator can still send manually once the\n * address is fixed). A transport failure is recorded as a `failed`\n * delivery by `sendInvoice` and not retried automatically.\n */\n\nexport const metadata = {\n event: 'billing.invoice.posted',\n persistent: true,\n id: 'billing-invoice-auto-send',\n}\n\ntype PostedPayload = {\n invoiceId?: string\n tenantId?: string\n organizationId?: string\n}\n\nexport async function autoSendInvoice(em: EntityManager, payload: PostedPayload, deps: SendInvoiceDeps = {}): Promise<'sent' | 'failed' | 'skipped'> {\n if (!payload?.invoiceId || !payload.tenantId || !payload.organizationId) return 'skipped'\n const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const invoice = await em.findOne(BillingInvoice, { id: payload.invoiceId, ...scope, deletedAt: null } as never)\n if (!invoice || invoice.testRun || invoice.status === 'draft' || invoice.documentType === 'receipt') return 'skipped'\n if (hasSuccessfulDelivery(invoice, 'auto')) return 'skipped'\n const account = await em.findOne(BillingAccount, { id: invoice.billAccountId, ...scope } as never)\n if (!account?.autoSendInvoice || !isDeliverableEmail(account.invoiceEmail)) return 'skipped'\n const result = await sendInvoice(em, { invoiceId: invoice.id, ...scope, trigger: 'auto' }, deps)\n return result.status\n}\n\nexport default async function handle(payload: PostedPayload): Promise<void> {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await autoSendInvoice(em, payload)\n}\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,uBAAuB,oBAAoB,mBAAyC;AActF,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAQA,eAAsB,gBAAgB,IAAmB,SAAwB,OAAwB,CAAC,GAA2C;AACnJ,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,YAAY,CAAC,QAAQ,eAAgB,QAAO;AAChF,QAAM,QAAQ,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AACnF,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,WAAW,GAAG,OAAO,WAAW,KAAK,CAAU;AAC9G,MAAI,CAAC,WAAW,QAAQ,WAAW,QAAQ,WAAW,WAAW,QAAQ,iBAAiB,UAAW,QAAO;AAC5G,MAAI,sBAAsB,SAAS,MAAM,EAAG,QAAO;AACnD,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,eAAe,GAAG,MAAM,CAAU;AACjG,MAAI,CAAC,SAAS,mBAAmB,CAAC,mBAAmB,QAAQ,YAAY,EAAG,QAAO;AACnF,QAAM,SAAS,MAAM,YAAY,IAAI,EAAE,WAAW,QAAQ,IAAI,GAAG,OAAO,SAAS,OAAO,GAAG,IAAI;AAC/F,SAAO,OAAO;AAChB;AAEA,eAAO,OAA8B,SAAuC;AAC1E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,gBAAgB,IAAI,OAAO;AACnC;",
6
+ "names": []
7
+ }
@@ -1,47 +1,83 @@
1
1
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
- import { SalesInvoice } from "@open-mercato/core/modules/sales/data/entities";
3
- import { resolveInvoiceStatusEntryId } from "../lib/invoiceStatus.js";
2
+ import { BillingInvoice, BillingPayment } from "../data/entities.js";
3
+ import { withAccountLock } from "../lib/accountLock.js";
4
+ import { allocate, applyAccountCredit, emptyEffects, mergeEffects, toCents } from "../lib/allocation.js";
5
+ import { emitAllocationEffects } from "../lib/allocationEvents.js";
6
+ import { emitBillingEvent } from "../events.js";
4
7
  const metadata = {
5
8
  event: "payment_gateways.payment.captured",
6
9
  persistent: true,
7
10
  id: "billing-payment-captured-to-paid"
8
11
  };
9
- async function handle(payload) {
10
- if (!payload?.paymentId || !payload.tenantId || !payload.organizationId) {
11
- return;
12
- }
13
- const container = await createRequestContainer();
14
- const em = container.resolve("em").fork();
15
- const invoice = await em.findOne(SalesInvoice, {
16
- id: payload.paymentId,
17
- tenantId: payload.tenantId,
18
- organizationId: payload.organizationId,
19
- deletedAt: null
12
+ async function recordGatewayCapture(em, payload) {
13
+ if (!payload?.paymentId || !payload.tenantId || !payload.organizationId) return "skipped";
14
+ const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId };
15
+ const invoice = await em.findOne(BillingInvoice, { id: payload.paymentId, ...scope, deletedAt: null });
16
+ if (!invoice || invoice.testRun || !["invoice", "debit_memo"].includes(invoice.documentType)) return "skipped";
17
+ const externalRef = payload.transactionId ?? payload.paymentId;
18
+ const existing = await em.findOne(BillingPayment, { ...scope, externalRef });
19
+ if (existing) return "duplicate";
20
+ if (!["posted", "partially_paid"].includes(invoice.status)) return "skipped";
21
+ const captured = toCents(payload.amount ?? invoice.outstanding);
22
+ if (captured <= 0) return "skipped";
23
+ const amount = (captured / 100).toFixed(4);
24
+ const now = /* @__PURE__ */ new Date();
25
+ const payment = em.create(BillingPayment, {
26
+ ...scope,
27
+ receivedAt: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())),
28
+ amount,
29
+ currencyCode: (payload.currencyCode ?? invoice.currencyCode).toUpperCase(),
30
+ reference: invoice.number,
31
+ source: "gateway",
32
+ billAccountId: invoice.billAccountId,
33
+ status: "matched",
34
+ unallocatedAmount: amount,
35
+ sourceRef: `gateway:${externalRef}`,
36
+ externalRef,
37
+ metadata: { provider_key: payload.providerKey ?? null },
38
+ createdAt: now,
39
+ updatedAt: now
20
40
  });
21
- if (!invoice) {
22
- return;
23
- }
24
- if (invoice.status === "paid") {
25
- return;
26
- }
27
- if (invoice.status !== "posted") {
28
- return;
29
- }
30
- const paidStatusEntryId = await resolveInvoiceStatusEntryId(
41
+ em.persist(payment);
42
+ await em.flush();
43
+ const effects = await withAccountLock(
31
44
  em,
32
- payload.tenantId,
33
- payload.organizationId,
34
- "paid"
45
+ { tenantId: scope.tenantId, billAccountId: invoice.billAccountId },
46
+ async (tem) => {
47
+ const all = emptyEffects();
48
+ const take = Math.min(captured, toCents(invoice.outstanding));
49
+ if (take > 0 && payment.currencyCode === invoice.currencyCode) {
50
+ mergeEffects(
51
+ all,
52
+ await allocate(tem, scope, {
53
+ source: { type: "payment", id: payment.id },
54
+ invoiceId: invoice.id,
55
+ amountCents: take,
56
+ by: "gateway"
57
+ })
58
+ );
59
+ }
60
+ mergeEffects(
61
+ all,
62
+ await applyAccountCredit(tem, scope, { id: invoice.billAccountId, currencyCode: payment.currencyCode }, {
63
+ onlySources: [{ type: "payment", id: payment.id }]
64
+ })
65
+ );
66
+ return all;
67
+ }
35
68
  );
36
- invoice.status = "paid";
37
- invoice.statusEntryId = paidStatusEntryId;
38
- invoice.paidTotalAmount = invoice.grandTotalGrossAmount;
39
- invoice.outstandingAmount = "0";
40
- invoice.updatedAt = /* @__PURE__ */ new Date();
41
- await em.flush();
69
+ await emitBillingEvent("billing.payment.created", { ...scope, paymentId: payment.id, source: "gateway" });
70
+ await emitAllocationEffects(scope, effects);
71
+ return "recorded";
72
+ }
73
+ async function handle(payload) {
74
+ const container = await createRequestContainer();
75
+ const em = container.resolve("em").fork();
76
+ await recordGatewayCapture(em, payload);
42
77
  }
43
78
  export {
44
79
  handle as default,
45
- metadata
80
+ metadata,
81
+ recordGatewayCapture
46
82
  };
47
83
  //# sourceMappingURL=payment-captured-to-paid.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/billing/subscribers/payment-captured-to-paid.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SalesInvoice } from '@open-mercato/core/modules/sales/data/entities'\nimport { resolveInvoiceStatusEntryId } from '../lib/invoiceStatus'\n\n/**\n * Subscriber: payment captured \u2192 billing invoice paid.\n *\n * Spec wishlist was `payments.payment.completed` carrying `invoice_id`.\n * The actual upstream event is `payment_gateways.payment.captured` and\n * its payload carries `paymentId` \u2014 set by whoever created the payment\n * session. Billing flows that drive their own payment sessions can\n * pass `paymentId = invoice.id`; the subscriber matches on that.\n *\n * Behaviour:\n * 1. Try to find a `core/sales` invoice with `id = payload.paymentId`\n * scoped to the same tenant/organization.\n * 2. If found AND its `status == 'posted'`, flip it to `'paid'`\n * (resolves the `paid` `DictionaryEntry`, updates `status` +\n * `status_entry_id`). Drafts and already-paid / voided invoices\n * are left untouched.\n * 3. If `paymentId` does not point at a billing-known invoice (e.g.\n * the payment was for a `sales.order`), the subscriber is a\n * no-op \u2014 every other module's own subscriber owns its slice.\n *\n * Cross-tenant safety: we always re-scope by `tenantId` +\n * `organizationId` from the event payload. A malformed payload (e.g.\n * missing scope fields) short-circuits without touching the DB.\n *\n * Idempotency: re-firing the same captured event finds the invoice\n * already paid and skips silently.\n */\n\nexport const metadata = {\n event: 'payment_gateways.payment.captured',\n persistent: true,\n id: 'billing-payment-captured-to-paid',\n}\n\ntype CapturedPayload = {\n paymentId?: string\n transactionId?: string\n organizationId?: string\n tenantId?: string\n providerKey?: string\n}\n\nexport default async function handle(payload: CapturedPayload): Promise<void> {\n if (!payload?.paymentId || !payload.tenantId || !payload.organizationId) {\n return\n }\n\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n\n const invoice = await em.findOne(SalesInvoice, {\n id: payload.paymentId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId,\n deletedAt: null,\n })\n if (!invoice) {\n // The captured payment isn't for a billing invoice \u2014 silent\n // no-op. Other subscribers (sales, checkout) handle their slice.\n return\n }\n if (invoice.status === 'paid') {\n // Already paid \u2014 idempotent re-firing.\n return\n }\n if (invoice.status !== 'posted') {\n // A captured payment for a draft / void invoice is suspicious but\n // not actionable here. Future iteration: log to audit_logs.\n return\n }\n\n const paidStatusEntryId = await resolveInvoiceStatusEntryId(\n em,\n payload.tenantId,\n payload.organizationId,\n 'paid',\n )\n invoice.status = 'paid'\n invoice.statusEntryId = paidStatusEntryId\n invoice.paidTotalAmount = invoice.grandTotalGrossAmount\n invoice.outstandingAmount = '0'\n invoice.updatedAt = new Date()\n await em.flush()\n}\n"],
5
- "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,oBAAoB;AAC7B,SAAS,mCAAmC;AA8BrC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAUA,eAAO,OAA8B,SAAyC;AAC5E,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,YAAY,CAAC,QAAQ,gBAAgB;AACvE;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAE3D,QAAM,UAAU,MAAM,GAAG,QAAQ,cAAc;AAAA,IAC7C,IAAI,QAAQ;AAAA,IACZ,UAAU,QAAQ;AAAA,IAClB,gBAAgB,QAAQ;AAAA,IACxB,WAAW;AAAA,EACb,CAAC;AACD,MAAI,CAAC,SAAS;AAGZ;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,QAAQ;AAE7B;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,UAAU;AAG/B;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAM;AAAA,IAC9B;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,EACF;AACA,UAAQ,SAAS;AACjB,UAAQ,gBAAgB;AACxB,UAAQ,kBAAkB,QAAQ;AAClC,UAAQ,oBAAoB;AAC5B,UAAQ,YAAY,oBAAI,KAAK;AAC7B,QAAM,GAAG,MAAM;AACjB;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { BillingInvoice, BillingPayment } from '../data/entities'\nimport { withAccountLock } from '../lib/accountLock'\nimport { allocate, applyAccountCredit, emptyEffects, mergeEffects, toCents, type AllocationEffects } from '../lib/allocation'\nimport { emitAllocationEffects } from '../lib/allocationEvents'\nimport { emitBillingEvent } from '../events'\n\n/**\n * Subscriber: gateway payment captured \u2192 billing payment + allocation\n * (Spec C, P-D9 \u2014 the single code path to \"paid\").\n *\n * The payment session is created with `paymentId = invoice.id`, so the\n * captured event identifies the billing invoice. Instead of flipping the\n * invoice status, the capture becomes a `BillingPayment` (`source =\n * gateway`, `external_ref = transactionId ?? paymentId`) allocated to that\n * invoice through the allocation service; any remainder is account credit.\n *\n * Idempotent: a re-delivered event finds the payment by `external_ref` and\n * does nothing. Payments for anything that is not an open billing\n * receivable are ignored (other modules own them).\n */\n\nexport const metadata = {\n event: 'payment_gateways.payment.captured',\n persistent: true,\n id: 'billing-payment-captured-to-paid',\n}\n\nexport type CapturedPayload = {\n paymentId?: string\n transactionId?: string\n organizationId?: string\n tenantId?: string\n providerKey?: string\n amount?: number | string\n currencyCode?: string\n}\n\nexport async function recordGatewayCapture(\n em: EntityManager,\n payload: CapturedPayload,\n): Promise<'recorded' | 'duplicate' | 'skipped'> {\n if (!payload?.paymentId || !payload.tenantId || !payload.organizationId) return 'skipped'\n const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const invoice = await em.findOne(BillingInvoice, { id: payload.paymentId, ...scope, deletedAt: null } as never)\n if (!invoice || invoice.testRun || !['invoice', 'debit_memo'].includes(invoice.documentType)) return 'skipped'\n const externalRef = payload.transactionId ?? payload.paymentId\n const existing = await em.findOne(BillingPayment, { ...scope, externalRef } as never)\n if (existing) return 'duplicate'\n if (!['posted', 'partially_paid'].includes(invoice.status)) return 'skipped'\n\n const captured = toCents(payload.amount ?? invoice.outstanding)\n if (captured <= 0) return 'skipped'\n const amount = (captured / 100).toFixed(4)\n const now = new Date()\n const payment = em.create(BillingPayment, {\n ...scope,\n receivedAt: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())),\n amount,\n currencyCode: (payload.currencyCode ?? invoice.currencyCode).toUpperCase(),\n reference: invoice.number,\n source: 'gateway',\n billAccountId: invoice.billAccountId,\n status: 'matched',\n unallocatedAmount: amount,\n sourceRef: `gateway:${externalRef}`,\n externalRef,\n metadata: { provider_key: payload.providerKey ?? null },\n createdAt: now,\n updatedAt: now,\n })\n em.persist(payment)\n await em.flush()\n\n const effects: AllocationEffects = await withAccountLock(\n em,\n { tenantId: scope.tenantId, billAccountId: invoice.billAccountId },\n async (tem) => {\n const all = emptyEffects()\n const take = Math.min(captured, toCents(invoice.outstanding))\n if (take > 0 && payment.currencyCode === invoice.currencyCode) {\n mergeEffects(\n all,\n await allocate(tem, scope, {\n source: { type: 'payment', id: payment.id },\n invoiceId: invoice.id,\n amountCents: take,\n by: 'gateway',\n }),\n )\n }\n mergeEffects(\n all,\n await applyAccountCredit(tem, scope, { id: invoice.billAccountId, currencyCode: payment.currencyCode }, {\n onlySources: [{ type: 'payment', id: payment.id }],\n }),\n )\n return all\n },\n )\n await emitBillingEvent('billing.payment.created', { ...scope, paymentId: payment.id, source: 'gateway' })\n await emitAllocationEffects(scope, effects)\n return 'recorded'\n}\n\nexport default async function handle(payload: CapturedPayload): Promise<void> {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await recordGatewayCapture(em, payload)\n}\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,uBAAuB;AAChC,SAAS,UAAU,oBAAoB,cAAc,cAAc,eAAuC;AAC1G,SAAS,6BAA6B;AACtC,SAAS,wBAAwB;AAiB1B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAYA,eAAsB,qBACpB,IACA,SAC+C;AAC/C,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,YAAY,CAAC,QAAQ,eAAgB,QAAO;AAChF,QAAM,QAAQ,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AACnF,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,WAAW,GAAG,OAAO,WAAW,KAAK,CAAU;AAC9G,MAAI,CAAC,WAAW,QAAQ,WAAW,CAAC,CAAC,WAAW,YAAY,EAAE,SAAS,QAAQ,YAAY,EAAG,QAAO;AACrG,QAAM,cAAc,QAAQ,iBAAiB,QAAQ;AACrD,QAAM,WAAW,MAAM,GAAG,QAAQ,gBAAgB,EAAE,GAAG,OAAO,YAAY,CAAU;AACpF,MAAI,SAAU,QAAO;AACrB,MAAI,CAAC,CAAC,UAAU,gBAAgB,EAAE,SAAS,QAAQ,MAAM,EAAG,QAAO;AAEnE,QAAM,WAAW,QAAQ,QAAQ,UAAU,QAAQ,WAAW;AAC9D,MAAI,YAAY,EAAG,QAAO;AAC1B,QAAM,UAAU,WAAW,KAAK,QAAQ,CAAC;AACzC,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,UAAU,GAAG,OAAO,gBAAgB;AAAA,IACxC,GAAG;AAAA,IACH,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,GAAG,IAAI,WAAW,CAAC,CAAC;AAAA,IACxF;AAAA,IACA,eAAe,QAAQ,gBAAgB,QAAQ,cAAc,YAAY;AAAA,IACzE,WAAW,QAAQ;AAAA,IACnB,QAAQ;AAAA,IACR,eAAe,QAAQ;AAAA,IACvB,QAAQ;AAAA,IACR,mBAAmB;AAAA,IACnB,WAAW,WAAW,WAAW;AAAA,IACjC;AAAA,IACA,UAAU,EAAE,cAAc,QAAQ,eAAe,KAAK;AAAA,IACtD,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AACD,KAAG,QAAQ,OAAO;AAClB,QAAM,GAAG,MAAM;AAEf,QAAM,UAA6B,MAAM;AAAA,IACvC;AAAA,IACA,EAAE,UAAU,MAAM,UAAU,eAAe,QAAQ,cAAc;AAAA,IACjE,OAAO,QAAQ;AACb,YAAM,MAAM,aAAa;AACzB,YAAM,OAAO,KAAK,IAAI,UAAU,QAAQ,QAAQ,WAAW,CAAC;AAC5D,UAAI,OAAO,KAAK,QAAQ,iBAAiB,QAAQ,cAAc;AAC7D;AAAA,UACE;AAAA,UACA,MAAM,SAAS,KAAK,OAAO;AAAA,YACzB,QAAQ,EAAE,MAAM,WAAW,IAAI,QAAQ,GAAG;AAAA,YAC1C,WAAW,QAAQ;AAAA,YACnB,aAAa;AAAA,YACb,IAAI;AAAA,UACN,CAAC;AAAA,QACH;AAAA,MACF;AACA;AAAA,QACE;AAAA,QACA,MAAM,mBAAmB,KAAK,OAAO,EAAE,IAAI,QAAQ,eAAe,cAAc,QAAQ,aAAa,GAAG;AAAA,UACtG,aAAa,CAAC,EAAE,MAAM,WAAW,IAAI,QAAQ,GAAG,CAAC;AAAA,QACnD,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,iBAAiB,2BAA2B,EAAE,GAAG,OAAO,WAAW,QAAQ,IAAI,QAAQ,UAAU,CAAC;AACxG,QAAM,sBAAsB,OAAO,OAAO;AAC1C,SAAO;AACT;AAEA,eAAO,OAA8B,SAAyC;AAC5E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,qBAAqB,IAAI,OAAO;AACxC;",
6
6
  "names": []
7
7
  }
@@ -35,14 +35,12 @@ async function handle(payload) {
35
35
  if (!account) {
36
36
  return;
37
37
  }
38
- const taxRate = await getTopupTaxRate(em);
39
- const numberGenerator = container.resolve(
40
- "salesDocumentNumberGenerator"
41
- );
42
- const taxService = container.resolve("taxCalculationService");
38
+ const taxRate = await getTopupTaxRate(em, {
39
+ tenantId: account.tenantId,
40
+ organizationId: account.organizationId
41
+ });
43
42
  const result = await captureTopup(
44
43
  em,
45
- { numberGenerator, taxService },
46
44
  {
47
45
  topup,
48
46
  account: {