@dainamite/billing 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/dist/modules/billing/acl.js +13 -1
  3. package/dist/modules/billing/acl.js.map +2 -2
  4. package/dist/modules/billing/api/accounts/[id]/summary/route.js +52 -0
  5. package/dist/modules/billing/api/accounts/[id]/summary/route.js.map +7 -0
  6. package/dist/modules/billing/api/accounts/route.js +47 -4
  7. package/dist/modules/billing/api/accounts/route.js.map +2 -2
  8. package/dist/modules/billing/api/export/account/[id]/route.js +11 -7
  9. package/dist/modules/billing/api/export/account/[id]/route.js.map +2 -2
  10. package/dist/modules/billing/api/invoices/[id]/memos/route.js +54 -0
  11. package/dist/modules/billing/api/invoices/[id]/memos/route.js.map +7 -0
  12. package/dist/modules/billing/api/invoices/[id]/pdf/route.js +70 -0
  13. package/dist/modules/billing/api/invoices/[id]/pdf/route.js.map +7 -0
  14. package/dist/modules/billing/api/invoices/[id]/route.js +44 -24
  15. package/dist/modules/billing/api/invoices/[id]/route.js.map +2 -2
  16. package/dist/modules/billing/api/invoices/[id]/send/route.js +107 -0
  17. package/dist/modules/billing/api/invoices/[id]/send/route.js.map +7 -0
  18. package/dist/modules/billing/api/invoices/add-line/route.js +2 -2
  19. package/dist/modules/billing/api/invoices/add-line/route.js.map +2 -2
  20. package/dist/modules/billing/api/invoices/delete-draft/route.js +33 -0
  21. package/dist/modules/billing/api/invoices/delete-draft/route.js.map +7 -0
  22. package/dist/modules/billing/api/invoices/edit-line/route.js +2 -2
  23. package/dist/modules/billing/api/invoices/edit-line/route.js.map +2 -2
  24. package/dist/modules/billing/api/invoices/post/route.js +2 -2
  25. package/dist/modules/billing/api/invoices/post/route.js.map +2 -2
  26. package/dist/modules/billing/api/invoices/remove-line/route.js +2 -2
  27. package/dist/modules/billing/api/invoices/remove-line/route.js.map +2 -2
  28. package/dist/modules/billing/api/invoices/route.js +45 -46
  29. package/dist/modules/billing/api/invoices/route.js.map +2 -2
  30. package/dist/modules/billing/api/items/bulk/route.js +1 -1
  31. package/dist/modules/billing/api/items/bulk/route.js.map +2 -2
  32. package/dist/modules/billing/api/items/change-price/route.js +44 -0
  33. package/dist/modules/billing/api/items/change-price/route.js.map +7 -0
  34. package/dist/modules/billing/api/items/route.js +19 -7
  35. package/dist/modules/billing/api/items/route.js.map +2 -2
  36. package/dist/modules/billing/api/payment-imports/[id]/route.js +49 -0
  37. package/dist/modules/billing/api/payment-imports/[id]/route.js.map +7 -0
  38. package/dist/modules/billing/api/payment-imports/route.js +57 -0
  39. package/dist/modules/billing/api/payment-imports/route.js.map +7 -0
  40. package/dist/modules/billing/api/payments/[id]/route.js +60 -0
  41. package/dist/modules/billing/api/payments/[id]/route.js.map +7 -0
  42. package/dist/modules/billing/api/payments/allocate/route.js +35 -0
  43. package/dist/modules/billing/api/payments/allocate/route.js.map +7 -0
  44. package/dist/modules/billing/api/payments/assign/route.js +36 -0
  45. package/dist/modules/billing/api/payments/assign/route.js.map +7 -0
  46. package/dist/modules/billing/api/payments/convert-to-topup/route.js +35 -0
  47. package/dist/modules/billing/api/payments/convert-to-topup/route.js.map +7 -0
  48. package/dist/modules/billing/api/payments/ignore/route.js +35 -0
  49. package/dist/modules/billing/api/payments/ignore/route.js.map +7 -0
  50. package/dist/modules/billing/api/payments/import/route.js +63 -0
  51. package/dist/modules/billing/api/payments/import/route.js.map +7 -0
  52. package/dist/modules/billing/api/payments/restore/route.js +35 -0
  53. package/dist/modules/billing/api/payments/restore/route.js.map +7 -0
  54. package/dist/modules/billing/api/payments/route.js +114 -0
  55. package/dist/modules/billing/api/payments/route.js.map +7 -0
  56. package/dist/modules/billing/api/payments/unallocate/route.js +35 -0
  57. package/dist/modules/billing/api/payments/unallocate/route.js.map +7 -0
  58. package/dist/modules/billing/api/payments/unassign/route.js +35 -0
  59. package/dist/modules/billing/api/payments/unassign/route.js.map +7 -0
  60. package/dist/modules/billing/api/run-outcomes/route.js +43 -6
  61. package/dist/modules/billing/api/run-outcomes/route.js.map +2 -2
  62. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js +61 -0
  63. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js.map +7 -0
  64. package/dist/modules/billing/api/runs/[id]/route.js +53 -0
  65. package/dist/modules/billing/api/runs/[id]/route.js.map +7 -0
  66. package/dist/modules/billing/api/runs/retry-failed/route.js +1 -1
  67. package/dist/modules/billing/api/runs/retry-failed/route.js.map +2 -2
  68. package/dist/modules/billing/api/runs/route.js +9 -3
  69. package/dist/modules/billing/api/runs/route.js.map +2 -2
  70. package/dist/modules/billing/api/settings/number-preview/route.js +42 -0
  71. package/dist/modules/billing/api/settings/number-preview/route.js.map +7 -0
  72. package/dist/modules/billing/api/settings/route.js +92 -0
  73. package/dist/modules/billing/api/settings/route.js.map +7 -0
  74. package/dist/modules/billing/api/statements/route.js +3 -0
  75. package/dist/modules/billing/api/statements/route.js.map +2 -2
  76. package/dist/modules/billing/api/test-invoices/wipe/route.js +2 -2
  77. package/dist/modules/billing/api/test-invoices/wipe/route.js.map +2 -2
  78. package/dist/modules/billing/backend/billing/accounts/[id]/page.js +121 -232
  79. package/dist/modules/billing/backend/billing/accounts/[id]/page.js.map +2 -2
  80. package/dist/modules/billing/backend/billing/accounts/create/page.js +6 -0
  81. package/dist/modules/billing/backend/billing/accounts/create/page.js.map +2 -2
  82. package/dist/modules/billing/backend/billing/accounts/page.js +63 -4
  83. package/dist/modules/billing/backend/billing/accounts/page.js.map +2 -2
  84. package/dist/modules/billing/backend/billing/invoices/[id]/page.js +297 -65
  85. package/dist/modules/billing/backend/billing/invoices/[id]/page.js.map +3 -3
  86. package/dist/modules/billing/backend/billing/invoices/page.js +6 -172
  87. package/dist/modules/billing/backend/billing/invoices/page.js.map +2 -2
  88. package/dist/modules/billing/backend/billing/items/[id]/page.js +51 -7
  89. package/dist/modules/billing/backend/billing/items/[id]/page.js.map +2 -2
  90. package/dist/modules/billing/backend/billing/items/create/page.js +9 -6
  91. package/dist/modules/billing/backend/billing/items/create/page.js.map +2 -2
  92. package/dist/modules/billing/backend/billing/items/page.js +8 -2
  93. package/dist/modules/billing/backend/billing/items/page.js.map +2 -2
  94. package/dist/modules/billing/backend/billing/payments/[id]/page.js +297 -0
  95. package/dist/modules/billing/backend/billing/payments/[id]/page.js.map +7 -0
  96. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js +21 -0
  97. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js.map +7 -0
  98. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js +74 -0
  99. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js.map +7 -0
  100. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js +21 -0
  101. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js.map +7 -0
  102. package/dist/modules/billing/backend/billing/payments/page.js +58 -0
  103. package/dist/modules/billing/backend/billing/payments/page.js.map +7 -0
  104. package/dist/modules/billing/backend/billing/payments/page.meta.js +18 -0
  105. package/dist/modules/billing/backend/billing/payments/page.meta.js.map +7 -0
  106. package/dist/modules/billing/backend/billing/runs/[id]/page.js +49 -14
  107. package/dist/modules/billing/backend/billing/runs/[id]/page.js.map +2 -2
  108. package/dist/modules/billing/backend/billing/runs/page.js +58 -7
  109. package/dist/modules/billing/backend/billing/runs/page.js.map +2 -2
  110. package/dist/modules/billing/backend/billing/statements/[id]/page.js +61 -6
  111. package/dist/modules/billing/backend/billing/statements/[id]/page.js.map +2 -2
  112. package/dist/modules/billing/backend/billing/statements/page.js +1 -1
  113. package/dist/modules/billing/backend/billing/statements/page.js.map +2 -2
  114. package/dist/modules/billing/backend/billing/topups/page.js +1 -1
  115. package/dist/modules/billing/backend/billing/topups/page.js.map +2 -2
  116. package/dist/modules/billing/backend/billing/transactions/page.js +1 -1
  117. package/dist/modules/billing/backend/billing/transactions/page.js.map +2 -2
  118. package/dist/modules/billing/backend/billing/usage/create/page.js +3 -2
  119. package/dist/modules/billing/backend/billing/usage/create/page.js.map +2 -2
  120. package/dist/modules/billing/backend/config/billing/page.js +472 -0
  121. package/dist/modules/billing/backend/config/billing/page.js.map +7 -0
  122. package/dist/modules/billing/backend/config/billing/page.meta.js +19 -0
  123. package/dist/modules/billing/backend/config/billing/page.meta.js.map +7 -0
  124. package/dist/modules/billing/cli.js +22 -1
  125. package/dist/modules/billing/cli.js.map +2 -2
  126. package/dist/modules/billing/commands/accounts.js +6 -0
  127. package/dist/modules/billing/commands/accounts.js.map +2 -2
  128. package/dist/modules/billing/commands/index.js +3 -0
  129. package/dist/modules/billing/commands/index.js.map +2 -2
  130. package/dist/modules/billing/commands/invoices.js +269 -167
  131. package/dist/modules/billing/commands/invoices.js.map +2 -2
  132. package/dist/modules/billing/commands/items.js +108 -0
  133. package/dist/modules/billing/commands/items.js.map +2 -2
  134. package/dist/modules/billing/commands/memos.js +179 -0
  135. package/dist/modules/billing/commands/memos.js.map +7 -0
  136. package/dist/modules/billing/commands/payments.js +379 -0
  137. package/dist/modules/billing/commands/payments.js.map +7 -0
  138. package/dist/modules/billing/commands/runs.js +151 -4
  139. package/dist/modules/billing/commands/runs.js.map +2 -2
  140. package/dist/modules/billing/commands/settings.js +59 -0
  141. package/dist/modules/billing/commands/settings.js.map +7 -0
  142. package/dist/modules/billing/commands/topups.js +9 -2
  143. package/dist/modules/billing/commands/topups.js.map +2 -2
  144. package/dist/modules/billing/commands/transactions.js +2 -2
  145. package/dist/modules/billing/commands/transactions.js.map +2 -2
  146. package/dist/modules/billing/components/AccountForm.js +149 -42
  147. package/dist/modules/billing/components/AccountForm.js.map +2 -2
  148. package/dist/modules/billing/components/AccountInvoicesSection.js +64 -0
  149. package/dist/modules/billing/components/AccountInvoicesSection.js.map +7 -0
  150. package/dist/modules/billing/components/AccountPaymentsSection.js +43 -0
  151. package/dist/modules/billing/components/AccountPaymentsSection.js.map +7 -0
  152. package/dist/modules/billing/components/AccountPicker.js +56 -0
  153. package/dist/modules/billing/components/AccountPicker.js.map +7 -0
  154. package/dist/modules/billing/components/AllocatePaymentDialog.js +134 -0
  155. package/dist/modules/billing/components/AllocatePaymentDialog.js.map +7 -0
  156. package/dist/modules/billing/components/BillingDataTable.js +21 -0
  157. package/dist/modules/billing/components/BillingDataTable.js.map +7 -0
  158. package/dist/modules/billing/components/BillingSettingsLink.js +19 -0
  159. package/dist/modules/billing/components/BillingSettingsLink.js.map +7 -0
  160. package/dist/modules/billing/components/ChangeItemPriceDialog.js +158 -0
  161. package/dist/modules/billing/components/ChangeItemPriceDialog.js.map +7 -0
  162. package/dist/modules/billing/components/CreateMemoDialog.js +200 -0
  163. package/dist/modules/billing/components/CreateMemoDialog.js.map +7 -0
  164. package/dist/modules/billing/components/CustomerLabel.js +33 -0
  165. package/dist/modules/billing/components/CustomerLabel.js.map +7 -0
  166. package/dist/modules/billing/components/InvoicesTable.js +270 -0
  167. package/dist/modules/billing/components/InvoicesTable.js.map +7 -0
  168. package/dist/modules/billing/components/ItemForm.js +176 -44
  169. package/dist/modules/billing/components/ItemForm.js.map +2 -2
  170. package/dist/modules/billing/components/ItemPriceField.js +46 -0
  171. package/dist/modules/billing/components/ItemPriceField.js.map +7 -0
  172. package/dist/modules/billing/components/LineFormDialog.js +25 -2
  173. package/dist/modules/billing/components/LineFormDialog.js.map +2 -2
  174. package/dist/modules/billing/components/ManualPaymentDialog.js +122 -0
  175. package/dist/modules/billing/components/ManualPaymentDialog.js.map +7 -0
  176. package/dist/modules/billing/components/MoneyInput.js +14 -0
  177. package/dist/modules/billing/components/MoneyInput.js.map +7 -0
  178. package/dist/modules/billing/components/PaymentUploadDialog.js +115 -0
  179. package/dist/modules/billing/components/PaymentUploadDialog.js.map +7 -0
  180. package/dist/modules/billing/components/PaymentsTable.js +171 -0
  181. package/dist/modules/billing/components/PaymentsTable.js.map +7 -0
  182. package/dist/modules/billing/components/PostRunDraftsButton.js +105 -0
  183. package/dist/modules/billing/components/PostRunDraftsButton.js.map +7 -0
  184. package/dist/modules/billing/components/PrepaidPanel.js +14 -4
  185. package/dist/modules/billing/components/PrepaidPanel.js.map +2 -2
  186. package/dist/modules/billing/components/RunCyclesSection.js +209 -0
  187. package/dist/modules/billing/components/RunCyclesSection.js.map +7 -0
  188. package/dist/modules/billing/components/TestRunActions.js +127 -0
  189. package/dist/modules/billing/components/TestRunActions.js.map +7 -0
  190. package/dist/modules/billing/components/account/AccountItemsTab.js +157 -0
  191. package/dist/modules/billing/components/account/AccountItemsTab.js.map +7 -0
  192. package/dist/modules/billing/components/account/AccountRunBillingDialog.js +122 -0
  193. package/dist/modules/billing/components/account/AccountRunBillingDialog.js.map +7 -0
  194. package/dist/modules/billing/components/account/AccountRunsTab.js +152 -0
  195. package/dist/modules/billing/components/account/AccountRunsTab.js.map +7 -0
  196. package/dist/modules/billing/components/account/AccountStatementsTab.js +98 -0
  197. package/dist/modules/billing/components/account/AccountStatementsTab.js.map +7 -0
  198. package/dist/modules/billing/components/account/AccountSummaryCards.js +125 -0
  199. package/dist/modules/billing/components/account/AccountSummaryCards.js.map +7 -0
  200. package/dist/modules/billing/components/account/AccountUsageTab.js +91 -0
  201. package/dist/modules/billing/components/account/AccountUsageTab.js.map +7 -0
  202. package/dist/modules/billing/components/account/AccountView.js +73 -0
  203. package/dist/modules/billing/components/account/AccountView.js.map +7 -0
  204. package/dist/modules/billing/components/account/accountRow.js +39 -0
  205. package/dist/modules/billing/components/account/accountRow.js.map +7 -0
  206. package/dist/modules/billing/components/customerNames.js +42 -0
  207. package/dist/modules/billing/components/customerNames.js.map +7 -0
  208. package/dist/modules/billing/data/entities.js +560 -4
  209. package/dist/modules/billing/data/entities.js.map +2 -2
  210. package/dist/modules/billing/data/entityIds.js +10 -1
  211. package/dist/modules/billing/data/entityIds.js.map +2 -2
  212. package/dist/modules/billing/data/validators.js +269 -15
  213. package/dist/modules/billing/data/validators.js.map +2 -2
  214. package/dist/modules/billing/events.js +50 -0
  215. package/dist/modules/billing/events.js.map +2 -2
  216. package/dist/modules/billing/i18n/de.json +880 -0
  217. package/dist/modules/billing/i18n/en.json +457 -21
  218. package/dist/modules/billing/i18n/es.json +880 -0
  219. package/dist/modules/billing/i18n/pl.json +458 -22
  220. package/dist/modules/billing/index.js +6 -2
  221. package/dist/modules/billing/index.js.map +2 -2
  222. package/dist/modules/billing/lib/accountFinancials.js +58 -0
  223. package/dist/modules/billing/lib/accountFinancials.js.map +7 -0
  224. package/dist/modules/billing/lib/accountLock.js +14 -0
  225. package/dist/modules/billing/lib/accountLock.js.map +7 -0
  226. package/dist/modules/billing/lib/accountStatus.js +9 -7
  227. package/dist/modules/billing/lib/accountStatus.js.map +2 -2
  228. package/dist/modules/billing/lib/accountSummary.js +106 -0
  229. package/dist/modules/billing/lib/accountSummary.js.map +7 -0
  230. package/dist/modules/billing/lib/allocation.js +356 -0
  231. package/dist/modules/billing/lib/allocation.js.map +7 -0
  232. package/dist/modules/billing/lib/allocationEvents.js +22 -0
  233. package/dist/modules/billing/lib/allocationEvents.js.map +7 -0
  234. package/dist/modules/billing/lib/billPeriod.js +15 -1
  235. package/dist/modules/billing/lib/billPeriod.js.map +2 -2
  236. package/dist/modules/billing/lib/billRunEngine.js +237 -102
  237. package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
  238. package/dist/modules/billing/lib/billingSettings.js +116 -0
  239. package/dist/modules/billing/lib/billingSettings.js.map +7 -0
  240. package/dist/modules/billing/lib/commandRoute.js +81 -0
  241. package/dist/modules/billing/lib/commandRoute.js.map +7 -0
  242. package/dist/modules/billing/lib/customerLookup.js +97 -0
  243. package/dist/modules/billing/lib/customerLookup.js.map +7 -0
  244. package/dist/modules/billing/lib/dateOnly.js +13 -0
  245. package/dist/modules/billing/lib/dateOnly.js.map +7 -0
  246. package/dist/modules/billing/lib/documentParties.js +16 -0
  247. package/dist/modules/billing/lib/documentParties.js.map +7 -0
  248. package/dist/modules/billing/lib/documentTypes.js +27 -0
  249. package/dist/modules/billing/lib/documentTypes.js.map +7 -0
  250. package/dist/modules/billing/lib/dueDate.js +18 -0
  251. package/dist/modules/billing/lib/dueDate.js.map +7 -0
  252. package/dist/modules/billing/lib/iban.js +29 -0
  253. package/dist/modules/billing/lib/iban.js.map +7 -0
  254. package/dist/modules/billing/lib/invoiceDelivery.js +133 -0
  255. package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
  256. package/dist/modules/billing/lib/invoiceLanguages.js +28 -0
  257. package/dist/modules/billing/lib/invoiceLanguages.js.map +7 -0
  258. package/dist/modules/billing/lib/invoiceWriter.js +107 -99
  259. package/dist/modules/billing/lib/invoiceWriter.js.map +2 -2
  260. package/dist/modules/billing/lib/itemBillingState.js +27 -0
  261. package/dist/modules/billing/lib/itemBillingState.js.map +7 -0
  262. package/dist/modules/billing/lib/itemPriceChange.js +18 -0
  263. package/dist/modules/billing/lib/itemPriceChange.js.map +7 -0
  264. package/dist/modules/billing/lib/itemSelector.js.map +2 -2
  265. package/dist/modules/billing/lib/lineAmounts.js +32 -0
  266. package/dist/modules/billing/lib/lineAmounts.js.map +7 -0
  267. package/dist/modules/billing/lib/memoGuards.js +25 -0
  268. package/dist/modules/billing/lib/memoGuards.js.map +7 -0
  269. package/dist/modules/billing/lib/navigation.js +48 -0
  270. package/dist/modules/billing/lib/navigation.js.map +7 -0
  271. package/dist/modules/billing/lib/numbering.js +120 -0
  272. package/dist/modules/billing/lib/numbering.js.map +7 -0
  273. package/dist/modules/billing/lib/overdue.js +36 -0
  274. package/dist/modules/billing/lib/overdue.js.map +7 -0
  275. package/dist/modules/billing/lib/paymentCsv.js +125 -0
  276. package/dist/modules/billing/lib/paymentCsv.js.map +7 -0
  277. package/dist/modules/billing/lib/paymentGateway.js +15 -0
  278. package/dist/modules/billing/lib/paymentGateway.js.map +7 -0
  279. package/dist/modules/billing/lib/paymentImport.js +164 -0
  280. package/dist/modules/billing/lib/paymentImport.js.map +7 -0
  281. package/dist/modules/billing/lib/paymentMatcher.js +36 -0
  282. package/dist/modules/billing/lib/paymentMatcher.js.map +7 -0
  283. package/dist/modules/billing/lib/pdf/attachmentStore.js +46 -0
  284. package/dist/modules/billing/lib/pdf/attachmentStore.js.map +7 -0
  285. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js +7 -0
  286. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js.map +7 -0
  287. package/dist/modules/billing/lib/pdf/invoiceModel.js +194 -0
  288. package/dist/modules/billing/lib/pdf/invoiceModel.js.map +7 -0
  289. package/dist/modules/billing/lib/pdf/invoicePdf.js +165 -0
  290. package/dist/modules/billing/lib/pdf/invoicePdf.js.map +7 -0
  291. package/dist/modules/billing/lib/pdf/invoiceTemplate.js +276 -0
  292. package/dist/modules/billing/lib/pdf/invoiceTemplate.js.map +7 -0
  293. package/dist/modules/billing/lib/prepaidConfig.js +17 -25
  294. package/dist/modules/billing/lib/prepaidConfig.js.map +2 -2
  295. package/dist/modules/billing/lib/prepaidConsume.js +26 -7
  296. package/dist/modules/billing/lib/prepaidConsume.js.map +2 -2
  297. package/dist/modules/billing/lib/prepaidPeriodClose.js +277 -158
  298. package/dist/modules/billing/lib/prepaidPeriodClose.js.map +2 -2
  299. package/dist/modules/billing/lib/prepaidTaxPoint.js +37 -0
  300. package/dist/modules/billing/lib/prepaidTaxPoint.js.map +7 -0
  301. package/dist/modules/billing/lib/seeds/demo.js +51 -3
  302. package/dist/modules/billing/lib/seeds/demo.js.map +2 -2
  303. package/dist/modules/billing/lib/seeds/paymentsSample.js +93 -0
  304. package/dist/modules/billing/lib/seeds/paymentsSample.js.map +7 -0
  305. package/dist/modules/billing/lib/seeds/sellerSettings.js +41 -0
  306. package/dist/modules/billing/lib/seeds/sellerSettings.js.map +7 -0
  307. package/dist/modules/billing/lib/servicePeriods.js +121 -0
  308. package/dist/modules/billing/lib/servicePeriods.js.map +7 -0
  309. package/dist/modules/billing/lib/testRunCleanup.js +24 -0
  310. package/dist/modules/billing/lib/testRunCleanup.js.map +7 -0
  311. package/dist/modules/billing/lib/topupCapture.js +2 -2
  312. package/dist/modules/billing/lib/topupCapture.js.map +2 -2
  313. package/dist/modules/billing/lib/topupReceipt.js +58 -79
  314. package/dist/modules/billing/lib/topupReceipt.js.map +2 -2
  315. package/dist/modules/billing/lib/usageRater.js.map +1 -1
  316. package/dist/modules/billing/lib/usageRunner.js +14 -6
  317. package/dist/modules/billing/lib/usageRunner.js.map +2 -2
  318. package/dist/modules/billing/lib/vat.js +39 -0
  319. package/dist/modules/billing/lib/vat.js.map +7 -0
  320. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js +15 -0
  321. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js.map +7 -0
  322. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js +25 -0
  323. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js.map +7 -0
  324. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js +115 -0
  325. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js.map +7 -0
  326. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js +47 -0
  327. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js.map +7 -0
  328. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js +89 -0
  329. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js.map +7 -0
  330. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js +17 -0
  331. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js.map +7 -0
  332. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js +27 -0
  333. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js.map +7 -0
  334. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js +29 -0
  335. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js.map +7 -0
  336. package/dist/modules/billing/setup.js +7 -184
  337. package/dist/modules/billing/setup.js.map +2 -2
  338. package/dist/modules/billing/subscribers/credit-memo-auto-send.js +16 -0
  339. package/dist/modules/billing/subscribers/credit-memo-auto-send.js.map +7 -0
  340. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js +16 -0
  341. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js.map +7 -0
  342. package/dist/modules/billing/subscribers/debit-memo-auto-send.js +16 -0
  343. package/dist/modules/billing/subscribers/debit-memo-auto-send.js.map +7 -0
  344. package/dist/modules/billing/subscribers/invoice-apply-credit.js +34 -0
  345. package/dist/modules/billing/subscribers/invoice-apply-credit.js.map +7 -0
  346. package/dist/modules/billing/subscribers/invoice-auto-send.js +30 -0
  347. package/dist/modules/billing/subscribers/invoice-auto-send.js.map +7 -0
  348. package/dist/modules/billing/subscribers/payment-captured-to-paid.js +69 -33
  349. package/dist/modules/billing/subscribers/payment-captured-to-paid.js.map +2 -2
  350. package/dist/modules/billing/subscribers/prepaid-topup-captured.js +4 -6
  351. package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +2 -2
  352. package/generated/entities/billing_account/index.ts +3 -0
  353. package/generated/entities/billing_allocation/index.ts +18 -0
  354. package/generated/entities/billing_document_sequence/index.ts +11 -0
  355. package/generated/entities/billing_invoice/index.ts +38 -0
  356. package/generated/entities/billing_invoice_line/index.ts +24 -0
  357. package/generated/entities/billing_item/index.ts +4 -0
  358. package/generated/entities/billing_payment/index.ts +25 -0
  359. package/generated/entities/billing_payment_import/index.ts +14 -0
  360. package/generated/entities/billing_run/index.ts +0 -1
  361. package/generated/entities/billing_run_outcome/index.ts +1 -0
  362. package/generated/entities/billing_settings/index.ts +26 -0
  363. package/generated/entities/billing_statement/index.ts +1 -0
  364. package/generated/entities.ids.generated.ts +7 -0
  365. package/package.json +5 -1
  366. package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +171 -0
  367. package/src/modules/billing/__integration__/TC-BILL-005.spec.ts +134 -0
  368. package/src/modules/billing/__integration__/TC-BILL-006.spec.ts +101 -0
  369. package/src/modules/billing/__integration__/TC-BILL-007.spec.ts +140 -0
  370. package/src/modules/billing/__integration__/TC-BILL-008.spec.ts +108 -0
  371. package/src/modules/billing/__integration__/TC-BILL-009.spec.ts +113 -0
  372. package/src/modules/billing/__integration__/TC-BILL-010.spec.ts +118 -0
  373. package/src/modules/billing/__integration__/TC-BILL-011.spec.ts +142 -0
  374. package/src/modules/billing/__integration__/TC-BILL-012.spec.ts +115 -0
  375. package/src/modules/billing/__integration__/TC-BILL-013.spec.ts +118 -0
  376. package/src/modules/billing/__integration__/sellerSettings.ts +24 -0
  377. package/src/modules/billing/__tests__/commands/invoices.test.ts +436 -354
  378. package/src/modules/billing/__tests__/commands/itemsBulk.test.ts +33 -0
  379. package/src/modules/billing/__tests__/commands/memos.test.ts +205 -0
  380. package/src/modules/billing/__tests__/commands/payments.test.ts +241 -0
  381. package/src/modules/billing/__tests__/commands/runsDelete.test.ts +146 -0
  382. package/src/modules/billing/__tests__/commands/runsPostDrafts.test.ts +106 -0
  383. package/src/modules/billing/__tests__/commands/topups.test.ts +11 -0
  384. package/src/modules/billing/__tests__/entityRegistry.test.ts +8 -1
  385. package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
  386. package/src/modules/billing/__tests__/i18n/dictionaries.test.ts +64 -0
  387. package/src/modules/billing/__tests__/lib/accountFinancials.test.ts +53 -0
  388. package/src/modules/billing/__tests__/lib/accountSummary.test.ts +97 -0
  389. package/src/modules/billing/__tests__/lib/allocation.test.ts +319 -0
  390. package/src/modules/billing/__tests__/lib/billRunEngine.test.ts +228 -17
  391. package/src/modules/billing/__tests__/lib/billingSettings.test.ts +109 -0
  392. package/src/modules/billing/__tests__/lib/customerLookup.test.ts +156 -0
  393. package/src/modules/billing/__tests__/lib/dueDate.test.ts +35 -0
  394. package/src/modules/billing/__tests__/lib/iban.test.ts +38 -0
  395. package/src/modules/billing/__tests__/lib/invoiceDelivery.test.ts +206 -0
  396. package/src/modules/billing/__tests__/lib/invoiceLanguages.test.ts +49 -0
  397. package/src/modules/billing/__tests__/lib/invoiceWriter.test.ts +212 -10
  398. package/src/modules/billing/__tests__/lib/itemBillingState.test.ts +42 -0
  399. package/src/modules/billing/__tests__/lib/itemPriceChange.test.ts +165 -0
  400. package/src/modules/billing/__tests__/lib/lineAmounts.test.ts +86 -0
  401. package/src/modules/billing/__tests__/lib/navigation.test.ts +71 -0
  402. package/src/modules/billing/__tests__/lib/numbering.test.ts +91 -0
  403. package/src/modules/billing/__tests__/lib/overdue.test.ts +36 -0
  404. package/src/modules/billing/__tests__/lib/paymentCsv.test.ts +148 -0
  405. package/src/modules/billing/__tests__/lib/paymentImport.test.ts +113 -0
  406. package/src/modules/billing/__tests__/lib/paymentsSample.test.ts +73 -0
  407. package/src/modules/billing/__tests__/lib/pdf/invoicePdf.test.ts +269 -0
  408. package/src/modules/billing/__tests__/lib/pdf/invoicePdfService.test.ts +147 -0
  409. package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +374 -98
  410. package/src/modules/billing/__tests__/lib/prepaidTaxPoint.test.ts +118 -0
  411. package/src/modules/billing/__tests__/lib/seedsDemo.test.ts +53 -2
  412. package/src/modules/billing/__tests__/lib/sellerSettings.test.ts +28 -0
  413. package/src/modules/billing/__tests__/lib/servicePeriods.test.ts +190 -0
  414. package/src/modules/billing/__tests__/lib/topupCapture.test.ts +6 -28
  415. package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +21 -52
  416. package/src/modules/billing/__tests__/lib/vat.test.ts +51 -0
  417. package/src/modules/billing/__tests__/package-isolation.test.ts +22 -8
  418. package/src/modules/billing/__tests__/setup.test.ts +13 -4
  419. package/src/modules/billing/__tests__/validators.test.ts +197 -3
  420. package/src/modules/billing/acl.ts +12 -0
  421. package/src/modules/billing/api/accounts/[id]/summary/route.ts +62 -0
  422. package/src/modules/billing/api/accounts/route.ts +59 -4
  423. package/src/modules/billing/api/export/account/[id]/route.ts +13 -11
  424. package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
  425. package/src/modules/billing/api/invoices/[id]/pdf/route.ts +80 -0
  426. package/src/modules/billing/api/invoices/[id]/route.ts +57 -70
  427. package/src/modules/billing/api/invoices/[id]/send/route.ts +127 -0
  428. package/src/modules/billing/api/invoices/add-line/route.ts +2 -2
  429. package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
  430. package/src/modules/billing/api/invoices/edit-line/route.ts +2 -2
  431. package/src/modules/billing/api/invoices/post/route.ts +7 -6
  432. package/src/modules/billing/api/invoices/remove-line/route.ts +2 -2
  433. package/src/modules/billing/api/invoices/route.ts +81 -86
  434. package/src/modules/billing/api/items/bulk/route.ts +2 -1
  435. package/src/modules/billing/api/items/change-price/route.ts +54 -0
  436. package/src/modules/billing/api/items/route.ts +23 -7
  437. package/src/modules/billing/api/payment-imports/[id]/route.ts +49 -0
  438. package/src/modules/billing/api/payment-imports/route.ts +57 -0
  439. package/src/modules/billing/api/payments/[id]/route.ts +63 -0
  440. package/src/modules/billing/api/payments/allocate/route.ts +35 -0
  441. package/src/modules/billing/api/payments/assign/route.ts +36 -0
  442. package/src/modules/billing/api/payments/convert-to-topup/route.ts +35 -0
  443. package/src/modules/billing/api/payments/ignore/route.ts +35 -0
  444. package/src/modules/billing/api/payments/import/route.ts +72 -0
  445. package/src/modules/billing/api/payments/restore/route.ts +35 -0
  446. package/src/modules/billing/api/payments/route.ts +147 -0
  447. package/src/modules/billing/api/payments/unallocate/route.ts +35 -0
  448. package/src/modules/billing/api/payments/unassign/route.ts +35 -0
  449. package/src/modules/billing/api/run-outcomes/route.ts +49 -6
  450. package/src/modules/billing/api/runs/[id]/post-drafts/route.ts +71 -0
  451. package/src/modules/billing/api/runs/[id]/route.ts +59 -0
  452. package/src/modules/billing/api/runs/retry-failed/route.ts +2 -1
  453. package/src/modules/billing/api/runs/route.ts +15 -7
  454. package/src/modules/billing/api/settings/number-preview/route.ts +46 -0
  455. package/src/modules/billing/api/settings/route.ts +116 -0
  456. package/src/modules/billing/api/statements/route.ts +5 -0
  457. package/src/modules/billing/api/test-invoices/wipe/route.ts +2 -2
  458. package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +151 -372
  459. package/src/modules/billing/backend/billing/accounts/create/page.tsx +6 -0
  460. package/src/modules/billing/backend/billing/accounts/page.tsx +70 -4
  461. package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +444 -95
  462. package/src/modules/billing/backend/billing/invoices/page.tsx +8 -227
  463. package/src/modules/billing/backend/billing/items/[id]/page.tsx +75 -6
  464. package/src/modules/billing/backend/billing/items/create/page.tsx +13 -8
  465. package/src/modules/billing/backend/billing/items/page.tsx +18 -2
  466. package/src/modules/billing/backend/billing/payments/[id]/page.meta.ts +19 -0
  467. package/src/modules/billing/backend/billing/payments/[id]/page.tsx +415 -0
  468. package/src/modules/billing/backend/billing/payments/imports/[id]/page.meta.ts +19 -0
  469. package/src/modules/billing/backend/billing/payments/imports/[id]/page.tsx +106 -0
  470. package/src/modules/billing/backend/billing/payments/page.meta.ts +16 -0
  471. package/src/modules/billing/backend/billing/payments/page.tsx +56 -0
  472. package/src/modules/billing/backend/billing/runs/[id]/page.tsx +49 -18
  473. package/src/modules/billing/backend/billing/runs/page.tsx +59 -8
  474. package/src/modules/billing/backend/billing/statements/[id]/page.tsx +86 -5
  475. package/src/modules/billing/backend/billing/statements/page.tsx +1 -1
  476. package/src/modules/billing/backend/billing/topups/page.tsx +1 -1
  477. package/src/modules/billing/backend/billing/transactions/page.tsx +1 -1
  478. package/src/modules/billing/backend/billing/usage/create/page.tsx +3 -2
  479. package/src/modules/billing/backend/config/billing/page.meta.ts +21 -0
  480. package/src/modules/billing/backend/config/billing/page.tsx +549 -0
  481. package/src/modules/billing/cli.ts +31 -1
  482. package/src/modules/billing/commands/accounts.ts +6 -0
  483. package/src/modules/billing/commands/index.ts +3 -0
  484. package/src/modules/billing/commands/invoices.ts +364 -231
  485. package/src/modules/billing/commands/items.ts +143 -0
  486. package/src/modules/billing/commands/memos.ts +218 -0
  487. package/src/modules/billing/commands/payments.ts +428 -0
  488. package/src/modules/billing/commands/runs.ts +205 -3
  489. package/src/modules/billing/commands/settings.ts +77 -0
  490. package/src/modules/billing/commands/topups.ts +12 -3
  491. package/src/modules/billing/commands/transactions.ts +2 -2
  492. package/src/modules/billing/components/AccountForm.tsx +199 -53
  493. package/src/modules/billing/components/AccountInvoicesSection.tsx +75 -0
  494. package/src/modules/billing/components/AccountPaymentsSection.tsx +42 -0
  495. package/src/modules/billing/components/AccountPicker.tsx +70 -0
  496. package/src/modules/billing/components/AllocatePaymentDialog.tsx +167 -0
  497. package/src/modules/billing/components/BillingDataTable.tsx +34 -0
  498. package/src/modules/billing/components/BillingSettingsLink.tsx +25 -0
  499. package/src/modules/billing/components/ChangeItemPriceDialog.tsx +180 -0
  500. package/src/modules/billing/components/CreateMemoDialog.tsx +232 -0
  501. package/src/modules/billing/components/CustomerLabel.tsx +53 -0
  502. package/src/modules/billing/components/InvoicesTable.tsx +344 -0
  503. package/src/modules/billing/components/ItemForm.tsx +233 -44
  504. package/src/modules/billing/components/ItemPriceField.tsx +81 -0
  505. package/src/modules/billing/components/LineFormDialog.tsx +25 -1
  506. package/src/modules/billing/components/ManualPaymentDialog.tsx +140 -0
  507. package/src/modules/billing/components/MoneyInput.tsx +26 -0
  508. package/src/modules/billing/components/PaymentUploadDialog.tsx +148 -0
  509. package/src/modules/billing/components/PaymentsTable.tsx +213 -0
  510. package/src/modules/billing/components/PostRunDraftsButton.tsx +129 -0
  511. package/src/modules/billing/components/PrepaidPanel.tsx +19 -6
  512. package/src/modules/billing/components/RunCyclesSection.tsx +298 -0
  513. package/src/modules/billing/components/TestRunActions.tsx +152 -0
  514. package/src/modules/billing/components/account/AccountItemsTab.tsx +192 -0
  515. package/src/modules/billing/components/account/AccountRunBillingDialog.tsx +147 -0
  516. package/src/modules/billing/components/account/AccountRunsTab.tsx +201 -0
  517. package/src/modules/billing/components/account/AccountStatementsTab.tsx +120 -0
  518. package/src/modules/billing/components/account/AccountSummaryCards.tsx +153 -0
  519. package/src/modules/billing/components/account/AccountUsageTab.tsx +122 -0
  520. package/src/modules/billing/components/account/AccountView.tsx +101 -0
  521. package/src/modules/billing/components/account/accountRow.ts +70 -0
  522. package/src/modules/billing/components/customerNames.ts +62 -0
  523. package/src/modules/billing/data/entities.ts +656 -6
  524. package/src/modules/billing/data/entityIds.ts +9 -0
  525. package/src/modules/billing/data/validators.ts +388 -8
  526. package/src/modules/billing/events.ts +56 -3
  527. package/src/modules/billing/i18n/de.json +880 -0
  528. package/src/modules/billing/i18n/en.json +457 -21
  529. package/src/modules/billing/i18n/es.json +880 -0
  530. package/src/modules/billing/i18n/pl.json +458 -22
  531. package/src/modules/billing/index.ts +6 -2
  532. package/src/modules/billing/lib/accountFinancials.ts +84 -0
  533. package/src/modules/billing/lib/accountLock.ts +32 -0
  534. package/src/modules/billing/lib/accountStatus.ts +11 -9
  535. package/src/modules/billing/lib/accountSummary.ts +172 -0
  536. package/src/modules/billing/lib/allocation.ts +515 -0
  537. package/src/modules/billing/lib/allocationEvents.ts +26 -0
  538. package/src/modules/billing/lib/billPeriod.ts +19 -0
  539. package/src/modules/billing/lib/billRunEngine.ts +350 -150
  540. package/src/modules/billing/lib/billingSettings.ts +145 -0
  541. package/src/modules/billing/lib/commandRoute.ts +112 -0
  542. package/src/modules/billing/lib/customerLookup.ts +157 -0
  543. package/src/modules/billing/lib/dateOnly.ts +22 -0
  544. package/src/modules/billing/lib/documentParties.ts +23 -0
  545. package/src/modules/billing/lib/documentTypes.ts +37 -0
  546. package/src/modules/billing/lib/dueDate.ts +26 -0
  547. package/src/modules/billing/lib/iban.ts +36 -0
  548. package/src/modules/billing/lib/invoiceDelivery.ts +196 -0
  549. package/src/modules/billing/lib/invoiceLanguages.ts +57 -0
  550. package/src/modules/billing/lib/invoiceWriter.ts +162 -148
  551. package/src/modules/billing/lib/itemBillingState.ts +67 -0
  552. package/src/modules/billing/lib/itemPriceChange.ts +56 -0
  553. package/src/modules/billing/lib/itemSelector.ts +4 -1
  554. package/src/modules/billing/lib/lineAmounts.ts +61 -0
  555. package/src/modules/billing/lib/memoGuards.ts +41 -0
  556. package/src/modules/billing/lib/navigation.ts +64 -0
  557. package/src/modules/billing/lib/numbering.ts +174 -0
  558. package/src/modules/billing/lib/overdue.ts +60 -0
  559. package/src/modules/billing/lib/paymentCsv.ts +171 -0
  560. package/src/modules/billing/lib/paymentGateway.ts +52 -0
  561. package/src/modules/billing/lib/paymentImport.ts +228 -0
  562. package/src/modules/billing/lib/paymentMatcher.ts +88 -0
  563. package/src/modules/billing/lib/pdf/attachmentStore.ts +60 -0
  564. package/src/modules/billing/lib/pdf/fonts/NotoSans-Bold.ttf +0 -0
  565. package/src/modules/billing/lib/pdf/fonts/NotoSans-Regular.ttf +0 -0
  566. package/src/modules/billing/lib/pdf/fonts/OFL.txt +93 -0
  567. package/src/modules/billing/lib/pdf/fonts/embeddedFonts.ts +9 -0
  568. package/src/modules/billing/lib/pdf/invoiceModel.ts +329 -0
  569. package/src/modules/billing/lib/pdf/invoicePdf.ts +220 -0
  570. package/src/modules/billing/lib/pdf/invoiceTemplate.ts +338 -0
  571. package/src/modules/billing/lib/prepaidConfig.ts +27 -36
  572. package/src/modules/billing/lib/prepaidConsume.ts +29 -6
  573. package/src/modules/billing/lib/prepaidPeriodClose.ts +407 -239
  574. package/src/modules/billing/lib/prepaidTaxPoint.ts +76 -0
  575. package/src/modules/billing/lib/seeds/demo.ts +79 -6
  576. package/src/modules/billing/lib/seeds/paymentsSample.ts +136 -0
  577. package/src/modules/billing/lib/seeds/sellerSettings.ts +78 -0
  578. package/src/modules/billing/lib/servicePeriods.ts +226 -0
  579. package/src/modules/billing/lib/testRunCleanup.ts +42 -0
  580. package/src/modules/billing/lib/topupCapture.ts +3 -4
  581. package/src/modules/billing/lib/topupReceipt.ts +70 -103
  582. package/src/modules/billing/lib/usageRater.ts +1 -1
  583. package/src/modules/billing/lib/usageRunner.ts +17 -5
  584. package/src/modules/billing/lib/vat.ts +56 -0
  585. package/src/modules/billing/migrations/Migration20261114000000_billing_customer_kind.ts +25 -0
  586. package/src/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.ts +37 -0
  587. package/src/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.ts +132 -0
  588. package/src/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.ts +58 -0
  589. package/src/modules/billing/migrations/Migration20261117000000_billing_payments.ts +97 -0
  590. package/src/modules/billing/migrations/Migration20261118000000_billing_memos.ts +21 -0
  591. package/src/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.ts +39 -0
  592. package/src/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.ts +35 -0
  593. package/src/modules/billing/setup.ts +11 -237
  594. package/src/modules/billing/subscribers/credit-memo-auto-send.ts +15 -0
  595. package/src/modules/billing/subscribers/debit-memo-apply-credit.ts +15 -0
  596. package/src/modules/billing/subscribers/debit-memo-auto-send.ts +15 -0
  597. package/src/modules/billing/subscribers/invoice-apply-credit.ts +39 -0
  598. package/src/modules/billing/subscribers/invoice-auto-send.ts +46 -0
  599. package/src/modules/billing/subscribers/payment-captured-to-paid.ts +84 -62
  600. package/src/modules/billing/subscribers/prepaid-topup-captured.ts +4 -8
  601. package/dist/modules/billing/lib/invoiceStatus.js +0 -38
  602. package/dist/modules/billing/lib/invoiceStatus.js.map +0 -7
  603. package/src/modules/billing/__tests__/lib/invoiceStatus.test.ts +0 -97
  604. package/src/modules/billing/lib/invoiceStatus.ts +0 -61
