Waarom ClientInvoice los staat van Invoice
Twee facturen-tabellen die op elkaar lijken maar niet zijn — de architectuur-keuze onder de financiële module.
Twee soorten facturen die niks met elkaar te maken hebben
De bureau-abonnementsfactuur die Senly naar het bureau stuurt is een Invoice. De factuur die het bureau naar zíjn klant stuurt via de financiële module is een ClientInvoice. Ze lijken op elkaar (bedrag, btw, PDF, betaal-link) maar ze hebben andere afzenders, andere ontvangers, andere btw-regimes en volledig andere administraties.
Waarom niet één tabel met een discriminator-veld
Een klassieke reactie is: één Invoice-tabel met een type-kolom ('own' of 'client'). Klinkt DRY, maar leidt tot een groeiende reeks null-velden per rij (klant-referentie is null voor eigen facturen, licentie-referentie is null voor klant-facturen) en tot fragiele queries die ergens een WHERE type='own' vergaten. Twee schone tabellen, twee helder gescheiden domeinen.
Wat dat wél deelt: PDF-renderer en betaal-link-generator
De layout-engine die de PDF genereert leest een neutrale invoice-shape (regels, klant, totaal, btw). Beide tabellen mappen zich naar die shape via een korte adapter. Zo blijft de renderer één stuk code dat op twee inputs draait, in plaats van twee die uit sync raken. Same voor de Mollie-/Stripe-/QR-generator: één betaal-link-service die weet niet welk type factuur eronder ligt.
Een ander gevolg: white-label mail voor ClientInvoice
Omdat ClientInvoice namens het bureau verstuurd wordt, mag Senly er niet in de header van staan. sendFromHostAccount stuurt via de mailbox van het bureau (Gmail, Outlook, IMAP) met bureau-branding. Voor Invoice — Senly aan bureau — mag 'invoices@senly.io' er wél op staan. Dezelfde mail-helper, tegenovergestelde standaardconfiguraties: de tabel bepaalt wie er "verstuurt".