@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,61 +1,53 @@
1
1
  import { NextResponse } from 'next/server'
2
2
  import type { EntityManager } from '@mikro-orm/postgresql'
3
- import { z } from 'zod'
4
3
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
5
4
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
+ import { billingInvoiceListQuerySchema } from '../../data/validators'
6
+ import { daysOverdueSql, isoDay, overdueSql } from '../../lib/overdue'
6
7
 
7
8
  /**
8
- * `GET /api/billing/invoices`
9
+ * `GET /api/billing/invoices` — paginated list of billing documents
10
+ * (Spec 0: billing-owned `billing_invoices`, never core `sales`).
9
11
  *
10
- * Lists `core/sales` invoices that the billing engine emitted (i.e.
11
- * carry `metadata.bill_run_id`). Hand-rolled rather than wrapped via
12
- * `makeCrudRoute` because the filter predicate is a JSONB
13
- * `metadata->>'bill_run_id' IS NOT NULL` check that doesn't map
14
- * cleanly onto the factory's `where`-shaped filter API, and the
15
- * entity itself is owned by `core/sales` — keeping the surface
16
- * read-only and hand-rolled avoids surprising the cross-module
17
- * reviewer.
12
+ * Filters (all on indexed columns): `status`, `documentType`, `billRunId`,
13
+ * `billAccountId`, `testRun` (`true` / `false`), `id`, `search` (number).
14
+ * Spec B: `overdue=true` (computed, B-D6 — see `lib/overdue.ts`), `dueFrom` /
15
+ * `dueTo` (due-date window). Each row carries `bill_account_name` (joined)
16
+ * and `days_overdue` (0 when not overdue).
18
17
  *
19
- * Filters:
20
- * - `status` — draft / posted / paid / void
21
- * - `billRunId` — exact match on `metadata->>'bill_run_id'`
22
- * - `billAccountId` — exact match on `metadata->>'bill_account_id'`
23
- * - `testRun=true|false` — flips the `metadata->>'test_run'` filter
24
- * - `search` — substring on invoice_number
25
- *
26
- * Sort: started_at DESC (most recent first). Pagination: standard
27
- * page / pageSize (capped at 100).
18
+ * Hand-written SQL instead of the CRUD factory: documents are written by the
19
+ * bill-run engine without query-index side effects, so the factory's
20
+ * query-engine path would not see them. Sort: `created_at DESC`.
28
21
  */
29
22
 
30
23
  export const metadata = {
31
24
  GET: { requireAuth: true, requireFeatures: ['billing.invoice.view'] },
32
25
  }
33
26
 
34
- const querySchema = z
35
- .object({
36
- page: z.coerce.number().int().min(1).default(1),
37
- pageSize: z.coerce.number().int().min(1).max(100).default(50),
38
- status: z.enum(['draft', 'posted', 'paid', 'void']).optional(),
39
- billRunId: z.string().uuid().optional(),
40
- billAccountId: z.string().uuid().optional(),
41
- testRun: z.coerce.boolean().optional(),
42
- search: z.string().optional(),
43
- })
44
- .passthrough()
45
-
46
27
  type BillingInvoiceRow = {
47
28
  id: string
48
- invoice_number: string
49
- status: string | null
50
- currency_code: string
29
+ number: string
30
+ document_type: string
31
+ status: string
32
+ test_run: boolean
33
+ bill_account_id: string
34
+ bill_account_name: string | null
35
+ bill_run_id: string | null
36
+ bill_date: string | null
37
+ period_start: string | null
38
+ period_end: string | null
51
39
  issue_date: string | null
52
40
  due_date: string | null
53
- subtotal_net_amount: string
54
- grand_total_net_amount: string
55
- grand_total_gross_amount: string
56
- paid_total_amount: string
57
- outstanding_amount: string
58
- metadata: Record<string, unknown> | null
41
+ currency_code: string
42
+ subtotal_net: string
43
+ tax_total: string
44
+ total_gross: string
45
+ paid_total: string
46
+ credited_total: string
47
+ outstanding: string
48
+ days_overdue: number
49
+ corrects_invoice_id: string | null
50
+ topup_id: string | null
59
51
  created_at: string
60
52
  updated_at: string
61
53
  }
