Invoicing¶
Generates invoices from premium data: creating invoice records, rendering PDFs, and submitting e-invoices via Storecove.
Temporary location
This module lives in shared/ until a global billing component is created. Once the architecture is settled, it will move to a dedicated component.
This module is responsible for:
- creating
Invoicerecords from uninvoiced premium entries or flat amounts - rendering PDFs using a multi-country, multi-language template engine
- submitting e-invoices to Storecove for company contracts
- producing CSV appendices detailing per-employee premium breakdowns
Domain concepts¶
Billing reasons¶
Each invoice is created with a BillingReason that describes why it was issued:
regularβ issued as part of the billing schedule; amounts are derived from uninvoiced premiums; only one per billing periodcorrectiveβ issued outside the billing schedule for any form of correction; amounts can be derived from uninvoiced premiums or set explicitly; no limit per periodadvanceβ a flat-amount invoice used to collect a payment upfront, typically when the solvency of the customer is in question or to apply late-fee penalties; no limit per periodprevoyance_overpayment_recoveryβ a flat-amount invoice to recover overpayments on prΓ©voyance contracts (currently only used in France)
Both member (individual policyholder) and company (B2B) invoices are supported, with separate layouts and breakdowns.
Invoice lifecycle¶
Invoicing sits downstream of the premium computation.
Premiums are computed by the premium component and stored as PremiumComponent records, each starting without an invoice_id.
When invoicing a contract for a period:
- Uninvoiced
PremiumComponentrecords are fetched for the contract and period. - An
Invoiceobject is created, capturing the amount breakdown, issue date, due date, and payment terms. - The caller persists the invoice, then marks the matching premium components as invoiced via
PremiumService.mark_premium_entries_as_invoiced(). - A PDF is generated from the invoice object; an e-invoice is submitted to Storecove for companies if they are registered on Peppol.
Key entities¶
| Entity | Purpose |
|---|---|
Invoice |
Immutable invoice record: period, contract, billing reason, payment terms, amount breakdown |
PaymentTerms |
Issue date, due date, optional installment schedule, payment method (SEPA / virtual IBAN) |
BillingSubscription |
Wraps a contract identifier and customer type (individual / company) |
InvoicePremiumBreakdown |
Aggregated view of premiums: current period, regularisations, anterior balance |
FlatAmount |
A fixed amount with optional description, used for advance and corrective invoices |
Invoice sections and lines¶
Invoices are structured as sections, each containing lines. The section and line types differ by invoice audience:
- Member invoices use
LineWithUnitPriceβ each line shows quantity Γ unit price = total - Company invoices use
LineWithAmountBreakdownβ each line shows the premium amount and tax separately - An
InstallmentScheduleSectioncan be appended when payment is split over several due dates
When the invoice total is negative, the template switches to credit note mode, adjusting payment instructions and FAQ copy accordingly.
Template engine¶
Architecture¶
The template engine uses inheritance to isolate per-product overrides from shared behaviour.
BreathableTemplate (templates/breathable/base.py) is the base class.
It provides the full rendering pipeline β a coverage page, a fee breakdown page, and a FAQ page β and exposes methods that subclasses override to produce their specific section layout, FAQ items, and translations.
Three subclasses cover the supported products:
| Subclass | File | Audience |
|---|---|---|
BreathableTemplateForMemberPolicy |
templates/breathable/member_policy.py |
Individual members |
BreathableTemplateForCompanyContract |
templates/breathable/company_contract.py |
Company health contracts |
BreathableTemplateForOccupationalHealth |
templates/breathable/occupational_health.py |
Occupational health (France) β extends company contract |
E-invoice generation lives under templates/e_invoice/ and is independent of the PDF pipeline.
When to customise¶
The best advice: do not customise the template.
It can be tempting to go deep on tailoring: copy, colours, mascots, FAQ, etc. It's satisfying work. But in our experience, we hit diminishing returns pretty fast. Once you nail the general look and feel, what matters most is clarity. You do not gain much by customising further. Each customisation option combines with the previous options, and at the time of writing we already have hundreds of combinations of layout, language, and copy. The more you add to the mix, the harder it is to predict how each change affects all combinations, and the harder it is to test.
We strongly recommend building the minimum needed on top of the existing base, and limiting yourself to changes required for compliance.
Mandatory steps when launching a new product¶
Translations¶
- Any copy we introduce must be translated to all available languages.
- When a new language is introduced, all existing copy must be translated.
- Copy must match the Alan tone in all languages.
- Use the translation requests β§ Slack channel.
Legal mentions¶
Legal mentions and invoicer details must always be accurate.
- Invoicer details depend on which Alan entity is issuing the invoice β this can vary per country and per product.
- Legal mentions depend on the country we are doing business in: we aim to comply with local law.
- Mentions appear in the footer and in the unpaid warning.
- Always make sure the content is aligned with your specific region's requirements. Ping Legal for it.