@@ -1,13 +1,13 @@
1
1
  "use client"
2
2
  import * as React from 'react'
3
3
  import Link from 'next/link'
4
- import { useParams } from 'next/navigation'
4
+ import { useParams, useRouter, useSearchParams } from 'next/navigation'
5
5
  import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
6
- import { Pencil, Plus, Trash2 } from 'lucide-react'
6
+ import { FileDown, Mail, Pencil, Plus, Trash2 } from 'lucide-react'
7
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
8
8
  import { Page, PageBody, PageHeader } from '@open-mercato/ui/backend/Page'
9
9
  import { FormHeader } from '@open-mercato/ui/backend/forms'
10
- import { DataTable } from '@open-mercato/ui/backend/DataTable'
10
+ import { BillingDataTable as DataTable } from '../../../../components/BillingDataTable'
11
11
  import { Tag } from '@open-mercato/ui/primitives/tag'
12
12
  import { Button } from '@open-mercato/ui/primitives/button'
13
13
  import { IconButton } from '@open-mercato/ui/primitives/icon-button'
@@ -20,6 +20,7 @@ import {
20
20
  } from '@open-mercato/ui/backend/utils/apiCall'
21
21
  import { normalizeCrudServerError } from '@open-mercato/ui/backend/utils/serverErrors'