@@ -76,67 +68,67 @@ export async function GET(req: Request) {
76
68
  }
77
69
 
78
70
  const url = new URL(req.url)
79
- const query = querySchema.parse(
80
- Object.fromEntries(url.searchParams.entries()),
81
- )
71
+ const query = billingInvoiceListQuerySchema.parse(Object.fromEntries(url.searchParams.entries()))
82
72
 
83
73
  const em = (container.resolve('em') as EntityManager).fork()
84
74
 
85
- // Build the predicate. `jsonb_exists(metadata, 'bill_run_id')` is
86
- // the function form of the JSONB `?` "key exists" operator — the
87
- // operator form cannot be used here because `em.execute` treats a
88
- // literal `?` as a positional parameter placeholder. Keeps us
89
- // narrow to billing-managed invoices, never bleeding into invoices
90
- // written by other modules.
91
- const whereClauses: string[] = [
92
- 'tenant_id = ?',
93
- 'organization_id = ?',
94
- 'deleted_at IS NULL',
95
- "jsonb_exists(metadata, 'bill_run_id')",
96
- ]
75
+ const whereClauses: string[] = ['i.tenant_id = ?', 'i.organization_id = ?', 'i.deleted_at IS NULL']
97
76
  const params: unknown[] = [auth.tenantId, organizationId]
