@dainamite/billing 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +172 -0
- package/README.md +14 -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 +46 -4
- package/dist/modules/billing/api/accounts/route.js.map +2 -2
- package/dist/modules/billing/api/export/account/[id]/route.js +16 -12
- 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 +69 -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 +3 -3
- 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 +3 -3
- 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 +3 -3
- 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 +44 -7
- 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 +3 -3
- package/dist/modules/billing/api/runs/retry-failed/route.js.map +2 -2
- package/dist/modules/billing/api/runs/route.js +11 -5
- 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/ce.js.map +2 -2
- 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 +272 -170
- 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 +154 -7
- 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 +615 -59
- 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 +70 -0
- package/dist/modules/billing/events.js.map +2 -2
- package/dist/modules/billing/i18n/en.json +457 -21
- package/dist/modules/billing/i18n/pl.json +457 -21
- 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 +241 -106
- package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
- package/dist/modules/billing/lib/billRunLabel.js.map +1 -1
- 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 +131 -0
- package/dist/modules/billing/lib/invoiceDelivery.js.map +7 -0
- package/dist/modules/billing/lib/invoiceLanguages.js +16 -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 +274 -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/tenantLock.js.map +1 -1
- 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/dist/modules/billing/workers/reap-stale-bill-runs.js +2 -2
- package/dist/modules/billing/workers/reap-stale-bill-runs.js.map +2 -2
- package/generated/entities/billing_account/index.ts +26 -0
- package/generated/entities/billing_account_balance/index.ts +13 -0
- package/generated/entities/billing_account_transaction/index.ts +21 -0
- package/generated/entities/billing_account_usage/index.ts +18 -0
- package/generated/entities/billing_allocation/index.ts +18 -0
- package/generated/entities/billing_document_sequence/index.ts +11 -0
- package/generated/entities/billing_draft_invoice_edit/index.ts +14 -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 +26 -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 +20 -0
- package/generated/entities/billing_run_outcome/index.ts +18 -0
- package/generated/entities/billing_settings/index.ts +26 -0
- package/generated/entities/billing_statement/index.ts +22 -0
- package/generated/entities/billing_topup/index.ts +20 -0
- package/generated/entities.ids.generated.ts +35 -0
- package/package.json +15 -10
- package/src/modules/billing/__integration__/TC-BILL-004.spec.ts +170 -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 +437 -355
- 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 +326 -0
- package/src/modules/billing/__tests__/events.test.ts +142 -0
- package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +28 -11
- 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 +231 -20
- 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 +189 -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 +199 -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 +193 -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 +58 -4
- package/src/modules/billing/api/export/account/[id]/route.ts +20 -18
- package/src/modules/billing/api/invoices/[id]/memos/route.ts +63 -0
- package/src/modules/billing/api/invoices/[id]/pdf/route.ts +79 -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 +3 -3
- package/src/modules/billing/api/invoices/delete-draft/route.ts +33 -0
- package/src/modules/billing/api/invoices/edit-line/route.ts +4 -4
- package/src/modules/billing/api/invoices/post/route.ts +7 -6
- package/src/modules/billing/api/invoices/remove-line/route.ts +3 -3
- 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 +50 -7
- 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 +4 -3
- package/src/modules/billing/api/runs/route.ts +17 -9
- 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 +71 -5
- package/src/modules/billing/backend/billing/invoices/[id]/page.tsx +445 -96
- 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 +19 -3
- 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 +50 -19
- package/src/modules/billing/backend/billing/runs/page.tsx +60 -9
- package/src/modules/billing/backend/billing/statements/[id]/page.tsx +87 -6
- package/src/modules/billing/backend/billing/statements/page.tsx +2 -2
- package/src/modules/billing/backend/billing/topups/page.tsx +2 -2
- package/src/modules/billing/backend/billing/transactions/page.tsx +2 -2
- 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/ce.ts +8 -7
- 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 +371 -238
- 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 +208 -6
- 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 +20 -7
- 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 +685 -15
- package/src/modules/billing/data/entityIds.ts +25 -11
- package/src/modules/billing/data/validators.ts +388 -8
- package/src/modules/billing/events.ts +82 -3
- package/src/modules/billing/i18n/en.json +457 -21
- package/src/modules/billing/i18n/pl.json +457 -21
- 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 +362 -162
- package/src/modules/billing/lib/billRunLabel.ts +1 -1
- 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 +197 -0
- package/src/modules/billing/lib/invoiceLanguages.ts +34 -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 +328 -0
- package/src/modules/billing/lib/pdf/invoicePdf.ts +216 -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 +410 -242
- 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/tenantLock.ts +1 -1
- 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/src/modules/billing/workers/reap-stale-bill-runs.ts +4 -4
- 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
|
@@ -15,10 +15,10 @@ import { metadata } from '../index'
|
|
|
15
15
|
|
|
16
16
|
const PACKAGE_ROOT = path.resolve(__dirname, '..')
|
|
17
17
|
|
|
18
|
-
// Must mirror peerDependencies in packages/billing/package.json
|
|
19
|
-
// relatives + node builtins). Adding a prefix here without adding it to
|
|
20
|
-
//
|
|
21
|
-
//
|
|
18
|
+
// Must mirror peerDependencies + dependencies in packages/billing/package.json
|
|
19
|
+
// (plus relatives + node builtins). Adding a prefix here without adding it to
|
|
20
|
+
// package.json = silent runtime failure for consumers that don't have the dep
|
|
21
|
+
// transitively. `pdf-lib` / `@pdf-lib/` are regular dependencies (Spec B PDF).
|
|
22
22
|
const ALLOWED_IMPORT_PREFIXES = [
|
|
23
23
|
'./',
|
|
24
24
|
'../',
|
|
@@ -36,6 +36,8 @@ const ALLOWED_IMPORT_PREFIXES = [
|
|
|
36
36
|
'@dainamite/',
|
|
37
37
|
'node:',
|
|
38
38
|
'@tanstack/',
|
|
39
|
+
'pdf-lib',
|
|
40
|
+
'@pdf-lib/',
|
|
39
41
|
]
|
|
40
42
|
|
|
41
43
|
const NODE_BUILTINS = new Set([
|
|
@@ -128,10 +130,22 @@ describe('@dainamite/billing package isolation', () => {
|
|
|
128
130
|
}
|
|
129
131
|
})
|
|
130
132
|
|
|
131
|
-
it('
|
|
132
|
-
expect(metadata.requires).toEqual(
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
it('requires only platform modules (Spec 0: no core business modules; Spec B: attachments)', () => {
|
|
134
|
+
expect(metadata.requires).toEqual(['auth', 'directory', 'attachments'])
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('never imports core sales / configs / dictionaries / payment_gateways (Spec 0)', () => {
|
|
138
|
+
const banned = new Set(['sales', 'configs', 'dictionaries', 'payment_gateways'])
|
|
139
|
+
const violations: string[] = []
|
|
140
|
+
for (const [file, specs] of importsByFile) {
|
|
141
|
+
for (const spec of specs) {
|
|
142
|
+
const subModule = extractCoreModuleSubpath(spec)
|
|
143
|
+
if (subModule && banned.has(subModule)) violations.push(` ${path.relative(PACKAGE_ROOT, file)} → ${spec}`)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (violations.length > 0) {
|
|
147
|
+
throw new Error(`Billing must not depend on core business modules:\n${violations.join('\n')}`)
|
|
148
|
+
}
|
|
135
149
|
})
|
|
136
150
|
|
|
137
151
|
it('does not import from sibling app modules', () => {
|
|
@@ -16,9 +16,17 @@ import setup from '../setup'
|
|
|
16
16
|
const featureIds = new Set<string>(features.map((f) => f.id))
|
|
17
17
|
|
|
18
18
|
describe('billing setup — contract', () => {
|
|
19
|
-
it('exports
|
|
20
|
-
expect(typeof setup.onTenantCreated).toBe('function')
|
|
19
|
+
it('exports a seedDefaults hook (billing settings) and no core-config tenant hook', () => {
|
|
21
20
|
expect(typeof setup.seedDefaults).toBe('function')
|
|
21
|
+
expect(setup.onTenantCreated).toBeUndefined()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('seedDefaults warms up the organization billing settings row', async () => {
|
|
25
|
+
const row = { id: 's-1' }
|
|
26
|
+
const em = { findOne: jest.fn(async () => row), execute: jest.fn() }
|
|
27
|
+
await setup.seedDefaults!({ em, tenantId: 't-1', organizationId: 'o-1' } as never)
|
|
28
|
+
expect(em.findOne).toHaveBeenCalledTimes(1)
|
|
29
|
+
expect(em.execute).not.toHaveBeenCalled()
|
|
22
30
|
})
|
|
23
31
|
|
|
24
32
|
it('does not declare seedExamples (billing ships no demo data)', () => {
|
|
@@ -77,8 +85,8 @@ describe('billing setup — contract', () => {
|
|
|
77
85
|
})
|
|
78
86
|
|
|
79
87
|
describe('billing acl — surface', () => {
|
|
80
|
-
it('exports exactly
|
|
81
|
-
expect(features).toHaveLength(
|
|
88
|
+
it('exports exactly 27 features (12 Phase 0 + 7 SPEC-002 prepaid + 2 Spec 0 settings + 1 Spec B send + 3 Spec C payments + 1 Spec D memos + 1 Spec F run delete)', () => {
|
|
89
|
+
expect(features).toHaveLength(27)
|
|
82
90
|
})
|
|
83
91
|
|
|
84
92
|
it('all feature IDs are prefixed `billing.` (no leaking module boundary)', () => {
|
|
@@ -98,6 +106,7 @@ describe('billing acl — surface', () => {
|
|
|
98
106
|
'billing.run.trigger',
|
|
99
107
|
'billing.run.dry_run',
|
|
100
108
|
'billing.run.view',
|
|
109
|
+
'billing.run.delete',
|
|
101
110
|
'billing.invoice.post',
|
|
102
111
|
'billing.invoice.edit_draft',
|
|
103
112
|
'billing.invoice.view',
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
rateJsonUsageVolume,
|
|
21
21
|
validateRateJson,
|
|
22
22
|
} from '../data/validators'
|
|
23
|
+
import { DEFAULT_INVOICE_LANGUAGE, SUPPORTED_INVOICE_LANGUAGES } from '../lib/invoiceLanguages'
|
|
23
24
|
|
|
24
25
|
describe('rate_json — one_time', () => {
|
|
25
26
|
it('accepts a positive amount', () => {
|
|
@@ -293,9 +294,6 @@ describe('exported enums', () => {
|
|
|
293
294
|
])
|
|
294
295
|
})
|
|
295
296
|
|
|
296
|
-
it('INVOICE_STATUSES matches the dictionary entries seeded by setup', () => {
|
|
297
|
-
expect([...INVOICE_STATUSES]).toEqual(['draft', 'posted', 'paid', 'void'])
|
|
298
|
-
})
|
|
299
297
|
})
|
|
300
298
|
|
|
301
299
|
// ─── Phase 1 — CRUD payload schemas ────────────────────────────────
|
|
@@ -304,6 +302,11 @@ import {
|
|
|
304
302
|
billingAccountCreateSchema,
|
|
305
303
|
billingAccountListQuerySchema,
|
|
306
304
|
billingAccountUpdateSchema,
|
|
305
|
+
billingItemBulkCreateSchema,
|
|
306
|
+
billingRunTriggerSchema,
|
|
307
|
+
CHARGE_TIMING_RECURRING_ONLY_MESSAGE,
|
|
308
|
+
billingInvoiceListQuerySchema,
|
|
309
|
+
billingSettingsUpdateSchema,
|
|
307
310
|
billingItemCreateSchema,
|
|
308
311
|
billingItemListQuerySchema,
|
|
309
312
|
billingItemUpdateSchema,
|
|
@@ -367,6 +370,45 @@ describe('billingAccountCreateSchema', () => {
|
|
|
367
370
|
expect(() => billingAccountCreateSchema.parse(withoutTenant)).toThrow()
|
|
368
371
|
void tenantId
|
|
369
372
|
})
|
|
373
|
+
// Spec E — B2C accounts + invoice-language picklist.
|
|
374
|
+
it('defaults customerKind to company', () => {
|
|
375
|
+
expect(billingAccountCreateSchema.parse(validAccountCreate).customerKind).toBe('company')
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
it('accepts customerKind person', () => {
|
|
379
|
+
const parsed = billingAccountCreateSchema.parse({ ...validAccountCreate, customerKind: 'person' })
|
|
380
|
+
expect(parsed.customerKind).toBe('person')
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
it('rejects an unknown customerKind', () => {
|
|
384
|
+
expect(() =>
|
|
385
|
+
billingAccountCreateSchema.parse({ ...validAccountCreate, customerKind: 'household' }),
|
|
386
|
+
).toThrow()
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
it('accepts every template-supported invoice language, case/space tolerant', () => {
|
|
390
|
+
for (const { code } of SUPPORTED_INVOICE_LANGUAGES) {
|
|
391
|
+
const parsed = billingAccountCreateSchema.parse({
|
|
392
|
+
...validAccountCreate,
|
|
393
|
+
invoiceLanguage: ` ${code.toUpperCase()} `,
|
|
394
|
+
})
|
|
395
|
+
expect(parsed.invoiceLanguage).toBe(code)
|
|
396
|
+
}
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
it('rejects an invoice language the template does not support', () => {
|
|
400
|
+
expect(() =>
|
|
401
|
+
billingAccountCreateSchema.parse({ ...validAccountCreate, invoiceLanguage: 'de' }),
|
|
402
|
+
).toThrow()
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
it('defaults invoiceLanguage when omitted', () => {
|
|
406
|
+
const { invoiceLanguage, ...withoutLanguage } = validAccountCreate
|
|
407
|
+
void invoiceLanguage
|
|
408
|
+
expect(billingAccountCreateSchema.parse(withoutLanguage).invoiceLanguage).toBe(
|
|
409
|
+
DEFAULT_INVOICE_LANGUAGE,
|
|
410
|
+
)
|
|
411
|
+
})
|
|
370
412
|
})
|
|
371
413
|
|
|
372
414
|
describe('billingAccountUpdateSchema', () => {
|
|
@@ -397,6 +439,16 @@ describe('billingAccountUpdateSchema', () => {
|
|
|
397
439
|
it('does not declare customerId (immutable per spec)', () => {
|
|
398
440
|
expect('customerId' in billingAccountUpdateSchema.shape).toBe(false)
|
|
399
441
|
})
|
|
442
|
+
|
|
443
|
+
it('does not declare customerKind (immutable per spec)', () => {
|
|
444
|
+
expect('customerKind' in billingAccountUpdateSchema.shape).toBe(false)
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
it('validates invoiceLanguage against supported languages', () => {
|
|
448
|
+
const base = { tenantId: TENANT, organizationId: ORG, id: ACCOUNT }
|
|
449
|
+
expect(billingAccountUpdateSchema.parse({ ...base, invoiceLanguage: 'PL' }).invoiceLanguage).toBe('pl')
|
|
450
|
+
expect(() => billingAccountUpdateSchema.parse({ ...base, invoiceLanguage: 'fr' })).toThrow()
|
|
451
|
+
})
|
|
400
452
|
})
|
|
401
453
|
|
|
402
454
|
describe('billingAccountListQuerySchema', () => {
|
|
@@ -415,6 +467,11 @@ describe('billingAccountListQuerySchema', () => {
|
|
|
415
467
|
expect(parsed.page).toBe(1)
|
|
416
468
|
expect(parsed.pageSize).toBe(50)
|
|
417
469
|
})
|
|
470
|
+
|
|
471
|
+
it('accepts a customerKind filter and rejects unknown kinds', () => {
|
|
472
|
+
expect(billingAccountListQuerySchema.parse({ customerKind: 'person' }).customerKind).toBe('person')
|
|
473
|
+
expect(() => billingAccountListQuerySchema.parse({ customerKind: 'robot' })).toThrow()
|
|
474
|
+
})
|
|
418
475
|
})
|
|
419
476
|
|
|
420
477
|
const validItemRecurring = {
|
|
@@ -592,3 +649,136 @@ describe('billingUsageListQuerySchema', () => {
|
|
|
592
649
|
expect(() => billingUsageListQuerySchema.parse({ pageSize: '101' })).toThrow()
|
|
593
650
|
})
|
|
594
651
|
})
|
|
652
|
+
|
|
653
|
+
// ─── Spec A — charge timing, proration, no catch-up flag ─────────
|
|
654
|
+
|
|
655
|
+
describe('Spec A validators', () => {
|
|
656
|
+
const recurring = {
|
|
657
|
+
tenantId: TENANT,
|
|
658
|
+
organizationId: ORG,
|
|
659
|
+
billAccountId: ACCOUNT,
|
|
660
|
+
type: 'recurring' as const,
|
|
661
|
+
billStartDate: '2026-11-14',
|
|
662
|
+
description: 'Internet 300',
|
|
663
|
+
rateJson: { unit_price: 79 },
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
it('accepts chargeTiming / prorate on recurring items and leaves defaults to the command', () => {
|
|
667
|
+
expect(billingItemCreateSchema.parse(recurring)).not.toHaveProperty('chargeTiming')
|
|
668
|
+
const parsed = billingItemCreateSchema.parse({ ...recurring, chargeTiming: 'in_arrears', prorate: false })
|
|
669
|
+
expect(parsed).toMatchObject({ chargeTiming: 'in_arrears', prorate: false })
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
it('rejects an unknown charge timing', () => {
|
|
673
|
+
expect(() => billingItemCreateSchema.parse({ ...recurring, chargeTiming: 'whenever' })).toThrow()
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
it('rejects non-default timing / proration on non-recurring items', () => {
|
|
677
|
+
const oneTime = { ...recurring, type: 'one_time' as const, rateJson: { amount: 10 } }
|
|
678
|
+
expect(billingItemCreateSchema.parse({ ...oneTime, chargeTiming: 'in_advance', prorate: true })).toBeTruthy()
|
|
679
|
+
expect(() => billingItemCreateSchema.parse({ ...oneTime, chargeTiming: 'in_arrears' })).toThrow(
|
|
680
|
+
CHARGE_TIMING_RECURRING_ONLY_MESSAGE,
|
|
681
|
+
)
|
|
682
|
+
expect(() => billingItemCreateSchema.parse({ ...oneTime, prorate: false })).toThrow(
|
|
683
|
+
CHARGE_TIMING_RECURRING_ONLY_MESSAGE,
|
|
684
|
+
)
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
it('applies the same rule to bulk entries and allows both on update', () => {
|
|
688
|
+
const { tenantId, organizationId, ...entry } = recurring
|
|
689
|
+
expect(() =>
|
|
690
|
+
billingItemBulkCreateSchema.parse({
|
|
691
|
+
tenantId,
|
|
692
|
+
organizationId,
|
|
693
|
+
items: [{ ...entry, type: 'usage', uomCode: 'gb', rateJson: { unit_price: 1 }, prorate: false }],
|
|
694
|
+
}),
|
|
695
|
+
).toThrow()
|
|
696
|
+
expect(
|
|
697
|
+
billingItemUpdateSchema.parse({ tenantId, organizationId, id: ACCOUNT, chargeTiming: 'in_arrears', prorate: false }),
|
|
698
|
+
).toMatchObject({ chargeTiming: 'in_arrears', prorate: false })
|
|
699
|
+
})
|
|
700
|
+
|
|
701
|
+
it('strips a legacy catchUp flag from the run trigger', () => {
|
|
702
|
+
const parsed = billingRunTriggerSchema.parse({ tenantId: TENANT, organizationId: ORG, catchUp: true })
|
|
703
|
+
expect(parsed).not.toHaveProperty('catchUp')
|
|
704
|
+
expect(parsed.mode).toBe('real')
|
|
705
|
+
})
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
// ─── Spec 0 — ledger validators ──────────────────────────────────
|
|
709
|
+
|
|
710
|
+
describe('Spec 0 validators', () => {
|
|
711
|
+
it('invoice statuses drop void and add partially_paid / credited', () => {
|
|
712
|
+
expect(INVOICE_STATUSES).toEqual(['draft', 'posted', 'partially_paid', 'paid', 'credited'])
|
|
713
|
+
})
|
|
714
|
+
|
|
715
|
+
it('parses testRun literally (false stays false)', () => {
|
|
716
|
+
expect(billingInvoiceListQuerySchema.parse({ testRun: 'false' }).testRun).toBe(false)
|
|
717
|
+
expect(billingInvoiceListQuerySchema.parse({ testRun: 'true' }).testRun).toBe(true)
|
|
718
|
+
expect(billingInvoiceListQuerySchema.parse({}).testRun).toBeUndefined()
|
|
719
|
+
expect(() => billingInvoiceListQuerySchema.parse({ status: 'void' })).toThrow()
|
|
720
|
+
})
|
|
721
|
+
|
|
722
|
+
it('validates number masks on settings update', () => {
|
|
723
|
+
const base = { tenantId: TENANT, organizationId: ORG }
|
|
724
|
+
expect(
|
|
725
|
+
billingSettingsUpdateSchema.parse({ ...base, numberMasks: { invoice: 'FV/{YYYY}/{SEQUENCE_NUM_YEAR:5}' } }).numberMasks,
|
|
726
|
+
).toEqual({ invoice: 'FV/{YYYY}/{SEQUENCE_NUM_YEAR:5}' })
|
|
727
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, numberMasks: { invoice: 'FV/{SEQUENCE_NUM_MONTH}' } })).toThrow(
|
|
728
|
+
'mask_month_scope_needs_year_and_month',
|
|
729
|
+
)
|
|
730
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, numberMasks: { bogus: 'X{SEQUENCE_NUM}' } })).toThrow()
|
|
731
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, topupTaxRate: 120 })).toThrow()
|
|
732
|
+
})
|
|
733
|
+
})
|
|
734
|
+
|
|
735
|
+
describe('Spec B validators', () => {
|
|
736
|
+
const base = { tenantId: TENANT, organizationId: ORG }
|
|
737
|
+
const item = {
|
|
738
|
+
...base,
|
|
739
|
+
billAccountId: ACCOUNT,
|
|
740
|
+
type: 'recurring' as const,
|
|
741
|
+
billStartDate: '2026-11-14',
|
|
742
|
+
description: 'Internet 300',
|
|
743
|
+
rateJson: { unit_price: 79 },
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
it('item taxRate is optional on create (the command fills the default) and bounded 0–100', () => {
|
|
747
|
+
expect(billingItemCreateSchema.parse(item)).not.toHaveProperty('taxRate')
|
|
748
|
+
expect(billingItemCreateSchema.parse({ ...item, taxRate: '8' }).taxRate).toBe(8)
|
|
749
|
+
expect(() => billingItemCreateSchema.parse({ ...item, taxRate: -1 })).toThrow()
|
|
750
|
+
expect(() => billingItemCreateSchema.parse({ ...item, taxRate: 101 })).toThrow()
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
it('normalizes and checksum-validates the seller IBAN; empty clears it', () => {
|
|
754
|
+
expect(billingSettingsUpdateSchema.parse({ ...base, iban: 'pl61 1090 1014 0000 0712 1981 2874' }).iban).toBe(
|
|
755
|
+
'PL61109010140000071219812874',
|
|
756
|
+
)
|
|
757
|
+
expect(billingSettingsUpdateSchema.parse({ ...base, iban: '' }).iban).toBeNull()
|
|
758
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, iban: 'PL61109010140000071219812875' })).toThrow(
|
|
759
|
+
'billing.settings.error.iban_invalid',
|
|
760
|
+
)
|
|
761
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, bic: 'XX' })).toThrow('billing.settings.error.bic_invalid')
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
it('validates seller address, terms and default rate', () => {
|
|
765
|
+
const parsed = billingSettingsUpdateSchema.parse({
|
|
766
|
+
...base,
|
|
767
|
+
legalName: ' Seller ',
|
|
768
|
+
taxId: '',
|
|
769
|
+
sellerAddress: { line1: 'ul. A 1', city: 'Kraków', postal_code: '30-001', country: 'PL' },
|
|
770
|
+
defaultPaymentTermsDays: '30',
|
|
771
|
+
defaultTaxRate: 23,
|
|
772
|
+
})
|
|
773
|
+
expect(parsed).toMatchObject({ legalName: 'Seller', taxId: null, defaultPaymentTermsDays: 30, defaultTaxRate: 23 })
|
|
774
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, sellerAddress: { line1: 'x' } })).toThrow()
|
|
775
|
+
expect(() => billingSettingsUpdateSchema.parse({ ...base, defaultPaymentTermsDays: 400 })).toThrow()
|
|
776
|
+
})
|
|
777
|
+
|
|
778
|
+
it('accepts overdue / due-date filters on the invoice list', () => {
|
|
779
|
+
const parsed = billingInvoiceListQuerySchema.parse({ overdue: 'true', dueFrom: '2026-11-01', dueTo: '2026-11-30' })
|
|
780
|
+
expect(parsed).toMatchObject({ overdue: true, dueFrom: '2026-11-01', dueTo: '2026-11-30' })
|
|
781
|
+
expect(() => billingInvoiceListQuerySchema.parse({ dueFrom: '01.11.2026' })).toThrow()
|
|
782
|
+
})
|
|
783
|
+
})
|
|
784
|
+
|
|
@@ -8,9 +8,18 @@ export const features = [
|
|
|
8
8
|
{ id: 'billing.run.trigger', title: 'Trigger Bill Run', module: 'billing' },
|
|
9
9
|
{ id: 'billing.run.dry_run', title: 'Trigger Bill Run (dry-run)', module: 'billing' },
|
|
10
10
|
{ id: 'billing.run.view', title: 'View Bill Run History', module: 'billing' },
|
|
11
|
+
// Spec F — delete test / dry runs (real runs are never deleted)
|
|
12
|
+
{ id: 'billing.run.delete', title: 'Delete Test / Dry Bill Runs', module: 'billing' },
|
|
11
13
|
{ id: 'billing.invoice.post', title: 'Post Draft Invoice', module: 'billing' },
|
|
12
14
|
{ id: 'billing.invoice.edit_draft', title: 'Edit Draft Invoice', module: 'billing' },
|
|
13
15
|
{ id: 'billing.invoice.view', title: 'View Billing Invoices', module: 'billing' },
|
|
16
|
+
{ id: 'billing.invoice.send', title: 'Email Billing Invoices', module: 'billing' },
|
|
17
|
+
// Spec D — corrective documents
|
|
18
|
+
{ id: 'billing.invoice.correct', title: 'Create Credit / Debit Memos', module: 'billing' },
|
|
19
|
+
// Spec C — payments
|
|
20
|
+
{ id: 'billing.payment.view', title: 'View Billing Payments', module: 'billing' },
|
|
21
|
+
{ id: 'billing.payment.manage', title: 'Manage Billing Payments (assign, allocate, ignore, convert)', module: 'billing' },
|
|
22
|
+
{ id: 'billing.payment.import', title: 'Import Bank Payments (CSV)', module: 'billing' },
|
|
14
23
|
// ─── Prepaid balance billing (SPEC-002) ──────────────────────
|
|
15
24
|
{ id: 'billing.balance.view', title: 'View Balance & Transactions', module: 'billing' },
|
|
16
25
|
{ id: 'billing.balance.adjust', title: 'Adjust Balance (manual credit/debit)', module: 'billing' },
|
|
@@ -19,6 +28,9 @@ export const features = [
|
|
|
19
28
|
{ id: 'billing.statement.view', title: 'View Consumption Statements', module: 'billing' },
|
|
20
29
|
{ id: 'billing.statement.generate', title: 'Generate Consumption Statement', module: 'billing' },
|
|
21
30
|
{ id: 'billing.credit.view', title: 'View Account Credit Status', module: 'billing' },
|
|
31
|
+
// ─── Billing settings (Spec 0) ───────────────────────────────
|
|
32
|
+
{ id: 'billing.settings.view', title: 'View Billing Settings', module: 'billing' },
|
|
33
|
+
{ id: 'billing.settings.manage', title: 'Manage Billing Settings', module: 'billing' },
|
|
22
34
|
] as const
|
|
23
35
|
|
|
24
36
|
export default features
|
|
@@ -0,0 +1,62 @@
|
|
|
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 { BillingAccount } from '../../../../data/entities'
|
|
6
|
+
import { getAccountWorkspaceSummary } from '../../../../lib/accountSummary'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `GET /api/billing/accounts/[id]/summary` — what the customer owes (Spec B
|
|
10
|
+
* AR summary; Spec E extends the same endpoint for the account workspace).
|
|
11
|
+
* One aggregate query; see `lib/accountSummary.ts`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const metadata = {
|
|
15
|
+
GET: { requireAuth: true, requireFeatures: ['billing.account.view'] },
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
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 = (auth as { orgId?: string }).orgId ?? null
|
|
26
|
+
if (!organizationId) {
|
|
27
|
+
return NextResponse.json({ error: 'Organization scope required' }, { status: 403 })
|
|
28
|
+
}
|
|
29
|
+
const { id: accountId } = await params
|
|
30
|
+
const em = (container.resolve('em') as EntityManager).fork()
|
|
31
|
+
const account = await em.findOne(BillingAccount, {
|
|
32
|
+
id: accountId,
|
|
33
|
+
tenantId: auth.tenantId,
|
|
34
|
+
organizationId,
|
|
35
|
+
deletedAt: null,
|
|
36
|
+
})
|
|
37
|
+
if (!account) {
|
|
38
|
+
return NextResponse.json({ error: 'Account not found' }, { status: 404 })
|
|
39
|
+
}
|
|
40
|
+
return NextResponse.json(await getAccountWorkspaceSummary(em, account))
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.error('[billing/accounts/summary.GET]', err)
|
|
43
|
+
return NextResponse.json({ error: 'Internal error' }, { status: 500 })
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const openApi = {
|
|
48
|
+
methods: {
|
|
49
|
+
GET: {
|
|
50
|
+
tags: ['Billing'],
|
|
51
|
+
summary: 'Get a billing account receivables summary',
|
|
52
|
+
parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } }],
|
|
53
|
+
description:
|
|
54
|
+
'Returns `{ bill_account_id, currency_code, open_amount, overdue_amount, overdue_count, ' +
|
|
55
|
+
'credit_amount }` over posted / partially paid invoices and debit memos (test runs excluded). ' +
|
|
56
|
+
'Overdue = past due date with outstanding > 0. `credit_amount` = unallocated payments + open credit memos. ' +
|
|
57
|
+
'Spec F (account workspace) adds `billing_mode`, `bill_cycle`, `next_bill_date`, `last_invoice` ' +
|
|
58
|
+
'(`{ id, number, issue_date, total_gross }` or null) and, for prepaid accounts, `prepaid { balance, ' +
|
|
59
|
+
'balance_status, credit_limit, last_statement }` (null for postpaid).',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}
|
|
@@ -2,7 +2,13 @@ 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 type { EntityManager } from '@mikro-orm/postgresql'
|
|
6
|
+
import type { AwilixContainer } from 'awilix'
|
|
5
7
|
import { BillingAccount } from '../../data/entities'
|
|
8
|
+
import { fetchAccountFinancials, fetchOverdueAccountIds, financialsOrZero } from '../../lib/accountFinancials'
|
|
9
|
+
|
|
10
|
+
/** A uuid no row has — narrows an `$in` filter to nothing. */
|
|
11
|
+
const NO_MATCH_ID = '00000000-0000-4000-8000-000000000000'
|
|
6
12
|
import { billingEntityIds } from '../../data/entityIds'
|
|
7
13
|
import {
|
|
8
14
|
billingAccountCreateSchema,
|
|
@@ -33,6 +39,7 @@ export const metadata = routeMetadata
|
|
|
33
39
|
const billingAccountListItemSchema = z.object({
|
|
34
40
|
id: z.string().uuid(),
|
|
35
41
|
customer_id: z.string(),
|
|
42
|
+
customer_kind: z.enum(['company', 'person']),
|
|
36
43
|
name: z.string(),
|
|
37
44
|
currency_code: z.string(),
|
|
38
45
|
bill_cycle: z.string(),
|
|
@@ -45,6 +52,11 @@ const billingAccountListItemSchema = z.object({
|
|
|
45
52
|
last_bill_date: z.string().nullable(),
|
|
46
53
|
billing_mode: z.string(),
|
|
47
54
|
credit_limit: z.string(),
|
|
55
|
+
payment_terms_days: z.number().int().nullable(),
|
|
56
|
+
auto_send_invoice: z.boolean(),
|
|
57
|
+
/** Spec F (F8): Σ outstanding of open receivables and its overdue subset (batched per page). */
|
|
58
|
+
balance_due: z.string(),
|
|
59
|
+
overdue_amount: z.string(),
|
|
48
60
|
is_active: z.boolean(),
|
|
49
61
|
organization_id: z.string().uuid(),
|
|
50
62
|
tenant_id: z.string().uuid(),
|
|
@@ -71,6 +83,7 @@ const crud = makeCrudRoute({
|
|
|
71
83
|
fields: [
|
|
72
84
|
'id',
|
|
73
85
|
'customer_id',
|
|
86
|
+
'customer_kind',
|
|
74
87
|
'name',
|
|
75
88
|
'currency_code',
|
|
76
89
|
'bill_cycle',
|
|
@@ -83,6 +96,8 @@ const crud = makeCrudRoute({
|
|
|
83
96
|
'last_bill_date',
|
|
84
97
|
'billing_mode',
|
|
85
98
|
'credit_limit',
|
|
99
|
+
'payment_terms_days',
|
|
100
|
+
'auto_send_invoice',
|
|
86
101
|
'is_active',
|
|
87
102
|
'organization_id',
|
|
88
103
|
'tenant_id',
|
|
@@ -95,16 +110,28 @@ const crud = makeCrudRoute({
|
|
|
95
110
|
updatedAt: 'updated_at',
|
|
96
111
|
nextBillDate: 'next_bill_date',
|
|
97
112
|
},
|
|
98
|
-
buildFilters: async (query) => {
|
|
113
|
+
buildFilters: async (query, ctx) => {
|
|
99
114
|
const filters: Record<string, unknown> = {}
|
|
115
|
+
// Spec F (F8): accounts with an overdue receivable — one indexed
|
|
116
|
+
// DISTINCT over billing_invoices, intersected with any `id` filter.
|
|
117
|
+
if (query.hasOverdue === true && ctx.auth?.tenantId) {
|
|
118
|
+
const organizationIds = ctx.organizationIds ?? (ctx.selectedOrganizationId ? [ctx.selectedOrganizationId] : [])
|
|
119
|
+
const em = ctx.container.resolve<EntityManager>('em')
|
|
120
|
+
const overdueIds = await fetchOverdueAccountIds(em, { tenantId: ctx.auth.tenantId, organizationIds })
|
|
121
|
+
filters.id = { $in: overdueIds.length > 0 ? overdueIds : [NO_MATCH_ID] }
|
|
122
|
+
}
|
|
100
123
|
// `?id=<uuid>` narrows the list to one row — the detail page
|
|
101
124
|
// reads a single account through this filter.
|
|
102
125
|
if (typeof query.id === 'string' && query.id) {
|
|
103
|
-
filters.id
|
|
126
|
+
const current = filters.id as { $in?: string[] } | undefined
|
|
127
|
+
filters.id = current?.$in ? { $in: current.$in.includes(query.id) ? [query.id] : [NO_MATCH_ID] } : { $eq: query.id }
|
|
104
128
|
}
|
|
105
129
|
if (typeof query.customerId === 'string' && query.customerId) {
|
|
106
130
|
filters.customer_id = { $eq: query.customerId }
|
|
107
131
|
}
|
|
132
|
+
if (typeof query.customerKind === 'string' && query.customerKind) {
|
|
133
|
+
filters.customer_kind = { $eq: query.customerKind }
|
|
134
|
+
}
|
|
108
135
|
if (typeof query.currencyCode === 'string' && query.currencyCode) {
|
|
109
136
|
filters.currency_code = { $eq: query.currencyCode.toUpperCase() }
|
|
110
137
|
}
|
|
@@ -124,6 +151,30 @@ const crud = makeCrudRoute({
|
|
|
124
151
|
return filters
|
|
125
152
|
},
|
|
126
153
|
},
|
|
154
|
+
hooks: {
|
|
155
|
+
// Spec F (F8): balance due / overdue per row — one GROUP BY for the page.
|
|
156
|
+
afterList: async (payload: unknown, ctx: unknown) => {
|
|
157
|
+
const items = ((payload as { items?: unknown[] } | null)?.items ?? []) as Array<Record<string, unknown>>
|
|
158
|
+
if (items.length === 0) return
|
|
159
|
+
const first = items[0]
|
|
160
|
+
const tenantId = typeof first.tenant_id === 'string' ? first.tenant_id : null
|
|
161
|
+
const organizationId = typeof first.organization_id === 'string' ? first.organization_id : null
|
|
162
|
+
const ids = items.map((row) => row.id).filter((id): id is string => typeof id === 'string')
|
|
163
|
+
const financials =
|
|
164
|
+
tenantId && organizationId
|
|
165
|
+
? await fetchAccountFinancials(
|
|
166
|
+
(ctx as { container: AwilixContainer }).container.resolve<EntityManager>('em'),
|
|
167
|
+
{ tenantId, organizationId },
|
|
168
|
+
ids,
|
|
169
|
+
)
|
|
170
|
+
: new Map()
|
|
171
|
+
for (const row of items) {
|
|
172
|
+
const values = financialsOrZero(financials, String(row.id))
|
|
173
|
+
row.balance_due = values.balance_due
|
|
174
|
+
row.overdue_amount = values.overdue_amount
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
},
|
|
127
178
|
actions: {
|
|
128
179
|
create: {
|
|
129
180
|
commandId: 'billing.accounts.create',
|
|
@@ -190,12 +241,15 @@ export const openApi = createBillingCrudOpenApi({
|
|
|
190
241
|
create: {
|
|
191
242
|
schema: billingAccountCreateSchema,
|
|
192
243
|
responseSchema: defaultCreateResponseSchema,
|
|
193
|
-
description:
|
|
244
|
+
description:
|
|
245
|
+
'Creates a new billing account for a customer — a company or a person (`customerKind`, default `company`). ' +
|
|
246
|
+
'`invoiceLanguage` must be a language supported by the invoice template (`en`, `pl`; default `en`).',
|
|
194
247
|
},
|
|
195
248
|
update: {
|
|
196
249
|
schema: billingAccountUpdateSchema,
|
|
197
250
|
responseSchema: defaultOkResponseSchema,
|
|
198
|
-
description:
|
|
251
|
+
description:
|
|
252
|
+
'Updates a billing account. `currencyCode`, `customerId` and `customerKind` are immutable.',
|
|
199
253
|
},
|
|
200
254
|
del: {
|
|
201
255
|
schema: z.object({ id: z.string().uuid() }),
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
BillingItem,
|
|
11
11
|
BillingStatement,
|
|
12
12
|
BillingTopup,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
BillingRunOutcome,
|
|
14
|
+
BillingDraftInvoiceEdit,
|
|
15
15
|
} from '../../../../data/entities'
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -22,10 +22,9 @@ import {
|
|
|
22
22
|
* - The account row itself.
|
|
23
23
|
* - Every active + soft-deleted `BillingItem` for the account.
|
|
24
24
|
* - Every `BillingAccountUsage` record.
|
|
25
|
-
* - Every `
|
|
26
|
-
* - Every `
|
|
27
|
-
*
|
|
28
|
-
* - Every `DraftInvoiceEdit` audit row for those invoices.
|
|
25
|
+
* - Every `BillingRunOutcome` row referencing the account.
|
|
26
|
+
* - Every billing document (`billing_invoices`) of the account.
|
|
27
|
+
* - Every `BillingDraftInvoiceEdit` audit row for those invoices.
|
|
29
28
|
*
|
|
30
29
|
* Scope: the caller's auth tenant/organization is the authority — a
|
|
31
30
|
* 404 is returned even for valid UUIDs that belong to a different
|
|
@@ -108,7 +107,7 @@ export async function GET(
|
|
|
108
107
|
{ limit: EXPORT_HARD_LIMIT, orderBy: { periodEnd: 'DESC' } },
|
|
109
108
|
),
|
|
110
109
|
em.find(
|
|
111
|
-
|
|
110
|
+
BillingRunOutcome,
|
|
112
111
|
{
|
|
113
112
|
tenantId,
|
|
114
113
|
organizationId,
|
|
@@ -154,18 +153,18 @@ export async function GET(
|
|
|
154
153
|
),
|
|
155
154
|
])
|
|
156
155
|
|
|
157
|
-
//
|
|
158
|
-
// predicate keeps non-billing core/sales invoices out.
|
|
156
|
+
// Billing documents created in the window (Spec 0: billing_invoices).
|
|
159
157
|
const invoiceRows = (await em.execute(
|
|
160
|
-
`SELECT id,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
158
|
+
`SELECT id, number, document_type, series, status, test_run, bill_run_id, bill_date,
|
|
159
|
+
period_start, period_end, issue_date, due_date, posted_at, currency_code,
|
|
160
|
+
subtotal_net, tax_total, total_gross, paid_total, credited_total, outstanding,
|
|
161
|
+
corrects_invoice_id, correction_reason, topup_id, buyer_snapshot, seller_snapshot,
|
|
162
|
+
metadata, created_at, updated_at
|
|
163
|
+
FROM billing_invoices
|
|
165
164
|
WHERE tenant_id = ?
|
|
166
165
|
AND organization_id = ?
|
|
167
166
|
AND deleted_at IS NULL
|
|
168
|
-
AND
|
|
167
|
+
AND bill_account_id = ?
|
|
169
168
|
AND created_at >= ?
|
|
170
169
|
AND created_at <= ?
|
|
171
170
|
ORDER BY created_at DESC
|
|
@@ -177,7 +176,7 @@ export async function GET(
|
|
|
177
176
|
const draftEdits =
|
|
178
177
|
invoiceIds.length > 0
|
|
179
178
|
? await em.find(
|
|
180
|
-
|
|
179
|
+
BillingDraftInvoiceEdit,
|
|
181
180
|
{
|
|
182
181
|
tenantId,
|
|
183
182
|
organizationId,
|
|
@@ -190,7 +189,10 @@ export async function GET(
|
|
|
190
189
|
return NextResponse.json({
|
|
191
190
|
exportedAt: new Date().toISOString(),
|
|
192
191
|
// v2 adds prepaid balance / transactions / top-ups / statements (SPEC-002).
|
|
193
|
-
|
|
192
|
+
// v3 (Spec 0): invoices come from billing_invoices with billing field names.
|
|
193
|
+
// v4 (Spec B): items carry taxRate; the account carries paymentTermsDays /
|
|
194
|
+
// autoSendInvoice; invoice metadata may carry draft_number / deliveries.
|
|
195
|
+
schemaVersion: 4,
|
|
194
196
|
tenantId,
|
|
195
197
|
organizationId,
|
|
196
198
|
window: {
|
|
@@ -272,7 +274,7 @@ export const openApi = {
|
|
|
272
274
|
},
|
|
273
275
|
],
|
|
274
276
|
description:
|
|
275
|
-
"Returns a JSON dump of a single Billing Account: the account itself, every Billing Item (no time cap — items often outlive a single export window), and the Usage records / BillRunOutcomes / emitted core/sales invoices /
|
|
277
|
+
"Returns a JSON dump of a single Billing Account: the account itself, every Billing Item (no time cap — items often outlive a single export window), and the Usage records / BillRunOutcomes / emitted core/sales invoices / BillingDraftInvoiceEdit rows whose timestamps fall in the [since, until] window (defaults to the last 12 months). Each collection is independently capped by EXPORT_HARD_LIMIT = 50,000 rows. Lifetime dumps for outlier accounts need a follow-up chunked background-job approach — out of scope for this v1 endpoint.",
|
|
276
278
|
},
|
|
277
279
|
},
|
|
278
280
|
}
|