Process automation
Procesautomatisering rond Navision 2009: medtech-case
Een Groningse medtech-distributeur draait op Navision 2009 en stemt 2.180 PO's per week af tussen twee EDI-formaten. Dit is de procesautomatisering die de grens trok.

Het was 16:40 op een vrijdag in Groningen en Henk had twee schermen open. Links een stapel inkooporders die 's nachts via EDI waren binnengekomen. Rechts een Navision 2009-sessie die hij had overgenomen van een collega die in 2019 met pensioen ging. Het matchpercentage die middag was 91%. De andere 9% was de reden dat hij nog op kantoor zat.
Deze post gaat over die 9%, en over de procesautomatisering-agent die we bouwden om ze zichtbaar te maken zonder de beslissingen bij Henk weg te halen.
Een 14 jaar oud grootboek dat nog steeds het bedrijf draaiend houdt
De klant is een medtech-distributeur van 31 mensen ten noorden van de stad. Ze halen Class IIa en IIb medische hulpmiddelen bij een handvol upstream-leveranciers en verschepen ze naar Nederlandse ziekenhuizen en zorginstellingen. Hun grootboek is Microsoft Dynamics NAV 2009, in tien jaar tijd gemaatwerkt door twee consultants die niet meer bereikbaar zijn.
Mainstream support voor die versie stopte in 2014. Extended support sloot in januari 2024, volgens Microsofts eigen lifecycle-pagina. Het team wist het. Ze hadden twee keer een migratie naar Business Central uitgewerkt en twee keer in de ijskast gezet. Het maatwerk is zwaar. De keten van ontvangsten gaat drie auditcycli terug. De kosten van die keten doorbreken waren altijd hoger dan de kosten van nog een jaar door op een EOL-stack.
Als je ooit operations lead bent geweest bij een kleine distributeur, ken je dit rekensommetje. De migratie komt volgend jaar, en volgend jaar is druk.
2.180 inkooporders per week, twee formaten, één grootboek
De doorzet is 2.180 inkooporders per week. Twee upstream-bronnen verzorgen het meeste volume. De groothandel in disposables stuurt EDIFACT D.96A voor de medische artikelen. De foodservice-distributeur, die naast de hulpmiddelen ook de cateringlijn voor zorginstellingen levert, stuurt een platte CSV met een 14-koloms header die sinds 2016 niet meer is veranderd, behalve op de dag dat iemand een btw-kolom toevoegde zonder iemand downstream te waarschuwen.
Artikelen worden gematcht op een hybride sleutel. Sommige regels hebben een GTIN. Andere een vendor-SKU. Soms allebei, maar de SKU is in 2021 verschoven toen één productfamilie bovenstrooms hernummerd werd en niemand de historische regels heeft bijgewerkt. De reconciliatie is dus geen join. Het is een gescoorde match, en de score liegt soms.
De MDR-laag die niemand kan overslaan
Hier wordt een normale three-way match interessant. De distributeur beweegt gereguleerde hulpmiddelen. Onder de EU Medical Device Regulation (2017/745) heeft elk hulpmiddel dat over een Nederlands laad-perron gaat een Unique Device Identifier die van fabrikant tot eindgebruiker traceerbaar moet zijn. Een mismatch tussen een goederenontvangstregel en een groothandel-PO is geen administratieve fout die je maandag wel oplost. Het is een audit-bevinding die drie weken later gevonden wordt, als het lotnummer al in een ziekenhuis ligt en de toezichthouder wil weten welke doos waar terechtkwam.
De reconciliatie is dus twee banen in één jas. Baan één is financieel: match de PO-regel aan de goederenontvangst aan de factuur en stel een journaalpost voor. Baan twee is regulatoir: als een regel niet matcht, bepaal of het verschil over prijs of aantal gaat (wachtrij van de controller) of over UDI, lot of batch (wachtrij van de kwaliteitsfunctionaris). Die twee mensen verantwoorden zich aan verschillende auditors, en één gezamenlijke wachtrij zou de één in de ander begraven.
De agent die we bouwden, en de grens die we trokken
We begonnen met read-only-toegang voor de agent. Niks anders. De Navision 2009 SQL Server staat binnen hun netwerk. We hebben hem ontsloten via een ODBC-connectie die alleen vier views ziet: Purchase Header, Purchase Line, Item Ledger Entry, Vendor Ledger Entry. Geen schrijfrechten. Geen rechten op stored procedures. De agent kon de wereld lezen. Veranderen kon hij niet.
Die beslissing is de ruggengraat van het project, en we komen later terug op het waarom.
De matching-logica is gewone code, geen modelcall. Modellen zijn nuttig voor de rommelige tekst op een leveranciers-factuur-PDF, maar de join zelf is deterministisch:
def match_po_to_receipt(po_line, candidate_receipts):
"""
Returns (best_match, confidence, route).
Confidence below 0.92 routes to the controller's queue.
UDI mismatch always routes to the quality-officer queue,
regardless of financial confidence.
"""
scored = []
for r in candidate_receipts:
s = 0.0
if r.item_no == po_line.item_no:
s += 0.50
if r.lot_no and r.lot_no == po_line.lot_no:
s += 0.25
if abs(r.qty - po_line.qty) < 0.001:
s += 0.15
if r.unit_price and within(r.unit_price, po_line.unit_price, 0.02):
s += 0.10
scored.append((r, s))
if not scored:
return None, 0.0, "no candidates"
best, conf = max(scored, key=lambda x: x[1])
if best.udi and po_line.udi and best.udi != po_line.udi:
return best, conf, "udi-mismatch -> quality-officer"
if conf < 0.92:
return best, conf, f"low-confidence ({conf:.2f}) -> controller"
return best, conf, "auto-proposed (awaiting sign-off)"
Drie dingen zijn belangrijk aan die code. De score verzint nooit een veld: als een regel geen UDI heeft, draagt de UDI-regel nul bij in plaats van te gokken. Een UDI-mismatch overrulet hoge financiële zekerheid, want een perfect geprijsde, perfect getelde doos met de verkeerde UDI is de gevaarlijkste regel in het bestand. En de hoogst mogelijke uitkomst is auto-proposed, nooit auto-posted.
Modellen als vertalers, nooit als actoren
Achter de matching-logica zit een ingestion-pipeline die het feit moet verwerken dat facturen, anders dan PO's, niet in EDIFACT of CSV binnenkomen. De disposables-groothandel stuurt een PDF die al negen jaar op dezelfde manier is opgemaakt en een feestje is om te parsen. De foodservice-distributeur stuurt een PDF waarvan de layout in 2025 twee keer veranderde nadat hun financiële team zonder aankondiging nieuwe templates uitrolde. Voor die documenten gebruiken we wel een model, niet voor de journaalpost, maar om regels te extraheren in dezelfde vorm die de deterministische matcher verwacht.
De modeloutput gaat naar een staging-tabel die de matcher leest. Het grootboek wordt nooit direct aangeraakt. Krijgt het model een regel verkeerd, dan is het ergste geval een match met lage zekerheid die naar de wachtrij van de controller gaat, dezelfde plek waar foute regels eerst al heen gingen. Dit patroon verdient een naam. Als een model achter een deterministische stap zit, is het model een vertaler, geen actor. Het mag fout zitten; de kosten van een fout zijn afgebakend; de mens aan het eind van de pipeline ziet wat het model miste. Die scheiding is de ruggengraat van elke procesautomatisering die we tegen een legacy-grootboek aanzetten.
Twee wachtrijen, twee auditors
De wachtrij van de controller is een naast-elkaar-weergave: voorgestelde journaalpost links, brondocumenten rechts, drie knoppen (tekenen, afwijzen, aanpassen). Ze werkt negentig regels in een uur weg, omdat de agent het saaie matchwerk al gedaan heeft en haar taak is om de acht foute te lezen.
De wachtrij van de kwaliteitsfunctionaris is opgebouwd rond het hulpmiddel, niet rond de journaalpost. Elke regel is een UDI, een lotnummer, een batch en een vraag. De groothandel zegt dat dit lot dinsdag verstuurd is. Wij hebben zeven dozen ontvangen. Zes komen overeen met de manifest. De zevende heeft een UDI die naar een vorige-generatie productcode verwijst. Beslis. Hij beslist. De agent schrijft een append-only audit-trail-regel. Hij tekent. Het bijbehorende journaalvoorstel gaat dan terug naar de controller voor financiële tekening.
Twee wachtrijen, twee handtekeningen, één grootboek. De agent verplaatst het werk; de mensen nemen de beslissingen met auditgewicht.
Waarom de agent zelf nooit een journaalpost boekt
Dit is de grens die we trokken, en die verdient uitleg, want eens in de twee weken vraagt iemand of we hem mogen verschuiven.
Er is geen tekort aan recente verhalen over AI-agents die onomkeerbare acties uitvoerden tegen cloud-API's, productie-databases of source repositories, en de mensen die ze inzetten zonder weg terug achterlieten. Het patroon is consistent over vendors en stacks, en het signaal ook: een agent die onomkeerbare acties uitvoert, is een agent die je dinsdag kan verpesten.
Een journaalpost in Navision is onomkeerbaar. Je kunt hem terugdraaien met een tegenboeking, maar het origineel blijft in het grootboek staan, en een Nederlandse accountant ziet allebei. De kosten van één verkeerde geboekte journaalpost door een agent zijn hoger dan de kosten van een controller die driehonderd correcte tekent. Daar heb je geen rekenmachine voor nodig.
In elk systeem waarin een verkeerde actie een permanente notitie achterlaat, stelt de agent voor en beslist de mens. Hem zelf laten boeken levert nul voordeel op.
De framing die we bij klanten gebruiken: de waarde van een agent zit in het werk dat hij wegneemt, niet in de verantwoordelijkheid die hij overneemt. Het werk van de controller was vóór onze agent 80% matchen en 20% beslissen. Daarna is het 5% lezen en 95% beslissen. Haar doorzet verdrievoudigde. Haar audit-blootstelling bewoog geen millimeter.
De eerste zes weken, die lelijk waren
We moeten eerlijk zijn over de uitrol. De eerste zes weken waren geen soepele glijvlucht naar productiviteit. Henk vertrouwde de agent niet. Hij hoorde de agent ook niet te vertrouwen. Wij hadden hem gebouwd; hij niet. De eerste zes weken draaiden dus als parallel systeem. De agent stelde voor; hij matchte met de hand; wij vergeleken.
Op dag één was de agent het 81% van de tijd met hem eens. Die 19% gap kwam vrijwel volledig door de SKU-drift uit de 2021-hernummering, waar we de matcher nog niets over hadden verteld. In week vier was de overeenstemming 96%, en de verschillen waren meestal gevallen waarin de agent gelijk had en Henk het al twee jaar uit gewoonte verkeerd deed.
Het doel van de parallelle run was niet om de agent te valideren. Het was om de controller een basis te geven voor het vertrouwen in de wachtrij die ze ging tekenen. Zonder dat zou elke handtekening de cognitieve last van een verse beslissing dragen. Met die basis vertrouwde ze tegen de tijd dat de wachtrij live ging op de score, omdat ze zes weken had gezien hoe die correleerde met haar eigen oordeel.
Wat er op vrijdag aan zijn bureau veranderde
De agent draait sinds januari in productie. Cijfers van vorige week: 2.180 PO's gereconcilieerd, tegenover ongeveer 1.940 een jaar geleden, omdat het team niet meer de long tail overslaat om de urgente wachtrij te legen. De gemiddelde reviewtijd van de controller per batch van negentig voorgestelde regels daalde van 47 minuten handmatig matchen naar 8,2 minuten lezen en tekenen. In het eerste kwartaal ving de wachtrij veertien UDI-mismatches op, waarvan twee echte MDR-bevindingen die anders naar ziekenhuizen waren gegaan. Het aantal journaalposten dat geboekt is zonder ondertekening door de controller is nul, en blijft nul.
Henk gaat nu om 16:40 op vrijdag naar huis. De 9% bestaat nog. Ze staat alleen 's ochtends op zijn scherm, gesorteerd, gescoord, wachtend op een beslissing in plaats van op een zoekopdracht.
Het kleinste dat je deze week kunt overnemen
Als jij finance draait op een EOL-grootboek en het migratiebudget elk kwartaal opnieuw doorschuift, begin je niet bij de migratie. Maak eerst de reconciliatie-inventaris. Tel de regels, tel de wachtrijen, tel de onomkeerbare acties. Overal waar een mens matchwerk doet dat een deterministisch script ook aankan, daar is automatiseringsterrein. Overal waar een mens een oordeel velt met auditgewicht, daar blijft het menselijk. De agent leeft daartussenin, en zijn mandaat eindigt bij de tekenpagina.
Toen we de procesautomatisering bouwden voor de Groningse distributeur, kwam de verleiding telkens terug om de agent de eenvoudige 91% zelf te laten afsluiten. We hebben dat niet gedaan. Het grootboek is ouder dan de jongste medewerker in het magazijn en het overleeft de agent ook. De taak van de agent is het werk voorbereiden, niet uitvoeren.
Kern
In elk systeem waarin een verkeerde actie een permanente notitie achterlaat, stelt de agent voor en beslist de mens. Hem zelf laten boeken levert nul voordeel op.
FAQ
Waarom hebben jullie ze niet van Navision 2009 af gemigreerd in plaats van eromheen te automatiseren?
De migratie naar Business Central is twee keer uitgewerkt en twee keer in de ijskast gezet, op kosten en risico. De agent is goedkoper, haalt de operationele pijn weg die de migratiedrang aanjoeg, en geeft het team de ruimte om op eigen tempo te migreren in plaats van onder deadlinedruk.
Hoe voorkomt de agent dat hij matches verzint als de brondata vies is?
De matchscore telt alleen velden mee die in beide records bestaan. Heeft een regel geen UDI of geen lotnummer, dan draagt de regel voor dat veld nul bij in plaats van te gokken. Lage totalen gaan naar een menselijke wachtrij in plaats van naar een zelfverzekerd ogend fout antwoord.
Wat gebeurt er tijdens een MDR-audit?
De append-only log geeft de auditor per regel een spoor: wie welke mismatch zag, wie besliste, wanneer, en tegen welk brondocument. Auditors hebben dit spoor tot nu toe verkozen boven het oude, op spreadsheets gebaseerde.
Werkt hetzelfde patroon voor andere legacy-systemen, niet alleen Navision?
Ja. Het patroon is read-only ingest, gescoorde deterministische match, twee wachtrijen voor twee soorten beslissingen, en menselijke ondertekening op elke onomkeerbare actie. De ondergrond doet er minder toe dan de regel dat de agent zelf nooit de actie uitvoert.
Hoe groot moet een team zijn voordat dit zichzelf terugverdient?
Het break-even-punt ligt niet bij headcount, maar bij de kosten van één foute grootboekregel. Overal waar een verkeerde journaalpost een auditreactie, een terugbetaling of een brief van de toezichthouder triggert, verdient een agent die voorstelt in plaats van boekt zichzelf bij de eerste opgevangen mismatch al terug.