@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.
- package/CHANGELOG.md +103 -0
- package/dist/modules/billing/acl.js +13 -1
- package/dist/modules/billing/acl.js.map +2 -2
- package/dist/modules/billing/api/accounts/[id]/summary/route.js +52 -0
- package/dist/modules/billing/api/accounts/[id]/summary/route.js.map +7 -0
- package/dist/modules/billing/api/accounts/route.js +47 -4
- package/dist/modules/billing/api/accounts/route.js.map +2 -2
- package/dist/modules/billing/api/export/account/[id]/route.js +11 -7
- package/dist/modules/billing/api/export/account/[id]/route.js.map +2 -2
- package/dist/modules/billing/api/invoices/[id]/memos/route.js +54 -0
- package/dist/modules/billing/api/invoices/[id]/memos/route.js.map +7 -0
- package/dist/modules/billing/api/invoices/[id]/pdf/route.js +70 -0
- package/dist/modules/billing/api/invoices/[id]/pdf/route.js.map +7 -0
- package/dist/modules/billing/api/invoices/[id]/route.js +44 -24
- package/dist/modules/billing/api/invoices/[id]/route.js.map +2 -2
- package/dist/modules/billing/api/invoices/[id]/send/route.js +107 -0
- package/dist/modules/billing/api/invoices/[id]/send/route.js.map +7 -0
- package/dist/modules/billing/api/invoices/add-line/route.js +2 -2
- package/dist/modules/billing/api/invoices/add-line/route.js.map +2 -2
- package/dist/modules/billing/api/invoices/delete-draft/route.js +33 -0
- package/dist/modules/billing/api/invoices/delete-draft/route.js.map +7 -0
- package/dist/modules/billing/api/invoices/edit-line/route.js +2 -2
- package/dist/modules/billing/api/invoices/edit-line/route.js.map +2 -2
- package/dist/modules/billing/api/invoices/post/route.js +2 -2
- package/dist/modules/billing/api/invoices/post/route.js.map +2 -2
- package/dist/modules/billing/api/invoices/remove-line/route.js +2 -2
- package/dist/modules/billing/api/invoices/remove-line/route.js.map +2 -2
- package/dist/modules/billing/api/invoices/route.js +45 -46
- package/dist/modules/billing/api/invoices/route.js.map +2 -2
- package/dist/modules/billing/api/items/bulk/route.js +1 -1
- package/dist/modules/billing/api/items/bulk/route.js.map +2 -2
- package/dist/modules/billing/api/items/change-price/route.js +44 -0
- package/dist/modules/billing/api/items/change-price/route.js.map +7 -0
- package/dist/modules/billing/api/items/route.js +19 -7
- package/dist/modules/billing/api/items/route.js.map +2 -2
- package/dist/modules/billing/api/payment-imports/[id]/route.js +49 -0
- package/dist/modules/billing/api/payment-imports/[id]/route.js.map +7 -0
- package/dist/modules/billing/api/payment-imports/route.js +57 -0
- package/dist/modules/billing/api/payment-imports/route.js.map +7 -0
- package/dist/modules/billing/api/payments/[id]/route.js +60 -0
- package/dist/modules/billing/api/payments/[id]/route.js.map +7 -0
- package/dist/modules/billing/api/payments/allocate/route.js +35 -0
- package/dist/modules/billing/api/payments/allocate/route.js.map +7 -0
- package/dist/modules/billing/api/payments/assign/route.js +36 -0
- package/dist/modules/billing/api/payments/assign/route.js.map +7 -0
- package/dist/modules/billing/api/payments/convert-to-topup/route.js +35 -0
- package/dist/modules/billing/api/payments/convert-to-topup/route.js.map +7 -0
- package/dist/modules/billing/api/payments/ignore/route.js +35 -0
- package/dist/modules/billing/api/payments/ignore/route.js.map +7 -0
- package/dist/modules/billing/api/payments/import/route.js +63 -0
- package/dist/modules/billing/api/payments/import/route.js.map +7 -0
- package/dist/modules/billing/api/payments/restore/route.js +35 -0
- package/dist/modules/billing/api/payments/restore/route.js.map +7 -0
- package/dist/modules/billing/api/payments/route.js +114 -0
- package/dist/modules/billing/api/payments/route.js.map +7 -0
- package/dist/modules/billing/api/payments/unallocate/route.js +35 -0
- package/dist/modules/billing/api/payments/unallocate/route.js.map +7 -0
- package/dist/modules/billing/api/payments/unassign/route.js +35 -0
- package/dist/modules/billing/api/payments/unassign/route.js.map +7 -0
- package/dist/modules/billing/api/run-outcomes/route.js +43 -6
- package/dist/modules/billing/api/run-outcomes/route.js.map +2 -2
- package/dist/modules/billing/api/runs/[id]/post-drafts/route.js +61 -0
- package/dist/modules/billing/api/runs/[id]/post-drafts/route.js.map +7 -0
- package/dist/modules/billing/api/runs/[id]/route.js +53 -0
- package/dist/modules/billing/api/runs/[id]/route.js.map +7 -0
- package/dist/modules/billing/api/runs/retry-failed/route.js +1 -1
- package/dist/modules/billing/api/runs/retry-failed/route.js.map +2 -2
- package/dist/modules/billing/api/runs/route.js +9 -3
- package/dist/modules/billing/api/runs/route.js.map +2 -2
- package/dist/modules/billing/api/settings/number-preview/route.js +42 -0
- package/dist/modules/billing/api/settings/number-preview/route.js.map +7 -0
- package/dist/modules/billing/api/settings/route.js +92 -0
- package/dist/modules/billing/api/settings/route.js.map +7 -0
- package/dist/modules/billing/api/statements/route.js +3 -0
- package/dist/modules/billing/api/statements/route.js.map +2 -2
- package/dist/modules/billing/api/test-invoices/wipe/route.js +2 -2
- package/dist/modules/billing/api/test-invoices/wipe/route.js.map +2 -2
- package/dist/modules/billing/backend/billing/accounts/[id]/page.js +121 -232
- package/dist/modules/billing/backend/billing/accounts/[id]/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/accounts/create/page.js +6 -0
- package/dist/modules/billing/backend/billing/accounts/create/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/accounts/page.js +63 -4
- package/dist/modules/billing/backend/billing/accounts/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/invoices/[id]/page.js +297 -65
- package/dist/modules/billing/backend/billing/invoices/[id]/page.js.map +3 -3
- package/dist/modules/billing/backend/billing/invoices/page.js +6 -172
- package/dist/modules/billing/backend/billing/invoices/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/items/[id]/page.js +51 -7
- package/dist/modules/billing/backend/billing/items/[id]/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/items/create/page.js +9 -6
- package/dist/modules/billing/backend/billing/items/create/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/items/page.js +8 -2
- package/dist/modules/billing/backend/billing/items/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/payments/[id]/page.js +297 -0
- package/dist/modules/billing/backend/billing/payments/[id]/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js +21 -0
- package/dist/modules/billing/backend/billing/payments/[id]/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js +74 -0
- package/dist/modules/billing/backend/billing/payments/imports/[id]/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js +21 -0
- package/dist/modules/billing/backend/billing/payments/imports/[id]/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/payments/page.js +58 -0
- package/dist/modules/billing/backend/billing/payments/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/payments/page.meta.js +18 -0
- package/dist/modules/billing/backend/billing/payments/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/runs/[id]/page.js +49 -14
- package/dist/modules/billing/backend/billing/runs/[id]/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/runs/page.js +58 -7
- package/dist/modules/billing/backend/billing/runs/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/statements/[id]/page.js +61 -6
- package/dist/modules/billing/backend/billing/statements/[id]/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/statements/page.js +1 -1
- package/dist/modules/billing/backend/billing/statements/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/topups/page.js +1 -1
- package/dist/modules/billing/backend/billing/topups/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/transactions/page.js +1 -1
- package/dist/modules/billing/backend/billing/transactions/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/usage/create/page.js +3 -2
- package/dist/modules/billing/backend/billing/usage/create/page.js.map +2 -2
- package/dist/modules/billing/backend/config/billing/page.js +472 -0
- package/dist/modules/billing/backend/config/billing/page.js.map +7 -0
- package/dist/modules/billing/backend/config/billing/page.meta.js +19 -0
- package/dist/modules/billing/backend/config/billing/page.meta.js.map +7 -0
- package/dist/modules/billing/cli.js +22 -1
- package/dist/modules/billing/cli.js.map +2 -2
- package/dist/modules/billing/commands/accounts.js +6 -0
- package/dist/modules/billing/commands/accounts.js.map +2 -2
- package/dist/modules/billing/commands/index.js +3 -0
- package/dist/modules/billing/commands/index.js.map +2 -2
- package/dist/modules/billing/commands/invoices.js +269 -167
- package/dist/modules/billing/commands/invoices.js.map +2 -2
- package/dist/modules/billing/commands/items.js +108 -0
- package/dist/modules/billing/commands/items.js.map +2 -2
- package/dist/modules/billing/commands/memos.js +179 -0
- package/dist/modules/billing/commands/memos.js.map +7 -0
- package/dist/modules/billing/commands/payments.js +379 -0
- package/dist/modules/billing/commands/payments.js.map +7 -0
- package/dist/modules/billing/commands/runs.js +151 -4
- package/dist/modules/billing/commands/runs.js.map +2 -2
- package/dist/modules/billing/commands/settings.js +59 -0
- package/dist/modules/billing/commands/settings.js.map +7 -0
- package/dist/modules/billing/commands/topups.js +9 -2
- package/dist/modules/billing/commands/topups.js.map +2 -2
- package/dist/modules/billing/commands/transactions.js +2 -2
- package/dist/modules/billing/commands/transactions.js.map +2 -2
- package/dist/modules/billing/components/AccountForm.js +149 -42
- package/dist/modules/billing/components/AccountForm.js.map +2 -2
- package/dist/modules/billing/components/AccountInvoicesSection.js +64 -0
- package/dist/modules/billing/components/AccountInvoicesSection.js.map +7 -0
- package/dist/modules/billing/components/AccountPaymentsSection.js +43 -0
- package/dist/modules/billing/components/AccountPaymentsSection.js.map +7 -0
- package/dist/modules/billing/components/AccountPicker.js +56 -0
- package/dist/modules/billing/components/AccountPicker.js.map +7 -0
- package/dist/modules/billing/components/AllocatePaymentDialog.js +134 -0
- package/dist/modules/billing/components/AllocatePaymentDialog.js.map +7 -0
- package/dist/modules/billing/components/BillingDataTable.js +21 -0
- package/dist/modules/billing/components/BillingDataTable.js.map +7 -0
- package/dist/modules/billing/components/BillingSettingsLink.js +19 -0
- package/dist/modules/billing/components/BillingSettingsLink.js.map +7 -0
- package/dist/modules/billing/components/ChangeItemPriceDialog.js +158 -0
- package/dist/modules/billing/components/ChangeItemPriceDialog.js.map +7 -0
- package/dist/modules/billing/components/CreateMemoDialog.js +200 -0
- package/dist/modules/billing/components/CreateMemoDialog.js.map +7 -0
- package/dist/modules/billing/components/CustomerLabel.js +33 -0
- package/dist/modules/billing/components/CustomerLabel.js.map +7 -0
- package/dist/modules/billing/components/InvoicesTable.js +270 -0
- package/dist/modules/billing/components/InvoicesTable.js.map +7 -0
- package/dist/modules/billing/components/ItemForm.js +176 -44
- package/dist/modules/billing/components/ItemForm.js.map +2 -2
- package/dist/modules/billing/components/ItemPriceField.js +46 -0
- package/dist/modules/billing/components/ItemPriceField.js.map +7 -0
- package/dist/modules/billing/components/LineFormDialog.js +25 -2
- package/dist/modules/billing/components/LineFormDialog.js.map +2 -2
- package/dist/modules/billing/components/ManualPaymentDialog.js +122 -0
- package/dist/modules/billing/components/ManualPaymentDialog.js.map +7 -0
- package/dist/modules/billing/components/MoneyInput.js +14 -0
- package/dist/modules/billing/components/MoneyInput.js.map +7 -0
- package/dist/modules/billing/components/PaymentUploadDialog.js +115 -0
- package/dist/modules/billing/components/PaymentUploadDialog.js.map +7 -0
- package/dist/modules/billing/components/PaymentsTable.js +171 -0
- package/dist/modules/billing/components/PaymentsTable.js.map +7 -0
- package/dist/modules/billing/components/PostRunDraftsButton.js +105 -0
- package/dist/modules/billing/components/PostRunDraftsButton.js.map +7 -0
- package/dist/modules/billing/components/PrepaidPanel.js +14 -4
- package/dist/modules/billing/components/PrepaidPanel.js.map +2 -2
- package/dist/modules/billing/components/RunCyclesSection.js +209 -0
- package/dist/modules/billing/components/RunCyclesSection.js.map +7 -0
- package/dist/modules/billing/components/TestRunActions.js +127 -0
- package/dist/modules/billing/components/TestRunActions.js.map +7 -0
- package/dist/modules/billing/components/account/AccountItemsTab.js +157 -0
- package/dist/modules/billing/components/account/AccountItemsTab.js.map +7 -0
- package/dist/modules/billing/components/account/AccountRunBillingDialog.js +122 -0
- package/dist/modules/billing/components/account/AccountRunBillingDialog.js.map +7 -0
- package/dist/modules/billing/components/account/AccountRunsTab.js +152 -0
- package/dist/modules/billing/components/account/AccountRunsTab.js.map +7 -0
- package/dist/modules/billing/components/account/AccountStatementsTab.js +98 -0
- package/dist/modules/billing/components/account/AccountStatementsTab.js.map +7 -0
- package/dist/modules/billing/components/account/AccountSummaryCards.js +125 -0
- package/dist/modules/billing/components/account/AccountSummaryCards.js.map +7 -0
- package/dist/modules/billing/components/account/AccountUsageTab.js +91 -0
- package/dist/modules/billing/components/account/AccountUsageTab.js.map +7 -0
- package/dist/modules/billing/components/account/AccountView.js +73 -0
- package/dist/modules/billing/components/account/AccountView.js.map +7 -0
- package/dist/modules/billing/components/account/accountRow.js +39 -0
- package/dist/modules/billing/components/account/accountRow.js.map +7 -0
- package/dist/modules/billing/components/customerNames.js +42 -0
- package/dist/modules/billing/components/customerNames.js.map +7 -0
- package/dist/modules/billing/data/entities.js +560 -4
- package/dist/modules/billing/data/entities.js.map +2 -2
- package/dist/modules/billing/data/entityIds.js +10 -1
- package/dist/modules/billing/data/entityIds.js.map +2 -2
- package/dist/modules/billing/data/validators.js +269 -15
- package/dist/modules/billing/data/validators.js.map +2 -2
- package/dist/modules/billing/events.js +50 -0
- package/dist/modules/billing/events.js.map +2 -2
- package/dist/modules/billing/i18n/de.json +880 -0
- package/dist/modules/billing/i18n/en.json +457 -21
- package/dist/modules/billing/i18n/es.json +880 -0
- package/dist/modules/billing/i18n/pl.json +458 -22
- package/dist/modules/billing/index.js +6 -2
- package/dist/modules/billing/index.js.map +2 -2
- package/dist/modules/billing/lib/accountFinancials.js +58 -0
- package/dist/modules/billing/lib/accountFinancials.js.map +7 -0
- package/dist/modules/billing/lib/accountLock.js +14 -0
- package/dist/modules/billing/lib/accountLock.js.map +7 -0
- package/dist/modules/billing/lib/accountStatus.js +9 -7
- package/dist/modules/billing/lib/accountStatus.js.map +2 -2
- package/dist/modules/billing/lib/accountSummary.js +106 -0
- package/dist/modules/billing/lib/accountSummary.js.map +7 -0
- package/dist/modules/billing/lib/allocation.js +356 -0
- package/dist/modules/billing/lib/allocation.js.map +7 -0
- package/dist/modules/billing/lib/allocationEvents.js +22 -0
- package/dist/modules/billing/lib/allocationEvents.js.map +7 -0
- package/dist/modules/billing/lib/billPeriod.js +15 -1
- package/dist/modules/billing/lib/billPeriod.js.map +2 -2
- package/dist/modules/billing/lib/billRunEngine.js +237 -102
- package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
- package/dist/modules/billing/lib/billingSettings.js +116 -0
- package/dist/modules/billing/lib/billingSettings.js.map +7 -0
- package/dist/modules/billing/lib/commandRoute.js +81 -0
- package/dist/modules/billing/lib/commandRoute.js.map +7 -0
- package/dist/modules/billing/lib/customerLookup.js +97 -0
- package/dist/modules/billing/lib/customerLookup.js.map +7 -0
- package/dist/modules/billing/lib/dateOnly.js +13 -0
- package/dist/modules/billing/lib/dateOnly.js.map +7 -0
- package/dist/modules/billing/lib/documentParties.js +16 -0
- package/dist/modules/billing/lib/documentParties.js.map +7 -0
- package/dist/modules/billing/lib/documentTypes.js +27 -0
- package/dist/modules/billing/lib/documentTypes.js.map +7 -0
- package/dist/modules/billing/lib/dueDate.js +18 -0
- package/dist/modules/billing/lib/dueDate.js.map +7 -0
- package/dist/modules/billing/lib/iban.js +29 -0
- package/dist/modules/billing/lib/iban.js.map +7 -0
- package/dist/modules/billing/lib/invoiceDelivery.js +133 -0
- package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
- package/dist/modules/billing/lib/invoiceLanguages.js +28 -0
- package/dist/modules/billing/lib/invoiceLanguages.js.map +7 -0
- package/dist/modules/billing/lib/invoiceWriter.js +107 -99
- package/dist/modules/billing/lib/invoiceWriter.js.map +2 -2
- package/dist/modules/billing/lib/itemBillingState.js +27 -0
- package/dist/modules/billing/lib/itemBillingState.js.map +7 -0
- package/dist/modules/billing/lib/itemPriceChange.js +18 -0
- package/dist/modules/billing/lib/itemPriceChange.js.map +7 -0
- package/dist/modules/billing/lib/itemSelector.js.map +2 -2
- package/dist/modules/billing/lib/lineAmounts.js +32 -0
- package/dist/modules/billing/lib/lineAmounts.js.map +7 -0
- package/dist/modules/billing/lib/memoGuards.js +25 -0
- package/dist/modules/billing/lib/memoGuards.js.map +7 -0
- package/dist/modules/billing/lib/navigation.js +48 -0
- package/dist/modules/billing/lib/navigation.js.map +7 -0
- package/dist/modules/billing/lib/numbering.js +120 -0
- package/dist/modules/billing/lib/numbering.js.map +7 -0
- package/dist/modules/billing/lib/overdue.js +36 -0
- package/dist/modules/billing/lib/overdue.js.map +7 -0
- package/dist/modules/billing/lib/paymentCsv.js +125 -0
- package/dist/modules/billing/lib/paymentCsv.js.map +7 -0
- package/dist/modules/billing/lib/paymentGateway.js +15 -0
- package/dist/modules/billing/lib/paymentGateway.js.map +7 -0
- package/dist/modules/billing/lib/paymentImport.js +164 -0
- package/dist/modules/billing/lib/paymentImport.js.map +7 -0
- package/dist/modules/billing/lib/paymentMatcher.js +36 -0
- package/dist/modules/billing/lib/paymentMatcher.js.map +7 -0
- package/dist/modules/billing/lib/pdf/attachmentStore.js +46 -0
- package/dist/modules/billing/lib/pdf/attachmentStore.js.map +7 -0
- package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js +7 -0
- package/dist/modules/billing/lib/pdf/fonts/embeddedFonts.js.map +7 -0
- package/dist/modules/billing/lib/pdf/invoiceModel.js +194 -0
- package/dist/modules/billing/lib/pdf/invoiceModel.js.map +7 -0
- package/dist/modules/billing/lib/pdf/invoicePdf.js +165 -0
- package/dist/modules/billing/lib/pdf/invoicePdf.js.map +7 -0
- package/dist/modules/billing/lib/pdf/invoiceTemplate.js +276 -0
- package/dist/modules/billing/lib/pdf/invoiceTemplate.js.map +7 -0
- package/dist/modules/billing/lib/prepaidConfig.js +17 -25
- package/dist/modules/billing/lib/prepaidConfig.js.map +2 -2
- package/dist/modules/billing/lib/prepaidConsume.js +26 -7
- package/dist/modules/billing/lib/prepaidConsume.js.map +2 -2
- package/dist/modules/billing/lib/prepaidPeriodClose.js +277 -158
- package/dist/modules/billing/lib/prepaidPeriodClose.js.map +2 -2
- package/dist/modules/billing/lib/prepaidTaxPoint.js +37 -0
- package/dist/modules/billing/lib/prepaidTaxPoint.js.map +7 -0
- package/dist/modules/billing/lib/seeds/demo.js +51 -3
- package/dist/modules/billing/lib/seeds/demo.js.map +2 -2
- package/dist/modules/billing/lib/seeds/paymentsSample.js +93 -0
- package/dist/modules/billing/lib/seeds/paymentsSample.js.map +7 -0
- package/dist/modules/billing/lib/seeds/sellerSettings.js +41 -0
- package/dist/modules/billing/lib/seeds/sellerSettings.js.map +7 -0
- package/dist/modules/billing/lib/servicePeriods.js +121 -0
- package/dist/modules/billing/lib/servicePeriods.js.map +7 -0
- package/dist/modules/billing/lib/testRunCleanup.js +24 -0
- package/dist/modules/billing/lib/testRunCleanup.js.map +7 -0
- package/dist/modules/billing/lib/topupCapture.js +2 -2
- package/dist/modules/billing/lib/topupCapture.js.map +2 -2
- package/dist/modules/billing/lib/topupReceipt.js +58 -79
- package/dist/modules/billing/lib/topupReceipt.js.map +2 -2
- package/dist/modules/billing/lib/usageRater.js.map +1 -1
- package/dist/modules/billing/lib/usageRunner.js +14 -6
- package/dist/modules/billing/lib/usageRunner.js.map +2 -2
- package/dist/modules/billing/lib/vat.js +39 -0
- package/dist/modules/billing/lib/vat.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js +15 -0
- package/dist/modules/billing/migrations/Migration20261114000000_billing_customer_kind.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js +25 -0
- package/dist/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js +115 -0
- package/dist/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js +47 -0
- package/dist/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js +89 -0
- package/dist/modules/billing/migrations/Migration20261117000000_billing_payments.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js +17 -0
- package/dist/modules/billing/migrations/Migration20261118000000_billing_memos.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js +27 -0
- package/dist/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js +29 -0
- package/dist/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.js.map +7 -0
- package/dist/modules/billing/setup.js +7 -184
- package/dist/modules/billing/setup.js.map +2 -2
- package/dist/modules/billing/subscribers/credit-memo-auto-send.js +16 -0
- package/dist/modules/billing/subscribers/credit-memo-auto-send.js.map +7 -0
- package/dist/modules/billing/subscribers/debit-memo-apply-credit.js +16 -0
- package/dist/modules/billing/subscribers/debit-memo-apply-credit.js.map +7 -0
- package/dist/modules/billing/subscribers/debit-memo-auto-send.js +16 -0
- package/dist/modules/billing/subscribers/debit-memo-auto-send.js.map +7 -0
- package/dist/modules/billing/subscribers/invoice-apply-credit.js +34 -0
- package/dist/modules/billing/subscribers/invoice-apply-credit.js.map +7 -0
- package/dist/modules/billing/subscribers/invoice-auto-send.js +30 -0
- package/dist/modules/billing/subscribers/invoice-auto-send.js.map +7 -0
- package/dist/modules/billing/subscribers/payment-captured-to-paid.js +69 -33
- package/dist/modules/billing/subscribers/payment-captured-to-paid.js.map +2 -2
- package/dist/modules/billing/subscribers/prepaid-topup-captured.js +4 -6
- package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +2 -2
- package/generated/entities/billing_account/index.ts +3 -0
- package/generated/entities/billing_allocation/index.ts +18 -0
- package/generated/entities/billing_document_sequence/index.ts +11 -0
- package/generated/entities/billing_invoice/index.ts +38 -0
- package/generated/entities/billing_invoice_line/index.ts +24 -0
- package/generated/entities/billing_item/index.ts +4 -0
- package/generated/entities/billing_payment/index.ts +25 -0
- package/generated/entities/billing_payment_import/index.ts +14 -0
- package/generated/entities/billing_run/index.ts +0 -1
- package/generated/entities/billing_run_outcome/index.ts +1 -0
- package/generated/entities/billing_settings/index.ts +26 -0
- package/generated/entities/billing_statement/index.ts +1 -0
- package/generated/entities.ids.generated.ts +7 -0
- package/package.json +5 -1
- package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +171 -0
- package/src/modules/billing/__integration__/TC-BILL-005.spec.ts +134 -0
- package/src/modules/billing/__integration__/TC-BILL-006.spec.ts +101 -0
- package/src/modules/billing/__integration__/TC-BILL-007.spec.ts +140 -0
- package/src/modules/billing/__integration__/TC-BILL-008.spec.ts +108 -0
- package/src/modules/billing/__integration__/TC-BILL-009.spec.ts +113 -0
- package/src/modules/billing/__integration__/TC-BILL-010.spec.ts +118 -0
- package/src/modules/billing/__integration__/TC-BILL-011.spec.ts +142 -0
- package/src/modules/billing/__integration__/TC-BILL-012.spec.ts +115 -0
- package/src/modules/billing/__integration__/TC-BILL-013.spec.ts +118 -0
- package/src/modules/billing/__integration__/sellerSettings.ts +24 -0
- package/src/modules/billing/__tests__/commands/invoices.test.ts +436 -354
- package/src/modules/billing/__tests__/commands/itemsBulk.test.ts +33 -0
- package/src/modules/billing/__tests__/commands/memos.test.ts +205 -0
- package/src/modules/billing/__tests__/commands/payments.test.ts +241 -0
- package/src/modules/billing/__tests__/commands/runsDelete.test.ts +146 -0
- package/src/modules/billing/__tests__/commands/runsPostDrafts.test.ts +106 -0
- package/src/modules/billing/__tests__/commands/topups.test.ts +11 -0
- package/src/modules/billing/__tests__/entityRegistry.test.ts +8 -1
- package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
- package/src/modules/billing/__tests__/i18n/dictionaries.test.ts +64 -0
- package/src/modules/billing/__tests__/lib/accountFinancials.test.ts +53 -0
- package/src/modules/billing/__tests__/lib/accountSummary.test.ts +97 -0
- package/src/modules/billing/__tests__/lib/allocation.test.ts +319 -0
- package/src/modules/billing/__tests__/lib/billRunEngine.test.ts +228 -17
- package/src/modules/billing/__tests__/lib/billingSettings.test.ts +109 -0
- package/src/modules/billing/__tests__/lib/customerLookup.test.ts +156 -0
- package/src/modules/billing/__tests__/lib/dueDate.test.ts +35 -0
- package/src/modules/billing/__tests__/lib/iban.test.ts +38 -0
- package/src/modules/billing/__tests__/lib/invoiceDelivery.test.ts +206 -0
- package/src/modules/billing/__tests__/lib/invoiceLanguages.test.ts +49 -0
- package/src/modules/billing/__tests__/lib/invoiceWriter.test.ts +212 -10
- package/src/modules/billing/__tests__/lib/itemBillingState.test.ts +42 -0
- package/src/modules/billing/__tests__/lib/itemPriceChange.test.ts +165 -0
- package/src/modules/billing/__tests__/lib/lineAmounts.test.ts +86 -0
- package/src/modules/billing/__tests__/lib/navigation.test.ts +71 -0
- package/src/modules/billing/__tests__/lib/numbering.test.ts +91 -0
- package/src/modules/billing/__tests__/lib/overdue.test.ts +36 -0
- package/src/modules/billing/__tests__/lib/paymentCsv.test.ts +148 -0
- package/src/modules/billing/__tests__/lib/paymentImport.test.ts +113 -0
- package/src/modules/billing/__tests__/lib/paymentsSample.test.ts +73 -0
- package/src/modules/billing/__tests__/lib/pdf/invoicePdf.test.ts +269 -0
- package/src/modules/billing/__tests__/lib/pdf/invoicePdfService.test.ts +147 -0
- package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +374 -98
- package/src/modules/billing/__tests__/lib/prepaidTaxPoint.test.ts +118 -0
- package/src/modules/billing/__tests__/lib/seedsDemo.test.ts +53 -2
- package/src/modules/billing/__tests__/lib/sellerSettings.test.ts +28 -0
- package/src/modules/billing/__tests__/lib/servicePeriods.test.ts +190 -0
- package/src/modules/billing/__tests__/lib/topupCapture.test.ts +6 -28
- package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +21 -52
- package/src/modules/billing/__tests__/lib/vat.test.ts +51 -0
- package/src/modules/billing/__tests__/package-isolation.test.ts +22 -8
- package/src/modules/billing/__tests__/setup.test.ts +13 -4
- package/src/modules/billing/__tests__/validators.test.ts +197 -3
- package/src/modules/billing/acl.ts +12 -0
- package/src/modules/billing/api/accounts/[id]/summary/route.ts +62 -0
- package/src/modules/billing/api/accounts/route.ts +59 -4
- package/src/modules/billing/api/export/account/[id]/route.ts +13 -11
- package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
- package/src/modules/billing/api/invoices/[id]/pdf/route.ts +80 -0
- package/src/modules/billing/api/invoices/[id]/route.ts +57 -70
- package/src/modules/billing/api/invoices/[id]/send/route.ts +127 -0
- package/src/modules/billing/api/invoices/add-line/route.ts +2 -2
- package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
- package/src/modules/billing/api/invoices/edit-line/route.ts +2 -2
- package/src/modules/billing/api/invoices/post/route.ts +7 -6
- package/src/modules/billing/api/invoices/remove-line/route.ts +2 -2
- package/src/modules/billing/api/invoices/route.ts +81 -86
- package/src/modules/billing/api/items/bulk/route.ts +2 -1
- package/src/modules/billing/api/items/change-price/route.ts +54 -0
- package/src/modules/billing/api/items/route.ts +23 -7
- package/src/modules/billing/api/payment-imports/[id]/route.ts +49 -0
- package/src/modules/billing/api/payment-imports/route.ts +57 -0
- package/src/modules/billing/api/payments/[id]/route.ts +63 -0
- package/src/modules/billing/api/payments/allocate/route.ts +35 -0
- package/src/modules/billing/api/payments/assign/route.ts +36 -0
- package/src/modules/billing/api/payments/convert-to-topup/route.ts +35 -0
- package/src/modules/billing/api/payments/ignore/route.ts +35 -0
- package/src/modules/billing/api/payments/import/route.ts +72 -0
- package/src/modules/billing/api/payments/restore/route.ts +35 -0
- package/src/modules/billing/api/payments/route.ts +147 -0
- package/src/modules/billing/api/payments/unallocate/route.ts +35 -0
- package/src/modules/billing/api/payments/unassign/route.ts +35 -0
- package/src/modules/billing/api/run-outcomes/route.ts +49 -6
- package/src/modules/billing/api/runs/[id]/post-drafts/route.ts +71 -0
- package/src/modules/billing/api/runs/[id]/route.ts +59 -0
- package/src/modules/billing/api/runs/retry-failed/route.ts +2 -1
- package/src/modules/billing/api/runs/route.ts +15 -7
- package/src/modules/billing/api/settings/number-preview/route.ts +46 -0
- package/src/modules/billing/api/settings/route.ts +116 -0
- package/src/modules/billing/api/statements/route.ts +5 -0
- package/src/modules/billing/api/test-invoices/wipe/route.ts +2 -2
- package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +151 -372
- package/src/modules/billing/backend/billing/accounts/create/page.tsx +6 -0
- package/src/modules/billing/backend/billing/accounts/page.tsx +70 -4
- package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +444 -95
- package/src/modules/billing/backend/billing/invoices/page.tsx +8 -227
- package/src/modules/billing/backend/billing/items/[id]/page.tsx +75 -6
- package/src/modules/billing/backend/billing/items/create/page.tsx +13 -8
- package/src/modules/billing/backend/billing/items/page.tsx +18 -2
- package/src/modules/billing/backend/billing/payments/[id]/page.meta.ts +19 -0
- package/src/modules/billing/backend/billing/payments/[id]/page.tsx +415 -0
- package/src/modules/billing/backend/billing/payments/imports/[id]/page.meta.ts +19 -0
- package/src/modules/billing/backend/billing/payments/imports/[id]/page.tsx +106 -0
- package/src/modules/billing/backend/billing/payments/page.meta.ts +16 -0
- package/src/modules/billing/backend/billing/payments/page.tsx +56 -0
- package/src/modules/billing/backend/billing/runs/[id]/page.tsx +49 -18
- package/src/modules/billing/backend/billing/runs/page.tsx +59 -8
- package/src/modules/billing/backend/billing/statements/[id]/page.tsx +86 -5
- package/src/modules/billing/backend/billing/statements/page.tsx +1 -1
- package/src/modules/billing/backend/billing/topups/page.tsx +1 -1
- package/src/modules/billing/backend/billing/transactions/page.tsx +1 -1
- package/src/modules/billing/backend/billing/usage/create/page.tsx +3 -2
- package/src/modules/billing/backend/config/billing/page.meta.ts +21 -0
- package/src/modules/billing/backend/config/billing/page.tsx +549 -0
- package/src/modules/billing/cli.ts +31 -1
- package/src/modules/billing/commands/accounts.ts +6 -0
- package/src/modules/billing/commands/index.ts +3 -0
- package/src/modules/billing/commands/invoices.ts +364 -231
- package/src/modules/billing/commands/items.ts +143 -0
- package/src/modules/billing/commands/memos.ts +218 -0
- package/src/modules/billing/commands/payments.ts +428 -0
- package/src/modules/billing/commands/runs.ts +205 -3
- package/src/modules/billing/commands/settings.ts +77 -0
- package/src/modules/billing/commands/topups.ts +12 -3
- package/src/modules/billing/commands/transactions.ts +2 -2
- package/src/modules/billing/components/AccountForm.tsx +199 -53
- package/src/modules/billing/components/AccountInvoicesSection.tsx +75 -0
- package/src/modules/billing/components/AccountPaymentsSection.tsx +42 -0
- package/src/modules/billing/components/AccountPicker.tsx +70 -0
- package/src/modules/billing/components/AllocatePaymentDialog.tsx +167 -0
- package/src/modules/billing/components/BillingDataTable.tsx +34 -0
- package/src/modules/billing/components/BillingSettingsLink.tsx +25 -0
- package/src/modules/billing/components/ChangeItemPriceDialog.tsx +180 -0
- package/src/modules/billing/components/CreateMemoDialog.tsx +232 -0
- package/src/modules/billing/components/CustomerLabel.tsx +53 -0
- package/src/modules/billing/components/InvoicesTable.tsx +344 -0
- package/src/modules/billing/components/ItemForm.tsx +233 -44
- package/src/modules/billing/components/ItemPriceField.tsx +81 -0
- package/src/modules/billing/components/LineFormDialog.tsx +25 -1
- package/src/modules/billing/components/ManualPaymentDialog.tsx +140 -0
- package/src/modules/billing/components/MoneyInput.tsx +26 -0
- package/src/modules/billing/components/PaymentUploadDialog.tsx +148 -0
- package/src/modules/billing/components/PaymentsTable.tsx +213 -0
- package/src/modules/billing/components/PostRunDraftsButton.tsx +129 -0
- package/src/modules/billing/components/PrepaidPanel.tsx +19 -6
- package/src/modules/billing/components/RunCyclesSection.tsx +298 -0
- package/src/modules/billing/components/TestRunActions.tsx +152 -0
- package/src/modules/billing/components/account/AccountItemsTab.tsx +192 -0
- package/src/modules/billing/components/account/AccountRunBillingDialog.tsx +147 -0
- package/src/modules/billing/components/account/AccountRunsTab.tsx +201 -0
- package/src/modules/billing/components/account/AccountStatementsTab.tsx +120 -0
- package/src/modules/billing/components/account/AccountSummaryCards.tsx +153 -0
- package/src/modules/billing/components/account/AccountUsageTab.tsx +122 -0
- package/src/modules/billing/components/account/AccountView.tsx +101 -0
- package/src/modules/billing/components/account/accountRow.ts +70 -0
- package/src/modules/billing/components/customerNames.ts +62 -0
- package/src/modules/billing/data/entities.ts +656 -6
- package/src/modules/billing/data/entityIds.ts +9 -0
- package/src/modules/billing/data/validators.ts +388 -8
- package/src/modules/billing/events.ts +56 -3
- package/src/modules/billing/i18n/de.json +880 -0
- package/src/modules/billing/i18n/en.json +457 -21
- package/src/modules/billing/i18n/es.json +880 -0
- package/src/modules/billing/i18n/pl.json +458 -22
- package/src/modules/billing/index.ts +6 -2
- package/src/modules/billing/lib/accountFinancials.ts +84 -0
- package/src/modules/billing/lib/accountLock.ts +32 -0
- package/src/modules/billing/lib/accountStatus.ts +11 -9
- package/src/modules/billing/lib/accountSummary.ts +172 -0
- package/src/modules/billing/lib/allocation.ts +515 -0
- package/src/modules/billing/lib/allocationEvents.ts +26 -0
- package/src/modules/billing/lib/billPeriod.ts +19 -0
- package/src/modules/billing/lib/billRunEngine.ts +350 -150
- package/src/modules/billing/lib/billingSettings.ts +145 -0
- package/src/modules/billing/lib/commandRoute.ts +112 -0
- package/src/modules/billing/lib/customerLookup.ts +157 -0
- package/src/modules/billing/lib/dateOnly.ts +22 -0
- package/src/modules/billing/lib/documentParties.ts +23 -0
- package/src/modules/billing/lib/documentTypes.ts +37 -0
- package/src/modules/billing/lib/dueDate.ts +26 -0
- package/src/modules/billing/lib/iban.ts +36 -0
- package/src/modules/billing/lib/invoiceDelivery.ts +196 -0
- package/src/modules/billing/lib/invoiceLanguages.ts +57 -0
- package/src/modules/billing/lib/invoiceWriter.ts +162 -148
- package/src/modules/billing/lib/itemBillingState.ts +67 -0
- package/src/modules/billing/lib/itemPriceChange.ts +56 -0
- package/src/modules/billing/lib/itemSelector.ts +4 -1
- package/src/modules/billing/lib/lineAmounts.ts +61 -0
- package/src/modules/billing/lib/memoGuards.ts +41 -0
- package/src/modules/billing/lib/navigation.ts +64 -0
- package/src/modules/billing/lib/numbering.ts +174 -0
- package/src/modules/billing/lib/overdue.ts +60 -0
- package/src/modules/billing/lib/paymentCsv.ts +171 -0
- package/src/modules/billing/lib/paymentGateway.ts +52 -0
- package/src/modules/billing/lib/paymentImport.ts +228 -0
- package/src/modules/billing/lib/paymentMatcher.ts +88 -0
- package/src/modules/billing/lib/pdf/attachmentStore.ts +60 -0
- package/src/modules/billing/lib/pdf/fonts/NotoSans-Bold.ttf +0 -0
- package/src/modules/billing/lib/pdf/fonts/NotoSans-Regular.ttf +0 -0
- package/src/modules/billing/lib/pdf/fonts/OFL.txt +93 -0
- package/src/modules/billing/lib/pdf/fonts/embeddedFonts.ts +9 -0
- package/src/modules/billing/lib/pdf/invoiceModel.ts +329 -0
- package/src/modules/billing/lib/pdf/invoicePdf.ts +220 -0
- package/src/modules/billing/lib/pdf/invoiceTemplate.ts +338 -0
- package/src/modules/billing/lib/prepaidConfig.ts +27 -36
- package/src/modules/billing/lib/prepaidConsume.ts +29 -6
- package/src/modules/billing/lib/prepaidPeriodClose.ts +407 -239
- package/src/modules/billing/lib/prepaidTaxPoint.ts +76 -0
- package/src/modules/billing/lib/seeds/demo.ts +79 -6
- package/src/modules/billing/lib/seeds/paymentsSample.ts +136 -0
- package/src/modules/billing/lib/seeds/sellerSettings.ts +78 -0
- package/src/modules/billing/lib/servicePeriods.ts +226 -0
- package/src/modules/billing/lib/testRunCleanup.ts +42 -0
- package/src/modules/billing/lib/topupCapture.ts +3 -4
- package/src/modules/billing/lib/topupReceipt.ts +70 -103
- package/src/modules/billing/lib/usageRater.ts +1 -1
- package/src/modules/billing/lib/usageRunner.ts +17 -5
- package/src/modules/billing/lib/vat.ts +56 -0
- package/src/modules/billing/migrations/Migration20261114000000_billing_customer_kind.ts +25 -0
- package/src/modules/billing/migrations/Migration20261114100000_billing_cycle_semantics.ts +37 -0
- package/src/modules/billing/migrations/Migration20261115000000_billing_invoice_ledger.ts +132 -0
- package/src/modules/billing/migrations/Migration20261116000000_billing_invoice_documents.ts +58 -0
- package/src/modules/billing/migrations/Migration20261117000000_billing_payments.ts +97 -0
- package/src/modules/billing/migrations/Migration20261118000000_billing_memos.ts +21 -0
- package/src/modules/billing/migrations/Migration20261119000000_billing_operator_feedback.ts +39 -0
- package/src/modules/billing/migrations/Migration20261120000000_billing_allocation_scope_indexes.ts +35 -0
- package/src/modules/billing/setup.ts +11 -237
- package/src/modules/billing/subscribers/credit-memo-auto-send.ts +15 -0
- package/src/modules/billing/subscribers/debit-memo-apply-credit.ts +15 -0
- package/src/modules/billing/subscribers/debit-memo-auto-send.ts +15 -0
- package/src/modules/billing/subscribers/invoice-apply-credit.ts +39 -0
- package/src/modules/billing/subscribers/invoice-auto-send.ts +46 -0
- package/src/modules/billing/subscribers/payment-captured-to-paid.ts +84 -62
- package/src/modules/billing/subscribers/prepaid-topup-captured.ts +4 -8
- package/dist/modules/billing/lib/invoiceStatus.js +0 -38
- package/dist/modules/billing/lib/invoiceStatus.js.map +0 -7
- package/src/modules/billing/__tests__/lib/invoiceStatus.test.ts +0 -97
- package/src/modules/billing/lib/invoiceStatus.ts +0 -61
|
@@ -1,61 +1,53 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
|
-
import { z } from 'zod'
|
|
4
3
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
5
4
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
|
+
import { billingInvoiceListQuerySchema } from '../../data/validators'
|
|
6
|
+
import { daysOverdueSql, isoDay, overdueSql } from '../../lib/overdue'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
* `GET /api/billing/invoices`
|
|
9
|
+
* `GET /api/billing/invoices` — paginated list of billing documents
|
|
10
|
+
* (Spec 0: billing-owned `billing_invoices`, never core `sales`).
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `
|
|
13
|
-
* `
|
|
14
|
-
*
|
|
15
|
-
* entity itself is owned by `core/sales` — keeping the surface
|
|
16
|
-
* read-only and hand-rolled avoids surprising the cross-module
|
|
17
|
-
* reviewer.
|
|
12
|
+
* Filters (all on indexed columns): `status`, `documentType`, `billRunId`,
|
|
13
|
+
* `billAccountId`, `testRun` (`true` / `false`), `id`, `search` (number).
|
|
14
|
+
* Spec B: `overdue=true` (computed, B-D6 — see `lib/overdue.ts`), `dueFrom` /
|
|
15
|
+
* `dueTo` (due-date window). Each row carries `bill_account_name` (joined)
|
|
16
|
+
* and `days_overdue` (0 when not overdue).
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* - `billAccountId` — exact match on `metadata->>'bill_account_id'`
|
|
23
|
-
* - `testRun=true|false` — flips the `metadata->>'test_run'` filter
|
|
24
|
-
* - `search` — substring on invoice_number
|
|
25
|
-
*
|
|
26
|
-
* Sort: started_at DESC (most recent first). Pagination: standard
|
|
27
|
-
* page / pageSize (capped at 100).
|
|
18
|
+
* Hand-written SQL instead of the CRUD factory: documents are written by the
|
|
19
|
+
* bill-run engine without query-index side effects, so the factory's
|
|
20
|
+
* query-engine path would not see them. Sort: `created_at DESC`.
|
|
28
21
|
*/
|
|
29
22
|
|
|
30
23
|
export const metadata = {
|
|
31
24
|
GET: { requireAuth: true, requireFeatures: ['billing.invoice.view'] },
|
|
32
25
|
}
|
|
33
26
|
|
|
34
|
-
const querySchema = z
|
|
35
|
-
.object({
|
|
36
|
-
page: z.coerce.number().int().min(1).default(1),
|
|
37
|
-
pageSize: z.coerce.number().int().min(1).max(100).default(50),
|
|
38
|
-
status: z.enum(['draft', 'posted', 'paid', 'void']).optional(),
|
|
39
|
-
billRunId: z.string().uuid().optional(),
|
|
40
|
-
billAccountId: z.string().uuid().optional(),
|
|
41
|
-
testRun: z.coerce.boolean().optional(),
|
|
42
|
-
search: z.string().optional(),
|
|
43
|
-
})
|
|
44
|
-
.passthrough()
|
|
45
|
-
|
|
46
27
|
type BillingInvoiceRow = {
|
|
47
28
|
id: string
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
29
|
+
number: string
|
|
30
|
+
document_type: string
|
|
31
|
+
status: string
|
|
32
|
+
test_run: boolean
|
|
33
|
+
bill_account_id: string
|
|
34
|
+
bill_account_name: string | null
|
|
35
|
+
bill_run_id: string | null
|
|
36
|
+
bill_date: string | null
|
|
37
|
+
period_start: string | null
|
|
38
|
+
period_end: string | null
|
|
51
39
|
issue_date: string | null
|
|
52
40
|
due_date: string | null
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
41
|
+
currency_code: string
|
|
42
|
+
subtotal_net: string
|
|
43
|
+
tax_total: string
|
|
44
|
+
total_gross: string
|
|
45
|
+
paid_total: string
|
|
46
|
+
credited_total: string
|
|
47
|
+
outstanding: string
|
|
48
|
+
days_overdue: number
|
|
49
|
+
corrects_invoice_id: string | null
|
|
50
|
+
topup_id: string | null
|
|
59
51
|
created_at: string
|
|
60
52
|
updated_at: string
|
|
61
53
|
}
|
|
@@ -76,67 +68,67 @@ export async function GET(req: Request) {
|
|
|
76
68
|
}
|
|
77
69
|
|
|
78
70
|
const url = new URL(req.url)
|
|
79
|
-
const query =
|
|
80
|
-
Object.fromEntries(url.searchParams.entries()),
|
|
81
|
-
)
|
|
71
|
+
const query = billingInvoiceListQuerySchema.parse(Object.fromEntries(url.searchParams.entries()))
|
|
82
72
|
|
|
83
73
|
const em = (container.resolve('em') as EntityManager).fork()
|
|
84
74
|
|
|
85
|
-
|
|
86
|
-
// the function form of the JSONB `?` "key exists" operator — the
|
|
87
|
-
// operator form cannot be used here because `em.execute` treats a
|
|
88
|
-
// literal `?` as a positional parameter placeholder. Keeps us
|
|
89
|
-
// narrow to billing-managed invoices, never bleeding into invoices
|
|
90
|
-
// written by other modules.
|
|
91
|
-
const whereClauses: string[] = [
|
|
92
|
-
'tenant_id = ?',
|
|
93
|
-
'organization_id = ?',
|
|
94
|
-
'deleted_at IS NULL',
|
|
95
|
-
"jsonb_exists(metadata, 'bill_run_id')",
|
|
96
|
-
]
|
|
75
|
+
const whereClauses: string[] = ['i.tenant_id = ?', 'i.organization_id = ?', 'i.deleted_at IS NULL']
|
|
97
76
|
const params: unknown[] = [auth.tenantId, organizationId]
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
77
|
+
const filters: Array<[unknown, string]> = [
|
|
78
|
+
[query.id, 'i.id = ?'],
|
|
79
|
+
[query.status, 'i.status = ?'],
|
|
80
|
+
[query.documentType, 'i.document_type = ?'],
|
|
81
|
+
[query.billRunId, 'i.bill_run_id = ?'],
|
|
82
|
+
[query.billAccountId, 'i.bill_account_id = ?'],
|
|
83
|
+
[query.testRun, 'i.test_run = ?'],
|
|
84
|
+
]
|
|
85
|
+
for (const [value, clause] of filters) {
|
|
86
|
+
if (value === undefined || value === null || value === '') continue
|
|
87
|
+
whereClauses.push(clause)
|
|
88
|
+
params.push(value)
|
|
102
89
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
90
|
+
const today = isoDay(new Date())
|
|
91
|
+
if (query.overdue === true) {
|
|
92
|
+
whereClauses.push(overdueSql('i'))
|
|
93
|
+
params.push(today)
|
|
94
|
+
} else if (query.overdue === false) {
|
|
95
|
+
whereClauses.push(`NOT COALESCE(${overdueSql("i")}, false)`)
|
|
96
|
+
params.push(today)
|
|
106
97
|
}
|
|
107
|
-
if (query.
|
|
108
|
-
whereClauses.push(
|
|
109
|
-
params.push(query.
|
|
98
|
+
if (query.dueFrom) {
|
|
99
|
+
whereClauses.push('i.due_date >= ?::date')
|
|
100
|
+
params.push(query.dueFrom)
|
|
110
101
|
}
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} else {
|
|
115
|
-
whereClauses.push("(metadata->>'test_run' IS NULL OR metadata->>'test_run' != 'true')")
|
|
116
|
-
}
|
|
102
|
+
if (query.dueTo) {
|
|
103
|
+
whereClauses.push('i.due_date <= ?::date')
|
|
104
|
+
params.push(query.dueTo)
|
|
117
105
|
}
|
|
118
|
-
if (
|
|
119
|
-
whereClauses.push('
|
|
120
|
-
params.push(`%${query.search.
|
|
106
|
+
if (query.search) {
|
|
107
|
+
whereClauses.push('i.number ILIKE ?')
|
|
108
|
+
params.push(`%${query.search.replace(/[%_\\]/g, (m) => `\\${m}`)}%`)
|
|
121
109
|
}
|
|
122
110
|
|
|
123
111
|
const whereSql = whereClauses.join(' AND ')
|
|
124
112
|
const countRows = (await em.execute(
|
|
125
|
-
`SELECT COUNT(*)::int AS total FROM
|
|
113
|
+
`SELECT COUNT(*)::int AS total FROM billing_invoices i WHERE ${whereSql}`,
|
|
126
114
|
params,
|
|
127
115
|
)) as unknown as Array<{ total: number }>
|
|
128
116
|
const total = countRows?.[0]?.total ?? 0
|
|
129
117
|
|
|
130
118
|
const offset = (query.page - 1) * query.pageSize
|
|
131
119
|
const itemRows = (await em.execute(
|
|
132
|
-
`SELECT id,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
120
|
+
`SELECT i.id, i.number, i.document_type, i.status, i.test_run, i.bill_account_id,
|
|
121
|
+
a.name AS bill_account_name, i.bill_run_id, i.bill_date, i.period_start, i.period_end,
|
|
122
|
+
i.issue_date, i.due_date, i.currency_code, i.subtotal_net, i.tax_total, i.total_gross,
|
|
123
|
+
i.paid_total, i.credited_total, i.outstanding, i.corrects_invoice_id, i.corrects_invoice_number, i.topup_id,
|
|
124
|
+
${daysOverdueSql('i')}::int AS days_overdue,
|
|
125
|
+
i.created_at, i.updated_at
|
|
126
|
+
FROM billing_invoices i
|
|
127
|
+
LEFT JOIN billing_accounts a ON a.id = i.bill_account_id AND a.tenant_id = i.tenant_id
|
|
136
128
|
WHERE ${whereSql}
|
|
137
|
-
ORDER BY created_at DESC
|
|
129
|
+
ORDER BY i.created_at DESC
|
|
138
130
|
LIMIT ? OFFSET ?`,
|
|
139
|
-
[...params, query.pageSize, offset],
|
|
131
|
+
[today, today, ...params, query.pageSize, offset],
|
|
140
132
|
)) as unknown as BillingInvoiceRow[]
|
|
141
133
|
|
|
142
134
|
return NextResponse.json({
|
|
@@ -156,12 +148,15 @@ export const openApi = {
|
|
|
156
148
|
methods: {
|
|
157
149
|
GET: {
|
|
158
150
|
tags: ['Billing'],
|
|
159
|
-
summary: 'List billing
|
|
151
|
+
summary: 'List billing documents',
|
|
160
152
|
description:
|
|
161
|
-
'
|
|
162
|
-
'
|
|
163
|
-
'
|
|
164
|
-
'/
|
|
153
|
+
'Paginated billing documents (invoices, credit / debit memos, top-up receipts) from ' +
|
|
154
|
+
'`billing_invoices`. Filters: status, documentType, billRunId, billAccountId, testRun ' +
|
|
155
|
+
'(`true`/`false`), id, number search, `overdue` (`true`/`false` — posted or partially paid, ' +
|
|
156
|
+
'past due, outstanding > 0), `dueFrom` / `dueTo` (YYYY-MM-DD). Each row adds `days_overdue`. ' +
|
|
157
|
+
'Fields use billing names: `number`, `document_type`, ' +
|
|
158
|
+
'`total_gross`, `outstanding`, `bill_date`, `period_start/end`, `bill_account_name`, … ' +
|
|
159
|
+
'(0.21.0 renamed them from the core-sales names — see MIGRATION.md).',
|
|
165
160
|
},
|
|
166
161
|
},
|
|
167
162
|
}
|
|
@@ -87,6 +87,7 @@ export const openApi = createBillingCrudOpenApi({
|
|
|
87
87
|
'Idempotent per `sourceRef` (one batched existence check). ' +
|
|
88
88
|
'Returns `{ created, deduplicated, items: [{ sourceRef, id, ' +
|
|
89
89
|
'deduplicated }] }`. Always HTTP 200 — duplicates are reported ' +
|
|
90
|
-
'in the body, never an error.'
|
|
90
|
+
'in the body, never an error. Entries accept `chargeTiming` / `prorate` ' +
|
|
91
|
+
'(recurring only; defaults `in_advance` / true).',
|
|
91
92
|
},
|
|
92
93
|
})
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { runCommandRoute } from '../../../lib/commandRoute'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `POST /api/billing/items/change-price` — change a recurring item's price
|
|
6
|
+
* from a date on: the item ends the day before `effectiveDate` and a copy with
|
|
7
|
+
* `unitPrice` starts on it (same account, description, timing, proration,
|
|
8
|
+
* VAT, price basis, references and end date). Returns both item ids.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const metadata = {
|
|
12
|
+
POST: { requireAuth: true, requireFeatures: ['billing.item.manage'] },
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const bodySchema = z.object({
|
|
16
|
+
id: z.string().uuid(),
|
|
17
|
+
effectiveDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
18
|
+
unitPrice: z.coerce.number().finite().nonnegative(),
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const responseSchema = z.object({ previousItemId: z.string().uuid(), newItemId: z.string().uuid() })
|
|
22
|
+
|
|
23
|
+
export async function POST(req: Request) {
|
|
24
|
+
return runCommandRoute(req, {
|
|
25
|
+
commandId: 'billing.items.change_price',
|
|
26
|
+
bodySchema,
|
|
27
|
+
resourceKind: 'billing.item',
|
|
28
|
+
resourceId: (body) => body.id,
|
|
29
|
+
logLabel: 'billing/items/change-price.POST',
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const openApi = {
|
|
34
|
+
methods: {
|
|
35
|
+
POST: {
|
|
36
|
+
tags: ['Billing'],
|
|
37
|
+
summary: "Change a recurring item's price from a date",
|
|
38
|
+
description:
|
|
39
|
+
'Ends the item the day before `effectiveDate` and creates a copy with the new `unitPrice` (on the item price basis) ' +
|
|
40
|
+
'starting on `effectiveDate`. Already-billed days after the change are credited / re-charged by the Bill Run per the ' +
|
|
41
|
+
"item's proration setting, so nothing is billed twice.",
|
|
42
|
+
requestBody: { schema: bodySchema },
|
|
43
|
+
responses: [{ status: 200, description: 'Both item ids', schema: responseSchema }],
|
|
44
|
+
errors: [
|
|
45
|
+
{ status: 404, description: 'Item not found' },
|
|
46
|
+
{
|
|
47
|
+
status: 422,
|
|
48
|
+
description:
|
|
49
|
+
'`billing.item.price_change_recurring_only` / `_inactive` / `_before_start` (must be after the start date) / `_after_end`',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
}
|
|
@@ -33,6 +33,9 @@ const billingItemListItemSchema = z.object({
|
|
|
33
33
|
id: z.string().uuid(),
|
|
34
34
|
bill_account_id: z.string().uuid(),
|
|
35
35
|
bill_account_name: z.string().nullable(),
|
|
36
|
+
/** Spec F (F2): the owning account's currency and mode, for the form. */
|
|
37
|
+
bill_account_currency: z.string().nullable(),
|
|
38
|
+
bill_account_mode: z.enum(['postpaid', 'prepaid']).nullable(),
|
|
36
39
|
type: z.string(),
|
|
37
40
|
bill_start_date: z.string(),
|
|
38
41
|
bill_end_date: z.string().nullable(),
|
|
@@ -44,6 +47,10 @@ const billingItemListItemSchema = z.object({
|
|
|
44
47
|
source_ref: z.string().nullable(),
|
|
45
48
|
currency_mismatch: z.boolean(),
|
|
46
49
|
billed_to_date: z.string().nullable(),
|
|
50
|
+
charge_timing: z.enum(['in_advance', 'in_arrears']),
|
|
51
|
+
prorate: z.boolean(),
|
|
52
|
+
tax_rate: z.union([z.string(), z.number()]),
|
|
53
|
+
price_basis: z.enum(['net', 'gross']),
|
|
47
54
|
is_active: z.boolean(),
|
|
48
55
|
organization_id: z.string().uuid(),
|
|
49
56
|
tenant_id: z.string().uuid(),
|
|
@@ -87,6 +94,10 @@ const crud = makeCrudRoute({
|
|
|
87
94
|
'source_ref',
|
|
88
95
|
'currency_mismatch',
|
|
89
96
|
'billed_to_date',
|
|
97
|
+
'charge_timing',
|
|
98
|
+
'prorate',
|
|
99
|
+
'tax_rate',
|
|
100
|
+
'price_basis',
|
|
90
101
|
'is_active',
|
|
91
102
|
'organization_id',
|
|
92
103
|
'tenant_id',
|
|
@@ -196,7 +207,7 @@ const crud = makeCrudRoute({
|
|
|
196
207
|
},
|
|
197
208
|
hooks: {
|
|
198
209
|
// Items reference their account by FK id only; the list + detail UI
|
|
199
|
-
// wants the
|
|
210
|
+
// wants the account name, currency and mode. One bounded query
|
|
200
211
|
// (≤ pageSize ids) resolves it after the page is fetched.
|
|
201
212
|
afterList: async (payload: unknown, ctx: unknown) => {
|
|
202
213
|
const items = ((payload as { items?: unknown[] } | null)?.items ?? []) as Array<
|
|
@@ -212,11 +223,12 @@ const crud = makeCrudRoute({
|
|
|
212
223
|
if (accountIds.length === 0) return
|
|
213
224
|
const em = (ctx as { container: AwilixContainer }).container.resolve<EntityManager>('em')
|
|
214
225
|
const accounts = await em.find(BillingAccount, { id: { $in: accountIds } })
|
|
215
|
-
const
|
|
216
|
-
accounts.map((a) => [String(a.id), a.name] as [string, unknown]),
|
|
217
|
-
)
|
|
226
|
+
const byId = new Map(accounts.map((a) => [String(a.id), a] as const))
|
|
218
227
|
for (const row of items) {
|
|
219
|
-
|
|
228
|
+
const account = byId.get(String(row.bill_account_id))
|
|
229
|
+
row.bill_account_name = account?.name ?? null
|
|
230
|
+
row.bill_account_currency = account?.currencyCode ?? null
|
|
231
|
+
row.bill_account_mode = account?.billingMode ?? null
|
|
220
232
|
}
|
|
221
233
|
},
|
|
222
234
|
},
|
|
@@ -238,14 +250,18 @@ export const openApi = createBillingCrudOpenApi({
|
|
|
238
250
|
'Creates a billing item. Idempotent via `sourceRef`: re-POSTing the same ' +
|
|
239
251
|
'`(tenantId, billAccountId, sourceRef)` returns the existing row with ' +
|
|
240
252
|
'`deduplicated: true` instead of creating a duplicate. The unique index ' +
|
|
241
|
-
'on `(tenant_id, bill_account_id, source_ref)` is the correctness gate.'
|
|
253
|
+
'on `(tenant_id, bill_account_id, source_ref)` is the correctness gate. ' +
|
|
254
|
+
'Recurring items accept `chargeTiming` (`in_advance` default | `in_arrears`) and ' +
|
|
255
|
+
'`prorate` (default true); other types reject non-default values (400).',
|
|
242
256
|
},
|
|
243
257
|
update: {
|
|
244
258
|
schema: billingItemUpdateSchema,
|
|
245
259
|
responseSchema: defaultOkResponseSchema,
|
|
246
260
|
description:
|
|
247
261
|
'Updates a billing item. `type` and `sourceRef` are immutable — to change ' +
|
|
248
|
-
'either, soft-delete the item and create a new one.'
|
|
262
|
+
'either, soft-delete the item and create a new one. `chargeTiming` / `prorate` ' +
|
|
263
|
+
'may change at any time on recurring items — billing resumes from `billed_to_date`, ' +
|
|
264
|
+
'so no day is billed twice.',
|
|
249
265
|
},
|
|
250
266
|
del: {
|
|
251
267
|
schema: z.object({ id: z.string().uuid() }),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
|
+
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
|
+
import {
|
|
6
|
+
organizationScopeRequiredResponse,
|
|
7
|
+
resolveActiveOrganizationId,
|
|
8
|
+
} from '@open-mercato/shared/lib/auth/organizationScope'
|
|
9
|
+
|
|
10
|
+
/** `GET /api/billing/payment-imports/[id]` — one upload batch with its row errors (Spec C). */
|
|
11
|
+
|
|
12
|
+
export const metadata = {
|
|
13
|
+
GET: { requireAuth: true, requireFeatures: ['billing.payment.view'] },
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
17
|
+
try {
|
|
18
|
+
const container = await createRequestContainer()
|
|
19
|
+
const auth = await getAuthFromRequest(req)
|
|
20
|
+
if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
21
|
+
const organizationId = resolveActiveOrganizationId(auth)
|
|
22
|
+
if (!organizationId) return organizationScopeRequiredResponse()
|
|
23
|
+
const { id } = await params
|
|
24
|
+
const em = (container.resolve('em') as EntityManager).fork()
|
|
25
|
+
const rows = (await em.execute(
|
|
26
|
+
`SELECT id, file_name, row_count, counts, errors, user_id, created_at
|
|
27
|
+
FROM billing_payment_imports
|
|
28
|
+
WHERE id = ? AND tenant_id = ? AND organization_id = ? AND deleted_at IS NULL`,
|
|
29
|
+
[id, auth.tenantId, organizationId],
|
|
30
|
+
)) as unknown as Array<Record<string, unknown>>
|
|
31
|
+
if (!rows?.length) return NextResponse.json({ error: 'Import not found' }, { status: 404 })
|
|
32
|
+
return NextResponse.json({ import: rows[0] })
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error('[billing/payment-imports/[id].GET]', err)
|
|
35
|
+
return NextResponse.json({ error: 'Internal error' }, { status: 500 })
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const openApi = {
|
|
40
|
+
methods: {
|
|
41
|
+
GET: {
|
|
42
|
+
tags: ['Billing'],
|
|
43
|
+
summary: 'Get a payment import batch',
|
|
44
|
+
description: 'Counts per outcome and the row errors (line number + message, capped at 200).',
|
|
45
|
+
responses: [{ status: 200, description: '`{ import }`' }],
|
|
46
|
+
errors: [{ status: 404, description: 'Import not found' }],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
|
+
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
|
+
import {
|
|
6
|
+
organizationScopeRequiredResponse,
|
|
7
|
+
resolveActiveOrganizationId,
|
|
8
|
+
} from '@open-mercato/shared/lib/auth/organizationScope'
|
|
9
|
+
import { buildQueryParams } from '@open-mercato/shared/lib/crud/query-params'
|
|
10
|
+
import { billingPaymentImportListQuerySchema } from '../../data/validators'
|
|
11
|
+
|
|
12
|
+
/** `GET /api/billing/payment-imports` — CSV upload batches, newest first (Spec C, C-D4). */
|
|
13
|
+
|
|
14
|
+
export const metadata = {
|
|
15
|
+
GET: { requireAuth: true, requireFeatures: ['billing.payment.view'] },
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function GET(req: Request) {
|
|
19
|
+
try {
|
|
20
|
+
const container = await createRequestContainer()
|
|
21
|
+
const auth = await getAuthFromRequest(req)
|
|
22
|
+
if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
23
|
+
const organizationId = resolveActiveOrganizationId(auth)
|
|
24
|
+
if (!organizationId) return organizationScopeRequiredResponse()
|
|
25
|
+
const query = billingPaymentImportListQuerySchema.parse(buildQueryParams(new URL(req.url).searchParams))
|
|
26
|
+
const em = (container.resolve('em') as EntityManager).fork()
|
|
27
|
+
const where = ['tenant_id = ?', 'organization_id = ?', 'deleted_at IS NULL']
|
|
28
|
+
const params: unknown[] = [auth.tenantId, organizationId]
|
|
29
|
+
if (query.id) {
|
|
30
|
+
where.push('id = ?')
|
|
31
|
+
params.push(query.id)
|
|
32
|
+
}
|
|
33
|
+
const totalRows = (await em.execute(`SELECT COUNT(*)::int AS total FROM billing_payment_imports WHERE ${where.join(' AND ')}`, params)) as unknown as Array<{ total: number }>
|
|
34
|
+
const total = totalRows?.[0]?.total ?? 0
|
|
35
|
+
const items = await em.execute(
|
|
36
|
+
`SELECT id, file_name, row_count, counts, user_id, created_at
|
|
37
|
+
FROM billing_payment_imports WHERE ${where.join(' AND ')}
|
|
38
|
+
ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
39
|
+
[...params, query.pageSize, (query.page - 1) * query.pageSize],
|
|
40
|
+
)
|
|
41
|
+
return NextResponse.json({ items, total, page: query.page, pageSize: query.pageSize, totalPages: total === 0 ? 1 : Math.ceil(total / query.pageSize) })
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error('[billing/payment-imports.GET]', err)
|
|
44
|
+
return NextResponse.json({ error: 'Internal error' }, { status: 500 })
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const openApi = {
|
|
49
|
+
methods: {
|
|
50
|
+
GET: {
|
|
51
|
+
tags: ['Billing'],
|
|
52
|
+
summary: 'List payment import batches',
|
|
53
|
+
description: 'CSV uploads with counts per outcome (allocated, partially_allocated, matched, unmatched, duplicate, rejected).',
|
|
54
|
+
query: billingPaymentImportListQuerySchema,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
|
+
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
|
+
import {
|
|
6
|
+
organizationScopeRequiredResponse,
|
|
7
|
+
resolveActiveOrganizationId,
|
|
8
|
+
} from '@open-mercato/shared/lib/auth/organizationScope'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `GET /api/billing/payments/[id]` — one payment with its active
|
|
12
|
+
* allocations (invoice number, amount, who / how allocated) — Spec C.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const metadata = {
|
|
16
|
+
GET: { requireAuth: true, requireFeatures: ['billing.payment.view'] },
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
20
|
+
try {
|
|
21
|
+
const container = await createRequestContainer()
|
|
22
|
+
const auth = await getAuthFromRequest(req)
|
|
23
|
+
if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
24
|
+
const organizationId = resolveActiveOrganizationId(auth)
|
|
25
|
+
if (!organizationId) return organizationScopeRequiredResponse()
|
|
26
|
+
const { id } = await params
|
|
27
|
+
const em = (container.resolve('em') as EntityManager).fork()
|
|
28
|
+
const rows = (await em.execute(
|
|
29
|
+
`SELECT p.*, a.name AS bill_account_name, a.billing_mode AS bill_account_mode
|
|
30
|
+
FROM billing_payments p
|
|
31
|
+
LEFT JOIN billing_accounts a ON a.id = p.bill_account_id AND a.tenant_id = p.tenant_id
|
|
32
|
+
WHERE p.id = ? AND p.tenant_id = ? AND p.organization_id = ? AND p.deleted_at IS NULL`,
|
|
33
|
+
[id, auth.tenantId, organizationId],
|
|
34
|
+
)) as unknown as Array<Record<string, unknown>>
|
|
35
|
+
if (!rows?.length) return NextResponse.json({ error: 'Payment not found' }, { status: 404 })
|
|
36
|
+
const allocations = await em.execute(
|
|
37
|
+
`SELECT al.id, al.invoice_id, i.number AS invoice_number, i.document_type, i.status AS invoice_status,
|
|
38
|
+
al.amount, al.currency_code, al.allocated_by, al.user_id, al.created_at
|
|
39
|
+
FROM billing_allocations al
|
|
40
|
+
LEFT JOIN billing_invoices i ON i.id = al.invoice_id
|
|
41
|
+
WHERE al.source_type = 'payment' AND al.source_id = ? AND al.tenant_id = ? AND al.organization_id = ?
|
|
42
|
+
AND al.deleted_at IS NULL
|
|
43
|
+
ORDER BY al.created_at ASC`,
|
|
44
|
+
[id, auth.tenantId, organizationId],
|
|
45
|
+
)
|
|
46
|
+
return NextResponse.json({ payment: rows[0], allocations })
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error('[billing/payments/[id].GET]', err)
|
|
49
|
+
return NextResponse.json({ error: 'Internal error' }, { status: 500 })
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const openApi = {
|
|
54
|
+
methods: {
|
|
55
|
+
GET: {
|
|
56
|
+
tags: ['Billing'],
|
|
57
|
+
summary: 'Get a billing payment',
|
|
58
|
+
description: 'The payment (incl. match reason, account, top-up link) and its active allocations.',
|
|
59
|
+
responses: [{ status: 200, description: '`{ payment, allocations[] }`' }],
|
|
60
|
+
errors: [{ status: 404, description: 'Payment not found in this organization' }],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { runCommandRoute } from '../../../lib/commandRoute'
|
|
3
|
+
|
|
4
|
+
/** `POST /api/billing/payments/allocate` — allocate a payment to invoices (Spec C). */
|
|
5
|
+
|
|
6
|
+
export const metadata = {
|
|
7
|
+
POST: { requireAuth: true, requireFeatures: ['billing.payment.manage'] },
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const bodySchema = z.object({ paymentId: z.string().uuid(), allocations: z.array(z.object({ invoiceId: z.string().uuid(), amount: z.coerce.number().positive() })).min(1).max(100) })
|
|
11
|
+
|
|
12
|
+
export async function POST(req: Request) {
|
|
13
|
+
return runCommandRoute(req, {
|
|
14
|
+
commandId: 'billing.payments.allocate',
|
|
15
|
+
bodySchema,
|
|
16
|
+
resourceKind: 'billing.payment',
|
|
17
|
+
resourceId: (body) => body.paymentId,
|
|
18
|
+
logLabel: 'billing/payments/allocate.POST',
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const openApi = {
|
|
23
|
+
methods: {
|
|
24
|
+
POST: {
|
|
25
|
+
tags: ['Billing'],
|
|
26
|
+
summary: 'Allocate a payment to invoices',
|
|
27
|
+
description: 'Allocates amounts of a payment to open invoices / debit memos of its account. Invoice paid / outstanding / status are recomputed from allocations.',
|
|
28
|
+
requestBody: { schema: bodySchema },
|
|
29
|
+
responses: [{ status: 200, description: 'Updated payment state' }],
|
|
30
|
+
errors: [
|
|
31
|
+
{ status: 409, description: '`billing.allocation.exceeds_outstanding` / `insufficient_unallocated` / `account_mismatch` / `currency_mismatch` / `invoice_not_open`' },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { runCommandRoute } from '../../../lib/commandRoute'
|
|
3
|
+
|
|
4
|
+
/** `POST /api/billing/payments/assign` — assign a payment to a billing account (Spec C). */
|
|
5
|
+
|
|
6
|
+
export const metadata = {
|
|
7
|
+
POST: { requireAuth: true, requireFeatures: ['billing.payment.manage'] },
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const bodySchema = z.object({ paymentId: z.string().uuid(), billAccountId: z.string().uuid() })
|
|
11
|
+
|
|
12
|
+
export async function POST(req: Request) {
|
|
13
|
+
return runCommandRoute(req, {
|
|
14
|
+
commandId: 'billing.payments.assign',
|
|
15
|
+
bodySchema,
|
|
16
|
+
resourceKind: 'billing.payment',
|
|
17
|
+
resourceId: (body) => body.paymentId,
|
|
18
|
+
logLabel: 'billing/payments/assign.POST',
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const openApi = {
|
|
23
|
+
methods: {
|
|
24
|
+
POST: {
|
|
25
|
+
tags: ['Billing'],
|
|
26
|
+
summary: 'Assign a payment to a billing account',
|
|
27
|
+
description: 'Assigns an unmatched payment to a postpaid account (status → matched) and applies it as credit to the account\'s open invoices, oldest due first.',
|
|
28
|
+
requestBody: { schema: bodySchema },
|
|
29
|
+
responses: [{ status: 200, description: 'Updated payment state' }],
|
|
30
|
+
errors: [
|
|
31
|
+
{ status: 404, description: 'Payment or account not found' },
|
|
32
|
+
{ status: 409, description: '`billing.payment.not_unmatched` / `prepaid_account` / `currency_mismatch`' },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { runCommandRoute } from '../../../lib/commandRoute'
|
|
3
|
+
|
|
4
|
+
/** `POST /api/billing/payments/convert-to-topup` — convert a payment into a prepaid top-up (Spec C). */
|
|
5
|
+
|
|
6
|
+
export const metadata = {
|
|
7
|
+
POST: { requireAuth: true, requireFeatures: ['billing.payment.manage', 'billing.topup.create'] },
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const bodySchema = z.object({ paymentId: z.string().uuid(), billAccountId: z.string().uuid() })
|
|
11
|
+
|
|
12
|
+
export async function POST(req: Request) {
|
|
13
|
+
return runCommandRoute(req, {
|
|
14
|
+
commandId: 'billing.payments.convert_to_topup',
|
|
15
|
+
bodySchema,
|
|
16
|
+
resourceKind: 'billing.payment',
|
|
17
|
+
resourceId: (body) => body.paymentId,
|
|
18
|
+
logLabel: 'billing/payments/convert-to-topup.POST',
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const openApi = {
|
|
23
|
+
methods: {
|
|
24
|
+
POST: {
|
|
25
|
+
tags: ['Billing'],
|
|
26
|
+
summary: 'Convert a payment into a prepaid top-up',
|
|
27
|
+
description: 'Turns an unmatched payment into a captured top-up of a prepaid account (balance credit, transaction and VAT receipt). Terminal; idempotent per payment.',
|
|
28
|
+
requestBody: { schema: bodySchema },
|
|
29
|
+
responses: [{ status: 200, description: 'Updated payment state' }],
|
|
30
|
+
errors: [
|
|
31
|
+
{ status: 409, description: '`billing.payment.not_prepaid` / `currency_mismatch` / `not_convertible`' },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|