Image

Automatiseer en personaliseer uw facturatieproces

PDF facturen met Python

Tim
12-05-2022

Facturen worden in veel gevallen verstuurd als PDF, en hierbij is vaak vraag naar manieren om deze bestanden te personaliseren en het creëren ervan te automatiseren. Veel boekhoudprogramma’s bieden ingebouwde functionaliteiten om facturen te genereren en deze vervolgens als PDF’s naar klanten te sturen. Deze functionaliteit biedt vaak geringe flexibiliteit als het gaat om opmaak, op maat gemaakte informatieonderdelen en/of het versturen van de betreffende facturen. In deze post richten wij ons op het opmaken van de PDF door middel van Python (ReportLab) en de mogelijkheden tot personalisatie en automatisering die deze biedt.

De PDF-bestandsextensie is een van de meest gebruikte extensies. PDF staat voor portable document format en is de standaard voor documenten waarbij de complete opmaak hetzelfde dient te blijven onafhankelijk van het platform waarmee deze gemaakt wordt. Bij Zypp zijn wij groot fan van platformonafhankelijke toepassingen, daarmee is PDF geen uitzondering.

PDF’s bestaan al sinds de jaren negentig en zijn sindsdien voor tal van verschillende zaken gebruikt. Een van de meest bekende toepassingen is voor het maken van facturen. Waarom? Je wil als verstuurder van een factuur zeker zijn dat de ontvanger exact dezelfde informatie ontvangt zoals jij die ook verstuurd hebt, om zo misverstanden te voorkomen (Word documenten met Google Docs openen anyone?). Daarnaast is een factuur ook een contactmoment met je klant, het is dus belangrijk om hier ook een goede indruk achter te kunnen laten!

In deze blog wordt uiteengezet hoe deze goede indruk mogelijk gemaakt kan worden door het gebruik van Python. Eerst zullen de basis functionaliteiten worden beschreven om tot een bestand te kunnen komen. En daarna zal er een korte inkijk gegeven worden in de mogelijkheden om de opmaak aan te passen. Veel leesplezier!

Benodigdheden

Maak een factuur

Er wordt gestart met het opzetten van de basisfunctionaliteiten: het inladen van Python packages, initialiseren van de ReportLab class en het inladen van het bestand. Er zal niet overal in detail worden getreden van specifieke functies van de betreffende packages, hiervoor wordt verwezen naar de documentatie van de packages zelf (zie links hierboven).

Er zal een korte beschrijving van de onderdelen in de code worden gegeven, dan de code zelf en uiteindelijk hoe de PDF er uitziet als de code gedraaid wordt. Hierdoor kan je makkelijk controleren of er dezelfde PDF geproduceerd wordt zodra je hiermee gaat experimenteren.

Uitleg
  • Importeer de packages, hiervoor wordt in de basis gebruik gemaakt van pandas en een aantal reportlab modules.
  • Creëer een class die de basis ReportLab class BaseDocTemplate erft. In dit geval wordt de volledig PDF aangemaakt en gevuld bij initialisatie, in uitgebreidere projecten wil je dit definiëren in losse methodes.
    De grootte van de pagina's (A4) wordt aangegeven samen met de naam van de PDF die gemaakt gaat worden.
    Nadat de basisonderdelen van de PDF zijn gedefinieerd (Frame=vlak waarin de data terecht komt, PageTemplate=indeling van de pagina), wordt de Table aangemaakt om de data in te zetten.
  • Bij het runnen van het script wordt de data ingeladen, en wordt dit als input gebruikt om de PDF te maken. Hiervoor kunnen dus allerlei bronnen voor gebruikt worden, zolang ze in te lezen zijn met Python.

Code
pdf_simple
De code voor de simpele PDF (click-to-copy).
Uitkomst
Het resultaat van de simpele PDF.

