Invoicing
I korthet
Invoicing turns every chargeable event into a numbered, multi-language, multi-issuer Invoice with per-line VAT, branded PDF templates, automatic generation on licence renewal and club affiliation, ECB reference rate captured at issue time, sequenced credit notes, status-history timeline, configurable reminder cadence, integrated debt-collection escalation and outstanding-balance enforcement that blocks club transfer and licence renewal until the debt clears.
Så fungerar det
Invoices are first-class documents in /invoices/ with line items carrying individual tax_rate and tax_amount fields; the Invoice rolls these up into subtotal, tax_total and total. Two automatic generators run on business events: /invoices/auto-generate/license-renewal accepts a list of fee_components (name, amount, recipient type), pulls the default InvoiceTemplate, applies its tax_rate and payment terms and assigns a sequenced number per season, while /invoices/auto-generate/affiliation issues a single-line invoice for club affiliation. Branding lives in the tenant-scoped InvoiceTemplate collection — logo, primary and secondary colour, header and footer text in i18n, issuer identity (name, address, organisation number, VAT number) and payment instructions; exactly one default template per tenant is enforced.
Multi-issuer invoicing distinguishes platform-issued, tenant-issued and OrgNode-issued invoices via Invoice.issuer_type plus issuer_tenant_id and issuer_org_node_id, enabling cross-tenant invoices such as FIPJP billing a national federation; validators enforce consistency and a backfill script tagged historical invoices as platform-issued. Multi-language PDFs render from templates/invoice/{template_name}/{lang}.html with English fallback and a structlog warning when a translation is missing; platform invoices are locked to English. The ECB reference rate captured at issue time travels with the Invoice for cross-currency audit.
PDF delivery runs through GET /invoices/{id}/pdf for download and POST /invoices/{id}/deliver for emailed delivery, which marks the Invoice delivered and emits INVOICE_DELIVERED notifications. Credit notes are modelled as their own CreditNote documents with line references back to the original Invoice, sequenced as CN-YYYY-NNNNNN per tenant, and progress through draft -> issued -> applied -> voided; the credit amount cannot exceed the remaining invoice balance. Status changes append to status_history with from_status, to_status, changed_by and reason; POST /invoices/mark-overdue is a cron-friendly batch that flips due-date-passed invoices to overdue.
Reminder cadence is configured per tenant via ReminderConfig (max_reminders 1-10, grace_period_days 0-90, schedule of days_after_due offsets, escalate_to_collection_after); /invoices/send-due-reminders runs the entire cycle and /invoices/reminder-queue previews the next batch. Outstanding sent / overdue / partially_paid invoices block club transfer (PL-301) and licence renewal through /debts/check/{debtor_id}.
Centrala funktioner
- Per-line VAT with subtotal, tax_total and total roll-up on every Invoice
- Auto-generation for licence renewal and club affiliation reusing default InvoiceTemplate
- Multi-issuer invoicing covering platform, tenant and OrgNode issuers, including cross-tenant FIPJP billing
- Multi-language PDF rendering with English fallback and ECB reference rate captured per invoice
- Credit notes with sequenced numbering per tenant per year and draft -> issued -> applied -> voided lifecycle
- Configurable reminder cadence with preview queue and automatic escalation to debt collection
- Outstanding-debt check that blocks club transfer and licence renewal at the API boundary
I praktiken
A Swedish district treasurer approves 120 senior licence renewals. The platform auto-generates 120 invoices, each with a 25 percent MOMS line, a sequenced number FAKTURA-2026-001234 onwards, and a delivery email in Swedish using the district's branded template. Three weeks later 14 invoices remain unpaid; the nightly cron flips them to overdue, /invoices/send-due-reminders dispatches a first reminder per ReminderConfig, and seven days later a second.
After the configured escalate_to_collection_after threshold, a DebtCollectionCase opens for the four still-unpaid players. When one of them later attempts to renew their licence, /debts/check/{debtor_id} returns blocked and the renewal endpoint refuses until the credit note or payment clears the balance.
Features i detta subsystem
10| ID | Status | Funktioner |
|---|---|---|
| F08.03.01 | Levererad | Invoice generation (line items, tax, totals) ✅ PL-F0803a |
| F08.03.02 | Levererad | Automatic invoice generation (license renewal, affiliation) ✅ PL-F0803a |
| F08.03.03 | Levererad | Invoice templates per federation ✅ PL-F0803a |
| F08.03.04 | Levererad | Invoice delivery (email, download) ✅ PL-F0803a |
| F08.03.05 | Planerad | ✅ Credit note management |
| F08.03.06 | Levererad | ✅ Invoice status tracking (draft, sent, paid, overdue) |
| F08.03.07 | Planerad | ✅ Payment reminder automation |
| F08.03.08 | Levererad | ✅ Debt collection workflow — involuntary dunning lifecycle: banner → 6 months read-only → +12 months data deletion ✅ PL-T047 |
| F08.03.09 | Levererad | Multi-issuer invoicing — Invoice.issuer_type ∈ {platform, tenant, org_node} + issuer_tenant_id/issuer_org_node_id separerar utställare från gäldenär; cross-tenant-fakturor möjliga (FIPJP → nationsförbund); validatorer enforcerar konsistens; backfill-skript sätter historiska fakturor till platform-utställda. ✅ PL-T091 |
| F08.03.10 | Levererad | Multi-language invoicing + ECB reference rate — Invoice.language (ISO-639-1) + per-språk PDF-templates (templates/invoice/{template_name}/{lang}.html) med en.html-fallback + structlog-warning; plattformsfakturor låsta till engelska; ECB-referenskurs fångad per faktura vid utfärdande (ecb_reference_rate + ecb_reference_date) för audit-spårbarhet i cross-currency-scenarier. ✅ PL-T091 |
Intressenter som behöver detta subsystem
Förekommer i 1 intressentanalyser