@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
|
@@ -1,175 +1,5 @@
|
|
|
1
1
|
import { features as billingAclFeatures } from "./acl.js";
|
|
2
|
-
import {
|
|
3
|
-
Dictionary,
|
|
4
|
-
DictionaryEntry
|
|
5
|
-
} from "@open-mercato/core/modules/dictionaries/data/entities";
|
|
6
|
-
import { ModuleConfig } from "@open-mercato/core/modules/configs/data/entities";
|
|
7
|
-
const BILLING_UOM_DICTIONARY_KEY = "billing.uom";
|
|
8
|
-
const SALES_INVOICE_STATUS_DICTIONARY_KEY = "sales.invoice_status";
|
|
9
|
-
const BILLING_UOM_CODES = [
|
|
10
|
-
// time
|
|
11
|
-
{ value: "hour", label: "Hour" },
|
|
12
|
-
{ value: "day", label: "Day" },
|
|
13
|
-
{ value: "week", label: "Week" },
|
|
14
|
-
{ value: "month", label: "Month" },
|
|
15
|
-
// volume
|
|
16
|
-
{ value: "gb", label: "Gigabyte" },
|
|
17
|
-
{ value: "tb", label: "Terabyte" },
|
|
18
|
-
{ value: "mb", label: "Megabyte" },
|
|
19
|
-
// requests / tokens
|
|
20
|
-
{ value: "request", label: "Request" },
|
|
21
|
-
{ value: "api_request", label: "API Request" },
|
|
22
|
-
{ value: "token", label: "Token" },
|
|
23
|
-
{ value: "input_token", label: "Input Token" },
|
|
24
|
-
{ value: "output_token", label: "Output Token" },
|
|
25
|
-
// seats / devices
|
|
26
|
-
{ value: "seat", label: "Seat" },
|
|
27
|
-
{ value: "user", label: "User" },
|
|
28
|
-
{ value: "device", label: "Device" },
|
|
29
|
-
{ value: "active_user", label: "Active User" }
|
|
30
|
-
];
|
|
31
|
-
const INVOICE_STATUS_ENTRIES = [
|
|
32
|
-
// `posted` is the canonical "issued" state and is also the default a
|
|
33
|
-
// freshly created invoice transitions to — but billing creates drafts,
|
|
34
|
-
// so `draft` is the default DictionaryEntry for new rows.
|
|
35
|
-
{ value: "draft", label: "Draft", isDefault: true, color: "#9ca3af" },
|
|
36
|
-
{ value: "posted", label: "Posted", isDefault: false, color: "#2563eb" },
|
|
37
|
-
{ value: "paid", label: "Paid", isDefault: false, color: "#16a34a" },
|
|
38
|
-
{ value: "void", label: "Void", isDefault: false, color: "#dc2626" }
|
|
39
|
-
];
|
|
40
|
-
async function ensureDictionary(em, scope, params) {
|
|
41
|
-
const existing = await em.findOne(Dictionary, {
|
|
42
|
-
tenantId: scope.tenantId,
|
|
43
|
-
organizationId: scope.organizationId,
|
|
44
|
-
key: params.key,
|
|
45
|
-
deletedAt: null
|
|
46
|
-
});
|
|
47
|
-
if (existing) return existing;
|
|
48
|
-
const dictionary = em.create(Dictionary, {
|
|
49
|
-
tenantId: scope.tenantId,
|
|
50
|
-
organizationId: scope.organizationId,
|
|
51
|
-
key: params.key,
|
|
52
|
-
name: params.name,
|
|
53
|
-
description: params.description,
|
|
54
|
-
isSystem: true,
|
|
55
|
-
isActive: true,
|
|
56
|
-
managerVisibility: "hidden",
|
|
57
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
58
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
59
|
-
});
|
|
60
|
-
em.persist(dictionary);
|
|
61
|
-
await em.flush();
|
|
62
|
-
return dictionary;
|
|
63
|
-
}
|
|
64
|
-
async function ensureDictionaryEntries(em, scope, dictionary, entries) {
|
|
65
|
-
const existing = await em.find(DictionaryEntry, {
|
|
66
|
-
dictionary,
|
|
67
|
-
tenantId: scope.tenantId,
|
|
68
|
-
organizationId: scope.organizationId
|
|
69
|
-
});
|
|
70
|
-
const existingValues = new Set(existing.map((e) => e.value));
|
|
71
|
-
let position = existing.length;
|
|
72
|
-
for (const entry of entries) {
|
|
73
|
-
if (existingValues.has(entry.value)) continue;
|
|
74
|
-
em.persist(
|
|
75
|
-
em.create(DictionaryEntry, {
|
|
76
|
-
dictionary,
|
|
77
|
-
tenantId: scope.tenantId,
|
|
78
|
-
organizationId: scope.organizationId,
|
|
79
|
-
value: entry.value,
|
|
80
|
-
normalizedValue: entry.value.trim().toLowerCase(),
|
|
81
|
-
label: entry.label,
|
|
82
|
-
color: entry.color ?? null,
|
|
83
|
-
position,
|
|
84
|
-
isDefault: entry.isDefault ?? false,
|
|
85
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
86
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
87
|
-
})
|
|
88
|
-
);
|
|
89
|
-
position += 1;
|
|
90
|
-
}
|
|
91
|
-
await em.flush();
|
|
92
|
-
}
|
|
93
|
-
async function seedBillingUomDictionary(em, scope) {
|
|
94
|
-
const dict = await ensureDictionary(em, scope, {
|
|
95
|
-
key: BILLING_UOM_DICTIONARY_KEY,
|
|
96
|
-
name: "Billing units of measure",
|
|
97
|
-
description: "Units billing accepts on usage records (exact match \u2014 no conversion)."
|
|
98
|
-
});
|
|
99
|
-
await ensureDictionaryEntries(em, scope, dict, BILLING_UOM_CODES);
|
|
100
|
-
}
|
|
101
|
-
async function seedInvoiceStatusDictionary(em, scope) {
|
|
102
|
-
const dict = await ensureDictionary(em, scope, {
|
|
103
|
-
key: SALES_INVOICE_STATUS_DICTIONARY_KEY,
|
|
104
|
-
name: "Sales invoice statuses",
|
|
105
|
-
description: "draft \u2192 posted \u2192 paid (or void). Drives the billing draft/post lifecycle."
|
|
106
|
-
});
|
|
107
|
-
await ensureDictionaryEntries(em, scope, dict, INVOICE_STATUS_ENTRIES);
|
|
108
|
-
}
|
|
109
|
-
async function ensureModuleConfig(em, params) {
|
|
110
|
-
const existing = await em.findOne(ModuleConfig, {
|
|
111
|
-
moduleId: params.moduleId,
|
|
112
|
-
name: params.name
|
|
113
|
-
});
|
|
114
|
-
if (existing) return;
|
|
115
|
-
em.persist(
|
|
116
|
-
em.create(ModuleConfig, {
|
|
117
|
-
moduleId: params.moduleId,
|
|
118
|
-
name: params.name,
|
|
119
|
-
valueJson: params.value,
|
|
120
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
121
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
122
|
-
})
|
|
123
|
-
);
|
|
124
|
-
await em.flush();
|
|
125
|
-
}
|
|
126
|
-
async function seedBillingConfigs(em) {
|
|
127
|
-
await ensureModuleConfig(em, {
|
|
128
|
-
moduleId: "billing",
|
|
129
|
-
name: "cron_schedule",
|
|
130
|
-
value: "0 2 * * *"
|
|
131
|
-
});
|
|
132
|
-
await ensureModuleConfig(em, {
|
|
133
|
-
moduleId: "billing",
|
|
134
|
-
name: "cron_enabled",
|
|
135
|
-
value: true
|
|
136
|
-
});
|
|
137
|
-
await ensureModuleConfig(em, {
|
|
138
|
-
moduleId: "billing",
|
|
139
|
-
name: "invoice_number.format",
|
|
140
|
-
value: "INV-{YYYY}-{0000001}"
|
|
141
|
-
});
|
|
142
|
-
await ensureModuleConfig(em, {
|
|
143
|
-
moduleId: "billing",
|
|
144
|
-
name: "invoice_number.reset_cycle",
|
|
145
|
-
value: "yearly"
|
|
146
|
-
});
|
|
147
|
-
await ensureModuleConfig(em, {
|
|
148
|
-
moduleId: "billing",
|
|
149
|
-
name: "prepaid.low_balance_threshold_default",
|
|
150
|
-
value: 0
|
|
151
|
-
});
|
|
152
|
-
await ensureModuleConfig(em, {
|
|
153
|
-
moduleId: "billing",
|
|
154
|
-
name: "prepaid.topup_provider",
|
|
155
|
-
value: "stripe"
|
|
156
|
-
});
|
|
157
|
-
await ensureModuleConfig(em, {
|
|
158
|
-
moduleId: "billing",
|
|
159
|
-
name: "prepaid.statement_enabled",
|
|
160
|
-
value: true
|
|
161
|
-
});
|
|
162
|
-
await ensureModuleConfig(em, {
|
|
163
|
-
moduleId: "billing",
|
|
164
|
-
name: "prepaid.topup_tax_rate",
|
|
165
|
-
value: 0
|
|
166
|
-
});
|
|
167
|
-
await ensureModuleConfig(em, {
|
|
168
|
-
moduleId: "billing",
|
|
169
|
-
name: "credit.near_limit_buffer_default",
|
|
170
|
-
value: 0
|
|
171
|
-
});
|
|
172
|
-
}
|
|
2
|
+
import { getBillingSettings } from "./lib/billingSettings.js";
|
|
173
3
|
const ALL_BILLING_FEATURES = billingAclFeatures.map((f) => f.id);
|
|
174
4
|
const setup = {
|
|
175
5
|
defaultRoleFeatures: {
|
|
@@ -191,26 +21,19 @@ const setup = {
|
|
|
191
21
|
"billing.balance.view",
|
|
192
22
|
"billing.credit.view",
|
|
193
23
|
"billing.topup.view",
|
|
194
|
-
"billing.statement.view"
|
|
24
|
+
"billing.statement.view",
|
|
25
|
+
"billing.settings.view",
|
|
26
|
+
"billing.payment.view"
|
|
195
27
|
],
|
|
196
28
|
// Narrow scope for external usage-ingestion API keys.
|
|
197
29
|
billing_usage_writer: ["billing.usage.ingest"]
|
|
198
30
|
},
|
|
199
31
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*/
|
|
203
|
-
async onTenantCreated({ em }) {
|
|
204
|
-
await seedBillingConfigs(em);
|
|
205
|
-
},
|
|
206
|
-
/**
|
|
207
|
-
* Reference data: dictionaries (UoM, invoice statuses). Always runs
|
|
208
|
-
* during `mercato init`. Idempotent — re-seed is safe.
|
|
32
|
+
* Reference data: the organization's billing settings row (Spec 0).
|
|
33
|
+
* Always runs during `mercato init`. Idempotent (race-safe upsert).
|
|
209
34
|
*/
|
|
210
35
|
async seedDefaults({ em, tenantId, organizationId }) {
|
|
211
|
-
|
|
212
|
-
await seedBillingUomDictionary(em, scope);
|
|
213
|
-
await seedInvoiceStatusDictionary(em, scope);
|
|
36
|
+
await getBillingSettings(em, { tenantId, organizationId });
|
|
214
37
|
}
|
|
215
38
|
};
|
|
216
39
|
var setup_default = setup;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/billing/setup.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { features as billingAclFeatures } from './acl'\nimport {\n Dictionary,\n DictionaryEntry,\n} from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { ModuleConfig } from '@open-mercato/core/modules/configs/data/entities'\n\n/**\n * Billing module setup \u2014 per-tenant defaults at module installation.\n *\n * Idempotency contract:\n * - All seed helpers below check for an existing row before inserting.\n * - Safe to re-run on every `mercato init` and on `auth sync-role-acls`.\n *\n * What this file seeds:\n * - `billing.uom` dictionary with 16 global codes (operators can add more).\n * - `sales.invoice_status` dictionary with `draft` / `posted` / `paid` /\n * `void` so the core/sales Invoice entity's dictionary-driven status\n * workflow has values to point at. (Core/sales does NOT seed these \u2014\n * billing owns them per Phase 0 validation.)\n * - `billing.cron_schedule` + `billing.cron_enabled` module configs.\n * - `billing.invoice_number.format` + `.reset_cycle` configs (per-tenant\n * defaults; the actual atomic numbering uses core/sales'\n * `SalesDocumentSequence` which is created by core/sales' own\n * `onTenantCreated`).\n *\n * Default role-feature grants:\n * - `admin` gets every `billing.*` feature.\n * - `billing_admin` is the day-to-day finance operator.\n * - `billing_finance_user` is read + dry-run (no posting / no real trigger).\n * - `billing_usage_writer` is the narrow scope for external system API keys.\n */\n\nconst BILLING_UOM_DICTIONARY_KEY = 'billing.uom'\nconst SALES_INVOICE_STATUS_DICTIONARY_KEY = 'sales.invoice_status'\n\nconst BILLING_UOM_CODES = [\n // time\n { value: 'hour', label: 'Hour' },\n { value: 'day', label: 'Day' },\n { value: 'week', label: 'Week' },\n { value: 'month', label: 'Month' },\n // volume\n { value: 'gb', label: 'Gigabyte' },\n { value: 'tb', label: 'Terabyte' },\n { value: 'mb', label: 'Megabyte' },\n // requests / tokens\n { value: 'request', label: 'Request' },\n { value: 'api_request', label: 'API Request' },\n { value: 'token', label: 'Token' },\n { value: 'input_token', label: 'Input Token' },\n { value: 'output_token', label: 'Output Token' },\n // seats / devices\n { value: 'seat', label: 'Seat' },\n { value: 'user', label: 'User' },\n { value: 'device', label: 'Device' },\n { value: 'active_user', label: 'Active User' },\n] as const\n\nconst INVOICE_STATUS_ENTRIES = [\n // `posted` is the canonical \"issued\" state and is also the default a\n // freshly created invoice transitions to \u2014 but billing creates drafts,\n // so `draft` is the default DictionaryEntry for new rows.\n { value: 'draft', label: 'Draft', isDefault: true, color: '#9ca3af' },\n { value: 'posted', label: 'Posted', isDefault: false, color: '#2563eb' },\n { value: 'paid', label: 'Paid', isDefault: false, color: '#16a34a' },\n { value: 'void', label: 'Void', isDefault: false, color: '#dc2626' },\n] as const\n\ntype SeedScope = { tenantId: string; organizationId: string }\n\nasync function ensureDictionary(\n em: EntityManager,\n scope: SeedScope,\n params: { key: string; name: string; description: string },\n): Promise<Dictionary> {\n const existing = await em.findOne(Dictionary, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n key: params.key,\n deletedAt: null,\n })\n if (existing) return existing\n const dictionary = em.create(Dictionary, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n key: params.key,\n name: params.name,\n description: params.description,\n isSystem: true,\n isActive: true,\n managerVisibility: 'hidden',\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(dictionary)\n await em.flush()\n return dictionary\n}\n\nasync function ensureDictionaryEntries(\n em: EntityManager,\n scope: SeedScope,\n dictionary: Dictionary,\n entries: ReadonlyArray<{\n value: string\n label: string\n isDefault?: boolean\n color?: string\n }>,\n): Promise<void> {\n const existing = await em.find(DictionaryEntry, {\n dictionary,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n const existingValues = new Set(existing.map((e) => e.value))\n let position = existing.length\n for (const entry of entries) {\n if (existingValues.has(entry.value)) continue\n em.persist(\n em.create(DictionaryEntry, {\n dictionary,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n value: entry.value,\n normalizedValue: entry.value.trim().toLowerCase(),\n label: entry.label,\n color: entry.color ?? null,\n position,\n isDefault: entry.isDefault ?? false,\n createdAt: new Date(),\n updatedAt: new Date(),\n }),\n )\n position += 1\n }\n await em.flush()\n}\n\nasync function seedBillingUomDictionary(em: EntityManager, scope: SeedScope): Promise<void> {\n const dict = await ensureDictionary(em, scope, {\n key: BILLING_UOM_DICTIONARY_KEY,\n name: 'Billing units of measure',\n description: 'Units billing accepts on usage records (exact match \u2014 no conversion).',\n })\n await ensureDictionaryEntries(em, scope, dict, BILLING_UOM_CODES)\n}\n\nasync function seedInvoiceStatusDictionary(em: EntityManager, scope: SeedScope): Promise<void> {\n const dict = await ensureDictionary(em, scope, {\n key: SALES_INVOICE_STATUS_DICTIONARY_KEY,\n name: 'Sales invoice statuses',\n description: 'draft \u2192 posted \u2192 paid (or void). Drives the billing draft/post lifecycle.',\n })\n await ensureDictionaryEntries(em, scope, dict, INVOICE_STATUS_ENTRIES)\n}\n\nasync function ensureModuleConfig(\n em: EntityManager,\n params: { moduleId: string; name: string; value: unknown },\n): Promise<void> {\n const existing = await em.findOne(ModuleConfig, {\n moduleId: params.moduleId,\n name: params.name,\n })\n if (existing) return\n em.persist(\n em.create(ModuleConfig, {\n moduleId: params.moduleId,\n name: params.name,\n valueJson: params.value as Record<string, unknown> | null,\n createdAt: new Date(),\n updatedAt: new Date(),\n }),\n )\n await em.flush()\n}\n\nasync function seedBillingConfigs(em: EntityManager): Promise<void> {\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'cron_schedule',\n value: '0 2 * * *',\n })\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'cron_enabled',\n value: true,\n })\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'invoice_number.format',\n value: 'INV-{YYYY}-{0000001}',\n })\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'invoice_number.reset_cycle',\n value: 'yearly',\n })\n\n // \u2500\u2500\u2500 Prepaid balance billing (SPEC-002) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Fallback low-balance threshold when a prepaid account leaves its own\n // `low_balance_threshold` null. 0 = off (status never flips to `low`\n // until an operator sets a per-account threshold).\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.low_balance_threshold_default',\n value: 0,\n })\n // Default gateway provider key for top-up sessions.\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.topup_provider',\n value: 'stripe',\n })\n // Master switch for period statements.\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.statement_enabled',\n value: true,\n })\n // VAT rate (percent) applied to top-up receipts. The top-up `amount` is\n // treated as GROSS (what the customer pays = what the balance is credited);\n // the core tax service computes net + VAT from this rate. 0 = no VAT until\n // an operator sets the jurisdiction's rate. (Deviation from xd-249, which\n // never resolves a rate \u2014 see CHANGELOG.)\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'prepaid.topup_tax_rate',\n value: 0,\n })\n // Fallback buffer for the `near_limit` credit status. 0 = warn only at the\n // limit itself.\n await ensureModuleConfig(em, {\n moduleId: 'billing',\n name: 'credit.near_limit_buffer_default',\n value: 0,\n })\n}\n\n// Derived from `acl.ts` so a new feature added there automatically lands\n// in every role that should get \"everything billing\" \u2014 no parallel list\n// to keep in sync.\nconst ALL_BILLING_FEATURES = billingAclFeatures.map((f) => f.id)\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n // Org admins get every billing feature \u2014 `billing.*` wildcard is matched\n // by the shared feature matcher (`hasFeature` is wildcard-aware).\n admin: ['billing.*'],\n\n // Day-to-day finance operator persona.\n billing_admin: [...ALL_BILLING_FEATURES],\n\n // Read-only + dry-run preview \u2014 auditor / finance-watcher persona.\n billing_finance_user: [\n 'billing.account.view',\n 'billing.item.view',\n 'billing.usage.view',\n 'billing.run.view',\n 'billing.run.dry_run',\n 'billing.invoice.view',\n // Prepaid read-only (SPEC-002): balances, transactions, top-ups,\n // statements, credit status \u2014 no adjust / no top-up initiation.\n 'billing.balance.view',\n 'billing.credit.view',\n 'billing.topup.view',\n 'billing.statement.view',\n ],\n\n // Narrow scope for external usage-ingestion API keys.\n billing_usage_writer: ['billing.usage.ingest'],\n },\n\n /**\n * Tenant init: per-tenant module configs (cron, invoice number defaults).\n * Runs inside `setupInitialTenant()`, always \u2014 no `--no-examples` gate.\n */\n async onTenantCreated({ em }) {\n await seedBillingConfigs(em)\n },\n\n /**\n * Reference data: dictionaries (UoM, invoice statuses). Always runs\n * during `mercato init`. Idempotent \u2014 re-seed is safe.\n */\n async seedDefaults({ em, tenantId, organizationId }) {\n const scope = { tenantId, organizationId }\n await seedBillingUomDictionary(em, scope)\n await seedInvoiceStatusDictionary(em, scope)\n },\n}\n\nexport default setup\n"],
|
|
5
|
-
"mappings": "AAEA,SAAS,YAAY,0BAA0B;AAC/C
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { features as billingAclFeatures } from './acl'\nimport { getBillingSettings } from './lib/billingSettings'\n\n/**\n * Billing module setup \u2014 per-tenant defaults at module installation.\n *\n * Idempotency contract:\n * - All seed helpers below check for an existing row before inserting.\n * - Safe to re-run on every `mercato init` and on `auth sync-role-acls`.\n *\n * What this file seeds (Spec 0 \u2014 no core `configs` / `dictionaries` /\n * `sales` rows any more):\n * - one `billing_settings` row per organization with the defaults\n * (prepaid defaults + number masks). `getBillingSettings` also creates\n * it lazily, so this is only a warm-up.\n *\n * Default role-feature grants:\n * - `admin` gets every `billing.*` feature.\n * - `billing_admin` is the day-to-day finance operator.\n * - `billing_finance_user` is read + dry-run (no posting / no real trigger).\n * - `billing_usage_writer` is the narrow scope for external system API keys.\n */\n\n// Derived from `acl.ts` so a new feature added there automatically lands\n// in every role that should get \"everything billing\" \u2014 no parallel list\n// to keep in sync.\nconst ALL_BILLING_FEATURES = billingAclFeatures.map((f) => f.id)\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n // Org admins get every billing feature \u2014 `billing.*` wildcard is matched\n // by the shared feature matcher (`hasFeature` is wildcard-aware).\n admin: ['billing.*'],\n\n // Day-to-day finance operator persona.\n billing_admin: [...ALL_BILLING_FEATURES],\n\n // Read-only + dry-run preview \u2014 auditor / finance-watcher persona.\n billing_finance_user: [\n 'billing.account.view',\n 'billing.item.view',\n 'billing.usage.view',\n 'billing.run.view',\n 'billing.run.dry_run',\n 'billing.invoice.view',\n // Prepaid read-only (SPEC-002): balances, transactions, top-ups,\n // statements, credit status \u2014 no adjust / no top-up initiation.\n 'billing.balance.view',\n 'billing.credit.view',\n 'billing.topup.view',\n 'billing.statement.view',\n 'billing.settings.view',\n 'billing.payment.view',\n ],\n\n // Narrow scope for external usage-ingestion API keys.\n billing_usage_writer: ['billing.usage.ingest'],\n },\n\n /**\n * Reference data: the organization's billing settings row (Spec 0).\n * Always runs during `mercato init`. Idempotent (race-safe upsert).\n */\n async seedDefaults({ em, tenantId, organizationId }) {\n await getBillingSettings(em as EntityManager, { tenantId, organizationId })\n },\n}\n\nexport default setup\n"],
|
|
5
|
+
"mappings": "AAEA,SAAS,YAAY,0BAA0B;AAC/C,SAAS,0BAA0B;AAyBnC,MAAM,uBAAuB,mBAAmB,IAAI,CAAC,MAAM,EAAE,EAAE;AAExD,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA;AAAA;AAAA,IAGnB,OAAO,CAAC,WAAW;AAAA;AAAA,IAGnB,eAAe,CAAC,GAAG,oBAAoB;AAAA;AAAA,IAGvC,sBAAsB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,sBAAsB,CAAC,sBAAsB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,EAAE,IAAI,UAAU,eAAe,GAAG;AACnD,UAAM,mBAAmB,IAAqB,EAAE,UAAU,eAAe,CAAC;AAAA,EAC5E;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
+
import { autoSendInvoice } from "./invoice-auto-send.js";
|
|
3
|
+
const metadata = {
|
|
4
|
+
event: "billing.credit_memo.posted",
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: "billing-credit-memo-auto-send"
|
|
7
|
+
};
|
|
8
|
+
async function handle(payload) {
|
|
9
|
+
const container = await createRequestContainer();
|
|
10
|
+
await autoSendInvoice(container.resolve("em").fork(), payload);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
handle as default,
|
|
14
|
+
metadata
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=credit-memo-auto-send.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/billing/subscribers/credit-memo-auto-send.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { autoSendInvoice } from './invoice-auto-send'\n\n/** Auto-send of posted credit memos for accounts with `auto_send_invoice` (Spec D, P-D9). */\nexport const metadata = {\n event: 'billing.credit_memo.posted',\n persistent: true,\n id: 'billing-credit-memo-auto-send',\n}\n\nexport default async function handle(payload: { invoiceId?: string; tenantId?: string; organizationId?: string }): Promise<void> {\n const container = await createRequestContainer()\n await autoSendInvoice((container.resolve('em') as EntityManager).fork(), payload)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAGzB,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,OAA8B,SAA4F;AAC/H,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,gBAAiB,UAAU,QAAQ,IAAI,EAAoB,KAAK,GAAG,OAAO;AAClF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { applyCreditForAccount } from "./invoice-apply-credit.js";
|
|
2
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
|
+
const metadata = {
|
|
4
|
+
event: "billing.debit_memo.posted",
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: "billing-debit-memo-apply-credit"
|
|
7
|
+
};
|
|
8
|
+
async function handle(payload) {
|
|
9
|
+
const container = await createRequestContainer();
|
|
10
|
+
await applyCreditForAccount(container.resolve("em").fork(), payload);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
handle as default,
|
|
14
|
+
metadata
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=debit-memo-apply-credit.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/billing/subscribers/debit-memo-apply-credit.ts"],
|
|
4
|
+
"sourcesContent": ["import { applyCreditForAccount, type PostedPayload } from './invoice-apply-credit'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\n\n/** Credit auto-apply when a debit memo is posted (Spec D, P-D6) \u2014 same handler as for invoices. */\nexport const metadata = {\n event: 'billing.debit_memo.posted',\n persistent: true,\n id: 'billing-debit-memo-apply-credit',\n}\n\nexport default async function handle(payload: PostedPayload): Promise<void> {\n const container = await createRequestContainer()\n await applyCreditForAccount((container.resolve('em') as EntityManager).fork(), payload)\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,6BAAiD;AAC1D,SAAS,8BAA8B;AAIhC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,OAA8B,SAAuC;AAC1E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,sBAAuB,UAAU,QAAQ,IAAI,EAAoB,KAAK,GAAG,OAAO;AACxF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
+
import { autoSendInvoice } from "./invoice-auto-send.js";
|
|
3
|
+
const metadata = {
|
|
4
|
+
event: "billing.debit_memo.posted",
|
|
5
|
+
persistent: true,
|
|
6
|
+
id: "billing-debit-memo-auto-send"
|
|
7
|
+
};
|
|
8
|
+
async function handle(payload) {
|
|
9
|
+
const container = await createRequestContainer();
|
|
10
|
+
await autoSendInvoice(container.resolve("em").fork(), payload);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
handle as default,
|
|
14
|
+
metadata
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=debit-memo-auto-send.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/billing/subscribers/debit-memo-auto-send.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { autoSendInvoice } from './invoice-auto-send'\n\n/** Auto-send of posted debit memos for accounts with `auto_send_invoice` (Spec D, P-D9). */\nexport const metadata = {\n event: 'billing.debit_memo.posted',\n persistent: true,\n id: 'billing-debit-memo-auto-send',\n}\n\nexport default async function handle(payload: { invoiceId?: string; tenantId?: string; organizationId?: string }): Promise<void> {\n const container = await createRequestContainer()\n await autoSendInvoice((container.resolve('em') as EntityManager).fork(), payload)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAGzB,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,OAA8B,SAA4F;AAC/H,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,gBAAiB,UAAU,QAAQ,IAAI,EAAoB,KAAK,GAAG,OAAO;AAClF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
+
import { BillingAccount } from "../data/entities.js";
|
|
3
|
+
import { withAccountLock } from "../lib/accountLock.js";
|
|
4
|
+
import { applyAccountCredit } from "../lib/allocation.js";
|
|
5
|
+
import { emitAllocationEffects } from "../lib/allocationEvents.js";
|
|
6
|
+
const metadata = {
|
|
7
|
+
event: "billing.invoice.posted",
|
|
8
|
+
persistent: true,
|
|
9
|
+
id: "billing-invoice-apply-credit"
|
|
10
|
+
};
|
|
11
|
+
async function applyCreditForAccount(em, payload) {
|
|
12
|
+
if (!payload?.billAccountId || !payload.tenantId || !payload.organizationId) return 0;
|
|
13
|
+
const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId };
|
|
14
|
+
const account = await em.findOne(BillingAccount, { id: payload.billAccountId, ...scope });
|
|
15
|
+
if (!account || account.billingMode === "prepaid") return 0;
|
|
16
|
+
const effects = await withAccountLock(
|
|
17
|
+
em,
|
|
18
|
+
{ tenantId: scope.tenantId, billAccountId: account.id },
|
|
19
|
+
(tem) => applyAccountCredit(tem, scope, { id: account.id, currencyCode: account.currencyCode })
|
|
20
|
+
);
|
|
21
|
+
await emitAllocationEffects(scope, effects);
|
|
22
|
+
return effects.created.length;
|
|
23
|
+
}
|
|
24
|
+
async function handle(payload) {
|
|
25
|
+
const container = await createRequestContainer();
|
|
26
|
+
const em = container.resolve("em").fork();
|
|
27
|
+
await applyCreditForAccount(em, payload);
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
applyCreditForAccount,
|
|
31
|
+
handle as default,
|
|
32
|
+
metadata
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=invoice-apply-credit.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/billing/subscribers/invoice-apply-credit.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { BillingAccount } from '../data/entities'\nimport { withAccountLock } from '../lib/accountLock'\nimport { applyAccountCredit } from '../lib/allocation'\nimport { emitAllocationEffects } from '../lib/allocationEvents'\n\n/**\n * Credit auto-apply on post (Spec C, D12): when an invoice is posted, any\n * unapplied credit of its account (overpayments, unallocated payments,\n * open credit memos) is spent on the account's open receivables, oldest due\n * date first. Persistent and safe to re-run (it only spends what is left).\n */\n\nexport const metadata = {\n event: 'billing.invoice.posted',\n persistent: true,\n id: 'billing-invoice-apply-credit',\n}\n\nexport type PostedPayload = { billAccountId?: string; tenantId?: string; organizationId?: string }\n\nexport async function applyCreditForAccount(em: EntityManager, payload: PostedPayload): Promise<number> {\n if (!payload?.billAccountId || !payload.tenantId || !payload.organizationId) return 0\n const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const account = await em.findOne(BillingAccount, { id: payload.billAccountId, ...scope } as never)\n if (!account || account.billingMode === 'prepaid') return 0\n const effects = await withAccountLock(em, { tenantId: scope.tenantId, billAccountId: account.id }, (tem) =>\n applyAccountCredit(tem, scope, { id: account.id, currencyCode: account.currencyCode }),\n )\n await emitAllocationEffects(scope, effects)\n return effects.created.length\n}\n\nexport default async function handle(payload: PostedPayload): Promise<void> {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await applyCreditForAccount(em, payload)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AAS/B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAIA,eAAsB,sBAAsB,IAAmB,SAAyC;AACtG,MAAI,CAAC,SAAS,iBAAiB,CAAC,QAAQ,YAAY,CAAC,QAAQ,eAAgB,QAAO;AACpF,QAAM,QAAQ,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AACnF,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,eAAe,GAAG,MAAM,CAAU;AACjG,MAAI,CAAC,WAAW,QAAQ,gBAAgB,UAAW,QAAO;AAC1D,QAAM,UAAU,MAAM;AAAA,IAAgB;AAAA,IAAI,EAAE,UAAU,MAAM,UAAU,eAAe,QAAQ,GAAG;AAAA,IAAG,CAAC,QAClG,mBAAmB,KAAK,OAAO,EAAE,IAAI,QAAQ,IAAI,cAAc,QAAQ,aAAa,CAAC;AAAA,EACvF;AACA,QAAM,sBAAsB,OAAO,OAAO;AAC1C,SAAO,QAAQ,QAAQ;AACzB;AAEA,eAAO,OAA8B,SAAuC;AAC1E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,sBAAsB,IAAI,OAAO;AACzC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
+
import { BillingAccount, BillingInvoice } from "../data/entities.js";
|
|
3
|
+
import { hasSuccessfulDelivery, isDeliverableEmail, sendInvoice } from "../lib/invoiceDelivery.js";
|
|
4
|
+
const metadata = {
|
|
5
|
+
event: "billing.invoice.posted",
|
|
6
|
+
persistent: true,
|
|
7
|
+
id: "billing-invoice-auto-send"
|
|
8
|
+
};
|
|
9
|
+
async function autoSendInvoice(em, payload, deps = {}) {
|
|
10
|
+
if (!payload?.invoiceId || !payload.tenantId || !payload.organizationId) return "skipped";
|
|
11
|
+
const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId };
|
|
12
|
+
const invoice = await em.findOne(BillingInvoice, { id: payload.invoiceId, ...scope, deletedAt: null });
|
|
13
|
+
if (!invoice || invoice.testRun || invoice.status === "draft" || invoice.documentType === "receipt") return "skipped";
|
|
14
|
+
if (hasSuccessfulDelivery(invoice, "auto")) return "skipped";
|
|
15
|
+
const account = await em.findOne(BillingAccount, { id: invoice.billAccountId, ...scope });
|
|
16
|
+
if (!account?.autoSendInvoice || !isDeliverableEmail(account.invoiceEmail)) return "skipped";
|
|
17
|
+
const result = await sendInvoice(em, { invoiceId: invoice.id, ...scope, trigger: "auto" }, deps);
|
|
18
|
+
return result.status;
|
|
19
|
+
}
|
|
20
|
+
async function handle(payload) {
|
|
21
|
+
const container = await createRequestContainer();
|
|
22
|
+
const em = container.resolve("em").fork();
|
|
23
|
+
await autoSendInvoice(em, payload);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
autoSendInvoice,
|
|
27
|
+
handle as default,
|
|
28
|
+
metadata
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=invoice-auto-send.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/billing/subscribers/invoice-auto-send.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { BillingAccount, BillingInvoice } from '../data/entities'\nimport { hasSuccessfulDelivery, isDeliverableEmail, sendInvoice, type SendInvoiceDeps } from '../lib/invoiceDelivery'\n\n/**\n * Auto-send (Spec B): `billing.invoice.posted` \u2192 email the document when the\n * account has `auto_send_invoice` on.\n *\n * Persistent and idempotent: a redelivered event finds a `sent` auto\n * delivery in `metadata.deliveries` and does nothing. Receipts, test\n * documents and accounts with a placeholder / missing email are skipped\n * without a delivery entry (the operator can still send manually once the\n * address is fixed). A transport failure is recorded as a `failed`\n * delivery by `sendInvoice` and not retried automatically.\n */\n\nexport const metadata = {\n event: 'billing.invoice.posted',\n persistent: true,\n id: 'billing-invoice-auto-send',\n}\n\ntype PostedPayload = {\n invoiceId?: string\n tenantId?: string\n organizationId?: string\n}\n\nexport async function autoSendInvoice(em: EntityManager, payload: PostedPayload, deps: SendInvoiceDeps = {}): Promise<'sent' | 'failed' | 'skipped'> {\n if (!payload?.invoiceId || !payload.tenantId || !payload.organizationId) return 'skipped'\n const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const invoice = await em.findOne(BillingInvoice, { id: payload.invoiceId, ...scope, deletedAt: null } as never)\n if (!invoice || invoice.testRun || invoice.status === 'draft' || invoice.documentType === 'receipt') return 'skipped'\n if (hasSuccessfulDelivery(invoice, 'auto')) return 'skipped'\n const account = await em.findOne(BillingAccount, { id: invoice.billAccountId, ...scope } as never)\n if (!account?.autoSendInvoice || !isDeliverableEmail(account.invoiceEmail)) return 'skipped'\n const result = await sendInvoice(em, { invoiceId: invoice.id, ...scope, trigger: 'auto' }, deps)\n return result.status\n}\n\nexport default async function handle(payload: PostedPayload): Promise<void> {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await autoSendInvoice(em, payload)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,uBAAuB,oBAAoB,mBAAyC;AActF,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAQA,eAAsB,gBAAgB,IAAmB,SAAwB,OAAwB,CAAC,GAA2C;AACnJ,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,YAAY,CAAC,QAAQ,eAAgB,QAAO;AAChF,QAAM,QAAQ,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AACnF,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,WAAW,GAAG,OAAO,WAAW,KAAK,CAAU;AAC9G,MAAI,CAAC,WAAW,QAAQ,WAAW,QAAQ,WAAW,WAAW,QAAQ,iBAAiB,UAAW,QAAO;AAC5G,MAAI,sBAAsB,SAAS,MAAM,EAAG,QAAO;AACnD,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,eAAe,GAAG,MAAM,CAAU;AACjG,MAAI,CAAC,SAAS,mBAAmB,CAAC,mBAAmB,QAAQ,YAAY,EAAG,QAAO;AACnF,QAAM,SAAS,MAAM,YAAY,IAAI,EAAE,WAAW,QAAQ,IAAI,GAAG,OAAO,SAAS,OAAO,GAAG,IAAI;AAC/F,SAAO,OAAO;AAChB;AAEA,eAAO,OAA8B,SAAuC;AAC1E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,gBAAgB,IAAI,OAAO;AACnC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,47 +1,83 @@
|
|
|
1
1
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { BillingInvoice, BillingPayment } from "../data/entities.js";
|
|
3
|
+
import { withAccountLock } from "../lib/accountLock.js";
|
|
4
|
+
import { allocate, applyAccountCredit, emptyEffects, mergeEffects, toCents } from "../lib/allocation.js";
|
|
5
|
+
import { emitAllocationEffects } from "../lib/allocationEvents.js";
|
|
6
|
+
import { emitBillingEvent } from "../events.js";
|
|
4
7
|
const metadata = {
|
|
5
8
|
event: "payment_gateways.payment.captured",
|
|
6
9
|
persistent: true,
|
|
7
10
|
id: "billing-payment-captured-to-paid"
|
|
8
11
|
};
|
|
9
|
-
async function
|
|
10
|
-
if (!payload?.paymentId || !payload.tenantId || !payload.organizationId)
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
async function recordGatewayCapture(em, payload) {
|
|
13
|
+
if (!payload?.paymentId || !payload.tenantId || !payload.organizationId) return "skipped";
|
|
14
|
+
const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId };
|
|
15
|
+
const invoice = await em.findOne(BillingInvoice, { id: payload.paymentId, ...scope, deletedAt: null });
|
|
16
|
+
if (!invoice || invoice.testRun || !["invoice", "debit_memo"].includes(invoice.documentType)) return "skipped";
|
|
17
|
+
const externalRef = payload.transactionId ?? payload.paymentId;
|
|
18
|
+
const existing = await em.findOne(BillingPayment, { ...scope, externalRef });
|
|
19
|
+
if (existing) return "duplicate";
|
|
20
|
+
if (!["posted", "partially_paid"].includes(invoice.status)) return "skipped";
|
|
21
|
+
const captured = toCents(payload.amount ?? invoice.outstanding);
|
|
22
|
+
if (captured <= 0) return "skipped";
|
|
23
|
+
const amount = (captured / 100).toFixed(4);
|
|
24
|
+
const now = /* @__PURE__ */ new Date();
|
|
25
|
+
const payment = em.create(BillingPayment, {
|
|
26
|
+
...scope,
|
|
27
|
+
receivedAt: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())),
|
|
28
|
+
amount,
|
|
29
|
+
currencyCode: (payload.currencyCode ?? invoice.currencyCode).toUpperCase(),
|
|
30
|
+
reference: invoice.number,
|
|
31
|
+
source: "gateway",
|
|
32
|
+
billAccountId: invoice.billAccountId,
|
|
33
|
+
status: "matched",
|
|
34
|
+
unallocatedAmount: amount,
|
|
35
|
+
sourceRef: `gateway:${externalRef}`,
|
|
36
|
+
externalRef,
|
|
37
|
+
metadata: { provider_key: payload.providerKey ?? null },
|
|
38
|
+
createdAt: now,
|
|
39
|
+
updatedAt: now
|
|
20
40
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (invoice.status === "paid") {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
if (invoice.status !== "posted") {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const paidStatusEntryId = await resolveInvoiceStatusEntryId(
|
|
41
|
+
em.persist(payment);
|
|
42
|
+
await em.flush();
|
|
43
|
+
const effects = await withAccountLock(
|
|
31
44
|
em,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
{ tenantId: scope.tenantId, billAccountId: invoice.billAccountId },
|
|
46
|
+
async (tem) => {
|
|
47
|
+
const all = emptyEffects();
|
|
48
|
+
const take = Math.min(captured, toCents(invoice.outstanding));
|
|
49
|
+
if (take > 0 && payment.currencyCode === invoice.currencyCode) {
|
|
50
|
+
mergeEffects(
|
|
51
|
+
all,
|
|
52
|
+
await allocate(tem, scope, {
|
|
53
|
+
source: { type: "payment", id: payment.id },
|
|
54
|
+
invoiceId: invoice.id,
|
|
55
|
+
amountCents: take,
|
|
56
|
+
by: "gateway"
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
mergeEffects(
|
|
61
|
+
all,
|
|
62
|
+
await applyAccountCredit(tem, scope, { id: invoice.billAccountId, currencyCode: payment.currencyCode }, {
|
|
63
|
+
onlySources: [{ type: "payment", id: payment.id }]
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
return all;
|
|
67
|
+
}
|
|
35
68
|
);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
await
|
|
69
|
+
await emitBillingEvent("billing.payment.created", { ...scope, paymentId: payment.id, source: "gateway" });
|
|
70
|
+
await emitAllocationEffects(scope, effects);
|
|
71
|
+
return "recorded";
|
|
72
|
+
}
|
|
73
|
+
async function handle(payload) {
|
|
74
|
+
const container = await createRequestContainer();
|
|
75
|
+
const em = container.resolve("em").fork();
|
|
76
|
+
await recordGatewayCapture(em, payload);
|
|
42
77
|
}
|
|
43
78
|
export {
|
|
44
79
|
handle as default,
|
|
45
|
-
metadata
|
|
80
|
+
metadata,
|
|
81
|
+
recordGatewayCapture
|
|
46
82
|
};
|
|
47
83
|
//# sourceMappingURL=payment-captured-to-paid.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/billing/subscribers/payment-captured-to-paid.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport {
|
|
5
|
-
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,oBAAoB;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { BillingInvoice, BillingPayment } from '../data/entities'\nimport { withAccountLock } from '../lib/accountLock'\nimport { allocate, applyAccountCredit, emptyEffects, mergeEffects, toCents, type AllocationEffects } from '../lib/allocation'\nimport { emitAllocationEffects } from '../lib/allocationEvents'\nimport { emitBillingEvent } from '../events'\n\n/**\n * Subscriber: gateway payment captured \u2192 billing payment + allocation\n * (Spec C, P-D9 \u2014 the single code path to \"paid\").\n *\n * The payment session is created with `paymentId = invoice.id`, so the\n * captured event identifies the billing invoice. Instead of flipping the\n * invoice status, the capture becomes a `BillingPayment` (`source =\n * gateway`, `external_ref = transactionId ?? paymentId`) allocated to that\n * invoice through the allocation service; any remainder is account credit.\n *\n * Idempotent: a re-delivered event finds the payment by `external_ref` and\n * does nothing. Payments for anything that is not an open billing\n * receivable are ignored (other modules own them).\n */\n\nexport const metadata = {\n event: 'payment_gateways.payment.captured',\n persistent: true,\n id: 'billing-payment-captured-to-paid',\n}\n\nexport type CapturedPayload = {\n paymentId?: string\n transactionId?: string\n organizationId?: string\n tenantId?: string\n providerKey?: string\n amount?: number | string\n currencyCode?: string\n}\n\nexport async function recordGatewayCapture(\n em: EntityManager,\n payload: CapturedPayload,\n): Promise<'recorded' | 'duplicate' | 'skipped'> {\n if (!payload?.paymentId || !payload.tenantId || !payload.organizationId) return 'skipped'\n const scope = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const invoice = await em.findOne(BillingInvoice, { id: payload.paymentId, ...scope, deletedAt: null } as never)\n if (!invoice || invoice.testRun || !['invoice', 'debit_memo'].includes(invoice.documentType)) return 'skipped'\n const externalRef = payload.transactionId ?? payload.paymentId\n const existing = await em.findOne(BillingPayment, { ...scope, externalRef } as never)\n if (existing) return 'duplicate'\n if (!['posted', 'partially_paid'].includes(invoice.status)) return 'skipped'\n\n const captured = toCents(payload.amount ?? invoice.outstanding)\n if (captured <= 0) return 'skipped'\n const amount = (captured / 100).toFixed(4)\n const now = new Date()\n const payment = em.create(BillingPayment, {\n ...scope,\n receivedAt: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())),\n amount,\n currencyCode: (payload.currencyCode ?? invoice.currencyCode).toUpperCase(),\n reference: invoice.number,\n source: 'gateway',\n billAccountId: invoice.billAccountId,\n status: 'matched',\n unallocatedAmount: amount,\n sourceRef: `gateway:${externalRef}`,\n externalRef,\n metadata: { provider_key: payload.providerKey ?? null },\n createdAt: now,\n updatedAt: now,\n })\n em.persist(payment)\n await em.flush()\n\n const effects: AllocationEffects = await withAccountLock(\n em,\n { tenantId: scope.tenantId, billAccountId: invoice.billAccountId },\n async (tem) => {\n const all = emptyEffects()\n const take = Math.min(captured, toCents(invoice.outstanding))\n if (take > 0 && payment.currencyCode === invoice.currencyCode) {\n mergeEffects(\n all,\n await allocate(tem, scope, {\n source: { type: 'payment', id: payment.id },\n invoiceId: invoice.id,\n amountCents: take,\n by: 'gateway',\n }),\n )\n }\n mergeEffects(\n all,\n await applyAccountCredit(tem, scope, { id: invoice.billAccountId, currencyCode: payment.currencyCode }, {\n onlySources: [{ type: 'payment', id: payment.id }],\n }),\n )\n return all\n },\n )\n await emitBillingEvent('billing.payment.created', { ...scope, paymentId: payment.id, source: 'gateway' })\n await emitAllocationEffects(scope, effects)\n return 'recorded'\n}\n\nexport default async function handle(payload: CapturedPayload): Promise<void> {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n await recordGatewayCapture(em, payload)\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,uBAAuB;AAChC,SAAS,UAAU,oBAAoB,cAAc,cAAc,eAAuC;AAC1G,SAAS,6BAA6B;AACtC,SAAS,wBAAwB;AAiB1B,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAYA,eAAsB,qBACpB,IACA,SAC+C;AAC/C,MAAI,CAAC,SAAS,aAAa,CAAC,QAAQ,YAAY,CAAC,QAAQ,eAAgB,QAAO;AAChF,QAAM,QAAQ,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AACnF,QAAM,UAAU,MAAM,GAAG,QAAQ,gBAAgB,EAAE,IAAI,QAAQ,WAAW,GAAG,OAAO,WAAW,KAAK,CAAU;AAC9G,MAAI,CAAC,WAAW,QAAQ,WAAW,CAAC,CAAC,WAAW,YAAY,EAAE,SAAS,QAAQ,YAAY,EAAG,QAAO;AACrG,QAAM,cAAc,QAAQ,iBAAiB,QAAQ;AACrD,QAAM,WAAW,MAAM,GAAG,QAAQ,gBAAgB,EAAE,GAAG,OAAO,YAAY,CAAU;AACpF,MAAI,SAAU,QAAO;AACrB,MAAI,CAAC,CAAC,UAAU,gBAAgB,EAAE,SAAS,QAAQ,MAAM,EAAG,QAAO;AAEnE,QAAM,WAAW,QAAQ,QAAQ,UAAU,QAAQ,WAAW;AAC9D,MAAI,YAAY,EAAG,QAAO;AAC1B,QAAM,UAAU,WAAW,KAAK,QAAQ,CAAC;AACzC,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,UAAU,GAAG,OAAO,gBAAgB;AAAA,IACxC,GAAG;AAAA,IACH,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,GAAG,IAAI,WAAW,CAAC,CAAC;AAAA,IACxF;AAAA,IACA,eAAe,QAAQ,gBAAgB,QAAQ,cAAc,YAAY;AAAA,IACzE,WAAW,QAAQ;AAAA,IACnB,QAAQ;AAAA,IACR,eAAe,QAAQ;AAAA,IACvB,QAAQ;AAAA,IACR,mBAAmB;AAAA,IACnB,WAAW,WAAW,WAAW;AAAA,IACjC;AAAA,IACA,UAAU,EAAE,cAAc,QAAQ,eAAe,KAAK;AAAA,IACtD,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AACD,KAAG,QAAQ,OAAO;AAClB,QAAM,GAAG,MAAM;AAEf,QAAM,UAA6B,MAAM;AAAA,IACvC;AAAA,IACA,EAAE,UAAU,MAAM,UAAU,eAAe,QAAQ,cAAc;AAAA,IACjE,OAAO,QAAQ;AACb,YAAM,MAAM,aAAa;AACzB,YAAM,OAAO,KAAK,IAAI,UAAU,QAAQ,QAAQ,WAAW,CAAC;AAC5D,UAAI,OAAO,KAAK,QAAQ,iBAAiB,QAAQ,cAAc;AAC7D;AAAA,UACE;AAAA,UACA,MAAM,SAAS,KAAK,OAAO;AAAA,YACzB,QAAQ,EAAE,MAAM,WAAW,IAAI,QAAQ,GAAG;AAAA,YAC1C,WAAW,QAAQ;AAAA,YACnB,aAAa;AAAA,YACb,IAAI;AAAA,UACN,CAAC;AAAA,QACH;AAAA,MACF;AACA;AAAA,QACE;AAAA,QACA,MAAM,mBAAmB,KAAK,OAAO,EAAE,IAAI,QAAQ,eAAe,cAAc,QAAQ,aAAa,GAAG;AAAA,UACtG,aAAa,CAAC,EAAE,MAAM,WAAW,IAAI,QAAQ,GAAG,CAAC;AAAA,QACnD,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,iBAAiB,2BAA2B,EAAE,GAAG,OAAO,WAAW,QAAQ,IAAI,QAAQ,UAAU,CAAC;AACxG,QAAM,sBAAsB,OAAO,OAAO;AAC1C,SAAO;AACT;AAEA,eAAO,OAA8B,SAAyC;AAC5E,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,QAAM,qBAAqB,IAAI,OAAO;AACxC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -35,14 +35,12 @@ async function handle(payload) {
|
|
|
35
35
|
if (!account) {
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
-
const taxRate = await getTopupTaxRate(em
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
42
|
-
const taxService = container.resolve("taxCalculationService");
|
|
38
|
+
const taxRate = await getTopupTaxRate(em, {
|
|
39
|
+
tenantId: account.tenantId,
|
|
40
|
+
organizationId: account.organizationId
|
|
41
|
+
});
|
|
43
42
|
const result = await captureTopup(
|
|
44
43
|
em,
|
|
45
|
-
{ numberGenerator, taxService },
|
|
46
44
|
{
|
|
47
45
|
topup,
|
|
48
46
|
account: {
|