98
-
99
- if (query.status) {
100
- whereClauses.push('status = ?')
101
- params.push(query.status)
77
+ const filters: Array<[unknown, string]> = [
78
+ [query.id, 'i.id = ?'],
79
+ [query.status, 'i.status = ?'],
80
+ [query.documentType, 'i.document_type = ?'],
81
+ [query.billRunId, 'i.bill_run_id = ?'],
82
+ [query.billAccountId, 'i.bill_account_id = ?'],
83
+ [query.testRun, 'i.test_run = ?'],
84
+ ]
85
+ for (const [value, clause] of filters) {
86
+ if (value === undefined || value === null || value === '') continue
87
+ whereClauses.push(clause)
88
+ params.push(value)
102
89
  }
103
- if (query.billRunId) {
104
- whereClauses.push("metadata->>'bill_run_id' = ?")
105
- params.push(query.billRunId)
90
+ const today = isoDay(new Date())
91
+ if (query.overdue === true) {
92
+ whereClauses.push(overdueSql('i'))
93
+ params.push(today)
94
+ } else if (query.overdue === false) {
95
+ whereClauses.push(`NOT COALESCE(${overdueSql("i")}, false)`)
96
+ params.push(today)
106
97
  }
107
- if (query.billAccountId) {
108
- whereClauses.push("metadata->>'bill_account_id' = ?")
109
- params.push(query.billAccountId)
98
+ if (query.dueFrom) {
99
+ whereClauses.push('i.due_date >= ?::date')
100
+ params.push(query.dueFrom)
110
101
  }
111
- if (typeof query.testRun === 'boolean') {
112
- if (query.testRun) {
113
- whereClauses.push("metadata->>'test_run' = 'true'")
114
- } else {
115
- whereClauses.push("(metadata->>'test_run' IS NULL OR metadata->>'test_run' != 'true')")
116
- }
102
+ if (query.dueTo) {
103
+ whereClauses.push('i.due_date <= ?::date')
104
+ params.push(query.dueTo)
117
105
  }
118
- if (typeof query.search === 'string' && query.search.trim()) {
119
- whereClauses.push('invoice_number ILIKE ?')
120
- params.push(`%${query.search.trim().replace(/[%_]/g, (m) => `\\${m}`)}%`)
106
+ if (query.search) {
107
+ whereClauses.push('i.number ILIKE ?')
108
+ params.push(`%${query.search.replace(/[%_\\]/g, (m) => `\\${m}`)}%`)
121
109
  }
122
110
 
123
111
  const whereSql = whereClauses.join(' AND ')
124
112
  const countRows = (await em.execute(
125
- `SELECT COUNT(*)::int AS total FROM sales_invoices WHERE ${whereSql}`,
113
+ `SELECT COUNT(*)::int AS total FROM billing_invoices i WHERE ${whereSql}`,
126
114
  params,
127
115
  )) as unknown as Array<{ total: number }>
128
116
  const total = countRows?.[0]?.total ?? 0
129
117
 
130
118
  const offset = (query.page - 1) * query.pageSize
131
119
  const itemRows = (await em.execute(
132
- `SELECT id, invoice_number, status, currency_code, issue_date, due_date,
133
- subtotal_net_amount, grand_total_net_amount, grand_total_gross_amount,
134
- paid_total_amount, outstanding_amount, metadata, created_at, updated_at
135
- FROM sales_invoices
120
+ `SELECT i.id, i.number, i.document_type, i.status, i.test_run, i.bill_account_id,
121
+ a.name AS bill_account_name, i.bill_run_id, i.bill_date, i.period_start, i.period_end,
122
+ i.issue_date, i.due_date, i.currency_code, i.subtotal_net, i.tax_total, i.total_gross,
123
+ i.paid_total, i.credited_total, i.outstanding, i.corrects_invoice_id, i.corrects_invoice_number, i.topup_id,
124
+ ${daysOverdueSql('i')}::int AS days_overdue,
125
+ i.created_at, i.updated_at
126
+ FROM billing_invoices i
127
+ LEFT JOIN billing_accounts a ON a.id = i.bill_account_id AND a.tenant_id = i.tenant_id
136
128
  WHERE ${whereSql}
137
- ORDER BY created_at DESC
129
+ ORDER BY i.created_at DESC
138
130
  LIMIT ? OFFSET ?`,
139
- [...params, query.pageSize, offset],
131
+ [today, today, ...params, query.pageSize, offset],
140
132
  )) as unknown as BillingInvoiceRow[]
141
133
 
142
134
  return NextResponse.json({
@@ -156,12 +148,15 @@ export const openApi = {
156
148
  methods: {
157
149
  GET: {
158
150
  tags: ['Billing'],
159
- summary: 'List billing-managed invoices',
151
+ summary: 'List billing documents',
160
152
  description:
161
- 'Returns a paginated list of `core/sales` invoices that the ' +
162
- 'billing engine emitted (matched via `metadata->>\'bill_run_id\'` ' +
163
- 'presence). Supports status / billRunId / billAccountId / testRun ' +
164
- '/ invoice_number search filters.',
153
+ 'Paginated billing documents (invoices, credit / debit memos, top-up receipts) from ' +
154
+ '`billing_invoices`. Filters: status, documentType, billRunId, billAccountId, testRun ' +
155
+ '(`true`/`false`), id, number search, `overdue` (`true`/`false` — posted or partially paid, ' +
156
+ 'past due, outstanding > 0), `dueFrom` / `dueTo` (YYYY-MM-DD). Each row adds `days_overdue`. ' +
157
+ 'Fields use billing names: `number`, `document_type`, ' +
158
+ '`total_gross`, `outstanding`, `bill_date`, `period_start/end`, `bill_account_name`, … ' +
159
+ '(0.21.0 renamed them from the core-sales names — see MIGRATION.md).',
165
160
  },
166
161
  },
167
162
  }
@@ -87,6 +87,7 @@ export const openApi = createBillingCrudOpenApi({
87
87
  'Idempotent per `sourceRef` (one batched existence check). ' +
88
88
  'Returns `{ created, deduplicated, items: [{ sourceRef, id, ' +
89
89
  'deduplicated }] }`. Always HTTP 200 — duplicates are reported ' +
90
- 'in the body, never an error.',
90
+ 'in the body, never an error. Entries accept `chargeTiming` / `prorate` ' +
91
+ '(recurring only; defaults `in_advance` / true).',
91
92
  },
92
93
  })
@@ -0,0 +1,54 @@
1
+ import { z } from 'zod'
2
+ import { runCommandRoute } from '../../../lib/commandRoute'
3
+
4
+ /**
5
+ * `POST /api/billing/items/change-price` — change a recurring item's price
6
+ * from a date on: the item ends the day before `effectiveDate` and a copy with
7
+ * `unitPrice` starts on it (same account, description, timing, proration,
8
+ * VAT, price basis, references and end date). Returns both item ids.
9
+ */
10
+
11
+ export const metadata = {
12
+ POST: { requireAuth: true, requireFeatures: ['billing.item.manage'] },
13
+ }
14
+
15
+ const bodySchema = z.object({
16
+ id: z.string().uuid(),
17
+ effectiveDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
18
+ unitPrice: z.coerce.number().finite().nonnegative(),
19
+ })
20
+
21
+ const responseSchema = z.object({ previousItemId: z.string().uuid(), newItemId: z.string().uuid() })
22
+
23
+ export async function POST(req: Request) {
24
+ return runCommandRoute(req, {
25
+ commandId: 'billing.items.change_price',
26
+ bodySchema,
27
+ resourceKind: 'billing.item',
28
+ resourceId: (body) => body.id,
29
+ logLabel: 'billing/items/change-price.POST',
30
+ })
31
+ }
32
+
33
+ export const openApi = {
34
+ methods: {
35
+ POST: {
36
+ tags: ['Billing'],
37
+ summary: "Change a recurring item's price from a date",
38
+ description:
39
+ 'Ends the item the day before `effectiveDate` and creates a copy with the new `unitPrice` (on the item price basis) ' +
40
+ 'starting on `effectiveDate`. Already-billed days after the change are credited / re-charged by the Bill Run per the ' +
41
+ "item's proration setting, so nothing is billed twice.",
42
+ requestBody: { schema: bodySchema },
43
+ responses: [{ status: 200, description: 'Both item ids', schema: responseSchema }],
44
+ errors: [
45
+ { status: 404, description: 'Item not found' },
46
+ {
47
+ status: 422,
48
+ description:
49
+ '`billing.item.price_change_recurring_only` / `_inactive` / `_before_start` (must be after the start date) / `_after_end`',
50
+ },
51
+ ],
52
+ },
53
+ },
54
+ }
@@ -33,6 +33,9 @@ const billingItemListItemSchema = z.object({
33
33
  id: z.string().uuid(),
34
34
  bill_account_id: z.string().uuid(),
35
35
  bill_account_name: z.string().nullable(),
36
+ /** Spec F (F2): the owning account's currency and mode, for the form. */
37
+ bill_account_currency: z.string().nullable(),
38
+ bill_account_mode: z.enum(['postpaid', 'prepaid']).nullable(),
36
39
  type: z.string(),
37
40
  bill_start_date: z.string(),
38
41
  bill_end_date: z.string().nullable(),
@@ -44,6 +47,10 @@ const billingItemListItemSchema = z.object({
44
47
  source_ref: z.string().nullable(),
45
48
  currency_mismatch: z.boolean(),
46
49
  billed_to_date: z.string().nullable(),
50
+ charge_timing: z.enum(['in_advance', 'in_arrears']),
51
+ prorate: z.boolean(),
52
+ tax_rate: z.union([z.string(), z.number()]),
53
+ price_basis: z.enum(['net', 'gross']),
47
54
  is_active: z.boolean(),
48
55
  organization_id: z.string().uuid(),
49
56
  tenant_id: z.string().uuid(),
@@ -87,6 +94,10 @@ const crud = makeCrudRoute({
87
94
  'source_ref',
88
95
  'currency_mismatch',
89
96
  'billed_to_date',
97
+ 'charge_timing',
98
+ 'prorate',
99
+ 'tax_rate',
100
+ 'price_basis',
90
101
  'is_active',
91
102
  'organization_id',
92
103
  'tenant_id',
@@ -196,7 +207,7 @@ const crud = makeCrudRoute({
196
207
  },
197
208
  hooks: {
198
209
  // Items reference their account by FK id only; the list + detail UI
199
- // wants the human-readable account name. One bounded query
210
+ // wants the account name, currency and mode. One bounded query
200
211
  // (≤ pageSize ids) resolves it after the page is fetched.
201
212
  afterList: async (payload: unknown, ctx: unknown) => {
202
213
  const items = ((payload as { items?: unknown[] } | null)?.items ?? []) as Array<
@@ -212,11 +223,12 @@ const crud = makeCrudRoute({
212
223
  if (accountIds.length === 0) return
213
224
  const em = (ctx as { container: AwilixContainer }).container.resolve<EntityManager>('em')
214
225
  const accounts = await em.find(BillingAccount, { id: { $in: accountIds } })
215
- const nameById = new Map(
216
- accounts.map((a) => [String(a.id), a.name] as [string, unknown]),
217
- )
226
+ const byId = new Map(accounts.map((a) => [String(a.id), a] as const))
218
227
  for (const row of items) {
219
- row.bill_account_name = nameById.get(String(row.bill_account_id)) ?? null
228
+ const account = byId.get(String(row.bill_account_id))
229
+ row.bill_account_name = account?.name ?? null
230
+ row.bill_account_currency = account?.currencyCode ?? null
231
+ row.bill_account_mode = account?.billingMode ?? null
220
232
  }
221
233
  },
222
234
  },
@@ -238,14 +250,18 @@ export const openApi = createBillingCrudOpenApi({
238
250
  'Creates a billing item. Idempotent via `sourceRef`: re-POSTing the same ' +
239
251
  '`(tenantId, billAccountId, sourceRef)` returns the existing row with ' +
240
252
  '`deduplicated: true` instead of creating a duplicate. The unique index ' +
241
- 'on `(tenant_id, bill_account_id, source_ref)` is the correctness gate.',
253
+ 'on `(tenant_id, bill_account_id, source_ref)` is the correctness gate. ' +
254
+ 'Recurring items accept `chargeTiming` (`in_advance` default | `in_arrears`) and ' +
255
+ '`prorate` (default true); other types reject non-default values (400).',
242
256
  },
243
257
  update: {
244
258
  schema: billingItemUpdateSchema,
245
259
  responseSchema: defaultOkResponseSchema,
246
260
  description:
247
261
  'Updates a billing item. `type` and `sourceRef` are immutable — to change ' +
248
- 'either, soft-delete the item and create a new one.',
262
+ 'either, soft-delete the item and create a new one. `chargeTiming` / `prorate` ' +
263
+ 'may change at any time on recurring items — billing resumes from `billed_to_date`, ' +
264
+ 'so no day is billed twice.',
249
265
  },
250
266
  del: {
251
267
  schema: z.object({ id: z.string().uuid() }),
@@ -0,0 +1,49 @@
1
+ import { NextResponse } from 'next/server'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
+ import {
6
+ organizationScopeRequiredResponse,
7
+ resolveActiveOrganizationId,
8
+ } from '@open-mercato/shared/lib/auth/organizationScope'
9
+
10
+ /** `GET /api/billing/payment-imports/[id]` — one upload batch with its row errors (Spec C). */
11
+
12
+ export const metadata = {
13
+ GET: { requireAuth: true, requireFeatures: ['billing.payment.view'] },
14
+ }
15
+
16
+ export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
17
+ try {
18
+ const container = await createRequestContainer()
19
+ const auth = await getAuthFromRequest(req)
20
+ if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
21
+ const organizationId = resolveActiveOrganizationId(auth)
22
+ if (!organizationId) return organizationScopeRequiredResponse()
23
+ const { id } = await params
24
+ const em = (container.resolve('em') as EntityManager).fork()
25
+ const rows = (await em.execute(
26
+ `SELECT id, file_name, row_count, counts, errors, user_id, created_at
27
+ FROM billing_payment_imports
28
+ WHERE id = ? AND tenant_id = ? AND organization_id = ? AND deleted_at IS NULL`,
29
+ [id, auth.tenantId, organizationId],
30
+ )) as unknown as Array<Record<string, unknown>>
31
+ if (!rows?.length) return NextResponse.json({ error: 'Import not found' }, { status: 404 })
32
+ return NextResponse.json({ import: rows[0] })
33
+ } catch (err) {
34
+ console.error('[billing/payment-imports/[id].GET]', err)
35
+ return NextResponse.json({ error: 'Internal error' }, { status: 500 })
36
+ }
37
+ }
38
+
39
+ export const openApi = {
40
+ methods: {
41
+ GET: {
42
+ tags: ['Billing'],
43
+ summary: 'Get a payment import batch',
44
+ description: 'Counts per outcome and the row errors (line number + message, capped at 200).',
45
+ responses: [{ status: 200, description: '`{ import }`' }],
46
+ errors: [{ status: 404, description: 'Import not found' }],
47
+ },
48
+ },
49
+ }
@@ -0,0 +1,57 @@
1
+ import { NextResponse } from 'next/server'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
+ import {
6
+ organizationScopeRequiredResponse,
7
+ resolveActiveOrganizationId,
8
+ } from '@open-mercato/shared/lib/auth/organizationScope'
9
+ import { buildQueryParams } from '@open-mercato/shared/lib/crud/query-params'
10
+ import { billingPaymentImportListQuerySchema } from '../../data/validators'
11
+
12
+ /** `GET /api/billing/payment-imports` — CSV upload batches, newest first (Spec C, C-D4). */
13
+
14
+ export const metadata = {
15
+ GET: { requireAuth: true, requireFeatures: ['billing.payment.view'] },
16
+ }
17
+
18
+ export async function GET(req: Request) {
19
+ try {
20
+ const container = await createRequestContainer()
21
+ const auth = await getAuthFromRequest(req)
22
+ if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
23
+ const organizationId = resolveActiveOrganizationId(auth)
24
+ if (!organizationId) return organizationScopeRequiredResponse()
25
+ const query = billingPaymentImportListQuerySchema.parse(buildQueryParams(new URL(req.url).searchParams))
26
+ const em = (container.resolve('em') as EntityManager).fork()
27
+ const where = ['tenant_id = ?', 'organization_id = ?', 'deleted_at IS NULL']
28
+ const params: unknown[] = [auth.tenantId, organizationId]
29
+ if (query.id) {
30
+ where.push('id = ?')
31
+ params.push(query.id)
32
+ }
33
+ const totalRows = (await em.execute(`SELECT COUNT(*)::int AS total FROM billing_payment_imports WHERE ${where.join(' AND ')}`, params)) as unknown as Array<{ total: number }>
34
+ const total = totalRows?.[0]?.total ?? 0
35
+ const items = await em.execute(
36
+ `SELECT id, file_name, row_count, counts, user_id, created_at
37
+ FROM billing_payment_imports WHERE ${where.join(' AND ')}
38
+ ORDER BY created_at DESC LIMIT ? OFFSET ?`,
39
+ [...params, query.pageSize, (query.page - 1) * query.pageSize],
40
+ )
41
+ return NextResponse.json({ items, total, page: query.page, pageSize: query.pageSize, totalPages: total === 0 ? 1 : Math.ceil(total / query.pageSize) })
42
+ } catch (err) {
43
+ console.error('[billing/payment-imports.GET]', err)
44
+ return NextResponse.json({ error: 'Internal error' }, { status: 500 })
45
+ }
46
+ }
47
+
48
+ export const openApi = {
49
+ methods: {
50
+ GET: {
51
+ tags: ['Billing'],
52
+ summary: 'List payment import batches',
53
+ description: 'CSV uploads with counts per outcome (allocated, partially_allocated, matched, unmatched, duplicate, rejected).',
54
+ query: billingPaymentImportListQuerySchema,
55
+ },
56
+ },
57
+ }
@@ -0,0 +1,63 @@
1
+ import { NextResponse } from 'next/server'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
5
+ import {
6
+ organizationScopeRequiredResponse,
7
+ resolveActiveOrganizationId,
8
+ } from '@open-mercato/shared/lib/auth/organizationScope'
9
+
10
+ /**
11
+ * `GET /api/billing/payments/[id]` — one payment with its active
12
+ * allocations (invoice number, amount, who / how allocated) — Spec C.
13
+ */
14
+
15
+ export const metadata = {
16
+ GET: { requireAuth: true, requireFeatures: ['billing.payment.view'] },
17
+ }
18
+
19
+ export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
20
+ try {
21
+ const container = await createRequestContainer()
22
+ const auth = await getAuthFromRequest(req)
23
+ if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
24
+ const organizationId = resolveActiveOrganizationId(auth)
25
+ if (!organizationId) return organizationScopeRequiredResponse()
26
+ const { id } = await params
27
+ const em = (container.resolve('em') as EntityManager).fork()
28
+ const rows = (await em.execute(
29
+ `SELECT p.*, a.name AS bill_account_name, a.billing_mode AS bill_account_mode
30
+ FROM billing_payments p
31
+ LEFT JOIN billing_accounts a ON a.id = p.bill_account_id AND a.tenant_id = p.tenant_id
32
+ WHERE p.id = ? AND p.tenant_id = ? AND p.organization_id = ? AND p.deleted_at IS NULL`,
33
+ [id, auth.tenantId, organizationId],
34
+ )) as unknown as Array<Record<string, unknown>>
35
+ if (!rows?.length) return NextResponse.json({ error: 'Payment not found' }, { status: 404 })
36
+ const allocations = await em.execute(
37
+ `SELECT al.id, al.invoice_id, i.number AS invoice_number, i.document_type, i.status AS invoice_status,
38
+ al.amount, al.currency_code, al.allocated_by, al.user_id, al.created_at
39
+ FROM billing_allocations al
40
+ LEFT JOIN billing_invoices i ON i.id = al.invoice_id
41
+ WHERE al.source_type = 'payment' AND al.source_id = ? AND al.tenant_id = ? AND al.organization_id = ?
42
+ AND al.deleted_at IS NULL
43
+ ORDER BY al.created_at ASC`,
44
+ [id, auth.tenantId, organizationId],
45
+ )
46
+ return NextResponse.json({ payment: rows[0], allocations })
47
+ } catch (err) {
48
+ console.error('[billing/payments/[id].GET]', err)
49
+ return NextResponse.json({ error: 'Internal error' }, { status: 500 })
50
+ }
51
+ }
52
+
53
+ export const openApi = {
54
+ methods: {
55
+ GET: {
56
+ tags: ['Billing'],
57
+ summary: 'Get a billing payment',
58
+ description: 'The payment (incl. match reason, account, top-up link) and its active allocations.',
59
+ responses: [{ status: 200, description: '`{ payment, allocations[] }`' }],
60
+ errors: [{ status: 404, description: 'Payment not found in this organization' }],
61
+ },
62
+ },
63
+ }
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod'
2
+ import { runCommandRoute } from '../../../lib/commandRoute'
3
+
4
+ /** `POST /api/billing/payments/allocate` — allocate a payment to invoices (Spec C). */
5
+
6
+ export const metadata = {
7
+ POST: { requireAuth: true, requireFeatures: ['billing.payment.manage'] },
8
+ }
9
+
10
+ const bodySchema = z.object({ paymentId: z.string().uuid(), allocations: z.array(z.object({ invoiceId: z.string().uuid(), amount: z.coerce.number().positive() })).min(1).max(100) })
11
+
12
+ export async function POST(req: Request) {
13
+ return runCommandRoute(req, {
14
+ commandId: 'billing.payments.allocate',
15
+ bodySchema,
16
+ resourceKind: 'billing.payment',
17
+ resourceId: (body) => body.paymentId,
18
+ logLabel: 'billing/payments/allocate.POST',
19
+ })
20
+ }
21
+
22
+ export const openApi = {
23
+ methods: {
24
+ POST: {
25
+ tags: ['Billing'],
26
+ summary: 'Allocate a payment to invoices',
27
+ description: 'Allocates amounts of a payment to open invoices / debit memos of its account. Invoice paid / outstanding / status are recomputed from allocations.',
28
+ requestBody: { schema: bodySchema },
29
+ responses: [{ status: 200, description: 'Updated payment state' }],
30
+ errors: [
31
+ { status: 409, description: '`billing.allocation.exceeds_outstanding` / `insufficient_unallocated` / `account_mismatch` / `currency_mismatch` / `invoice_not_open`' },
32
+ ],
33
+ },
34
+ },
35
+ }
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod'
2
+ import { runCommandRoute } from '../../../lib/commandRoute'
3
+
4
+ /** `POST /api/billing/payments/assign` — assign a payment to a billing account (Spec C). */
5
+
6
+ export const metadata = {
7
+ POST: { requireAuth: true, requireFeatures: ['billing.payment.manage'] },
8
+ }
9
+
10
+ const bodySchema = z.object({ paymentId: z.string().uuid(), billAccountId: z.string().uuid() })
11
+
12
+ export async function POST(req: Request) {
13
+ return runCommandRoute(req, {
14
+ commandId: 'billing.payments.assign',
15
+ bodySchema,
16
+ resourceKind: 'billing.payment',
17
+ resourceId: (body) => body.paymentId,
18
+ logLabel: 'billing/payments/assign.POST',
19
+ })
20
+ }
21
+
22
+ export const openApi = {
23
+ methods: {
24
+ POST: {
25
+ tags: ['Billing'],
26
+ summary: 'Assign a payment to a billing account',
27
+ description: 'Assigns an unmatched payment to a postpaid account (status → matched) and applies it as credit to the account\'s open invoices, oldest due first.',
28
+ requestBody: { schema: bodySchema },
29
+ responses: [{ status: 200, description: 'Updated payment state' }],
30
+ errors: [
31
+ { status: 404, description: 'Payment or account not found' },
32
+ { status: 409, description: '`billing.payment.not_unmatched` / `prepaid_account` / `currency_mismatch`' },
33
+ ],
34
+ },
35
+ },
36
+ }
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod'
2
+ import { runCommandRoute } from '../../../lib/commandRoute'
3
+
4
+ /** `POST /api/billing/payments/convert-to-topup` — convert a payment into a prepaid top-up (Spec C). */
5
+
6
+ export const metadata = {
7
+ POST: { requireAuth: true, requireFeatures: ['billing.payment.manage', 'billing.topup.create'] },
8
+ }
9
+
10
+ const bodySchema = z.object({ paymentId: z.string().uuid(), billAccountId: z.string().uuid() })
11
+
12
+ export async function POST(req: Request) {
13
+ return runCommandRoute(req, {
14
+ commandId: 'billing.payments.convert_to_topup',
15
+ bodySchema,
16
+ resourceKind: 'billing.payment',
17
+ resourceId: (body) => body.paymentId,
18
+ logLabel: 'billing/payments/convert-to-topup.POST',
19
+ })
20
+ }
21
+
22
+ export const openApi = {
23
+ methods: {
24
+ POST: {
25
+ tags: ['Billing'],
26
+ summary: 'Convert a payment into a prepaid top-up',
27
+ description: 'Turns an unmatched payment into a captured top-up of a prepaid account (balance credit, transaction and VAT receipt). Terminal; idempotent per payment.',
28
+ requestBody: { schema: bodySchema },
29
+ responses: [{ status: 200, description: 'Updated payment state' }],
30
+ errors: [
31
+ { status: 409, description: '`billing.payment.not_prepaid` / `currency_mismatch` / `not_convertible`' },
32
+ ],
33
+ },
34
+ },
35
+ }