Skip to main content
Petanque Life

Invoicing

F08.03 10 features Platform+

At a glance

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.

How it works

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}.

Key capabilities

  • 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

In practice

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 in this subsystem

10
ID Status Features
F08.03.01 Shipped Invoice generation (line items, tax, totals) ✅ PL-F0803a
F08.03.02 Shipped Automatic invoice generation (license renewal, affiliation) ✅ PL-F0803a
F08.03.03 Shipped Invoice templates per federation ✅ PL-F0803a
F08.03.04 Shipped Invoice delivery (email, download) ✅ PL-F0803a
F08.03.05 Planned ✅ Credit note management
F08.03.06 Shipped ✅ Invoice status tracking (draft, sent, paid, overdue)
F08.03.07 Planned ✅ Payment reminder automation
F08.03.08 Shipped ✅ Debt collection workflow — involuntary dunning lifecycle: banner → 6 months read-only → +12 months data deletion ✅ PL-T047
F08.03.09 Shipped 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 Shipped 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

Stakeholders who need this subsystem

Surfaces in 1 stakeholder analyses