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
- Python
- Bestanden
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 aantalreportlab
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 deTable
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
Uitkomst
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 dex1=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 hetx1
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 inon_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 nieuwFrame
en deParagraph
methode wordt aangemaakt. Hier kan de tekst naar wens worden ingevuld, en worden uitgebreid met meerdere elementen aan defooter_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
Uitkomst
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
ensecondary_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 metParagraph
aangemaakt wordt. In dit geval worden er twee stijl-sets aangemaakt waarin lettertype, lettergrootte en tekstkleur worden gedefinieerd. Ook kan de uitlijning metalignment
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 aanTable()
. 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()
enrestoreState()
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
Uitkomst
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!