Zet deze factuur als inkooporder in de boekhouding, maar laat me eerst
precies zien wat je gaat boeken.
Een koppeling die alleen leest uit een boekhoudpakket, kan niets kapotmaken. Hooguit is hij traag of verouderd. Een koppeling die schrijft, kan in één nacht honderd verkeerde boekingen maken, en die haal je er met de hand weer uit.
Wij bouwden de afgelopen weken twee koppelingen die allebei schrijven: een voor een drankengroothandel met slijterij die met Exact Online werkt, en een voor een café dat met Nmbrs Accounting (het vroegere Yuki) werkt. De eerste draait sinds oktober, de tweede zit in de testfase. Ze delen één manier van werken voor alles wat de boekhouding in gaat. Die staat hieronder. De klanten blijven anoniem en er staan hier geen bedragen, prijzen of marges.
Schrijven is een lijst, geen recht
Lezen en schrijven zitten in twee aparte stukken code. Het lezende deel mag alles opvragen wat het nodig heeft. Het schrijvende deel kent een vaste lijst met acties, en verder niets.
Bij de groothandel zijn dat er acht, van een magazijnverplaatsing uit de kassa-export tot het zetten van een omrekenfactor op een leveranciersartikel. Bij het café zijn het er twee: een verkoopfactuur laten verwerken en een document in de inkoopmap zetten.
Een nieuwe schrijfactie komt er alleen bij als de eigenaar er expliciet om vraagt, en dan als een eigen klus met een eigen oplevering. Niet als bijvangst van iets anders. Dat klinkt bureaucratisch, maar het is precies de vraag die je wil dat iemand stelt: moet deze software dit echt mogen?
Een test die de lijst bewaakt
Afspraken in een document worden vergeten. Daarom staat de lijst ook in een test.
Die test kijkt in de code zelf. Heeft de schrijvende klasse alleen de afgesproken functies? Stuurt hij alleen naar de vaste adressen in de API? Gebruikt hij alleen de methoden die erbij horen, dus geen verwijderopdracht? En wordt hij alleen aangeroepen vanaf de plekken die we hebben afgesproken? Een tweede test doorzoekt de hele codebase op netwerkverkeer buiten de toegestane klassen.
Komt er ergens een schrijfactie bij die niet op de lijst staat, dan faalt de build en gaat er niets live. Dat geldt voor ons, en net zo goed voor een AI-assistent die meebouwt. Die kan snel en goed code schrijven, maar hij kan deze grens niet ongemerkt verleggen. In de projectinstructies staat bovendien dat deze tests niet versoepeld mogen worden.
Controle voordat er iets de deur uit gaat
Elk verzoek naar de boekhouding gaat eerst langs een controle in onze eigen code. Alleen bekende velden, geldige verwijzingen, een aantal dat niet nul is, een prijs binnen redelijke grenzen, niet meer dan een vast aantal regels.
Het slimme zit in waar die controle nog meer draait: bij het tonen van het voorstel. Zou een boeking straks door de controle vallen, dan zie je dat al op het scherm, als een blokkade met uitleg, voordat iemand op de knop drukt. Je krijgt dus geen foutmelding van het boekhoudpakket achteraf, maar een rode regel vooraf die zegt wat er mist.
Eerst kijken, dan boeken
Elke schrijfactie begint met een voorstel. Je ziet welke regels erin gaan, met welke aantallen en bedragen. Daaronder staat een vinkje: "Ik heb het voorstel nagekeken". Zonder dat vinkje geen knop.
Het formulier stuurt bovendien het aantal regels en het totaal mee dat je op het scherm zag. Is het voorstel in de tussentijd veranderd, omdat er bijvoorbeeld een factuur opnieuw is ingelezen, dan wordt de boeking geweigerd. Je boekt dus altijd wat je gezien hebt.
Twee dingen horen daarbij. Opdrachten die vanaf de command line schrijven, draaien standaard als proef en doen pas echt iets met een extra vlag. En na elke schrijfactie lezen we terug wat er nu werkelijk in de boekhouding staat. Waarom dat nodig is, schreven we in wat de Exact-documentatie niet zegt.
Onzeker is een eigen toestand
Het lastigste moment van een schrijvende koppeling is niet de fout. Het is de time-out. Je hebt iets verstuurd en er komt geen antwoord. Staat het er nu wel of niet?
Bij het café heet dat "onzeker", en dat is een eigen toestand naast gelukt en mislukt. De app probeert het dan niet vanzelf opnieuw, want dan heb je kans op een dubbele factuur. Een beheerder kijkt in Nmbrs en kiest: het staat erin, of probeer het nog eens. Mislukt het inloggen, dan is er niets verstuurd en is het gewoon een fout. Mislukt het versturen, dan wordt er ook geen factuurnummer verbruikt.
Bij de groothandel gaat het bij inkooporders anders, en dat is geen tegenstrijdigheid. Daar proberen we het bij een time-out of een drukke API wel opnieuw, hooguit drie keer, na twee, tien en dertig minuten. Maar elke poging begint met een controle in Exact of de order er al staat, op het factuurnummer in de referentie. Automatisch opnieuw proberen mag alleen als je betrouwbaar kunt nagaan of de eerste poging aankwam. Kan dat niet, dan beslist een mens.
Ontwikkelen zonder verbinding
De ontwikkelomgeving praat nooit met een echte boekhouding. Bij Exact heeft dat ook een technische reden: wie het toegangsbewijs ververst, maakt dat van de ander ongeldig. Een testomgeving die meedoet, legt productie stil.
Voor het café draait de ontwikkelomgeving tegen een nagebouwde Nmbrs-server. Met een paar codewoorden in een omschrijving laat je die een factuur weigeren of de verbinding laten hangen, zodat je de foutpaden kunt testen zonder op een echte storing te wachten. De allereerste echte schrijfactie ging via een ja/nee-vraag op de telefoon, zoals in de ja/nee-knop voor je AI-agent.
Veelgemaakte fouten
"Geef de koppeling alvast schrijfrechten, misschien is het later handig." Dan bepaalt de koppeling wat hij mag, in plaats van de eigenaar. Begin met lezen en voeg schrijfacties een voor een toe.
"Het pakket gaf een 201, dus het staat erin." Een 201 zegt dat je verzoek is aangenomen. Wat er staat, weet je pas als je het hebt teruggelezen.
"Bij een time-out proberen we het gewoon nog een keer." Alleen als je eerst kunt controleren of de eerste keer aankwam. Anders boek je dubbel.
"De regels staan in de documentatie." Regels die niet in een test staan, zijn voornemens. Leg de lijst met schrijfacties vast in code die faalt als hij wordt overschreden.
"De testomgeving gebruikt dezelfde koppeling, alleen met testdata." Bij pakketten die het toegangsbewijs roteren, gooi je daarmee productie eruit. Laat ontwikkelwerk tegen een kopie of een nagebouwde server draaien.
Zo bouwen we elke koppeling, of het nu om Exact Online, MplusKASSA of Nmbrs gaat. Wil je iets vergelijkbaars voor je eigen administratie, kijk dan bij maatwerk.