Het is te zien dat hoofdzakelijk de data zonder layout op een specifieke plek van de A4 geplaatst is (zie de argumenten in de Frame method). Dit lijkt nog ver van een factuur, maar inmiddels is er wel een PDF gecreëerd door middel van Python (#winnen). Lees snel door om te kijken hoe hier meer structuur aan toegevoegd kan worden.

Indeling factuur aanpassen

De volgende stap om de PDF meer op een factuur te laten lijken is om verschillende onderdelen op een natuurlijke plek neer te zetten. Hierbij zullen er meer elementen worden toegevoegd ten opzichte van de versie hierboven. Er worden onder andere adresgegevens, datum, titels, factuurnummers en een footer toegevoegd.

Uitleg
De vorige codebase is uitgebreid met de volgende zaken als meest belangrijke elementen.
  • De locatie en grootte van het vlak met de data is aangepast. Het Frame element heeft nu de breedte van het document (self.width) en hierdoor is de x1=0 positie gelijk gekomen met de linkerkant van het document. Om nu de tabel een bepaalde afstand van de rand te printen wordt er een waarde groter dan 0 meegegeven voor het x1 argument (y1 idem dito).
  • Voor de pagina-indeling wordt nu een methode meegegeven aan het onPage argument. Hiermee kan er door middel van verschillende methodes (gegroepeerd in on_first_page()) verschillende elementen worden toegevoegd aan de PDF. In deze blog worden alleen PDF's met één pagina getoond, daarom dat de naam van de methode misschien overbodig lijkt. In het geval van meerdere pagina's wil je vaak een andere pagina-indeling op de 1e pagina ten opzichte van de rest, en heb je dus verschillende methodes om je pagina-elementen te groeperen.
    • add_default_info() wordt gebruikt om algemene informatie op de pagina te krijgen. In dit geval is dit alleen de footer die door middel van een nieuw Frame en de Paragraph methode wordt aangemaakt. Hier kan de tekst naar wens worden ingevuld, en worden uitgebreid met meerdere elementen aan de footer_list.
    • Verschillende methodes printen een specifieke string op een bepaalde positie. Hier kan jezelf ook extra elementen aan toevoegen, namen van methodes aanpassen of door middel van een iteratief proces meerdere facturen aanmaken (met bijvoorbeeld verschillende factuurnummers) door de string niet hard te coderen.
Code
pdf_structure
De code voor de PDF met structuur (click-to-copy).
Uitkomst
Het resultaat van de PDF met structuur.

Nu zijn de eerste contouren van een factuur zichtbaar door het toevoegen van een aantal structurele elementen aan de PDF. Zaken als adressering, (sub)titels en footers zijn vaak essentiële onderdelen van een factuur. Door de juiste gegevens in te vullen, kan dit zelfs al voldoen aan de minimale voorwaarden voor een geldige factuur. Denk hierbij aan het invullen van BTW-nummer, KvK-nummer en uw adressering (zie ook hier).

Opmaak factuur aanpassen

De laatste stap die wordt behandeld is het verbeteren van de opmaak. Hierin worden de mogelijkheden beschreven om kleuren, lettertypes en afbeeldingen aan te passen of toe te voegen.

Uitleg

In deze stap wordt het Babel package toegevoegd om de getallen netjes als valuta te kunnen tonen. Er zijn talloze andere packages die gebruikt kunnen worden om opmaak te verbeteren, in dit geval is er voor gekozen om de verscheidenheid te minimaliseren.

  • Er wordt gestart met het formatteren van de data. De bedragen worden opgemaakt als valuta, kolomnamen met hoofdletters neergezet en een witregel toegevoegd boven de regel met het totaalbedrag.
  • Er worden hier kleuren gedefinieerd die op verschillende plekken in het document gebruikt kunnen worden. Door de mogelijkheid van hex-kleurcodes is er volledige vrijheid om company_color en secondary_color te bepalen. Hiermee kan al een groot deel van het document gekoppeld worden aan de merkidentiteit van het bedrijf.
  • Door middel van de ParagraphStyle methode kan er opmaak worden meegegeven aan tekst die met Paragraph aangemaakt wordt. In dit geval worden er twee stijl-sets aangemaakt waarin lettertype, lettergrootte en tekstkleur worden gedefinieerd. Ook kan de uitlijning met alignment worden bepaald (links, centraal, rechts, spreiden = 0, 1, 2, 4).
  • In set_table() worden nu ook de kolombreedte en rijhoogte bepaald door dit als argument mee te geven aan Table(). Er worden drie verschillende rijhoogtes aangegeven, de 1e is voor de rij met kolomnamen, daarna de rest van de inhoud en als laatste wordt er meer ruimte gegeven voor de rij met het totaal.

    De tabel wordt verder opgemaakt door lijnen, kleuren, lettergrootte en uitlijning te definiëren over de verschillende cellen van de tabel.

    Er wordt onder de tabel nog een footnote toegevoegd om hier informatie voor de ontvanger neer te zetten.

  • Om de merkidentiteit nog duidelijker te maken kunnen er afbeeldingen van bijvoorbeeld het logo worden toegevoegd. In dit geval wordt dit gedaan bovenaan het document en in de footer. In de drawImage methode wordt de bronlocatie van de afbeelding en de locatie en afmetingen op de pagina aangegeven.
  • De verschillende tekst elementen worden opgemaakt met kleur, lettertypegrootte en lettertype. Om de opmaak specifiek voor die elementen aan te geven wordt er gebruik gemaakt van de saveState() en restoreState() methodes.
  • Naast afbeeldingen kunnen er ook (gekleurde) vlakken worden toegevoegd. Hier is dit gedaan om de footer een andere kleur te geven. Het vlak is hier als een rechthoek gedefinieerd met rect().
  • Door het paginanummer te onttrekken met de getPageNumber() methode van ReportLab is het mogelijk om deze vervolgens op de pagina te printen op de gewenste positie.
Code
pdf_layout
De code voor de PDF met opmaak (click-to-copy).
Uitkomst
Het resultaat van de PDF met personalisatie.

Zie hier: een opgemaakte factuur! Er zijn veel verschillen in bijvoorbeeld kleuren en lettergrootte gebruikt om de verschillende mogelijkheden aan te duiden. De afbeeldingen en bedrijfskleuren kunnen de factuur een herkenbaar document maken, zodat klanten direct weten met wie ze te maken hebben.

Ten slotte

In deze blog is er beschreven hoe een gepersonaliseerde factuur gemaakt kan worden d.m.v. Python. Er is geprobeerd een tipje van de sluier te lichten in deze wondere wereld. Dit is slechts het begin van de mogelijkheden van PDF's met Python en we hopen je hiermee geïnspireerd en/of geholpen te hebben. Bedankt voor het lezen en als je nog tips of vragen hebt laat het ons gerust weten!

Contact ons

Vond je dit artikel interessant?

  • ✅ Zorg dat je ons volgt op LinkedIn voor nieuwe content!
divider graphic