@dainamite/billing 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/dist/modules/billing/acl.js +13 -1
  3. package/dist/modules/billing/acl.js.map +2 -2
  4. package/dist/modules/billing/api/accounts/[id]/summary/route.js +52 -0
  5. package/dist/modules/billing/api/accounts/[id]/summary/route.js.map +7 -0
  6. package/dist/modules/billing/api/accounts/route.js +47 -4
  7. package/dist/modules/billing/api/accounts/route.js.map +2 -2
  8. package/dist/modules/billing/api/export/account/[id]/route.js +11 -7
  9. package/dist/modules/billing/api/export/account/[id]/route.js.map +2 -2
  10. package/dist/modules/billing/api/invoices/[id]/memos/route.js +54 -0
  11. package/dist/modules/billing/api/invoices/[id]/memos/route.js.map +7 -0
  12. package/dist/modules/billing/api/invoices/[id]/pdf/route.js +70 -0
  13. package/dist/modules/billing/api/invoices/[id]/pdf/route.js.map +7 -0
  14. package/dist/modules/billing/api/invoices/[id]/route.js +44 -24
  15. package/dist/modules/billing/api/invoices/[id]/route.js.map +2 -2
  16. package/dist/modules/billing/api/invoices/[id]/send/route.js +107 -0
  17. package/dist/modules/billing/api/invoices/[id]/send/route.js.map +7 -0
  18. package/dist/modules/billing/api/invoices/add-line/route.js +2 -2
  19. package/dist/modules/billing/api/invoices/add-line/route.js.map +2 -2
  20. package/dist/modules/billing/api/invoices/delete-draft/route.js +33 -0
  21. package/dist/modules/billing/api/invoices/delete-draft/route.js.map +7 -0
  22. package/dist/modules/billing/api/invoices/edit-line/route.js +2 -2
  23. package/dist/modules/billing/api/invoices/edit-line/route.js.map +2 -2
  24. package/dist/modules/billing/api/invoices/post/route.js +2 -2
  25. package/dist/modules/billing/api/invoices/post/route.js.map +2 -2
  26. package/dist/modules/billing/api/invoices/remove-line/route.js +2 -2
  27. package/dist/modules/billing/api/invoices/remove-line/route.js.map +2 -2
  28. package/dist/modules/billing/api/invoices/route.js +45 -46
  29. package/dist/modules/billing/api/invoices/route.js.map +2 -2
  30. package/dist/modules/billing/api/items/bulk/route.js +1 -1
  31. package/dist/modules/billing/api/items/bulk/route.js.map +2 -2
  32. package/dist/modules/billing/api/items/change-price/route.js +44 -0
  33. package/dist/modules/billing/api/items/change-price/route.js.map +7 -0
  34. package/dist/modules/billing/api/items/route.js +19 -7
  35. package/dist/modules/billing/api/items/route.js.map +2 -2
  36. package/dist/modules/billing/api/payment-imports/[id]/route.js +49 -0
  37. package/dist/modules/billing/api/payment-imports/[id]/route.js.map +7 -0
  38. package/dist/modules/billing/api/payment-imports/route.js +57 -0
  39. package/dist/modules/billing/api/payment-imports/route.js.map +7 -0
  40. package/dist/modules/billing/api/payments/[id]/route.js +60 -0
  41. package/dist/modules/billing/api/payments/[id]/route.js.map +7 -0
  42. package/dist/modules/billing/api/payments/allocate/route.js +35 -0
  43. package/dist/modules/billing/api/payments/allocate/route.js.map +7 -0
  44. package/dist/modules/billing/api/payments/assign/route.js +36 -0
  45. package/dist/modules/billing/api/payments/assign/route.js.map +7 -0
  46. package/dist/modules/billing/api/payments/convert-to-topup/route.js +35 -0
  47. package/dist/modules/billing/api/payments/convert-to-topup/route.js.map +7 -0
  48. package/dist/modules/billing/api/payments/ignore/route.js +35 -0
  49. package/dist/modules/billing/api/payments/ignore/route.js.map +7 -0
  50. package/dist/modules/billing/api/payments/import/route.js +63 -0
  51. package/dist/modules/billing/api/payments/import/route.js.map +7 -0
  52. package/dist/modules/billing/api/payments/restore/route.js +35 -0
  53. package/dist/modules/billing/api/payments/restore/route.js.map +7 -0
  54. package/dist/modules/billing/api/payments/route.js +114 -0
  55. package/dist/modules/billing/api/payments/route.js.map +7 -0
  56. package/dist/modules/billing/api/payments/unallocate/route.js +35 -0
  57. package/dist/modules/billing/api/payments/unallocate/route.js.map +7 -0
  58. package/dist/modules/billing/api/payments/unassign/route.js +35 -0
  59. package/dist/modules/billing/api/payments/unassign/route.js.map +7 -0
  60. package/dist/modules/billing/api/run-outcomes/route.js +43 -6
  61. package/dist/modules/billing/api/run-outcomes/route.js.map +2 -2
  62. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js +61 -0
  63. package/dist/modules/billing/api/runs/[id]/post-drafts/route.js.map +7 -0
  64. package/dist/modules/billing/api/runs/[id]/route.js +53 -0
  65. package/dist/modules/billing/api/runs/[id]/route.js.map +7 -0
  66. package/dist/modules/billing/api/runs/retry-failed/route.js +1 -1
  67. package/dist/modules/billing/api/runs/retry-failed/route.js.map +2 -2
  68. package/dist/modules/billing/api/runs/route.js +9 -3
  69. package/dist/modules/billing/api/runs/route.js.map +2 -2
  70. package/dist/modules/billing/api/settings/number-preview/route.js +42 -0
  71. package/dist/modules/billing/api/settings/number-preview/route.js.map +7 -0
  72. package/dist/modules/billing/api/settings/route.js +92 -0
  73. package/dist/modules/billing/api/settings/route.js.map +7 -0
  74. package/dist/modules/billing/api/statements/route.js +3 -0
  75. package/dist/modules/billing/api/statements/route.js.map +2 -2
  76. package/dist/modules/billing/api/test-invoices/wipe/route.js +2 -2
  77. package/dist/modules/billing/api/test-invoices/wipe/route.js.map +2 -2
  78. package/dist/modules/billing/backend/billing/accounts/[id]/page.js +121 -232
  79. package/dist/modules/billing/backend/billing/accounts/[id]/page.js.map +2 -2
  80. package/dist/modules/billing/backend/billing/accounts/create/page.js +6 -0
  81. package/dist/modules/billing/backend/billing/accounts/create/page.js.map +2 -2
  82. package/dist/modules/billing/backend/billing/accounts/page.js +63 -4
  83. package/dist/modules/billing/backend/billing/accounts/page.js.map +2 -2
  84. package/dist/modules/billing/backend/billing/invoices/[id]/page.js +297 -65
  85. package/dist/modules/billing/backend/billing/invoices/[id]/page.js.map +3 -3
  86. package/dist/modules/billing/backend/billing/invoices/page.js +6 -172
  87. package/dist/modules/billing/backend/billing/invoices/page.js.map +2 -2
  88. package/dist/modules/billing/backend/billing/items/[id]/page.js +51 -7
  89. package/dist/modules/billing/backend/billing/items/[id]/page.js.map +2 -2
  90. package/dist/modules/billing/backend/billing/items/create/page.js +9 -6
  91. package/dist/modules/billing/backend/billing/items/create/page.js.map +2 -2
  92. package/dist/modules/billing/backend/billing/items/page.js +8 -2
  93. package/dist/modules/billing/backend/billing/items/page.js.map +2 -2
  94. package/dist/modules/billing/backend/billing/payments/[id]/page.js +297 -0
  95. package/dist/modules/billing/backend/billing/payments/[id]/page.js.map +7 -0
  96. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js +21 -0
  97. package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js.map +7 -0
  98. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js +74 -0
  99. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js.map +7 -0
  100. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js +21 -0
  101. package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js.map +7 -0
  102. package/dist/modules/billing/backend/billing/payments/page.js +58 -0
  103. package/dist/modules/billing/backend/billing/payments/page.js.map +7 -0
  104. package/dist/modules/billing/backend/billing/payments/page.meta.js +18 -0
  105. package/dist/modules/billing/backend/billing/payments/page.meta.js.map +7 -0
  106. package/dist/modules/billing/backend/billing/runs/[id]/page.js +49 -14
  107. package/dist/modules/billing/backend/billing/runs/[id]/page.js.map +2 -2
  108. package/dist/modules/billing/backend/billing/runs/page.js +58 -7
  109. package/dist/modules/billing/backend/billing/runs/page.js.map +2 -2
  110. package/dist/modules/billing/backend/billing/statements/[id]/page.js +61 -6
  111. package/dist/modules/billing/backend/billing/statements/[id]/page.js.map +2 -2
  112. package/dist/modules/billing/backend/billing/statements/page.js +1 -1
  113. package/dist/modules/billing/backend/billing/statements/page.js.map +2 -2
  114. package/dist/modules/billing/backend/billing/topups/page.js +1 -1
  115. package/dist/modules/billing/backend/billing/topups/page.js.map +2 -2
  116. package/dist/modules/billing/backend/billing/transactions/page.js +1 -1
  117. package/dist/modules/billing/backend/billing/transactions/page.js.map +2 -2
  118. package/dist/modules/billing/backend/billing/usage/create/page.js +3 -2
  119. package/dist/modules/billing/backend/billing/usage/create/page.js.map +2 -2
  120. package/dist/modules/billing/backend/config/billing/page.js +472 -0
  121. package/dist/modules/billing/backend/config/billing/page.js.map +7 -0
  122. package/dist/modules/billing/backend/config/billing/page.meta.js +19 -0
  123. package/dist/modules/billing/backend/config/billing/page.meta.js.map +7 -0
  124. package/dist/modules/billing/cli.js +22 -1
  125. package/dist/modules/billing/cli.js.map +2 -2
  126. package/dist/modules/billing/commands/accounts.js +6 -0
  127. package/dist/modules/billing/commands/accounts.js.map +2 -2
  128. package/dist/modules/billing/commands/index.js +3 -0
  129. package/dist/modules/billing/commands/index.js.map +2 -2
  130. package/dist/modules/billing/commands/invoices.js +269 -167
  131. package/dist/modules/billing/commands/invoices.js.map +2 -2
  132. package/dist/modules/billing/commands/items.js +108 -0
  133. package/dist/modules/billing/commands/items.js.map +2 -2
  134. package/dist/modules/billing/commands/memos.js +179 -0
  135. package/dist/modules/billing/commands/memos.js.map +7 -0
  136. package/dist/modules/billing/commands/payments.js +379 -0
  137. package/dist/modules/billing/commands/payments.js.map +7 -0
  138. package/dist/modules/billing/commands/runs.js +151 -4
  139. package/dist/modules/billing/commands/runs.js.map +2 -2
  140. package/dist/modules/billing/commands/settings.js +59 -0
  141. package/dist/modules/billing/commands/settings.js.map +7 -0
  142. package/dist/modules/billing/commands/topups.js +9 -2
  143. package/dist/modules/billing/commands/topups.js.map +2 -2
  144. package/dist/modules/billing/commands/transactions.js +2 -2
  145. package/dist/modules/billing/commands/transactions.js.map +2 -2
  146. package/dist/modules/billing/components/AccountForm.js +149 -42
  147. package/dist/modules/billing/components/AccountForm.js.map +2 -2
  148. package/dist/modules/billing/components/AccountInvoicesSection.js +64 -0
  149. package/dist/modules/billing/components/AccountInvoicesSection.js.map +7 -0
  150. package/dist/modules/billing/components/AccountPaymentsSection.js +43 -0
  151. package/dist/modules/billing/components/AccountPaymentsSection.js.map +7 -0
  152. package/dist/modules/billing/components/AccountPicker.js +56 -0
  153. package/dist/modules/billing/components/AccountPicker.js.map +7 -0
  154. package/dist/modules/billing/components/AllocatePaymentDialog.js +134 -0
  155. package/dist/modules/billing/components/AllocatePaymentDialog.js.map +7 -0
  156. package/dist/modules/billing/components/BillingDataTable.js +21 -0
  157. package/dist/modules/billing/components/BillingDataTable.js.map +7 -0
  158. package/dist/modules/billing/components/BillingSettingsLink.js +19 -0
  159. package/dist/modules/billing/components/BillingSettingsLink.js.map +7 -0
  160. package/dist/modules/billing/components/ChangeItemPriceDialog.js +158 -0
  161. package/dist/modules/billing/components/ChangeItemPriceDialog.js.map +7 -0
  162. package/dist/modules/billing/components/CreateMemoDialog.js +200 -0
  163. package/dist/modules/billing/components/CreateMemoDialog.js.map +7 -0
  164. package/dist/modules/billing/components/CustomerLabel.js +33 -0
  165. package/dist/modules/billing/components/CustomerLabel.js.map +7 -0
  166. package/dist/modules/billing/components/InvoicesTable.js +270 -0
  167. package/dist/modules/billing/components/InvoicesTable.js.map +7 -0
  168. package/dist/modules/billing/components/ItemForm.js +176 -44
  169. package/dist/modules/billing/components/ItemForm.js.map +2 -2
  170. package/dist/modules/billing/components/ItemPriceField.js +46 -0
  171. package/dist/modules/billing/components/ItemPriceField.js.map +7 -0
  172. package/dist/modules/billing/components/LineFormDialog.js +25 -2
  173. package/dist/modules/billing/components/LineFormDialog.js.map +2 -2
  174. package/dist/modules/billing/components/ManualPaymentDialog.js +122 -0
  175. package/dist/modules/billing/components/ManualPaymentDialog.js.map +7 -0
  176. package/dist/modules/billing/components/MoneyInput.js +14 -0
  177. package/dist/modules/billing/components/MoneyInput.js.map +7 -0
  178. package/dist/modules/billing/components/PaymentUploadDialog.js +115 -0
  179. package/dist/modules/billing/components/PaymentUploadDialog.js.map +7 -0
  180. package/dist/modules/billing/components/PaymentsTable.js +171 -0
  181. package/dist/modules/billing/components/PaymentsTable.js.map +7 -0
  182. package/dist/modules/billing/components/PostRunDraftsButton.js +105 -0
  183. package/dist/modules/billing/components/PostRunDraftsButton.js.map +7 -0
  184. package/dist/modules/billing/components/PrepaidPanel.js +14 -4
  185. package/dist/modules/billing/components/PrepaidPanel.js.map +2 -2
  186. package/dist/modules/billing/components/RunCyclesSection.js +209 -0
  187. package/dist/modules/billing/components/RunCyclesSection.js.map +7 -0
  188. package/dist/modules/billing/components/TestRunActions.js +127 -0
  189. package/dist/modules/billing/components/TestRunActions.js.map +7 -0
  190. package/dist/modules/billing/components/account/AccountItemsTab.js +157 -0
  191. package/dist/modules/billing/components/account/AccountItemsTab.js.map +7 -0
  192. package/dist/modules/billing/components/account/AccountRunBillingDialog.js +122 -0
  193. package/dist/modules/billing/components/account/AccountRunBillingDialog.js.map +7 -0
  194. package/dist/modules/billing/components/account/AccountRunsTab.js +152 -0
  195. package/dist/modules/billing/components/account/AccountRunsTab.js.map +7 -0
  196. package/dist/modules/billing/components/account/AccountStatementsTab.js +98 -0
  197. package/dist/modules/billing/components/account/AccountStatementsTab.js.map +7 -0
  198. package/dist/modules/billing/components/account/AccountSummaryCards.js +125 -0
  199. package/dist/modules/billing/components/account/AccountSummaryCards.js.map +7 -0
  200. package/dist/modules/billing/components/account/AccountUsageTab.js +91 -0
  201. package/dist/modules/billing/components/account/AccountUsageTab.js.map +7 -0
  202. package/dist/modules/billing/components/account/AccountView.js +73 -0
  203. package/dist/modules/billing/components/account/AccountView.js.map +7 -0
  204. package/dist/modules/billing/components/account/accountRow.js +39 -0
  205. package/dist/modules/billing/components/account/accountRow.js.map +7 -0
  206. package/dist/modules/billing/components/customerNames.js +42 -0
  207. package/dist/modules/billing/components/customerNames.js.map +7 -0
  208. package/dist/modules/billing/data/entities.js +560 -4
  209. package/dist/modules/billing/data/entities.js.map +2 -2
  210. package/dist/modules/billing/data/entityIds.js +10 -1
  211. package/dist/modules/billing/data/entityIds.js.map +2 -2
  212. package/dist/modules/billing/data/validators.js +269 -15
  213. package/dist/modules/billing/data/validators.js.map +2 -2
  214. package/dist/modules/billing/events.js +50 -0
  215. package/dist/modules/billing/events.js.map +2 -2
  216. package/dist/modules/billing/i18n/de.json +880 -0
  217. package/dist/modules/billing/i18n/en.json +457 -21
  218. package/dist/modules/billing/i18n/es.json +880 -0
  219. package/dist/modules/billing/i18n/pl.json +458 -22
  220. package/dist/modules/billing/index.js +6 -2
  221. package/dist/modules/billing/index.js.map +2 -2
  222. package/dist/modules/billing/lib/accountFinancials.js +58 -0
  223. package/dist/modules/billing/lib/accountFinancials.js.map +7 -0
  224. package/dist/modules/billing/lib/accountLock.js +14 -0
  225. package/dist/modules/billing/lib/accountLock.js.map +7 -0
  226. package/dist/modules/billing/lib/accountStatus.js +9 -7
  227. package/dist/modules/billing/lib/accountStatus.js.map +2 -2
  228. package/dist/modules/billing/lib/accountSummary.js +106 -0
  229. package/dist/modules/billing/lib/accountSummary.js.map +7 -0
  230. package/dist/modules/billing/lib/allocation.js +356 -0
  231. package/dist/modules/billing/lib/allocation.js.map +7 -0
  232. package/dist/modules/billing/lib/allocationEvents.js +22 -0
  233. package/dist/modules/billing/lib/allocationEvents.js.map +7 -0
  234. package/dist/modules/billing/lib/billPeriod.js +15 -1
  235. package/dist/modules/billing/lib/billPeriod.js.map +2 -2
  236. package/dist/modules/billing/lib/billRunEngine.js +237 -102
  237. package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
  238. package/dist/modules/billing/lib/billingSettings.js +116 -0
  239. package/dist/modules/billing/lib/billingSettings.js.map +7 -0
  240. package/dist/modules/billing/lib/commandRoute.js +81 -0
  241. package/dist/modules/billing/lib/commandRoute.js.map +7 -0
  242. package/dist/modules/billing/lib/customerLookup.js +97 -0
  243. package/dist/modules/billing/lib/customerLookup.js.map +7 -0
  244. package/dist/modules/billing/lib/dateOnly.js +13 -0
  245. package/dist/modules/billing/lib/dateOnly.js.map +7 -0
  246. package/dist/modules/billing/lib/documentParties.js +16 -0
  247. package/dist/modules/billing/lib/documentParties.js.map +7 -0
  248. package/dist/modules/billing/lib/documentTypes.js +27 -0
  249. package/dist/modules/billing/lib/documentTypes.js.map +7 -0
  250. package/dist/modules/billing/lib/dueDate.js +18 -0
  251. package/dist/modules/billing/lib/dueDate.js.map +7 -0
  252. package/dist/modules/billing/lib/iban.js +29 -0
  253. package/dist/modules/billing/lib/iban.js.map +7 -0
  254. package/dist/modules/billing/lib/invoiceDelivery.js +133 -0
  255. package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
  256. package/dist/modules/billing/lib/invoiceLanguages.js +28 -0
  257. package/dist/modules/billing/lib/invoiceLanguages.js.map +7 -0
  258. package/dist/modules/billing/lib/invoiceWriter.js +107 -99
  259. package/dist/modules/billing/lib/invoiceWriter.js.map +2 -2
  260. package/dist/modules/billing/lib/itemBillingState.js +27 -0
  261. package/dist/modules/billing/lib/itemBillingState.js.map +7 -0
  262. package/dist/modules/billing/lib/itemPriceChange.js +18 -0
  263. package/dist/modules/billing/lib/itemPriceChange.js.map +7 -0
  264. package/dist/modules/billing/lib/itemSelector.js.map +2 -2
  265. package/dist/modules/billing/lib/lineAmounts.js +32 -0
  266. package/dist/modules/billing/lib/lineAmounts.js.map +7 -0
  267. package/dist/modules/billing/lib/memoGuards.js +25 -0
  268. package/dist/modules/billing/lib/memoGuards.js.map +7 -0
  269. package/dist/modules/billing/lib/navigation.js +48 -0
  270. package/dist/modules/billing/lib/navigation.js.map +7 -0
  271. package/dist/modules/billing/lib/numbering.js +120 -0
  272. package/dist/modules/billing/lib/numbering.js.map +7 -0
  273. package/dist/modules/billing/lib/overdue.js +36 -0
  274. package/dist/modules/billing/lib/overdue.js.map +7 -0
  275. package/dist/modules/billing/lib/paymentCsv.js +125 -0
  276. package/dist/modules/billing/lib/paymentCsv.js.map +7 -0
  277. package/dist/modules/billing/lib/paymentGateway.js +15 -0
  278. package/dist/modules/billing/lib/paymentGateway.js.map +7 -0
  279. package/dist/modules/billing/lib/paymentImport.js +164 -0
  280. package/dist/modules/billing/lib/paymentImport.js.map +7 -0
  281. package/dist/modules/billing/lib/paymentMatcher.js +36 -0
  282. package/dist/modules/billing/lib/paymentMatcher.js.map +7 -0
  283. package/dist/modules/billing/lib/pdf/attachmentStore.js +46 -0
  284. package/dist/modules/billing/lib/pdf/attachmentStore.js.map +7 -0
  285. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js +7 -0
  286. package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js.map +7 -0
  287. package/dist/modules/billing/lib/pdf/invoiceModel.js +194 -0
  288. package/dist/modules/billing/lib/pdf/invoiceModel.js.map +7 -0
  289. package/dist/modules/billing/lib/pdf/invoicePdf.js +165 -0
  290. package/dist/modules/billing/lib/pdf/invoicePdf.js.map +7 -0
  291. package/dist/modules/billing/lib/pdf/invoiceTemplate.js +276 -0
  292. package/dist/modules/billing/lib/pdf/invoiceTemplate.js.map +7 -0
  293. package/dist/modules/billing/lib/prepaidConfig.js +17 -25
  294. package/dist/modules/billing/lib/prepaidConfig.js.map +2 -2
  295. package/dist/modules/billing/lib/prepaidConsume.js +26 -7
  296. package/dist/modules/billing/lib/prepaidConsume.js.map +2 -2
  297. package/dist/modules/billing/lib/prepaidPeriodClose.js +277 -158
  298. package/dist/modules/billing/lib/prepaidPeriodClose.js.map +2 -2
  299. package/dist/modules/billing/lib/prepaidTaxPoint.js +37 -0
  300. package/dist/modules/billing/lib/prepaidTaxPoint.js.map +7 -0
  301. package/dist/modules/billing/lib/seeds/demo.js +51 -3
  302. package/dist/modules/billing/lib/seeds/demo.js.map +2 -2
  303. package/dist/modules/billing/lib/seeds/paymentsSample.js +93 -0
  304. package/dist/modules/billing/lib/seeds/paymentsSample.js.map +7 -0
  305. package/dist/modules/billing/lib/seeds/sellerSettings.js +41 -0
  306. package/dist/modules/billing/lib/seeds/sellerSettings.js.map +7 -0
  307. package/dist/modules/billing/lib/servicePeriods.js +121 -0
  308. package/dist/modules/billing/lib/servicePeriods.js.map +7 -0
  309. package/dist/modules/billing/lib/testRunCleanup.js +24 -0
  310. package/dist/modules/billing/lib/testRunCleanup.js.map +7 -0
  311. package/dist/modules/billing/lib/topupCapture.js +2 -2
  312. package/dist/modules/billing/lib/topupCapture.js.map +2 -2
  313. package/dist/modules/billing/lib/topupReceipt.js +58 -79
  314. package/dist/modules/billing/lib/topupReceipt.js.map +2 -2
  315. package/dist/modules/billing/lib/usageRater.js.map +1 -1
  316. package/dist/modules/billing/lib/usageRunner.js +14 -6
  317. package/dist/modules/billing/lib/usageRunner.js.map +2 -2
  318. package/dist/modules/billing/lib/vat.js +39 -0
  319. package/dist/modules/billing/lib/vat.js.map +7 -0
  320. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js +15 -0
  321. package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js.map +7 -0
  322. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js +25 -0
  323. package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js.map +7 -0
  324. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js +115 -0
  325. package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js.map +7 -0
  326. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js +47 -0
  327. package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js.map +7 -0
  328. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js +89 -0
  329. package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js.map +7 -0
  330. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js +17 -0
  331. package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js.map +7 -0
  332. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js +27 -0
  333. package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js.map +7 -0
  334. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js +29 -0
  335. package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js.map +7 -0
  336. package/dist/modules/billing/setup.js +7 -184
  337. package/dist/modules/billing/setup.js.map +2 -2
  338. package/dist/modules/billing/subscribers/credit-memo-auto-send.js +16 -0
  339. package/dist/modules/billing/subscribers/credit-memo-auto-send.js.map +7 -0
  340. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js +16 -0
  341. package/dist/modules/billing/subscribers/debit-memo-apply-credit.js.map +7 -0
  342. package/dist/modules/billing/subscribers/debit-memo-auto-send.js +16 -0
  343. package/dist/modules/billing/subscribers/debit-memo-auto-send.js.map +7 -0
  344. package/dist/modules/billing/subscribers/invoice-apply-credit.js +34 -0
  345. package/dist/modules/billing/subscribers/invoice-apply-credit.js.map +7 -0
  346. package/dist/modules/billing/subscribers/invoice-auto-send.js +30 -0
  347. package/dist/modules/billing/subscribers/invoice-auto-send.js.map +7 -0
  348. package/dist/modules/billing/subscribers/payment-captured-to-paid.js +69 -33
  349. package/dist/modules/billing/subscribers/payment-captured-to-paid.js.map +2 -2
  350. package/dist/modules/billing/subscribers/prepaid-topup-captured.js +4 -6
  351. package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +2 -2
  352. package/generated/entities/billing_account/index.ts +3 -0
  353. package/generated/entities/billing_allocation/index.ts +18 -0
  354. package/generated/entities/billing_document_sequence/index.ts +11 -0
  355. package/generated/entities/billing_invoice/index.ts +38 -0
  356. package/generated/entities/billing_invoice_line/index.ts +24 -0
  357. package/generated/entities/billing_item/index.ts +4 -0
  358. package/generated/entities/billing_payment/index.ts +25 -0
  359. package/generated/entities/billing_payment_import/index.ts +14 -0
  360. package/generated/entities/billing_run/index.ts +0 -1
  361. package/generated/entities/billing_run_outcome/index.ts +1 -0
  362. package/generated/entities/billing_settings/index.ts +26 -0
  363. package/generated/entities/billing_statement/index.ts +1 -0
  364. package/generated/entities.ids.generated.ts +7 -0
  365. package/package.json +5 -1
  366. package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +171 -0
  367. package/src/modules/billing/__integration__/TC-BILL-005.spec.ts +134 -0
  368. package/src/modules/billing/__integration__/TC-BILL-006.spec.ts +101 -0
  369. package/src/modules/billing/__integration__/TC-BILL-007.spec.ts +140 -0
  370. package/src/modules/billing/__integration__/TC-BILL-008.spec.ts +108 -0
  371. package/src/modules/billing/__integration__/TC-BILL-009.spec.ts +113 -0
  372. package/src/modules/billing/__integration__/TC-BILL-010.spec.ts +118 -0
  373. package/src/modules/billing/__integration__/TC-BILL-011.spec.ts +142 -0
  374. package/src/modules/billing/__integration__/TC-BILL-012.spec.ts +115 -0
  375. package/src/modules/billing/__integration__/TC-BILL-013.spec.ts +118 -0
  376. package/src/modules/billing/__integration__/sellerSettings.ts +24 -0
  377. package/src/modules/billing/__tests__/commands/invoices.test.ts +436 -354
  378. package/src/modules/billing/__tests__/commands/itemsBulk.test.ts +33 -0
  379. package/src/modules/billing/__tests__/commands/memos.test.ts +205 -0
  380. package/src/modules/billing/__tests__/commands/payments.test.ts +241 -0
  381. package/src/modules/billing/__tests__/commands/runsDelete.test.ts +146 -0
  382. package/src/modules/billing/__tests__/commands/runsPostDrafts.test.ts +106 -0
  383. package/src/modules/billing/__tests__/commands/topups.test.ts +11 -0
  384. package/src/modules/billing/__tests__/entityRegistry.test.ts +8 -1
  385. package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
  386. package/src/modules/billing/__tests__/i18n/dictionaries.test.ts +64 -0
  387. package/src/modules/billing/__tests__/lib/accountFinancials.test.ts +53 -0
  388. package/src/modules/billing/__tests__/lib/accountSummary.test.ts +97 -0
  389. package/src/modules/billing/__tests__/lib/allocation.test.ts +319 -0
  390. package/src/modules/billing/__tests__/lib/billRunEngine.test.ts +228 -17
  391. package/src/modules/billing/__tests__/lib/billingSettings.test.ts +109 -0
  392. package/src/modules/billing/__tests__/lib/customerLookup.test.ts +156 -0
  393. package/src/modules/billing/__tests__/lib/dueDate.test.ts +35 -0
  394. package/src/modules/billing/__tests__/lib/iban.test.ts +38 -0
  395. package/src/modules/billing/__tests__/lib/invoiceDelivery.test.ts +206 -0
  396. package/src/modules/billing/__tests__/lib/invoiceLanguages.test.ts +49 -0
  397. package/src/modules/billing/__tests__/lib/invoiceWriter.test.ts +212 -10
  398. package/src/modules/billing/__tests__/lib/itemBillingState.test.ts +42 -0
  399. package/src/modules/billing/__tests__/lib/itemPriceChange.test.ts +165 -0
  400. package/src/modules/billing/__tests__/lib/lineAmounts.test.ts +86 -0
  401. package/src/modules/billing/__tests__/lib/navigation.test.ts +71 -0
  402. package/src/modules/billing/__tests__/lib/numbering.test.ts +91 -0
  403. package/src/modules/billing/__tests__/lib/overdue.test.ts +36 -0
  404. package/src/modules/billing/__tests__/lib/paymentCsv.test.ts +148 -0
  405. package/src/modules/billing/__tests__/lib/paymentImport.test.ts +113 -0
  406. package/src/modules/billing/__tests__/lib/paymentsSample.test.ts +73 -0
  407. package/src/modules/billing/__tests__/lib/pdf/invoicePdf.test.ts +269 -0
  408. package/src/modules/billing/__tests__/lib/pdf/invoicePdfService.test.ts +147 -0
  409. package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +374 -98
  410. package/src/modules/billing/__tests__/lib/prepaidTaxPoint.test.ts +118 -0
  411. package/src/modules/billing/__tests__/lib/seedsDemo.test.ts +53 -2
  412. package/src/modules/billing/__tests__/lib/sellerSettings.test.ts +28 -0
  413. package/src/modules/billing/__tests__/lib/servicePeriods.test.ts +190 -0
  414. package/src/modules/billing/__tests__/lib/topupCapture.test.ts +6 -28
  415. package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +21 -52
  416. package/src/modules/billing/__tests__/lib/vat.test.ts +51 -0
  417. package/src/modules/billing/__tests__/package-isolation.test.ts +22 -8
  418. package/src/modules/billing/__tests__/setup.test.ts +13 -4
  419. package/src/modules/billing/__tests__/validators.test.ts +197 -3
  420. package/src/modules/billing/acl.ts +12 -0
  421. package/src/modules/billing/api/accounts/[id]/summary/route.ts +62 -0
  422. package/src/modules/billing/api/accounts/route.ts +59 -4
  423. package/src/modules/billing/api/export/account/[id]/route.ts +13 -11
  424. package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
  425. package/src/modules/billing/api/invoices/[id]/pdf/route.ts +80 -0
  426. package/src/modules/billing/api/invoices/[id]/route.ts +57 -70
  427. package/src/modules/billing/api/invoices/[id]/send/route.ts +127 -0
  428. package/src/modules/billing/api/invoices/add-line/route.ts +2 -2
  429. package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
  430. package/src/modules/billing/api/invoices/edit-line/route.ts +2 -2
  431. package/src/modules/billing/api/invoices/post/route.ts +7 -6
  432. package/src/modules/billing/api/invoices/remove-line/route.ts +2 -2
  433. package/src/modules/billing/api/invoices/route.ts +81 -86
  434. package/src/modules/billing/api/items/bulk/route.ts +2 -1
  435. package/src/modules/billing/api/items/change-price/route.ts +54 -0
  436. package/src/modules/billing/api/items/route.ts +23 -7
  437. package/src/modules/billing/api/payment-imports/[id]/route.ts +49 -0
  438. package/src/modules/billing/api/payment-imports/route.ts +57 -0
  439. package/src/modules/billing/api/payments/[id]/route.ts +63 -0
  440. package/src/modules/billing/api/payments/allocate/route.ts +35 -0
  441. package/src/modules/billing/api/payments/assign/route.ts +36 -0
  442. package/src/modules/billing/api/payments/convert-to-topup/route.ts +35 -0
  443. package/src/modules/billing/api/payments/ignore/route.ts +35 -0
  444. package/src/modules/billing/api/payments/import/route.ts +72 -0
  445. package/src/modules/billing/api/payments/restore/route.ts +35 -0
  446. package/src/modules/billing/api/payments/route.ts +147 -0
  447. package/src/modules/billing/api/payments/unallocate/route.ts +35 -0
  448. package/src/modules/billing/api/payments/unassign/route.ts +35 -0
  449. package/src/modules/billing/api/run-outcomes/route.ts +49 -6
  450. package/src/modules/billing/api/runs/[id]/post-drafts/route.ts +71 -0
  451. package/src/modules/billing/api/runs/[id]/route.ts +59 -0
  452. package/src/modules/billing/api/runs/retry-failed/route.ts +2 -1
  453. package/src/modules/billing/api/runs/route.ts +15 -7
  454. package/src/modules/billing/api/settings/number-preview/route.ts +46 -0
  455. package/src/modules/billing/api/settings/route.ts +116 -0
  456. package/src/modules/billing/api/statements/route.ts +5 -0
  457. package/src/modules/billing/api/test-invoices/wipe/route.ts +2 -2
  458. package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +151 -372
  459. package/src/modules/billing/backend/billing/accounts/create/page.tsx +6 -0
  460. package/src/modules/billing/backend/billing/accounts/page.tsx +70 -4
  461. package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +444 -95
  462. package/src/modules/billing/backend/billing/invoices/page.tsx +8 -227
  463. package/src/modules/billing/backend/billing/items/[id]/page.tsx +75 -6
  464. package/src/modules/billing/backend/billing/items/create/page.tsx +13 -8
  465. package/src/modules/billing/backend/billing/items/page.tsx +18 -2
  466. package/src/modules/billing/backend/billing/payments/[id]/page.meta.ts +19 -0
  467. package/src/modules/billing/backend/billing/payments/[id]/page.tsx +415 -0
  468. package/src/modules/billing/backend/billing/payments/imports/[id]/page.meta.ts +19 -0
  469. package/src/modules/billing/backend/billing/payments/imports/[id]/page.tsx +106 -0
  470. package/src/modules/billing/backend/billing/payments/page.meta.ts +16 -0
  471. package/src/modules/billing/backend/billing/payments/page.tsx +56 -0
  472. package/src/modules/billing/backend/billing/runs/[id]/page.tsx +49 -18
  473. package/src/modules/billing/backend/billing/runs/page.tsx +59 -8
  474. package/src/modules/billing/backend/billing/statements/[id]/page.tsx +86 -5
  475. package/src/modules/billing/backend/billing/statements/page.tsx +1 -1
  476. package/src/modules/billing/backend/billing/topups/page.tsx +1 -1
  477. package/src/modules/billing/backend/billing/transactions/page.tsx +1 -1
  478. package/src/modules/billing/backend/billing/usage/create/page.tsx +3 -2
  479. package/src/modules/billing/backend/config/billing/page.meta.ts +21 -0
  480. package/src/modules/billing/backend/config/billing/page.tsx +549 -0
  481. package/src/modules/billing/cli.ts +31 -1
  482. package/src/modules/billing/commands/accounts.ts +6 -0
  483. package/src/modules/billing/commands/index.ts +3 -0
  484. package/src/modules/billing/commands/invoices.ts +364 -231
  485. package/src/modules/billing/commands/items.ts +143 -0
  486. package/src/modules/billing/commands/memos.ts +218 -0
  487. package/src/modules/billing/commands/payments.ts +428 -0
  488. package/src/modules/billing/commands/runs.ts +205 -3
  489. package/src/modules/billing/commands/settings.ts +77 -0
  490. package/src/modules/billing/commands/topups.ts +12 -3
  491. package/src/modules/billing/commands/transactions.ts +2 -2
  492. package/src/modules/billing/components/AccountForm.tsx +199 -53
  493. package/src/modules/billing/components/AccountInvoicesSection.tsx +75 -0
  494. package/src/modules/billing/components/AccountPaymentsSection.tsx +42 -0
  495. package/src/modules/billing/components/AccountPicker.tsx +70 -0
  496. package/src/modules/billing/components/AllocatePaymentDialog.tsx +167 -0
  497. package/src/modules/billing/components/BillingDataTable.tsx +34 -0
  498. package/src/modules/billing/components/BillingSettingsLink.tsx +25 -0
  499. package/src/modules/billing/components/ChangeItemPriceDialog.tsx +180 -0
  500. package/src/modules/billing/components/CreateMemoDialog.tsx +232 -0
  501. package/src/modules/billing/components/CustomerLabel.tsx +53 -0
  502. package/src/modules/billing/components/InvoicesTable.tsx +344 -0
  503. package/src/modules/billing/components/ItemForm.tsx +233 -44
  504. package/src/modules/billing/components/ItemPriceField.tsx +81 -0
  505. package/src/modules/billing/components/LineFormDialog.tsx +25 -1
  506. package/src/modules/billing/components/ManualPaymentDialog.tsx +140 -0
  507. package/src/modules/billing/components/MoneyInput.tsx +26 -0
  508. package/src/modules/billing/components/PaymentUploadDialog.tsx +148 -0
  509. package/src/modules/billing/components/PaymentsTable.tsx +213 -0
  510. package/src/modules/billing/components/PostRunDraftsButton.tsx +129 -0
  511. package/src/modules/billing/components/PrepaidPanel.tsx +19 -6
  512. package/src/modules/billing/components/RunCyclesSection.tsx +298 -0
  513. package/src/modules/billing/components/TestRunActions.tsx +152 -0
  514. package/src/modules/billing/components/account/AccountItemsTab.tsx +192 -0
  515. package/src/modules/billing/components/account/AccountRunBillingDialog.tsx +147 -0
  516. package/src/modules/billing/components/account/AccountRunsTab.tsx +201 -0
  517. package/src/modules/billing/components/account/AccountStatementsTab.tsx +120 -0
  518. package/src/modules/billing/components/account/AccountSummaryCards.tsx +153 -0
  519. package/src/modules/billing/components/account/AccountUsageTab.tsx +122 -0
  520. package/src/modules/billing/components/account/AccountView.tsx +101 -0
  521. package/src/modules/billing/components/account/accountRow.ts +70 -0
  522. package/src/modules/billing/components/customerNames.ts +62 -0
  523. package/src/modules/billing/data/entities.ts +656 -6
  524. package/src/modules/billing/data/entityIds.ts +9 -0
  525. package/src/modules/billing/data/validators.ts +388 -8
  526. package/src/modules/billing/events.ts +56 -3
  527. package/src/modules/billing/i18n/de.json +880 -0
  528. package/src/modules/billing/i18n/en.json +457 -21
  529. package/src/modules/billing/i18n/es.json +880 -0
  530. package/src/modules/billing/i18n/pl.json +458 -22
  531. package/src/modules/billing/index.ts +6 -2
  532. package/src/modules/billing/lib/accountFinancials.ts +84 -0
  533. package/src/modules/billing/lib/accountLock.ts +32 -0
  534. package/src/modules/billing/lib/accountStatus.ts +11 -9
  535. package/src/modules/billing/lib/accountSummary.ts +172 -0
  536. package/src/modules/billing/lib/allocation.ts +515 -0
  537. package/src/modules/billing/lib/allocationEvents.ts +26 -0
  538. package/src/modules/billing/lib/billPeriod.ts +19 -0
  539. package/src/modules/billing/lib/billRunEngine.ts +350 -150
  540. package/src/modules/billing/lib/billingSettings.ts +145 -0
  541. package/src/modules/billing/lib/commandRoute.ts +112 -0
  542. package/src/modules/billing/lib/customerLookup.ts +157 -0
  543. package/src/modules/billing/lib/dateOnly.ts +22 -0
  544. package/src/modules/billing/lib/documentParties.ts +23 -0
  545. package/src/modules/billing/lib/documentTypes.ts +37 -0
  546. package/src/modules/billing/lib/dueDate.ts +26 -0
  547. package/src/modules/billing/lib/iban.ts +36 -0
  548. package/src/modules/billing/lib/invoiceDelivery.ts +196 -0
  549. package/src/modules/billing/lib/invoiceLanguages.ts +57 -0
  550. package/src/modules/billing/lib/invoiceWriter.ts +162 -148
  551. package/src/modules/billing/lib/itemBillingState.ts +67 -0
  552. package/src/modules/billing/lib/itemPriceChange.ts +56 -0
  553. package/src/modules/billing/lib/itemSelector.ts +4 -1
  554. package/src/modules/billing/lib/lineAmounts.ts +61 -0
  555. package/src/modules/billing/lib/memoGuards.ts +41 -0
  556. package/src/modules/billing/lib/navigation.ts +64 -0
  557. package/src/modules/billing/lib/numbering.ts +174 -0
  558. package/src/modules/billing/lib/overdue.ts +60 -0
  559. package/src/modules/billing/lib/paymentCsv.ts +171 -0
  560. package/src/modules/billing/lib/paymentGateway.ts +52 -0
  561. package/src/modules/billing/lib/paymentImport.ts +228 -0
  562. package/src/modules/billing/lib/paymentMatcher.ts +88 -0
  563. package/src/modules/billing/lib/pdf/attachmentStore.ts +60 -0
  564. package/src/modules/billing/lib/pdf/fonts/NotoSans-Bold.ttf +0 -0
  565. package/src/modules/billing/lib/pdf/fonts/NotoSans-Regular.ttf +0 -0
  566. package/src/modules/billing/lib/pdf/fonts/OFL.txt +93 -0
  567. package/src/modules/billing/lib/pdf/fonts/embeddedFonts.ts +9 -0
  568. package/src/modules/billing/lib/pdf/invoiceModel.ts +329 -0
  569. package/src/modules/billing/lib/pdf/invoicePdf.ts +220 -0
  570. package/src/modules/billing/lib/pdf/invoiceTemplate.ts +338 -0
  571. package/src/modules/billing/lib/prepaidConfig.ts +27 -36
  572. package/src/modules/billing/lib/prepaidConsume.ts +29 -6
  573. package/src/modules/billing/lib/prepaidPeriodClose.ts +407 -239
  574. package/src/modules/billing/lib/prepaidTaxPoint.ts +76 -0
  575. package/src/modules/billing/lib/seeds/demo.ts +79 -6
  576. package/src/modules/billing/lib/seeds/paymentsSample.ts +136 -0
  577. package/src/modules/billing/lib/seeds/sellerSettings.ts +78 -0
  578. package/src/modules/billing/lib/servicePeriods.ts +226 -0
  579. package/src/modules/billing/lib/testRunCleanup.ts +42 -0
  580. package/src/modules/billing/lib/topupCapture.ts +3 -4
  581. package/src/modules/billing/lib/topupReceipt.ts +70 -103
  582. package/src/modules/billing/lib/usageRater.ts +1 -1
  583. package/src/modules/billing/lib/usageRunner.ts +17 -5
  584. package/src/modules/billing/lib/vat.ts +56 -0
  585. package/src/modules/billing/migrations/Migration20261114000000_billing_customer_kind.ts +25 -0
  586. package/src/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.ts +37 -0
  587. package/src/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.ts +132 -0
  588. package/src/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.ts +58 -0
  589. package/src/modules/billing/migrations/Migration20261117000000_billing_payments.ts +97 -0
  590. package/src/modules/billing/migrations/Migration20261118000000_billing_memos.ts +21 -0
  591. package/src/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.ts +39 -0
  592. package/src/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.ts +35 -0
  593. package/src/modules/billing/setup.ts +11 -237
  594. package/src/modules/billing/subscribers/credit-memo-auto-send.ts +15 -0
  595. package/src/modules/billing/subscribers/debit-memo-apply-credit.ts +15 -0
  596. package/src/modules/billing/subscribers/debit-memo-auto-send.ts +15 -0
  597. package/src/modules/billing/subscribers/invoice-apply-credit.ts +39 -0
  598. package/src/modules/billing/subscribers/invoice-auto-send.ts +46 -0
  599. package/src/modules/billing/subscribers/payment-captured-to-paid.ts +84 -62
  600. package/src/modules/billing/subscribers/prepaid-topup-captured.ts +4 -8
  601. package/dist/modules/billing/lib/invoiceStatus.js +0 -38
  602. package/dist/modules/billing/lib/invoiceStatus.js.map +0 -7
  603. package/src/modules/billing/__tests__/lib/invoiceStatus.test.ts +0 -97
  604. package/src/modules/billing/lib/invoiceStatus.ts +0 -61
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/billing/api/invoices/%5Bid%5D/memos/route.ts"],
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { readRequestBody, runCommandRoute } from '../../../../lib/commandRoute'\n\n/**\n * `POST /api/billing/invoices/[id]/memos` \u2014 create a DRAFT credit or debit\n * memo correcting a posted billing invoice (Spec D). Post it with\n * `POST /api/billing/invoices/post`.\n */\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.correct'] },\n}\n\nconst lineSchema = z.object({\n correctsLineId: z.string().uuid().optional(),\n description: z.string().trim().min(1).max(500),\n quantity: z.coerce.number().positive(),\n unitPriceNet: z.coerce.number().nonnegative(),\n taxRate: z.coerce.number().min(0).max(100).optional(),\n})\n\nconst bodySchema = z.object({\n invoiceId: z.string().uuid(),\n type: z.enum(['credit_memo', 'debit_memo']),\n reason: z.string().trim().min(1).max(1000),\n lines: z.array(lineSchema).max(200).optional(),\n})\n\nexport async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {\n const { id } = await params\n const raw = (await readRequestBody(req)) as Record<string, unknown>\n return runCommandRoute(\n req,\n {\n commandId: 'billing.invoices.create_memo',\n bodySchema,\n resourceKind: 'billing.invoice',\n resourceId: (body) => body.invoiceId,\n logLabel: 'billing/invoices/[id]/memos.POST',\n },\n { ...(raw && typeof raw === 'object' ? raw : {}), invoiceId: id },\n )\n}\n\nexport const openApi = {\n methods: {\n POST: {\n tags: ['Billing'],\n summary: 'Create a credit or debit memo',\n description:\n 'Creates a draft memo for a posted / partially paid / paid invoice (a fully credited invoice ' +\n 'accepts debit memos only). `reason` is required and printed. Credit memo without `lines` = full ' +\n 'credit of every original line; lines with `correctsLineId` keep the original VAT rate; new lines ' +\n 'default to the organization rate. Amounts are positive \u2014 the document type gives the sign.',\n requestBody: { schema: bodySchema.omit({ invoiceId: true }) },\n responses: [{ status: 200, description: '`{ memoId, number, documentType, totalGross }`' }],\n errors: [\n { status: 409, description: '`billing.memo.invalid_original` / `billing.memo.exceeds_invoice`' },\n { status: 400, description: '`billing.memo.invalid_line`' },\n ],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,iBAAiB,uBAAuB;AAQ1C,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAC1E;AAEA,MAAM,aAAa,EAAE,OAAO;AAAA,EAC1B,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3C,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC7C,UAAU,EAAE,OAAO,OAAO,EAAE,SAAS;AAAA,EACrC,cAAc,EAAE,OAAO,OAAO,EAAE,YAAY;AAAA,EAC5C,SAAS,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AACtD,CAAC;AAED,MAAM,aAAa,EAAE,OAAO;AAAA,EAC1B,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,MAAM,EAAE,KAAK,CAAC,eAAe,YAAY,CAAC;AAAA,EAC1C,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,GAAI;AAAA,EACzC,OAAO,EAAE,MAAM,UAAU,EAAE,IAAI,GAAG,EAAE,SAAS;AAC/C,CAAC;AAED,eAAsB,KAAK,KAAc,EAAE,OAAO,GAAwC;AACxF,QAAM,EAAE,GAAG,IAAI,MAAM;AACrB,QAAM,MAAO,MAAM,gBAAgB,GAAG;AACtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,WAAW;AAAA,MACX;AAAA,MACA,cAAc;AAAA,MACd,YAAY,CAAC,SAAS,KAAK;AAAA,MAC3B,UAAU;AAAA,IACZ;AAAA,IACA,EAAE,GAAI,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC,GAAI,WAAW,GAAG;AAAA,EAClE;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,MAAM,CAAC,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,aACE;AAAA,MAIF,aAAa,EAAE,QAAQ,WAAW,KAAK,EAAE,WAAW,KAAK,CAAC,EAAE;AAAA,MAC5D,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,iDAAiD,CAAC;AAAA,MAC1F,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,mEAAmE;AAAA,QAC/F,EAAE,QAAQ,KAAK,aAAa,8BAA8B;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,70 @@
1
+ import { NextResponse } from "next/server";
2
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
3
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { BillingInvoice } from "../../../../data/entities.js";
5
+ import { getInvoicePdf } from "../../../../lib/pdf/invoicePdf.js";
6
+ import { INVOICE_LANGUAGE_CODES } from "../../../../lib/invoiceLanguages.js";
7
+ const metadata = {
8
+ GET: { requireAuth: true, requireFeatures: ["billing.invoice.view"] }
9
+ };
10
+ async function GET(req, { params }) {
11
+ try {
12
+ const container = await createRequestContainer();
13
+ const auth = await getAuthFromRequest(req);
14
+ if (!auth || !auth.tenantId) {
15
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
16
+ }
17
+ const organizationId = auth.orgId ?? null;
18
+ if (!organizationId) {
19
+ return NextResponse.json({ error: "Organization scope required" }, { status: 403 });
20
+ }
21
+ const { id } = await params;
22
+ const em = container.resolve("em").fork();
23
+ const invoice = await em.findOne(BillingInvoice, {
24
+ id,
25
+ tenantId: auth.tenantId,
26
+ organizationId,
27
+ deletedAt: null
28
+ });
29
+ if (!invoice) {
30
+ return NextResponse.json({ error: "Invoice not found" }, { status: 404 });
31
+ }
32
+ const pdf = await getInvoicePdf(em, invoice);
33
+ const download = new URL(req.url).searchParams.get("download") === "1";
34
+ return new NextResponse(Buffer.from(pdf.bytes), {
35
+ status: 200,
36
+ headers: {
37
+ "Content-Type": "application/pdf",
38
+ "Content-Length": String(pdf.bytes.byteLength),
39
+ "Content-Disposition": `${download ? "attachment" : "inline"}; filename="${pdf.fileName}"`,
40
+ // Drafts change with every edit; frozen documents never do.
41
+ "Cache-Control": pdf.frozen ? "private, max-age=300" : "no-store",
42
+ "X-Content-Type-Options": "nosniff"
43
+ }
44
+ });
45
+ } catch (err) {
46
+ console.error("[billing/invoices/[id]/pdf.GET]", err);
47
+ return NextResponse.json({ error: "Internal error" }, { status: 500 });
48
+ }
49
+ }
50
+ const openApi = {
51
+ methods: {
52
+ GET: {
53
+ tags: ["Billing"],
54
+ summary: "Download a billing document PDF",
55
+ parameters: [
56
+ { name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } },
57
+ { name: "download", in: "query", required: false, schema: { type: "string", enum: ["1"] } }
58
+ ],
59
+ description: `\`application/pdf\`. Posted documents return the PDF frozen at post (an attachment); drafts and test documents are rendered live with a DRAFT / TEST watermark and never stored. Labels follow the account invoice language (${INVOICE_LANGUAGE_CODES.join(" / ")}).`,
60
+ responses: [{ status: 200, description: "PDF document (`application/pdf`)" }],
61
+ errors: [{ status: 404, description: "Invoice not found in this organization" }]
62
+ }
63
+ }
64
+ };
65
+ export {
66
+ GET,
67
+ metadata,
68
+ openApi
69
+ };
70
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/billing/api/invoices/%5Bid%5D/pdf/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { BillingInvoice } from '../../../../data/entities'\nimport { getInvoicePdf } from '../../../../lib/pdf/invoicePdf'\nimport { INVOICE_LANGUAGE_CODES } from '../../../../lib/invoiceLanguages'\n\n/**\n * `GET /api/billing/invoices/[id]/pdf` \u2014 the document PDF (Spec B).\n *\n * Posted documents: the frozen attachment (rendered and frozen on first\n * request if freezing failed at post). Drafts / test documents: a live\n * render with a DRAFT / TEST watermark, never stored. `?download=1` forces\n * an attachment disposition; otherwise the browser shows it inline.\n */\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['billing.invoice.view'] },\n}\n\nexport async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const organizationId = (auth as { orgId?: string }).orgId ?? null\n if (!organizationId) {\n return NextResponse.json({ error: 'Organization scope required' }, { status: 403 })\n }\n const { id } = await params\n const em = (container.resolve('em') as EntityManager).fork()\n const invoice = await em.findOne(BillingInvoice, {\n id,\n tenantId: auth.tenantId,\n organizationId,\n deletedAt: null,\n } as never)\n if (!invoice) {\n return NextResponse.json({ error: 'Invoice not found' }, { status: 404 })\n }\n const pdf = await getInvoicePdf(em, invoice)\n const download = new URL(req.url).searchParams.get('download') === '1'\n return new NextResponse(Buffer.from(pdf.bytes), {\n status: 200,\n headers: {\n 'Content-Type': 'application/pdf',\n 'Content-Length': String(pdf.bytes.byteLength),\n 'Content-Disposition': `${download ? 'attachment' : 'inline'}; filename=\"${pdf.fileName}\"`,\n // Drafts change with every edit; frozen documents never do.\n 'Cache-Control': pdf.frozen ? 'private, max-age=300' : 'no-store',\n 'X-Content-Type-Options': 'nosniff',\n },\n })\n } catch (err) {\n console.error('[billing/invoices/[id]/pdf.GET]', err)\n return NextResponse.json({ error: 'Internal error' }, { status: 500 })\n }\n}\n\nexport const openApi = {\n methods: {\n GET: {\n tags: ['Billing'],\n summary: 'Download a billing document PDF',\n parameters: [\n { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } },\n { name: 'download', in: 'query', required: false, schema: { type: 'string', enum: ['1'] } },\n ],\n description:\n '`application/pdf`. Posted documents return the PDF frozen at post (an attachment); drafts ' +\n 'and test documents are rendered live with a DRAFT / TEST watermark and never stored. ' +\n `Labels follow the account invoice language (${INVOICE_LANGUAGE_CODES.join(' / ')}).`,\n responses: [{ status: 200, description: 'PDF document (`application/pdf`)' }],\n errors: [{ status: 404, description: 'Invoice not found in this organization' }],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAWhC,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACtE;AAEA,eAAsB,IAAI,KAAc,EAAE,OAAO,GAAwC;AACvF,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAI,CAAC,QAAQ,CAAC,KAAK,UAAU;AAC3B,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AACA,UAAM,iBAAkB,KAA4B,SAAS;AAC7D,QAAI,CAAC,gBAAgB;AACnB,aAAO,aAAa,KAAK,EAAE,OAAO,8BAA8B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACpF;AACA,UAAM,EAAE,GAAG,IAAI,MAAM;AACrB,UAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,UAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB;AAAA,MAC/C;AAAA,MACA,UAAU,KAAK;AAAA,MACf;AAAA,MACA,WAAW;AAAA,IACb,CAAU;AACV,QAAI,CAAC,SAAS;AACZ,aAAO,aAAa,KAAK,EAAE,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC1E;AACA,UAAM,MAAM,MAAM,cAAc,IAAI,OAAO;AAC3C,UAAM,WAAW,IAAI,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,UAAU,MAAM;AACnE,WAAO,IAAI,aAAa,OAAO,KAAK,IAAI,KAAK,GAAG;AAAA,MAC9C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,kBAAkB,OAAO,IAAI,MAAM,UAAU;AAAA,QAC7C,uBAAuB,GAAG,WAAW,eAAe,QAAQ,eAAe,IAAI,QAAQ;AAAA;AAAA,QAEvF,iBAAiB,IAAI,SAAS,yBAAyB;AAAA,QACvD,0BAA0B;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,mCAAmC,GAAG;AACpD,WAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACvE;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,KAAK;AAAA,MACH,MAAM,CAAC,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,EAAE,MAAM,MAAM,IAAI,QAAQ,UAAU,MAAM,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO,EAAE;AAAA,QACrF,EAAE,MAAM,YAAY,IAAI,SAAS,UAAU,OAAO,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,GAAG,EAAE,EAAE;AAAA,MAC5F;AAAA,MACA,aACE,gOAE+C,uBAAuB,KAAK,KAAK,CAAC;AAAA,MACnF,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,mCAAmC,CAAC;AAAA,MAC5E,QAAQ,CAAC,EAAE,QAAQ,KAAK,aAAa,yCAAyC,CAAC;AAAA,IACjF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -1,6 +1,7 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
3
3
  import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
4
+ import { daysOverdueSql, isoDay } from "../../../lib/overdue.js";
4
5
  const metadata = {
5
6
  GET: { requireAuth: true, requireFeatures: ["billing.invoice.view"] }
6
7
  };
@@ -20,40 +21,59 @@ async function GET(req, { params }) {
20
21
  }
21
22
  const { id: invoiceId } = await params;
22
23
  const em = container.resolve("em").fork();
24
+ const today = isoDay(/* @__PURE__ */ new Date());
23
25
  const invoiceRows = await em.execute(
24
- `SELECT id, invoice_number, status, status_entry_id, currency_code,
25
- issue_date, due_date,
26
- subtotal_net_amount, subtotal_gross_amount,
27
- discount_total_amount, tax_total_amount,
28
- grand_total_net_amount, grand_total_gross_amount,
29
- paid_total_amount, outstanding_amount,
30
- metadata, created_at, updated_at
31
- FROM sales_invoices
32
- WHERE id = ?
33
- AND tenant_id = ?
34
- AND organization_id = ?
35
- AND deleted_at IS NULL
36
- AND jsonb_exists(metadata, 'bill_run_id')`,
37
- [invoiceId, auth.tenantId, organizationId]
26
+ `SELECT i.id, i.number, i.document_type, i.series, i.status, i.test_run, i.bill_account_id,
27
+ a.name AS bill_account_name, i.bill_run_id, i.bill_date, i.period_start, i.period_end,
28
+ i.issue_date, i.due_date, i.posted_at, i.currency_code, i.subtotal_net, i.tax_total,
29
+ i.total_gross, i.paid_total, i.credited_total, i.outstanding, i.corrects_invoice_id,
30
+ i.correction_reason, i.corrects_invoice_number, i.corrects_issue_date,
31
+ i.buyer_snapshot, i.seller_snapshot, i.topup_id, i.metadata,
32
+ i.pdf_attachment_id, ${daysOverdueSql("i")}::int AS days_overdue,
33
+ i.created_at, i.updated_at
34
+ FROM billing_invoices i
35
+ LEFT JOIN billing_accounts a ON a.id = i.bill_account_id AND a.tenant_id = i.tenant_id
36
+ WHERE i.id = ? AND i.tenant_id = ? AND i.organization_id = ? AND i.deleted_at IS NULL`,
37
+ [today, today, invoiceId, auth.tenantId, organizationId]
38
38
  );
39
39
  if (!invoiceRows || invoiceRows.length === 0) {
40
40
  return NextResponse.json({ error: "Invoice not found" }, { status: 404 });
41
41
  }
42
42
  const invoice = invoiceRows[0];
43
43
  const lineRows = await em.execute(
44
- `SELECT id, line_number, kind, description, quantity, currency_code,
45
- unit_price_net, unit_price_gross, tax_rate, tax_amount,
46
- total_net_amount, total_gross_amount, metadata
47
- FROM sales_invoice_lines
48
- WHERE invoice_id = ?
49
- AND tenant_id = ?
50
- AND organization_id = ?
44
+ `SELECT id, line_number, billing_item_id, billing_type, description, quantity,
45
+ unit_price_net, tax_rate, net_amount, tax_amount, gross_amount,
46
+ service_period_start, service_period_end, corrects_line_id, metadata
47
+ FROM billing_invoice_lines
48
+ WHERE invoice_id = ? AND tenant_id = ? AND organization_id = ? AND deleted_at IS NULL
51
49
  ORDER BY line_number ASC`,
52
50
  [invoiceId, auth.tenantId, organizationId]
53
51
  );
52
+ const allocations = await em.execute(
53
+ `SELECT al.id, al.source_type, al.source_id, al.amount, al.currency_code, al.allocated_by, al.created_at,
54
+ CASE WHEN al.source_type = 'payment' THEN COALESCE(p.reference, p.payer_name)
55
+ ELSE m.number END AS source_label,
56
+ p.received_at AS payment_received_at
57
+ FROM billing_allocations al
58
+ LEFT JOIN billing_payments p ON al.source_type = 'payment' AND p.id = al.source_id
59
+ LEFT JOIN billing_invoices m ON al.source_type = 'credit_memo' AND m.id = al.source_id
60
+ WHERE al.invoice_id = ? AND al.tenant_id = ? AND al.organization_id = ? AND al.deleted_at IS NULL
61
+ ORDER BY al.created_at ASC`,
62
+ [invoiceId, auth.tenantId, organizationId]
63
+ );
64
+ const corrections = await em.execute(
65
+ `SELECT id, number, document_type, status, total_gross, outstanding, currency_code, correction_reason, created_at
66
+ FROM billing_invoices
67
+ WHERE corrects_invoice_id = ? AND tenant_id = ? AND organization_id = ? AND deleted_at IS NULL
68
+ ORDER BY created_at ASC`,
69
+ [invoiceId, auth.tenantId, organizationId]
70
+ );
54
71
  return NextResponse.json({
72
+ corrections,
73
+ allocations,
55
74
  invoice,
56
- lines: lineRows
75
+ // Lines carry the document currency for display convenience.
76
+ lines: lineRows.map((line) => ({ ...line, currency_code: invoice.currency_code }))
57
77
  });
58
78
  } catch (err) {
59
79
  console.error("[billing/invoices/[id].GET]", err);
@@ -64,8 +84,8 @@ const openApi = {
64
84
  methods: {
65
85
  GET: {
66
86
  tags: ["Billing"],
67
- summary: "Get a billing-managed invoice (with lines)",
68
- description: "Returns the `core/sales` invoice + every line, scoped to billing-managed invoices (`metadata.bill_run_id` set). Non-billing invoices return 404 even when the UUID resolves at `/api/sales/invoices/[id]`.",
87
+ summary: "Get a billing document (with lines)",
88
+ description: "Returns one billing document from `billing_invoices` (invoice, memo or receipt) with its lines, the frozen buyer / seller snapshots, `bill_account_name` and `allocations[]` (Spec C: payments / credit memos that settled it, with `source_label`) and `corrections[]` (Spec D memos). 404 outside the caller's organization.",
69
89
  parameters: [
70
90
  {
71
91
  name: "id",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/api/invoices/%5Bid%5D/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\n\n/**\n * `GET /api/billing/invoices/[id]` \u2014 billing-invoice detail.\n *\n * Returns the `core/sales` invoice row + its lines, but only if the\n * invoice is billing-managed (carries `metadata.bill_run_id`). Other\n * `core/sales` invoices return 404 here even though the same UUID\n * resolves at `/api/sales/invoices/[id]` \u2014 this endpoint is the\n * billing operator's surface, scoped to the billing universe.\n */\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['billing.invoice.view'] },\n}\n\ntype InvoiceRow = {\n id: string\n invoice_number: string\n status: string | null\n status_entry_id: string | null\n currency_code: string\n issue_date: string | null\n due_date: string | null\n subtotal_net_amount: string\n subtotal_gross_amount: string\n discount_total_amount: string\n tax_total_amount: string\n grand_total_net_amount: string\n grand_total_gross_amount: string\n paid_total_amount: string\n outstanding_amount: string\n metadata: Record<string, unknown> | null\n created_at: string\n updated_at: string\n}\n\ntype InvoiceLineRow = {\n id: string\n line_number: number\n kind: string\n description: string | null\n quantity: string\n currency_code: string\n unit_price_net: string\n unit_price_gross: string\n tax_rate: string\n tax_amount: string\n total_net_amount: string\n total_gross_amount: string\n metadata: Record<string, unknown> | null\n}\n\nexport async function GET(\n req: Request,\n { params }: { params: Promise<{ id: string }> },\n) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const organizationId = (auth as { orgId?: string }).orgId ?? null\n if (!organizationId) {\n return NextResponse.json(\n { error: 'Organization scope required' },\n { status: 403 },\n )\n }\n\n const { id: invoiceId } = await params\n const em = (container.resolve('em') as EntityManager).fork()\n\n const invoiceRows = (await em.execute(\n `SELECT id, invoice_number, status, status_entry_id, currency_code,\n issue_date, due_date,\n subtotal_net_amount, subtotal_gross_amount,\n discount_total_amount, tax_total_amount,\n grand_total_net_amount, grand_total_gross_amount,\n paid_total_amount, outstanding_amount,\n metadata, created_at, updated_at\n FROM sales_invoices\n WHERE id = ?\n AND tenant_id = ?\n AND organization_id = ?\n AND deleted_at IS NULL\n AND jsonb_exists(metadata, 'bill_run_id')`,\n [invoiceId, auth.tenantId, organizationId],\n )) as unknown as InvoiceRow[]\n\n if (!invoiceRows || invoiceRows.length === 0) {\n return NextResponse.json({ error: 'Invoice not found' }, { status: 404 })\n }\n\n const invoice = invoiceRows[0]\n\n const lineRows = (await em.execute(\n `SELECT id, line_number, kind, description, quantity, currency_code,\n unit_price_net, unit_price_gross, tax_rate, tax_amount,\n total_net_amount, total_gross_amount, metadata\n FROM sales_invoice_lines\n WHERE invoice_id = ?\n AND tenant_id = ?\n AND organization_id = ?\n ORDER BY line_number ASC`,\n [invoiceId, auth.tenantId, organizationId],\n )) as unknown as InvoiceLineRow[]\n\n return NextResponse.json({\n invoice,\n lines: lineRows,\n })\n } catch (err) {\n console.error('[billing/invoices/[id].GET]', err)\n return NextResponse.json({ error: 'Internal error' }, { status: 500 })\n }\n}\n\nexport const openApi = {\n methods: {\n GET: {\n tags: ['Billing'],\n summary: 'Get a billing-managed invoice (with lines)',\n description:\n 'Returns the `core/sales` invoice + every line, scoped to ' +\n \"billing-managed invoices (`metadata.bill_run_id` set). Non-\" +\n 'billing invoices return 404 even when the UUID resolves at ' +\n '`/api/sales/invoices/[id]`.',\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string', format: 'uuid' },\n },\n ],\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AAY5B,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACtE;AAuCA,eAAsB,IACpB,KACA,EAAE,OAAO,GACT;AACA,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAI,CAAC,QAAQ,CAAC,KAAK,UAAU;AAC3B,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AACA,UAAM,iBAAkB,KAA4B,SAAS;AAC7D,QAAI,CAAC,gBAAgB;AACnB,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,8BAA8B;AAAA,QACvC,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,EAAE,IAAI,UAAU,IAAI,MAAM;AAChC,UAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAE3D,UAAM,cAAe,MAAM,GAAG;AAAA,MAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaA,CAAC,WAAW,KAAK,UAAU,cAAc;AAAA,IAC3C;AAEA,QAAI,CAAC,eAAe,YAAY,WAAW,GAAG;AAC5C,aAAO,aAAa,KAAK,EAAE,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC1E;AAEA,UAAM,UAAU,YAAY,CAAC;AAE7B,UAAM,WAAY,MAAM,GAAG;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,CAAC,WAAW,KAAK,UAAU,cAAc;AAAA,IAC3C;AAEA,WAAO,aAAa,KAAK;AAAA,MACvB;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,+BAA+B,GAAG;AAChD,WAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACvE;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,KAAK;AAAA,MACH,MAAM,CAAC,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,aACE;AAAA,MAIF,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { daysOverdueSql, isoDay } from '../../../lib/overdue'\n\n/**\n * `GET /api/billing/invoices/[id]` \u2014 one billing document with its lines\n * (Spec 0: `billing_invoices` / `billing_invoice_lines`). Documents of other\n * modules are never reachable here.\n */\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['billing.invoice.view'] },\n}\n\ntype InvoiceRow = Record<string, unknown> & { id: string; bill_account_id: string }\ntype InvoiceLineRow = Record<string, unknown> & { id: string }\n\nexport async function GET(\n req: Request,\n { params }: { params: Promise<{ id: string }> },\n) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const organizationId = (auth as { orgId?: string }).orgId ?? null\n if (!organizationId) {\n return NextResponse.json(\n { error: 'Organization scope required' },\n { status: 403 },\n )\n }\n\n const { id: invoiceId } = await params\n const em = (container.resolve('em') as EntityManager).fork()\n\n const today = isoDay(new Date())\n const invoiceRows = (await em.execute(\n `SELECT i.id, i.number, i.document_type, i.series, i.status, i.test_run, i.bill_account_id,\n a.name AS bill_account_name, i.bill_run_id, i.bill_date, i.period_start, i.period_end,\n i.issue_date, i.due_date, i.posted_at, i.currency_code, i.subtotal_net, i.tax_total,\n i.total_gross, i.paid_total, i.credited_total, i.outstanding, i.corrects_invoice_id,\n i.correction_reason, i.corrects_invoice_number, i.corrects_issue_date,\n i.buyer_snapshot, i.seller_snapshot, i.topup_id, i.metadata,\n i.pdf_attachment_id, ${daysOverdueSql('i')}::int AS days_overdue,\n i.created_at, i.updated_at\n FROM billing_invoices i\n LEFT JOIN billing_accounts a ON a.id = i.bill_account_id AND a.tenant_id = i.tenant_id\n WHERE i.id = ? AND i.tenant_id = ? AND i.organization_id = ? AND i.deleted_at IS NULL`,\n [today, today, invoiceId, auth.tenantId, organizationId],\n )) as unknown as InvoiceRow[]\n\n if (!invoiceRows || invoiceRows.length === 0) {\n return NextResponse.json({ error: 'Invoice not found' }, { status: 404 })\n }\n\n const invoice = invoiceRows[0]\n\n const lineRows = (await em.execute(\n `SELECT id, line_number, billing_item_id, billing_type, description, quantity,\n unit_price_net, tax_rate, net_amount, tax_amount, gross_amount,\n service_period_start, service_period_end, corrects_line_id, metadata\n FROM billing_invoice_lines\n WHERE invoice_id = ? AND tenant_id = ? AND organization_id = ? AND deleted_at IS NULL\n ORDER BY line_number ASC`,\n [invoiceId, auth.tenantId, organizationId],\n )) as unknown as InvoiceLineRow[]\n\n // Spec C: what settled this receivable (payments; Spec D adds credit memos).\n const allocations = await em.execute(\n `SELECT al.id, al.source_type, al.source_id, al.amount, al.currency_code, al.allocated_by, al.created_at,\n CASE WHEN al.source_type = 'payment' THEN COALESCE(p.reference, p.payer_name)\n ELSE m.number END AS source_label,\n p.received_at AS payment_received_at\n FROM billing_allocations al\n LEFT JOIN billing_payments p ON al.source_type = 'payment' AND p.id = al.source_id\n LEFT JOIN billing_invoices m ON al.source_type = 'credit_memo' AND m.id = al.source_id\n WHERE al.invoice_id = ? AND al.tenant_id = ? AND al.organization_id = ? AND al.deleted_at IS NULL\n ORDER BY al.created_at ASC`,\n [invoiceId, auth.tenantId, organizationId],\n )\n\n // Spec D: memos correcting this document.\n const corrections = await em.execute(\n `SELECT id, number, document_type, status, total_gross, outstanding, currency_code, correction_reason, created_at\n FROM billing_invoices\n WHERE corrects_invoice_id = ? AND tenant_id = ? AND organization_id = ? AND deleted_at IS NULL\n ORDER BY created_at ASC`,\n [invoiceId, auth.tenantId, organizationId],\n )\n\n return NextResponse.json({\n corrections,\n allocations,\n invoice,\n // Lines carry the document currency for display convenience.\n lines: lineRows.map((line) => ({ ...line, currency_code: invoice.currency_code })),\n })\n } catch (err) {\n console.error('[billing/invoices/[id].GET]', err)\n return NextResponse.json({ error: 'Internal error' }, { status: 500 })\n }\n}\n\nexport const openApi = {\n methods: {\n GET: {\n tags: ['Billing'],\n summary: 'Get a billing document (with lines)',\n description:\n 'Returns one billing document from `billing_invoices` (invoice, memo or receipt) with its ' +\n 'lines, the frozen buyer / seller snapshots, `bill_account_name` and `allocations[]` (Spec C: ' +\n 'payments / credit memos that settled it, with `source_label`) and `corrections[]` (Spec D memos). ' +\n '404 outside the ' +\n 'caller\\'s organization.',\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string', format: 'uuid' },\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,gBAAgB,cAAc;AAQhC,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACtE;AAKA,eAAsB,IACpB,KACA,EAAE,OAAO,GACT;AACA,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAI,CAAC,QAAQ,CAAC,KAAK,UAAU;AAC3B,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AACA,UAAM,iBAAkB,KAA4B,SAAS;AAC7D,QAAI,CAAC,gBAAgB;AACnB,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,8BAA8B;AAAA,QACvC,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,EAAE,IAAI,UAAU,IAAI,MAAM;AAChC,UAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAE3D,UAAM,QAAQ,OAAO,oBAAI,KAAK,CAAC;AAC/B,UAAM,cAAe,MAAM,GAAG;AAAA,MAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAM+B,eAAe,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,MAKlD,CAAC,OAAO,OAAO,WAAW,KAAK,UAAU,cAAc;AAAA,IACzD;AAEA,QAAI,CAAC,eAAe,YAAY,WAAW,GAAG;AAC5C,aAAO,aAAa,KAAK,EAAE,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC1E;AAEA,UAAM,UAAU,YAAY,CAAC;AAE7B,UAAM,WAAY,MAAM,GAAG;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,CAAC,WAAW,KAAK,UAAU,cAAc;AAAA,IAC3C;AAGA,UAAM,cAAc,MAAM,GAAG;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,CAAC,WAAW,KAAK,UAAU,cAAc;AAAA,IAC3C;AAGA,UAAM,cAAc,MAAM,GAAG;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA,MAIA,CAAC,WAAW,KAAK,UAAU,cAAc;AAAA,IAC3C;AAEA,WAAO,aAAa,KAAK;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA,OAAO,SAAS,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,eAAe,QAAQ,cAAc,EAAE;AAAA,IACnF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,+BAA+B,GAAG;AAChD,WAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACvE;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,KAAK;AAAA,MACH,MAAM,CAAC,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,aACE;AAAA,MAKF,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,107 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
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 { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
10
+ import { bridgeLegacyGuard, runMutationGuards } from "@open-mercato/shared/lib/crud/mutation-guard-registry";
11
+ const metadata = {
12
+ POST: { requireAuth: true, requireFeatures: ["billing.invoice.send"] }
13
+ };
14
+ function userFeatures(auth) {
15
+ const features = auth?.features;
16
+ return Array.isArray(features) ? features.filter((value) => typeof value === "string") : [];
17
+ }
18
+ async function POST(req, { params }) {
19
+ try {
20
+ const container = await createRequestContainer();
21
+ const auth = await getAuthFromRequest(req);
22
+ if (!auth || !auth.tenantId) {
23
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
24
+ }
25
+ const organizationId = resolveActiveOrganizationId(auth);
26
+ if (!organizationId) return organizationScopeRequiredResponse();
27
+ const { id } = await params;
28
+ const ctx = {
29
+ container,
30
+ auth,
31
+ organizationScope: null,
32
+ selectedOrganizationId: organizationId,
33
+ organizationIds: [organizationId],
34
+ request: req
35
+ };
36
+ const guardInput = {
37
+ tenantId: auth.tenantId,
38
+ organizationId,
39
+ userId: auth.sub ?? "",
40
+ resourceKind: "billing.invoice",
41
+ resourceId: id,
42
+ operation: "update",
43
+ requestMethod: req.method,
44
+ requestHeaders: req.headers
45
+ };
46
+ const legacyGuard = bridgeLegacyGuard(container);
47
+ const guardResult = legacyGuard ? await runMutationGuards([legacyGuard], guardInput, { userFeatures: userFeatures(auth) }) : { ok: true, afterSuccessCallbacks: [] };
48
+ if (!guardResult.ok) {
49
+ return NextResponse.json(guardResult.errorBody ?? { error: "Operation blocked by guard" }, {
50
+ status: guardResult.errorStatus ?? 422
51
+ });
52
+ }
53
+ const commandBus = container.resolve("commandBus");
54
+ const response = await commandBus.execute("billing.invoices.send", {
55
+ input: { tenantId: auth.tenantId, organizationId, invoiceId: id },
56
+ ctx
57
+ });
58
+ const result = response.result;
59
+ for (const callback of guardResult.afterSuccessCallbacks) {
60
+ if (!callback.guard.afterSuccess) continue;
61
+ try {
62
+ await callback.guard.afterSuccess({ ...guardInput, metadata: callback.metadata ?? null });
63
+ } catch (err) {
64
+ console.error("[billing/invoices/[id]/send.POST] guard afterSuccess failed", err);
65
+ }
66
+ }
67
+ return NextResponse.json(result ?? { invoiceId: id, status: "failed", error: null });
68
+ } catch (err) {
69
+ if (isCrudHttpError(err)) {
70
+ return NextResponse.json(err.body, { status: err.status });
71
+ }
72
+ console.error("[billing/invoices/[id]/send.POST]", err);
73
+ return NextResponse.json({ error: "Internal error" }, { status: 500 });
74
+ }
75
+ }
76
+ const openApi = {
77
+ methods: {
78
+ POST: {
79
+ tags: ["Billing"],
80
+ summary: "Email a posted billing document",
81
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
82
+ description: 'Sends the frozen PDF to the billing account invoice email through the platform email transport. Each attempt is appended to `metadata.deliveries` and emits `billing.invoice.sent` / `billing.invoice.send_failed`. Transport failures return 200 with `status: "failed"` and the error.',
83
+ responses: [
84
+ {
85
+ status: 200,
86
+ description: "Delivery attempted",
87
+ schema: z.object({
88
+ invoiceId: z.string().uuid(),
89
+ to: z.string(),
90
+ status: z.enum(["sent", "failed"]),
91
+ error: z.string().nullable()
92
+ })
93
+ }
94
+ ],
95
+ errors: [
96
+ { status: 409, description: "`billing.invoice.not_posted` \u2014 drafts and test documents cannot be sent" },
97
+ { status: 422, description: "`billing.invoice.email_invalid` \u2014 placeholder or malformed invoice email" }
98
+ ]
99
+ }
100
+ }
101
+ };
102
+ export {
103
+ POST,
104
+ metadata,
105
+ openApi
106
+ };
107
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/billing/api/invoices/%5Bid%5D/send/route.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport {\n organizationScopeRequiredResponse,\n resolveActiveOrganizationId,\n} from '@open-mercato/shared/lib/auth/organizationScope'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { bridgeLegacyGuard, runMutationGuards } from '@open-mercato/shared/lib/crud/mutation-guard-registry'\nimport type { SendInvoiceResult } from '../../../../lib/invoiceDelivery'\n\n/**\n * `POST /api/billing/invoices/[id]/send` \u2014 emails a posted billing document\n * with its frozen PDF to the account's invoice email (Spec B), via the\n * `billing.invoices.send` command.\n *\n * 200 `{ invoiceId, to, status: 'sent' | 'failed', error }` \u2014 a transport\n * failure is a recorded `failed` delivery, not an HTTP error.\n * 409 `billing.invoice.not_posted` (draft / test). 422\n * `billing.invoice.email_invalid` (placeholder or malformed address).\n */\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.send'] },\n}\n\nfunction userFeatures(auth: unknown): string[] {\n const features = (auth as { features?: unknown })?.features\n return Array.isArray(features) ? features.filter((value): value is string => typeof value === 'string') : []\n}\n\nexport async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const organizationId = resolveActiveOrganizationId(auth)\n if (!organizationId) return organizationScopeRequiredResponse()\n const { id } = await params\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId: organizationId,\n organizationIds: [organizationId],\n request: req,\n }\n // Custom write route \u2192 run the shared mutation guards (record locks etc.)\n // as `update` on the invoice before sending.\n const guardInput = {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'billing.invoice',\n resourceId: id,\n operation: 'update' as const,\n requestMethod: req.method,\n requestHeaders: req.headers,\n }\n const legacyGuard = bridgeLegacyGuard(container)\n const guardResult = legacyGuard\n ? await runMutationGuards([legacyGuard], guardInput, { userFeatures: userFeatures(auth) })\n : { ok: true as const, afterSuccessCallbacks: [] }\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, {\n status: guardResult.errorStatus ?? 422,\n })\n }\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const response = await commandBus.execute('billing.invoices.send', {\n input: { tenantId: auth.tenantId, organizationId, invoiceId: id },\n ctx,\n })\n const result = (response as { result?: SendInvoiceResult }).result\n for (const callback of guardResult.afterSuccessCallbacks) {\n if (!callback.guard.afterSuccess) continue\n try {\n await callback.guard.afterSuccess({ ...guardInput, metadata: callback.metadata ?? null })\n } catch (err) {\n console.error('[billing/invoices/[id]/send.POST] guard afterSuccess failed', err)\n }\n }\n return NextResponse.json(result ?? { invoiceId: id, status: 'failed', error: null })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n console.error('[billing/invoices/[id]/send.POST]', err)\n return NextResponse.json({ error: 'Internal error' }, { status: 500 })\n }\n}\n\nexport const openApi = {\n methods: {\n POST: {\n tags: ['Billing'],\n summary: 'Email a posted billing document',\n parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } }],\n description:\n 'Sends the frozen PDF to the billing account invoice email through the platform email ' +\n 'transport. Each attempt is appended to `metadata.deliveries` and emits ' +\n '`billing.invoice.sent` / `billing.invoice.send_failed`. Transport failures return ' +\n '200 with `status: \"failed\"` and the error.',\n responses: [\n {\n status: 200,\n description: 'Delivery attempted',\n schema: z.object({\n invoiceId: z.string().uuid(),\n to: z.string(),\n status: z.enum(['sent', 'failed']),\n error: z.string().nullable(),\n }),\n },\n ],\n errors: [\n { status: 409, description: '`billing.invoice.not_posted` \u2014 drafts and test documents cannot be sent' },\n { status: 422, description: '`billing.invoice.email_invalid` \u2014 placeholder or malformed invoice email' },\n ],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,SAAS,uBAAuB;AAChC,SAAS,mBAAmB,yBAAyB;AAc9C,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACvE;AAEA,SAAS,aAAa,MAAyB;AAC7C,QAAM,WAAY,MAAiC;AACnD,SAAO,MAAM,QAAQ,QAAQ,IAAI,SAAS,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ,IAAI,CAAC;AAC7G;AAEA,eAAsB,KAAK,KAAc,EAAE,OAAO,GAAwC;AACxF,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAI,CAAC,QAAQ,CAAC,KAAK,UAAU;AAC3B,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AACA,UAAM,iBAAiB,4BAA4B,IAAI;AACvD,QAAI,CAAC,eAAgB,QAAO,kCAAkC;AAC9D,UAAM,EAAE,GAAG,IAAI,MAAM;AACrB,UAAM,MAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,wBAAwB;AAAA,MACxB,iBAAiB,CAAC,cAAc;AAAA,MAChC,SAAS;AAAA,IACX;AAGA,UAAM,aAAa;AAAA,MACjB,UAAU,KAAK;AAAA,MACf;AAAA,MACA,QAAQ,KAAK,OAAO;AAAA,MACpB,cAAc;AAAA,MACd,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,eAAe,IAAI;AAAA,MACnB,gBAAgB,IAAI;AAAA,IACtB;AACA,UAAM,cAAc,kBAAkB,SAAS;AAC/C,UAAM,cAAc,cAChB,MAAM,kBAAkB,CAAC,WAAW,GAAG,YAAY,EAAE,cAAc,aAAa,IAAI,EAAE,CAAC,IACvF,EAAE,IAAI,MAAe,uBAAuB,CAAC,EAAE;AACnD,QAAI,CAAC,YAAY,IAAI;AACnB,aAAO,aAAa,KAAK,YAAY,aAAa,EAAE,OAAO,6BAA6B,GAAG;AAAA,QACzF,QAAQ,YAAY,eAAe;AAAA,MACrC,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,UAAU,QAAQ,YAAY;AACjD,UAAM,WAAW,MAAM,WAAW,QAAQ,yBAAyB;AAAA,MACjE,OAAO,EAAE,UAAU,KAAK,UAAU,gBAAgB,WAAW,GAAG;AAAA,MAChE;AAAA,IACF,CAAC;AACD,UAAM,SAAU,SAA4C;AAC5D,eAAW,YAAY,YAAY,uBAAuB;AACxD,UAAI,CAAC,SAAS,MAAM,aAAc;AAClC,UAAI;AACF,cAAM,SAAS,MAAM,aAAa,EAAE,GAAG,YAAY,UAAU,SAAS,YAAY,KAAK,CAAC;AAAA,MAC1F,SAAS,KAAK;AACZ,gBAAQ,MAAM,+DAA+D,GAAG;AAAA,MAClF;AAAA,IACF;AACA,WAAO,aAAa,KAAK,UAAU,EAAE,WAAW,IAAI,QAAQ,UAAU,OAAO,KAAK,CAAC;AAAA,EACrF,SAAS,KAAK;AACZ,QAAI,gBAAgB,GAAG,GAAG;AACxB,aAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,IAC3D;AACA,YAAQ,MAAM,qCAAqC,GAAG;AACtD,WAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACvE;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,MAAM,CAAC,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,YAAY,CAAC,EAAE,MAAM,MAAM,IAAI,QAAQ,UAAU,MAAM,QAAQ,EAAE,MAAM,UAAU,QAAQ,OAAO,EAAE,CAAC;AAAA,MACnG,aACE;AAAA,MAIF,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO;AAAA,YACf,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,YAC3B,IAAI,EAAE,OAAO;AAAA,YACb,QAAQ,EAAE,KAAK,CAAC,QAAQ,QAAQ,CAAC;AAAA,YACjC,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,UAC7B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,+EAA0E;AAAA,QACtG,EAAE,QAAQ,KAAK,aAAa,gFAA2E;AAAA,MACzG;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -2,10 +2,10 @@ import { z } from "zod";
2
2
  import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
3
  import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
- import { SalesInvoice } from "@open-mercato/core/modules/sales/data/entities";
6
5
  import { billingEntityIds } from "../../../data/entityIds.js";
7
6
  import { billingInvoiceAddLineSchema } from "../../../data/validators.js";
8
7
  import { createBillingCrudOpenApi } from "../../openapi.js";
8
+ import { BillingInvoice } from "../../../data/entities.js";
9
9
  const routeMetadata = {
10
10
  POST: { requireAuth: true, requireFeatures: ["billing.invoice.edit_draft"] }
11
11
  };
@@ -19,7 +19,7 @@ const rawBodySchema = z.object({}).passthrough();
19
19
  const crud = makeCrudRoute({
20
20
  metadata: routeMetadata,
21
21
  orm: {
22
- entity: SalesInvoice,
22
+ entity: BillingInvoice,
23
23
  idField: "id",
24
24
  orgField: "organizationId",
25
25
  tenantField: "tenantId",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/api/invoices/add-line/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { SalesInvoice } from '@open-mercato/core/modules/sales/data/entities'\nimport { billingEntityIds } from '../../../data/entityIds'\nimport { billingInvoiceAddLineSchema } from '../../../data/validators'\nimport { createBillingCrudOpenApi } from '../../openapi'\n\nconst routeMetadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.edit_draft'] },\n}\n\nexport const metadata = routeMetadata\n\nconst addLineResponseSchema = z.object({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n auditId: z.string().uuid(),\n})\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: SalesInvoice,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: z.object({}).passthrough(),\n entityId: billingEntityIds.draftInvoiceEdit,\n fields: ['id'],\n buildFilters: async () => ({}),\n },\n actions: {\n create: {\n commandId: 'billing.invoices.add_draft_line',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n return billingInvoiceAddLineSchema.parse(scoped)\n },\n response: ({ result }) => ({\n invoiceId: result?.invoiceId ?? null,\n invoiceLineId: result?.invoiceLineId ?? null,\n auditId: result?.auditId ?? null,\n }),\n status: 201,\n },\n },\n})\n\nexport const POST = crud.POST\n\nexport const openApi = createBillingCrudOpenApi({\n resourceName: 'BillingInvoiceLineAdd',\n pluralName: 'BillingInvoiceLineAdds',\n querySchema: z.object({}).passthrough(),\n listResponseSchema: z.object({ items: z.array(z.unknown()) }),\n create: {\n schema: billingInvoiceAddLineSchema,\n responseSchema: addLineResponseSchema,\n description:\n 'Appends a new line to a draft invoice (e.g. operator adds a ' +\n 'one-off adjustment). Writes a `BillingDraftInvoiceEdit` audit row ' +\n '(action=`line_added`, `before_json=null`). Recomputes invoice ' +\n 'totals. Refuses non-draft invoices.',\n },\n})\n"],
5
- "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,mCAAmC;AAC5C,SAAS,gCAAgC;AAEzC,MAAM,gBAAgB;AAAA,EACpB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,4BAA4B,EAAE;AAC7E;AAEO,MAAM,WAAW;AAExB,MAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,SAAS,EAAE,OAAO,EAAE,KAAK;AAC3B,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,IACjC,UAAU,iBAAiB;AAAA,IAC3B,QAAQ,CAAC,IAAI;AAAA,IACb,cAAc,aAAa,CAAC;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,eAAO,4BAA4B,MAAM,MAAM;AAAA,MACjD;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,WAAW,QAAQ,aAAa;AAAA,QAChC,eAAe,QAAQ,iBAAiB;AAAA,QACxC,SAAS,QAAQ,WAAW;AAAA,MAC9B;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF,CAAC;AAEM,MAAM,OAAO,KAAK;AAElB,MAAM,UAAU,yBAAyB;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,EACtC,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC5D,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aACE;AAAA,EAIJ;AACF,CAAC;",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { billingEntityIds } from '../../../data/entityIds'\nimport { billingInvoiceAddLineSchema } from '../../../data/validators'\nimport { createBillingCrudOpenApi } from '../../openapi'\nimport { BillingInvoice } from '../../../data/entities'\n\nconst routeMetadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.edit_draft'] },\n}\n\nexport const metadata = routeMetadata\n\nconst addLineResponseSchema = z.object({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n auditId: z.string().uuid(),\n})\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: BillingInvoice,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: z.object({}).passthrough(),\n entityId: billingEntityIds.draftInvoiceEdit,\n fields: ['id'],\n buildFilters: async () => ({}),\n },\n actions: {\n create: {\n commandId: 'billing.invoices.add_draft_line',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n return billingInvoiceAddLineSchema.parse(scoped)\n },\n response: ({ result }) => ({\n invoiceId: result?.invoiceId ?? null,\n invoiceLineId: result?.invoiceLineId ?? null,\n auditId: result?.auditId ?? null,\n }),\n status: 201,\n },\n },\n})\n\nexport const POST = crud.POST\n\nexport const openApi = createBillingCrudOpenApi({\n resourceName: 'BillingInvoiceLineAdd',\n pluralName: 'BillingInvoiceLineAdds',\n querySchema: z.object({}).passthrough(),\n listResponseSchema: z.object({ items: z.array(z.unknown()) }),\n create: {\n schema: billingInvoiceAddLineSchema,\n responseSchema: addLineResponseSchema,\n description:\n 'Appends a new line to a draft invoice (e.g. operator adds a ' +\n 'one-off adjustment). Writes a `BillingDraftInvoiceEdit` audit row ' +\n '(action=`line_added`, `before_json=null`). Recomputes invoice ' +\n 'totals. Refuses non-draft invoices.',\n },\n})\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,mCAAmC;AAC5C,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAE/B,MAAM,gBAAgB;AAAA,EACpB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,4BAA4B,EAAE;AAC7E;AAEO,MAAM,WAAW;AAExB,MAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,SAAS,EAAE,OAAO,EAAE,KAAK;AAC3B,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,IACjC,UAAU,iBAAiB;AAAA,IAC3B,QAAQ,CAAC,IAAI;AAAA,IACb,cAAc,aAAa,CAAC;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,eAAO,4BAA4B,MAAM,MAAM;AAAA,MACjD;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,WAAW,QAAQ,aAAa;AAAA,QAChC,eAAe,QAAQ,iBAAiB;AAAA,QACxC,SAAS,QAAQ,WAAW;AAAA,MAC9B;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF,CAAC;AAEM,MAAM,OAAO,KAAK;AAElB,MAAM,UAAU,yBAAyB;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,EACtC,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC5D,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aACE;AAAA,EAIJ;AACF,CAAC;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { runCommandRoute } from "../../../lib/commandRoute.js";
3
+ const metadata = {
4
+ POST: { requireAuth: true, requireFeatures: ["billing.invoice.correct"] }
5
+ };
6
+ const bodySchema = z.object({ invoiceId: z.string().uuid() });
7
+ async function POST(req) {
8
+ return runCommandRoute(req, {
9
+ commandId: "billing.invoices.delete_draft",
10
+ bodySchema,
11
+ resourceKind: "billing.invoice",
12
+ resourceId: (body) => body.invoiceId,
13
+ logLabel: "billing/invoices/delete-draft.POST"
14
+ });
15
+ }
16
+ const openApi = {
17
+ methods: {
18
+ POST: {
19
+ tags: ["Billing"],
20
+ summary: "Delete a draft memo",
21
+ description: "Deletes a draft credit or debit memo with its lines. Posted documents are never deleted (no void).",
22
+ requestBody: { schema: bodySchema },
23
+ responses: [{ status: 200, description: "`{ deleted: true }`" }],
24
+ errors: [{ status: 409, description: "`billing.memo.not_draft`" }]
25
+ }
26
+ }
27
+ };
28
+ export {
29
+ POST,
30
+ metadata,
31
+ openApi
32
+ };
33
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/billing/api/invoices/delete-draft/route.ts"],
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { runCommandRoute } from '../../../lib/commandRoute'\n\n/** `POST /api/billing/invoices/delete-draft` \u2014 delete a DRAFT credit / debit memo (Spec D, D-D7). */\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.correct'] },\n}\n\nconst bodySchema = z.object({ invoiceId: z.string().uuid() })\n\nexport async function POST(req: Request) {\n return runCommandRoute(req, {\n commandId: 'billing.invoices.delete_draft',\n bodySchema,\n resourceKind: 'billing.invoice',\n resourceId: (body) => body.invoiceId,\n logLabel: 'billing/invoices/delete-draft.POST',\n })\n}\n\nexport const openApi = {\n methods: {\n POST: {\n tags: ['Billing'],\n summary: 'Delete a draft memo',\n description: 'Deletes a draft credit or debit memo with its lines. Posted documents are never deleted (no void).',\n requestBody: { schema: bodySchema },\n responses: [{ status: 200, description: '`{ deleted: true }`' }],\n errors: [{ status: 409, description: '`billing.memo.not_draft`' }],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,uBAAuB;AAIzB,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAC1E;AAEA,MAAM,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAE5D,eAAsB,KAAK,KAAc;AACvC,SAAO,gBAAgB,KAAK;AAAA,IAC1B,WAAW;AAAA,IACX;AAAA,IACA,cAAc;AAAA,IACd,YAAY,CAAC,SAAS,KAAK;AAAA,IAC3B,UAAU;AAAA,EACZ,CAAC;AACH;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,MAAM,CAAC,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,aAAa;AAAA,MACb,aAAa,EAAE,QAAQ,WAAW;AAAA,MAClC,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,sBAAsB,CAAC;AAAA,MAC/D,QAAQ,CAAC,EAAE,QAAQ,KAAK,aAAa,2BAA2B,CAAC;AAAA,IACnE;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -2,7 +2,6 @@ import { z } from "zod";
2
2
  import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
3
  import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
- import { SalesInvoice } from "@open-mercato/core/modules/sales/data/entities";
6
5
  import { billingEntityIds } from "../../../data/entityIds.js";
7
6
  import {
8
7
  billingInvoiceAddLineSchema,
@@ -10,6 +9,7 @@ import {
10
9
  billingInvoiceRemoveLineSchema
11
10
  } from "../../../data/validators.js";
12
11
  import { createBillingCrudOpenApi } from "../../openapi.js";
12
+ import { BillingInvoice } from "../../../data/entities.js";
13
13
  const routeMetadata = {
14
14
  POST: { requireAuth: true, requireFeatures: ["billing.invoice.edit_draft"] }
15
15
  };
@@ -23,7 +23,7 @@ const rawBodySchema = z.object({}).passthrough();
23
23
  const crud = makeCrudRoute({
24
24
  metadata: routeMetadata,
25
25
  orm: {
26
- entity: SalesInvoice,
26
+ entity: BillingInvoice,
27
27
  idField: "id",
28
28
  orgField: "organizationId",
29
29
  tenantField: "tenantId",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/api/invoices/edit-line/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { SalesInvoice } from '@open-mercato/core/modules/sales/data/entities'\nimport { billingEntityIds } from '../../../data/entityIds'\nimport {\n billingInvoiceAddLineSchema,\n billingInvoiceEditLineSchema,\n billingInvoiceRemoveLineSchema,\n} from '../../../data/validators'\nimport { createBillingCrudOpenApi } from '../../openapi'\n\n/**\n * `POST /api/billing/invoices/edit-line` \u2014 edits one line of a draft\n * invoice. Refuses non-drafts (409 / `billing.invoice.not_draft`).\n * Writes a `BillingDraftInvoiceEdit` audit row per spec. Recomputes invoice\n * totals from the surviving lines after the edit.\n *\n * Operator surface: route is gated by `billing.invoice.edit_draft`.\n * Future Phase 4c admin UI calls into the same command via this route.\n */\n\nconst routeMetadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.edit_draft'] },\n}\n\nexport const metadata = routeMetadata\n\nconst editLineResponseSchema = z.object({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n auditId: z.string().uuid(),\n})\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: SalesInvoice,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: z.object({}).passthrough(),\n entityId: billingEntityIds.draftInvoiceEdit,\n fields: ['id'],\n buildFilters: async () => ({}),\n },\n actions: {\n create: {\n commandId: 'billing.invoices.edit_draft_line',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n return billingInvoiceEditLineSchema.parse(scoped)\n },\n response: ({ result }) => ({\n invoiceId: result?.invoiceId ?? null,\n invoiceLineId: result?.invoiceLineId ?? null,\n auditId: result?.auditId ?? null,\n }),\n status: 200,\n },\n },\n})\n\nexport const POST = crud.POST\n\nexport const openApi = createBillingCrudOpenApi({\n resourceName: 'BillingInvoiceLineEdit',\n pluralName: 'BillingInvoiceLineEdits',\n querySchema: z.object({}).passthrough(),\n listResponseSchema: z.object({ items: z.array(z.unknown()) }),\n create: {\n schema: billingInvoiceEditLineSchema,\n responseSchema: editLineResponseSchema,\n description:\n 'Edits one line of a draft invoice (description, quantity, ' +\n \"unit_price, or explicit `totalNetAmount` override). Writes a \" +\n '`BillingDraftInvoiceEdit` audit row with before+after snapshots and ' +\n 'recomputes invoice totals. Refuses non-draft invoices with ' +\n 'HTTP 409 + `billing.invoice.not_draft`.',\n },\n})\n\n// Re-export the add/remove route schemas so the OpenAPI bundle keeps\n// them discoverable from a single import surface \u2014 the dedicated\n// routes (sibling folders) own the actual handlers.\nexport const _phaseSchemaRefs = {\n add: billingInvoiceAddLineSchema,\n remove: billingInvoiceRemoveLineSchema,\n}\n"],
5
- "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gCAAgC;AAYzC,MAAM,gBAAgB;AAAA,EACpB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,4BAA4B,EAAE;AAC7E;AAEO,MAAM,WAAW;AAExB,MAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,SAAS,EAAE,OAAO,EAAE,KAAK;AAC3B,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,IACjC,UAAU,iBAAiB;AAAA,IAC3B,QAAQ,CAAC,IAAI;AAAA,IACb,cAAc,aAAa,CAAC;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,eAAO,6BAA6B,MAAM,MAAM;AAAA,MAClD;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,WAAW,QAAQ,aAAa;AAAA,QAChC,eAAe,QAAQ,iBAAiB;AAAA,QACxC,SAAS,QAAQ,WAAW;AAAA,MAC9B;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF,CAAC;AAEM,MAAM,OAAO,KAAK;AAElB,MAAM,UAAU,yBAAyB;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,EACtC,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC5D,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aACE;AAAA,EAKJ;AACF,CAAC;AAKM,MAAM,mBAAmB;AAAA,EAC9B,KAAK;AAAA,EACL,QAAQ;AACV;",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { billingEntityIds } from '../../../data/entityIds'\nimport {\n billingInvoiceAddLineSchema,\n billingInvoiceEditLineSchema,\n billingInvoiceRemoveLineSchema,\n} from '../../../data/validators'\nimport { createBillingCrudOpenApi } from '../../openapi'\nimport { BillingInvoice } from '../../../data/entities'\n\n/**\n * `POST /api/billing/invoices/edit-line` \u2014 edits one line of a draft\n * invoice. Refuses non-drafts (409 / `billing.invoice.not_draft`).\n * Writes a `BillingDraftInvoiceEdit` audit row per spec. Recomputes invoice\n * totals from the surviving lines after the edit.\n *\n * Operator surface: route is gated by `billing.invoice.edit_draft`.\n * Future Phase 4c admin UI calls into the same command via this route.\n */\n\nconst routeMetadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.edit_draft'] },\n}\n\nexport const metadata = routeMetadata\n\nconst editLineResponseSchema = z.object({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n auditId: z.string().uuid(),\n})\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: BillingInvoice,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: z.object({}).passthrough(),\n entityId: billingEntityIds.draftInvoiceEdit,\n fields: ['id'],\n buildFilters: async () => ({}),\n },\n actions: {\n create: {\n commandId: 'billing.invoices.edit_draft_line',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n return billingInvoiceEditLineSchema.parse(scoped)\n },\n response: ({ result }) => ({\n invoiceId: result?.invoiceId ?? null,\n invoiceLineId: result?.invoiceLineId ?? null,\n auditId: result?.auditId ?? null,\n }),\n status: 200,\n },\n },\n})\n\nexport const POST = crud.POST\n\nexport const openApi = createBillingCrudOpenApi({\n resourceName: 'BillingInvoiceLineEdit',\n pluralName: 'BillingInvoiceLineEdits',\n querySchema: z.object({}).passthrough(),\n listResponseSchema: z.object({ items: z.array(z.unknown()) }),\n create: {\n schema: billingInvoiceEditLineSchema,\n responseSchema: editLineResponseSchema,\n description:\n 'Edits one line of a draft invoice (description, quantity, ' +\n \"unit_price, or explicit `totalNetAmount` override). Writes a \" +\n '`BillingDraftInvoiceEdit` audit row with before+after snapshots and ' +\n 'recomputes invoice totals. Refuses non-draft invoices with ' +\n 'HTTP 409 + `billing.invoice.not_draft`.',\n },\n})\n\n// Re-export the add/remove route schemas so the OpenAPI bundle keeps\n// them discoverable from a single import surface \u2014 the dedicated\n// routes (sibling folders) own the actual handlers.\nexport const _phaseSchemaRefs = {\n add: billingInvoiceAddLineSchema,\n remove: billingInvoiceRemoveLineSchema,\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAY/B,MAAM,gBAAgB;AAAA,EACpB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,4BAA4B,EAAE;AAC7E;AAEO,MAAM,WAAW;AAExB,MAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO,EAAE,KAAK;AAAA,EAC/B,SAAS,EAAE,OAAO,EAAE,KAAK;AAC3B,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,IACjC,UAAU,iBAAiB;AAAA,IAC3B,QAAQ,CAAC,IAAI;AAAA,IACb,cAAc,aAAa,CAAC;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,eAAO,6BAA6B,MAAM,MAAM;AAAA,MAClD;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,WAAW,QAAQ,aAAa;AAAA,QAChC,eAAe,QAAQ,iBAAiB;AAAA,QACxC,SAAS,QAAQ,WAAW;AAAA,MAC9B;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF,CAAC;AAEM,MAAM,OAAO,KAAK;AAElB,MAAM,UAAU,yBAAyB;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,EACtC,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC5D,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aACE;AAAA,EAKJ;AACF,CAAC;AAKM,MAAM,mBAAmB;AAAA,EAC9B,KAAK;AAAA,EACL,QAAQ;AACV;",
6
6
  "names": []
7
7
  }
@@ -2,10 +2,10 @@ import { z } from "zod";
2
2
  import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
3
  import { withScopedPayload } from "@open-mercato/shared/lib/api/scoped";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
- import { SalesInvoice } from "@open-mercato/core/modules/sales/data/entities";
6
5
  import { billingEntityIds } from "../../../data/entityIds.js";
7
6
  import { billingInvoicePostSchema } from "../../../data/validators.js";
8
7
  import { createBillingCrudOpenApi } from "../../openapi.js";
8
+ import { BillingInvoice } from "../../../data/entities.js";
9
9
  const routeMetadata = {
10
10
  POST: { requireAuth: true, requireFeatures: ["billing.invoice.post"] }
11
11
  };
@@ -20,7 +20,7 @@ const rawBodySchema = z.object({}).passthrough();
20
20
  const crud = makeCrudRoute({
21
21
  metadata: routeMetadata,
22
22
  orm: {
23
- entity: SalesInvoice,
23
+ entity: BillingInvoice,
24
24
  idField: "id",
25
25
  orgField: "organizationId",
26
26
  tenantField: "tenantId",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/billing/api/invoices/post/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { SalesInvoice } from '@open-mercato/core/modules/sales/data/entities'\nimport { billingEntityIds } from '../../../data/entityIds'\nimport { billingInvoicePostSchema } from '../../../data/validators'\nimport { createBillingCrudOpenApi } from '../../openapi'\n\n/**\n * `POST /api/billing/invoices/post`\n *\n * Operator action: flip a billing-drafted invoice from `draft` \u2192\n * `posted`. The command refuses non-draft inputs (409 with\n * `billing.invoice.not_draft`) and test-mode invoices (409 with\n * `billing.invoice.test_run`). The invoice number is NOT re-assigned\n * (it was set at draft create \u2014 see Phase 2 deviation note in the\n * spec).\n *\n * Implemented as a create-only `makeCrudRoute` so it inherits the same\n * RBAC + OpenAPI plumbing as the rest of the billing surface. The\n * `entity` is `SalesInvoice` only because the factory requires one;\n * the GET half is never exposed on this URL.\n */\n\nconst routeMetadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.post'] },\n}\n\nexport const metadata = routeMetadata\n\nconst postResponseSchema = z.object({\n invoiceId: z.string().uuid(),\n invoiceNumber: z.string(),\n status: z.literal('posted'),\n lineCount: z.number().int().nonnegative(),\n})\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: SalesInvoice,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: z.object({}).passthrough(),\n // `entityId` is technically a core/sales concept, but the factory\n // only needs it as an identifier \u2014 using a billing-namespaced one\n // keeps the registry tidy (no surprise list endpoints).\n entityId: billingEntityIds.draftInvoiceEdit,\n fields: ['id'],\n buildFilters: async () => ({}),\n },\n actions: {\n create: {\n commandId: 'billing.invoices.post',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n return billingInvoicePostSchema.parse(scoped)\n },\n response: ({ result }) => ({\n invoiceId: result?.invoiceId ?? null,\n invoiceNumber: result?.invoiceNumber ?? null,\n status: result?.status ?? null,\n lineCount: result?.lineCount ?? 0,\n }),\n status: 200,\n },\n },\n})\n\nexport const POST = crud.POST\n\nexport const openApi = createBillingCrudOpenApi({\n resourceName: 'BillingInvoicePost',\n pluralName: 'BillingInvoicePosts',\n querySchema: z.object({}).passthrough(),\n listResponseSchema: z.object({ items: z.array(z.unknown()) }),\n create: {\n schema: billingInvoicePostSchema,\n responseSchema: postResponseSchema,\n description:\n 'Flips a billing-drafted `core/sales` invoice from `draft` to ' +\n '`posted`. Refuses non-draft invoices (409 / ' +\n '`billing.invoice.not_draft`) and test-mode invoices (409 / ' +\n '`billing.invoice.test_run`). Fires `billing.invoice.posted` + ' +\n 'one `billing.invoice.line_posted` per line. The invoice number ' +\n 'is NOT re-assigned (set at draft create \u2014 see Phase 2 deviation).',\n },\n})\n"],
5
- "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,gCAAgC;AACzC,SAAS,gCAAgC;AAkBzC,MAAM,gBAAgB;AAAA,EACpB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACvE;AAEO,MAAM,WAAW;AAExB,MAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO;AAAA,EACxB,QAAQ,EAAE,QAAQ,QAAQ;AAAA,EAC1B,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC1C,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA;AAAA;AAAA;AAAA,IAIjC,UAAU,iBAAiB;AAAA,IAC3B,QAAQ,CAAC,IAAI;AAAA,IACb,cAAc,aAAa,CAAC;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,eAAO,yBAAyB,MAAM,MAAM;AAAA,MAC9C;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,WAAW,QAAQ,aAAa;AAAA,QAChC,eAAe,QAAQ,iBAAiB;AAAA,QACxC,QAAQ,QAAQ,UAAU;AAAA,QAC1B,WAAW,QAAQ,aAAa;AAAA,MAClC;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF,CAAC;AAEM,MAAM,OAAO,KAAK;AAElB,MAAM,UAAU,yBAAyB;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,EACtC,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC5D,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aACE;AAAA,EAMJ;AACF,CAAC;",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { withScopedPayload } from '@open-mercato/shared/lib/api/scoped'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { billingEntityIds } from '../../../data/entityIds'\nimport { billingInvoicePostSchema } from '../../../data/validators'\nimport { createBillingCrudOpenApi } from '../../openapi'\nimport { BillingInvoice } from '../../../data/entities'\n\n/**\n * `POST /api/billing/invoices/post`\n *\n * Operator action: flip a billing-drafted invoice from `draft` \u2192\n * `posted`. The command refuses non-draft inputs (409 with\n * `billing.invoice.not_draft`) and test-mode invoices (409 with\n * `billing.invoice.test_run`). The series number is claimed at post\n * (Spec 0 numbering masks) \u2014 drafts carry a temporary `DRAFT-\u2026` number.\n * 409 `billing.invoice.number_conflict` when the mask repeats an issued\n * number.\n *\n * Implemented as a create-only `makeCrudRoute` so it inherits the same\n * RBAC + OpenAPI plumbing as the rest of the billing surface. The\n * `entity` is `BillingInvoice` only because the factory requires one;\n * the GET half is never exposed on this URL.\n */\n\nconst routeMetadata = {\n POST: { requireAuth: true, requireFeatures: ['billing.invoice.post'] },\n}\n\nexport const metadata = routeMetadata\n\nconst postResponseSchema = z.object({\n invoiceId: z.string().uuid(),\n invoiceNumber: z.string(),\n status: z.literal('posted'),\n lineCount: z.number().int().nonnegative(),\n})\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: BillingInvoice,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: z.object({}).passthrough(),\n // `entityId` is technically a core/sales concept, but the factory\n // only needs it as an identifier \u2014 using a billing-namespaced one\n // keeps the registry tidy (no surprise list endpoints).\n entityId: billingEntityIds.draftInvoiceEdit,\n fields: ['id'],\n buildFilters: async () => ({}),\n },\n actions: {\n create: {\n commandId: 'billing.invoices.post',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n return billingInvoicePostSchema.parse(scoped)\n },\n response: ({ result }) => ({\n invoiceId: result?.invoiceId ?? null,\n invoiceNumber: result?.invoiceNumber ?? null,\n status: result?.status ?? null,\n lineCount: result?.lineCount ?? 0,\n }),\n status: 200,\n },\n },\n})\n\nexport const POST = crud.POST\n\nexport const openApi = createBillingCrudOpenApi({\n resourceName: 'BillingInvoicePost',\n pluralName: 'BillingInvoicePosts',\n querySchema: z.object({}).passthrough(),\n listResponseSchema: z.object({ items: z.array(z.unknown()) }),\n create: {\n schema: billingInvoicePostSchema,\n responseSchema: postResponseSchema,\n description:\n 'Flips a billing-drafted `core/sales` invoice from `draft` to ' +\n '`posted`. Refuses non-draft invoices (409 / ' +\n '`billing.invoice.not_draft`) and test-mode invoices (409 / ' +\n '`billing.invoice.test_run`). Fires `billing.invoice.posted` + ' +\n 'one `billing.invoice.line_posted` per line. The invoice number ' +\n 'is NOT re-assigned (set at draft create \u2014 see Phase 2 deviation).',\n },\n})\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,gCAAgC;AACzC,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;AAmB/B,MAAM,gBAAgB;AAAA,EACpB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACvE;AAEO,MAAM,WAAW;AAExB,MAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO;AAAA,EACxB,QAAQ,EAAE,QAAQ,QAAQ;AAAA,EAC1B,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAC1C,CAAC;AAED,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA;AAAA;AAAA;AAAA,IAIjC,UAAU,iBAAiB;AAAA,IAC3B,QAAQ,CAAC,IAAI;AAAA,IACb,cAAc,aAAa,CAAC;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,eAAO,yBAAyB,MAAM,MAAM;AAAA,MAC9C;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,WAAW,QAAQ,aAAa;AAAA,QAChC,eAAe,QAAQ,iBAAiB;AAAA,QACxC,QAAQ,QAAQ,UAAU;AAAA,QAC1B,WAAW,QAAQ,aAAa;AAAA,MAClC;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AACF,CAAC;AAEM,MAAM,OAAO,KAAK;AAElB,MAAM,UAAU,yBAAyB;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAAA,EACtC,oBAAoB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC5D,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aACE;AAAA,EAMJ;AACF,CAAC;",
6
6
  "names": []
7
7
  }