22
22
  import { LineFormDialog, type LineFormValues } from '../../../../components/LineFormDialog'
23
+ import { BillingSettingsLink } from '../../../../components/BillingSettingsLink'
23
24
  import {
24
25
  DetailCard,
25
26
  DetailField,
@@ -27,51 +28,95 @@ import {
27
28
  StatCard,
28
29
  } from '../../../../components/DetailFields'
29
30
  import { billRunName } from '../../../../lib/billRunLabel'
31
+ import { invoicePdfHref, resolveInvoiceReturnTarget } from '../../../../lib/navigation'
32
+ import { CreateMemoDialog } from '../../../../components/CreateMemoDialog'
30
33
 
34
+ // Spec 0: billing_invoices / billing_invoice_lines field names.
31
35
  type BillingInvoice = {
32
36
  id: string
33
- invoice_number: string
34
- status: 'draft' | 'posted' | 'paid' | 'void' | null
37
+ number: string
38
+ document_type: 'invoice' | 'credit_memo' | 'debit_memo' | 'receipt'
39
+ status: 'draft' | 'posted' | 'partially_paid' | 'paid' | 'credited'
40
+ test_run: boolean
41
+ bill_account_id: string
42
+ bill_account_name: string | null
43
+ bill_run_id: string | null
44
+ bill_date: string | null
45
+ period_start: string | null
46
+ period_end: string | null
35
47
  currency_code: string
36
48
  issue_date: string | null
37
49
  due_date: string | null
38
- subtotal_net_amount: string
39
- grand_total_net_amount: string
40
- grand_total_gross_amount: string
41
- paid_total_amount: string
42
- outstanding_amount: string
43
- metadata: {
44
- bill_run_id?: string
45
- bill_account_id?: string
46
- bill_period_start?: string
47
- bill_period_end?: string
48
- test_run?: boolean
49
- } | null
50
+ subtotal_net: string
51
+ tax_total: string
52
+ total_gross: string
53
+ paid_total: string
54
+ outstanding: string
55
+ days_overdue?: number
56
+ pdf_attachment_id?: string | null
57
+ // Spec D — corrective documents
58
+ corrects_invoice_id?: string | null
59
+ corrects_invoice_number?: string | null
60
+ correction_reason?: string | null
61
+ buyer_snapshot?: { invoice_email?: string } | null
62
+ metadata?: { draft_number?: string; deliveries?: InvoiceDelivery[] } | null
50
63
  created_at: string
51
64
  updated_at: string
52
65
  }
53
66
 
67
+ // Spec B: one entry per email attempt (metadata.deliveries).
68
+ type InvoiceDelivery = {
69
+ at: string
70
+ to: string
71
+ status: 'sent' | 'failed'
72
+ error?: string | null
73
+ trigger: 'manual' | 'auto'
74
+ }
75
+
54
76
  type InvoiceLine = {
55
77
  id: string
56
78
  line_number: number
57
- kind: string
79
+ billing_type: string
58
80
  description: string | null
59
81
  quantity: string
60
82
  currency_code: string
61
83
  unit_price_net: string
62
- total_net_amount: string
63
- total_gross_amount: string
64
- metadata: {
65
- billing_item_id?: string
66
- billing_type?: 'one_time' | 'recurring' | 'usage'
67
- operator_added?: boolean
68
- usage_tier_breakdown?: unknown
69
- } | null
84
+ tax_rate: string | number | null
85
+ net_amount: string
86
+ tax_amount: string
87
+ gross_amount: string
88
+ service_period_start: string | null
89
+ service_period_end: string | null
90
+ metadata: { operator_added?: boolean; usage_tier_breakdown?: unknown } | null
91
+ }
92
+
93
+ // Spec C: what settled this receivable (payments; Spec D: credit memos).
94
+ type InvoiceAllocation = {
95
+ id: string
96
+ source_type: 'payment' | 'credit_memo'
97
+ source_id: string
98
+ source_label: string | null
99
+ amount: string
100
+ currency_code: string
101
+ allocated_by: string
102
+ created_at: string
70
103
  }
71
104
 
72
105
  type DetailResponse = {
73
106
  invoice: BillingInvoice
74
107
  lines: InvoiceLine[]
108
+ allocations?: InvoiceAllocation[]
109
+ corrections?: InvoiceCorrection[]
110
+ }
111
+
112
+ // Spec D: memos correcting this document.
113
+ type InvoiceCorrection = {
114
+ id: string
115
+ number: string
116
+ document_type: 'credit_memo' | 'debit_memo'
117
+ status: string
118
+ total_gross: string
119
+ currency_code: string
75
120
  }
76
121
 
77
122
  function statusVariant(
@@ -79,11 +124,11 @@ function statusVariant(
79
124
  ): 'default' | 'success' | 'warning' | 'error' {
80
125
  switch (status) {
81
126
  case 'paid':
127
+ case 'credited':
82
128
  return 'success'
83
129
  case 'posted':
130
+ case 'partially_paid':
84
131
  return 'warning'
85
- case 'void':
86
- return 'error'
87
132
  case 'draft':
88
133
  default:
89
134
  return 'default'
@@ -91,11 +136,7 @@ function statusVariant(
91
136
  }
92
137
 
93
138
  function lineKindVariant(
94
- type: InvoiceLine['metadata'] extends infer M
95
- ? M extends { billing_type?: infer T }
96
- ? T
97
- : never
98
- : never,
139
+ type: string,
99
140
  ): 'default' | 'success' | 'warning' | 'error' {
100
141
  switch (type) {
101
142
  case 'one_time':
@@ -135,7 +176,7 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
135
176
  const [error, setError] = React.useState<string | null>(null)
136
177
  const [loading, setLoading] = React.useState(true)
137
178
  const [posting, setPosting] = React.useState(false)
138
- const [wiping, setWiping] = React.useState(false)
179
+ const [settingsIncomplete, setSettingsIncomplete] = React.useState(false)
139
180
 
140
181
  // Client-side pagination for invoice lines. Caps the table at 100 rows
141
182
  // per page (per the OM DataTable convention) — invoices typically have
@@ -154,9 +195,106 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
154
195
  const [dialogTargetLine, setDialogTargetLine] = React.useState<InvoiceLine | null>(null)
155
196
  const [dialogSubmitting, setDialogSubmitting] = React.useState(false)
156
197
 
157
- // Confirm flows: wipe-test + remove-line both use ConfirmDialog
198
+ // Confirm flows (remove line, send, memo delete) use ConfirmDialog
158
199
  // (per UI AGENTS.md: NEVER `window.confirm`).
159
200
  const { confirm, ConfirmDialogElement } = useConfirmDialog()
201
+ const [allocations, setAllocations] = React.useState<InvoiceAllocation[]>([])
202
+ const [corrections, setCorrections] = React.useState<InvoiceCorrection[]>([])
203
+ const [memoDialog, setMemoDialog] = React.useState<'credit_memo' | 'debit_memo' | null>(null)
204
+ const router = useRouter()
205
+ const correctionColumns = React.useMemo<ColumnDef<InvoiceCorrection>[]>(
206
+ () => [
207
+ {
208
+ accessorKey: 'number',
209
+ header: t('billing.invoices.columns.number', 'Number'),
210
+ cell: ({ row }) => (
211
+ <Link href={`/backend/billing/invoices/${row.original.id}`} className="text-primary hover:underline">
212
+ {row.original.number}
213
+ </Link>
214
+ ),
215
+ },
216
+ {
217
+ accessorKey: 'document_type',
218
+ header: t('billing.invoices.columns.type', 'Type'),
219
+ cell: ({ row }) =>
220
+ row.original.document_type === 'credit_memo'
221
+ ? t('billing.invoices.document_type.credit_memo', 'Credit memo')
222
+ : t('billing.invoices.document_type.debit_memo', 'Debit memo'),
223
+ },
224
+ { accessorKey: 'status', header: t('billing.invoices.columns.status', 'Status') },
225
+ {
226
+ accessorKey: 'total_gross',
227
+ header: t('billing.invoices.columns.total', 'Total'),
228
+ cell: ({ row }) =>
229
+ formatMoney(
230
+ String((row.original.document_type === 'credit_memo' ? -1 : 1) * Number.parseFloat(row.original.total_gross)),
231
+ row.original.currency_code,
232
+ ),
233
+ },
234
+ ],
235
+ [t],
236
+ )
237
+ const handleDeleteDraftMemo = React.useCallback(async () => {
238
+ if (!invoice) return
239
+ const ok = await confirm({
240
+ title: t('billing.memo.delete.confirm', 'Delete this draft memo?'),
241
+ text: t('billing.memo.delete.text', 'The draft and its lines are removed. Posted documents are never deleted.'),
242
+ confirmText: t('billing.memo.delete.action', 'Delete draft'),
243
+ variant: 'destructive',
244
+ })
245
+ if (!ok) return
246
+ try {
247
+ await apiCallOrThrow('/api/billing/invoices/delete-draft', {
248
+ method: 'POST',
249
+ headers: { 'Content-Type': 'application/json' },
250
+ body: JSON.stringify({ invoiceId: invoice.id }),
251
+ })
252
+ flash(t('billing.memo.deleted', 'Draft memo deleted'), 'success')
253
+ router.push(invoice.corrects_invoice_id ? `/backend/billing/invoices/${invoice.corrects_invoice_id}` : '/backend/billing/invoices')
254
+ } catch (err) {
255
+ flash(normalizeCrudServerError(err).message || t('billing.memo.delete.failed', 'Could not delete the draft'), 'error')
256
+ }
257
+ }, [confirm, invoice, router, t])
258
+ const allocationColumns = React.useMemo<ColumnDef<InvoiceAllocation>[]>(
259
+ () => [
260
+ {
261
+ accessorKey: 'source_label',
262
+ header: t('billing.invoices.payments.source', 'Source'),
263
+ cell: ({ row }) => (
264
+ <Link
265
+ href={
266
+ row.original.source_type === 'payment'
267
+ ? `/backend/billing/payments/${row.original.source_id}`
268
+ : `/backend/billing/invoices/${row.original.source_id}`
269
+ }
270
+ className="text-primary hover:underline"
271
+ >
272
+ {row.original.source_type === 'payment'
273
+ ? `${t('billing.invoices.payments.payment', 'Payment')}${row.original.source_label ? ` · ${row.original.source_label}` : ''}`
274
+ : `${t('billing.invoices.payments.credit_memo', 'Credit memo')} ${row.original.source_label ?? ''}`}
275
+ </Link>
276
+ ),
277
+ meta: { truncate: true, maxWidth: '320px' },
278
+ },
279
+ {
280
+ accessorKey: 'amount',
281
+ header: t('billing.payments.columns.amount', 'Amount'),
282
+ cell: ({ row }) => formatMoney(row.original.amount, row.original.currency_code),
283
+ },
284
+ {
285
+ accessorKey: 'created_at',
286
+ header: t('billing.payments.allocations.at', 'When'),
287
+ cell: ({ row }) => new Date(row.original.created_at).toLocaleDateString(),
288
+ },
289
+ ],
290
+ [t],
291
+ )
292
+ const searchParams = useSearchParams()
293
+ const backHref = resolveInvoiceReturnTarget({
294
+ from: searchParams?.get('from'),
295
+ accountId: searchParams?.get('accountId'),
296
+ })
297
+ const [sending, setSending] = React.useState(false)
160
298
 
161
299
  const load = React.useCallback(async () => {
162
300
  if (!invoiceId) return
@@ -168,6 +306,8 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
168
306
  )
169
307
  setInvoice(data.invoice)
170
308
  setLines(data.lines ?? [])
309
+ setAllocations(data.allocations ?? [])
310
+ setCorrections(data.corrections ?? [])
171
311
  } catch (err) {
172
312
  const { message } = normalizeCrudServerError(err)
173
313
  setError(message || t('billing.invoices.detail.error.load', 'Failed to load invoice'))
@@ -182,8 +322,8 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
182
322
 
183
323
  // Resolve the FK names once the invoice is loaded (one bounded
184
324
  // request each — Bill Run name is derived from its as-of date).
185
- const billRunId = invoice?.metadata?.bill_run_id
186
- const billAccountId = invoice?.metadata?.bill_account_id
325
+ const billRunId = invoice?.bill_run_id
326
+ const billAccountId = invoice?.bill_account_id
187
327
  React.useEffect(() => {
188
328
  if (billAccountId) {
189
329
  readApiResultOrThrow<{ items: Array<{ name: string }> }>(
@@ -218,55 +358,60 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
218
358
  )
219
359
  flash(
220
360
  t('billing.invoices.post.success', 'Invoice posted') +
221
- ` (${call.result?.invoiceNumber ?? invoice.invoice_number})`,
361
+ ` (${call.result?.invoiceNumber ?? invoice.number})`,
222
362
  'success',
223
363
  )
224
364
  void load()
225
365
  } catch (err) {
226
366
  const { message } = normalizeCrudServerError(err)
227
- flash(message || t('billing.invoices.post.error', 'Post failed'), 'error')
367
+ const code = (err as { body?: { code?: string } } | null)?.body?.code
368
+ if (code === 'billing.settings.incomplete') setSettingsIncomplete(true)
369
+ flash(
370
+ code === 'billing.settings.incomplete'
371
+ ? t(
372
+ 'billing.invoices.post.settings_incomplete',
373
+ 'Fill in the seller details in Settings → Billing before posting invoices.',
374
+ )
375
+ : message || t('billing.invoices.post.error', 'Post failed'),
376
+ 'error',
377
+ )
228
378
  } finally {
229
379
  setPosting(false)
230
380
  }
231
381
  }, [invoice, load, t])
232
382
 
233
- const handleWipeTest = React.useCallback(async () => {
383
+ const handleSend = React.useCallback(async () => {
234
384
  if (!invoice) return
385
+ const recipient = invoice.buyer_snapshot?.invoice_email ?? ''
386
+ const alreadySent = (invoice.metadata?.deliveries ?? []).some((d) => d.status === 'sent')
235
387
  const ok = await confirm({
236
- title: t('billing.invoices.wipe.confirm.title', 'Wipe test invoices?'),
237
- text: t(
238
- 'billing.invoices.wipe.confirm.text',
239
- 'Every test invoice from this Bill Run will be permanently deleted. This cannot be undone.',
240
- ),
241
- confirmText: t('billing.invoices.wipe.confirm.button', 'Delete test invoices'),
242
- variant: 'destructive',
388
+ title: alreadySent
389
+ ? t('billing.invoices.send.confirm.title_resend', 'Resend invoice?')
390
+ : t('billing.invoices.send.confirm.title', 'Send invoice?'),
391
+ text: t('billing.invoices.send.confirm.text', 'The PDF is emailed to {email}.').replace('{email}', recipient),
392
+ confirmText: t('billing.invoices.send.action', 'Send'),
243
393
  })
244
394
  if (!ok) return
245
- setWiping(true)
395
+ setSending(true)
246
396
  try {
247
- const billRunId = invoice.metadata?.bill_run_id
248
- const call = await apiCallOrThrow<{ invoicesRemoved: number }>(
249
- '/api/billing/test-invoices/wipe',
250
- {
251
- method: 'POST',
252
- headers: { 'Content-Type': 'application/json' },
253
- body: JSON.stringify(billRunId ? { billRunId } : {}),
254
- },
255
- )
256
- flash(
257
- t('billing.invoices.wipe.success', 'Test invoices removed') +
258
- ` (${call.result?.invoicesRemoved ?? 0})`,
259
- 'success',
397
+ const call = await apiCallOrThrow<{ status: 'sent' | 'failed'; error?: string | null }>(
398
+ `/api/billing/invoices/${encodeURIComponent(invoice.id)}/send`,
399
+ { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' },
260
400
  )
261
- // The invoice we were looking at is hard-deleted — navigate away
262
- // on success by reloading; the detail load will 404 and the
263
- // user clicks back.
401
+ if (call.result?.status === 'sent') {
402
+ flash(t('billing.invoices.send.success', 'Invoice sent'), 'success')
403
+ } else {
404
+ flash(
405
+ `${t('billing.invoices.send.failed', 'Sending failed')}${call.result?.error ? `: ${call.result.error}` : ''}`,
406
+ 'error',
407
+ )
408
+ }
264
409
  void load()
265
410
  } catch (err) {
266
411
  const { message } = normalizeCrudServerError(err)
267
- flash(message || t('billing.invoices.wipe.error', 'Wipe failed'), 'error')
412
+ flash(message || t('billing.invoices.send.failed', 'Sending failed'), 'error')
268
413
  } finally {
269
- setWiping(false)
414
+ setSending(false)
270
415
  }
271
416
  }, [confirm, invoice, load, t])
272
417
 
@@ -286,6 +431,7 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
286
431
  description: values.description,
287
432
  quantity: values.quantity,
288
433
  unitPriceNet: values.unitPriceNet,
434
+ ...(values.taxRate !== undefined ? { taxRate: values.taxRate } : {}),
289
435
  }),
290
436
  })
291
437
  flash(t('billing.invoices.lines.add.success', 'Line added'), 'success')
@@ -303,6 +449,7 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
303
449
  ...(values.totalNetAmount !== undefined
304
450
  ? { totalNetAmount: values.totalNetAmount }
305
451
  : {}),
452
+ ...(values.taxRate !== undefined ? { taxRate: values.taxRate } : {}),
306
453
  },
307
454
  }),
308
455
  })
@@ -355,6 +502,47 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
355
502
 
356
503
  const canEditLines = invoice?.status === 'draft'
357
504
 
505
+ // Newest first; deliveries are a short, append-only log on the invoice.
506
+ const deliveries = React.useMemo(
507
+ () => [...(invoice?.metadata?.deliveries ?? [])].reverse(),
508
+ [invoice?.metadata?.deliveries],
509
+ )
510
+ const deliveryColumns = React.useMemo<ColumnDef<InvoiceDelivery>[]>(
511
+ () => [
512
+ {
513
+ accessorKey: 'at',
514
+ header: t('billing.invoices.deliveries.columns.at', 'When'),
515
+ cell: ({ row }) => new Date(row.original.at).toLocaleString(),
516
+ },
517
+ { accessorKey: 'to', header: t('billing.invoices.deliveries.columns.to', 'Recipient') },
518
+ {
519
+ accessorKey: 'status',
520
+ header: t('billing.invoices.deliveries.columns.status', 'Status'),
521
+ cell: ({ row }) =>
522
+ row.original.status === 'sent' ? (
523
+ <Tag variant="success">{t('billing.invoices.deliveries.status.sent', 'Sent')}</Tag>
524
+ ) : (
525
+ <Tag variant="error">{t('billing.invoices.deliveries.status.failed', 'Failed')}</Tag>
526
+ ),
527
+ },
528
+ {
529
+ accessorKey: 'trigger',
530
+ header: t('billing.invoices.deliveries.columns.trigger', 'Trigger'),
531
+ cell: ({ row }) =>
532
+ row.original.trigger === 'auto'
533
+ ? t('billing.invoices.deliveries.trigger.auto', 'Automatic')
534
+ : t('billing.invoices.deliveries.trigger.manual', 'Manual'),
535
+ },
536
+ {
537
+ accessorKey: 'error',
538
+ header: t('billing.invoices.deliveries.columns.error', 'Error'),
539
+ cell: ({ row }) => row.original.error ?? '—',
540
+ meta: { truncate: true, maxWidth: '280px' },
541
+ },
542
+ ],
543
+ [t],
544
+ )
545
+
358
546
  const lineColumns = React.useMemo<ColumnDef<InvoiceLine>[]>(
359
547
  () => [
360
548
  {
@@ -365,7 +553,7 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
365
553
  accessorKey: 'description',
366
554
  header: t('billing.invoices.lines.columns.description', 'Description'),
367
555
  cell: ({ row }) => {
368
- const type = row.original.metadata?.billing_type
556
+ const type = row.original.billing_type
369
557
  const operatorAdded = row.original.metadata?.operator_added === true
370
558
  return (
371
559
  <div className="flex flex-col gap-1">
@@ -393,10 +581,25 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
393
581
  formatMoney(row.original.unit_price_net, row.original.currency_code),
394
582
  },
395
583
  {
396
- accessorKey: 'total_net_amount',
584
+ accessorKey: 'net_amount',
397
585
  header: t('billing.invoices.lines.columns.total', 'Total net'),
398
586
  cell: ({ row }) =>
399
- formatMoney(row.original.total_net_amount, row.original.currency_code),
587
+ formatMoney(row.original.net_amount, row.original.currency_code),
588
+ },
589
+ {
590
+ accessorKey: 'tax_rate',
591
+ header: t('billing.invoices.lines.columns.tax_rate', 'VAT %'),
592
+ cell: ({ row }) => (row.original.tax_rate != null ? `${Number(row.original.tax_rate)} %` : '—'),
593
+ },
594
+ {
595
+ accessorKey: 'tax_amount',
596
+ header: t('billing.invoices.lines.columns.tax_amount', 'VAT'),
597
+ cell: ({ row }) => formatMoney(row.original.tax_amount, row.original.currency_code),
598
+ },
599
+ {
600
+ accessorKey: 'gross_amount',
601
+ header: t('billing.invoices.lines.columns.gross', 'Gross'),
602
+ cell: ({ row }) => formatMoney(row.original.gross_amount, row.original.currency_code),
400
603
  },
401
604
  {
402
605
  id: 'actions',
@@ -438,6 +641,7 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
438
641
  description: dialogTargetLine.description ?? '',
439
642
  quantity: Number.parseFloat(dialogTargetLine.quantity),
440
643
  unitPriceNet: Number.parseFloat(dialogTargetLine.unit_price_net),
644
+ taxRate: dialogTargetLine.tax_rate != null ? Number.parseFloat(String(dialogTargetLine.tax_rate)) : undefined,
441
645
  }
442
646
  }, [dialogMode, dialogTargetLine])
443
647
 
@@ -462,20 +666,38 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
462
666
  )
463
667
  }
464
668
 
465
- const isTest = invoice.metadata?.test_run === true
669
+ const isTest = invoice.test_run === true
466
670
  const isDraft = invoice.status === 'draft'
467
671
 
468
672
  return (
469
673
  <Page>
470
674
  <FormHeader
471
675
  mode="detail"
472
- backHref="/backend/billing/invoices"
676
+ backHref={backHref}
473
677
  entityTypeLabel={t('billing.invoices.detail.title', 'Billing Invoice')}
474
- title={invoice.invoice_number}
678
+ title={invoice.number}
475
679
  statusBadge={
476
680
  <div className="flex items-center gap-2 flex-wrap">
477
- <Tag variant={statusVariant(invoice.status)}>{invoice.status ?? '—'}</Tag>
478
- {isTest ? <Tag variant="warning">TEST</Tag> : null}
681
+ <Tag variant={statusVariant(invoice.status)}>{invoice.status}</Tag>
682
+ {invoice.document_type === 'credit_memo' ? (
683
+ <Tag variant="info">{t('billing.invoices.document_type.credit_memo', 'Credit memo')}</Tag>
684
+ ) : invoice.document_type === 'debit_memo' ? (
685
+ <Tag variant="info">{t('billing.invoices.document_type.debit_memo', 'Debit memo')}</Tag>
686
+ ) : null}
687
+ {isTest ? (
688
+ invoice.bill_run_id ? (
689
+ <Link href={`/backend/billing/runs/${invoice.bill_run_id}`}>
690
+ <Tag variant="warning">{t('billing.invoices.test_run_tag', 'Test run')}</Tag>
691
+ </Link>
692
+ ) : (
693
+ <Tag variant="warning">{t('billing.invoices.test_run_tag', 'Test run')}</Tag>
694
+ )
695
+ ) : null}
696
+ {(invoice.days_overdue ?? 0) > 0 ? (
697
+ <Tag variant="error">
698
+ {t('billing.invoices.overdue_days', 'Overdue {days} d').replace('{days}', String(invoice.days_overdue))}
699
+ </Tag>
700
+ ) : null}
479
701
  </div>
480
702
  }
481
703
  actionsContent={
@@ -487,15 +709,37 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
487
709
  : t('billing.invoices.post.action', 'Post invoice')}
488
710
  </Button>
489
711
  ) : null}
490
- {isTest ? (
491
- <Button
492
- variant="outline"
493
- onClick={handleWipeTest}
494
- disabled={wiping}
495
- >
496
- {wiping
497
- ? t('billing.invoices.wipe.in_progress', 'Wiping…')
498
- : t('billing.invoices.wipe.action', 'Wipe test invoices for this run')}
712
+ <Button type="button" variant="outline" asChild>
713
+ <a href={invoicePdfHref(invoice.id)} target="_blank" rel="noopener noreferrer">
714
+ <FileDown size={16} />
715
+ {isDraft
716
+ ? t('billing.invoices.actions.pdf_preview', 'Preview PDF')
717
+ : t('billing.invoices.actions.pdf', 'Download PDF')}
718
+ </a>
719
+ </Button>
720
+ {!isDraft && !isTest && invoice.document_type !== 'receipt' ? (
721
+ <Button type="button" variant="outline" onClick={() => void handleSend()} disabled={sending}>
722
+ <Mail size={16} />
723
+ {sending
724
+ ? t('billing.invoices.send.in_progress', 'Sending…')
725
+ : (invoice.metadata?.deliveries ?? []).some((d) => d.status === 'sent')
726
+ ? t('billing.invoices.send.resend', 'Resend')
727
+ : t('billing.invoices.send.action', 'Send')}
728
+ </Button>
729
+ ) : null}
730
+ {invoice.document_type === 'invoice' && !isTest && ['posted', 'partially_paid', 'paid'].includes(invoice.status) ? (
731
+ <Button type="button" variant="outline" onClick={() => setMemoDialog('credit_memo')}>
732
+ {t('billing.memo.create_credit.action', 'Create credit memo')}
733
+ </Button>
734
+ ) : null}
735
+ {invoice.document_type === 'invoice' && !isTest && ['posted', 'partially_paid', 'paid', 'credited'].includes(invoice.status) ? (
736
+ <Button type="button" variant="outline" onClick={() => setMemoDialog('debit_memo')}>
737
+ {t('billing.memo.create_debit.action', 'Create debit memo')}
738
+ </Button>
739
+ ) : null}
740
+ {isDraft && (invoice.document_type === 'credit_memo' || invoice.document_type === 'debit_memo') ? (
741
+ <Button type="button" variant="outline" onClick={() => void handleDeleteDraftMemo()}>
742
+ {t('billing.memo.delete.action', 'Delete draft')}
499
743
  </Button>
500
744
  ) : null}
501
745
  </>
@@ -503,18 +747,29 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
503
747
  />
504
748
  <PageBody>
505
749
  <div className="space-y-6">
750
+ {settingsIncomplete ? (
751
+ <div className="flex flex-wrap items-center justify-between gap-3 rounded-md border border-status-warning-border bg-status-warning-bg px-4 py-3 text-sm text-status-warning-text">
752
+ <span>
753
+ {t(
754
+ 'billing.invoices.post.settings_incomplete',
755
+ 'Fill in the seller details in Settings → Billing before posting invoices.',
756
+ )}
757
+ </span>
758
+ <BillingSettingsLink />
759
+ </div>
760
+ ) : null}
506
761
  <DetailCard>
507
762
  <DetailField label={t('billing.invoices.detail.field.period', 'Bill period')}>
508
- {invoice.metadata?.bill_period_start ?? '—'} →{' '}
509
- {invoice.metadata?.bill_period_end ?? '—'}
763
+ {invoice.period_start?.slice(0, 10) ?? '—'} →{' '}
764
+ {invoice.period_end?.slice(0, 10) ?? '—'}
510
765
  </DetailField>
511
766
  <DetailField label={t('billing.invoices.detail.field.bill_run', 'Bill Run')}>
512
- {invoice.metadata?.bill_run_id ? (
767
+ {invoice.bill_run_id ? (
513
768
  <Link
514
- href={`/backend/billing/runs/${invoice.metadata.bill_run_id}`}
769
+ href={`/backend/billing/runs/${invoice.bill_run_id}`}
515
770
  className="text-primary hover:underline"
516
771
  >
517
- {runName ?? invoice.metadata.bill_run_id}
772
+ {runName ?? invoice.bill_run_id}
518
773
  </Link>
519
774
  ) : (
520
775
  '—'
@@ -523,12 +778,12 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
523
778
  <DetailField
524
779
  label={t('billing.invoices.detail.field.account', 'Billing Account')}
525
780
  >
526
- {invoice.metadata?.bill_account_id ? (
781
+ {invoice.bill_account_id ? (
527
782
  <Link
528
- href={`/backend/billing/accounts/${invoice.metadata.bill_account_id}`}
783
+ href={`/backend/billing/accounts/${invoice.bill_account_id}`}
529
784
  className="text-primary hover:underline"
530
785
  >
531
- {accountName ?? invoice.metadata.bill_account_id}
786
+ {accountName ?? invoice.bill_account_name ?? invoice.bill_account_id}
532
787
  </Link>
533
788
  ) : (
534
789
  '—'
@@ -537,6 +792,24 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
537
792
  <DetailField label={t('billing.invoices.detail.field.issued', 'Issued')}>
538
793
  {invoice.issue_date?.slice(0, 10) ?? '—'}
539
794
  </DetailField>
795
+ <DetailField label={t('billing.invoices.detail.field.due', 'Due')}>
796
+ {invoice.due_date?.slice(0, 10) ?? '—'}
797
+ </DetailField>
798
+ {invoice.corrects_invoice_id ? (
799
+ <DetailField label={t('billing.memo.corrects', 'Corrects')}>
800
+ <Link href={`/backend/billing/invoices/${invoice.corrects_invoice_id}`} className="text-primary hover:underline">
801
+ {invoice.corrects_invoice_number ?? invoice.corrects_invoice_id}
802
+ </Link>
803
+ </DetailField>
804
+ ) : null}
805
+ {invoice.correction_reason ? (
806
+ <DetailField label={t('billing.memo.reason_label', 'Reason')}>{invoice.correction_reason}</DetailField>
807
+ ) : null}
808
+ {invoice.metadata?.draft_number ? (
809
+ <DetailField label={t('billing.invoices.detail.field.draft_number', 'Draft number')}>
810
+ <span className="font-mono text-xs">{invoice.metadata.draft_number}</span>
811
+ </DetailField>
812
+ ) : null}
540
813
  <DetailField label={t('billing.common.id', 'ID')}>
541
814
  <span className="font-mono text-xs">{invoice.id}</span>
542
815
  </DetailField>
@@ -545,19 +818,19 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
545
818
  <StatCard>
546
819
  <Stat
547
820
  label={t('billing.invoices.detail.subtotal', 'Subtotal net')}
548
- value={formatMoney(invoice.subtotal_net_amount, invoice.currency_code)}
821
+ value={formatMoney(invoice.subtotal_net, invoice.currency_code)}
549
822
  />
550
823
  <Stat
551
824
  label={t('billing.invoices.detail.total', 'Grand total')}
552
- value={formatMoney(invoice.grand_total_gross_amount, invoice.currency_code)}
825
+ value={formatMoney(invoice.total_gross, invoice.currency_code)}
553
826
  />
554
827
  <Stat
555
828
  label={t('billing.invoices.detail.paid', 'Paid')}
556
- value={formatMoney(invoice.paid_total_amount, invoice.currency_code)}
829
+ value={formatMoney(invoice.paid_total, invoice.currency_code)}
557
830
  />
558
831
  <Stat
559
832
  label={t('billing.invoices.detail.outstanding', 'Outstanding')}
560
- value={formatMoney(invoice.outstanding_amount, invoice.currency_code)}
833
+ value={formatMoney(invoice.outstanding, invoice.currency_code)}
561
834
  />
562
835
  </StatCard>
563
836
 
@@ -593,6 +866,64 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
593
866
  }}
594
867
  />
595
868
  </div>
869
+
870
+ {corrections.length > 0 ? (
871
+ <div>
872
+ <h2 className="text-base font-semibold mb-2">{t('billing.memo.corrections', 'Corrections')}</h2>
873
+ <DataTable
874
+ columns={correctionColumns}
875
+ data={corrections}
876
+ isLoading={false}
877
+ pagination={{
878
+ page: 1,
879
+ pageSize: Math.max(corrections.length, 1),
880
+ total: corrections.length,
881
+ totalPages: 1,
882
+ onPageChange: () => undefined,
883
+ }}
884
+ />
885
+ </div>
886
+ ) : null}
887
+
888
+ {!isDraft ? (
889
+ <div>
890
+ <h2 className="text-base font-semibold mb-2">{t('billing.invoices.payments.title', 'Payments')}</h2>
891
+ <DataTable
892
+ columns={allocationColumns}
893
+ data={allocations}
894
+ isLoading={false}
895
+ emptyState={t('billing.invoices.payments.empty', 'No payments yet.')}
896
+ pagination={{
897
+ page: 1,
898
+ pageSize: Math.max(allocations.length, 1),
899
+ total: allocations.length,
900
+ totalPages: 1,
901
+ onPageChange: () => undefined,
902
+ }}
903
+ />
904
+ </div>
905
+ ) : null}
906
+
907
+ {!isDraft ? (
908
+ <div>
909
+ <h2 className="text-base font-semibold mb-2">
910
+ {t('billing.invoices.deliveries.title', 'Email deliveries')}
911
+ </h2>
912
+ <DataTable
913
+ columns={deliveryColumns}
914
+ data={deliveries}
915
+ isLoading={false}
916
+ emptyState={t('billing.invoices.deliveries.empty', 'Not sent yet.')}
917
+ pagination={{
918
+ page: 1,
919
+ pageSize: Math.max(deliveries.length, 1),
920
+ total: deliveries.length,
921
+ totalPages: 1,
922
+ onPageChange: () => undefined,
923
+ }}
924
+ />
925
+ </div>
926
+ ) : null}
596
927
  </div>
597
928
 
598
929
  <LineFormDialog
@@ -606,6 +937,24 @@ export default function BillingInvoiceDetailPage(props: { params?: { id?: string
606
937
  }}
607
938
  onSubmit={handleSubmitLine}
608
939
  />
940
+ {memoDialog ? (
941
+ <CreateMemoDialog
942
+ open
943
+ type={memoDialog}
944
+ invoiceId={invoice.id}
945
+ invoiceNumber={invoice.number}
946
+ currencyCode={invoice.currency_code}
947
+ lines={lines.map((line) => ({
948
+ id: line.id,
949
+ description: line.description,
950
+ quantity: line.quantity,
951
+ unit_price_net: line.unit_price_net,
952
+ tax_rate: line.tax_rate,
953
+ }))}
954
+ onClose={() => setMemoDialog(null)}
955
+ onCreated={(memoId) => router.push(`/backend/billing/invoices/${memoId}`)}
956
+ />
957
+ ) : null}
609
958
  {ConfirmDialogElement}
610
959
  </PageBody>
611
960
  </Page>