Imported from levidestaercke70-byte/euralogics-mcp-plugin (
euralogics-mcp/skills/euralogics-planning/SKILL.md). Install upstream withnpx skills add levidestaercke70-byte/euralogics-mcp-plugin --skill euralogics-planning. Copyright stays with the author.
Euralogics-planning via de MCP-connector
Deze skill helpt je de Euralogics-planning te bedienen via de euralogics
MCP-connector. De connector is per gebruiker ingelogd en strikt per klant
afgeschermd: je ziet en wijzigt uitsluitend de data van de gekoppelde klant
(tenant). De tenant zit in het login-token — je hoeft (en kunt) hem nooit als
argument meegeven.
Veiligheidsregel (altijd toepassen)
Bevestig destructieve of definitieve acties altijd eerst bij de gebruiker voor je ze uitvoert. Concreet:
- Verwijderen —
delete_order,delete_shipment,delete_planning_rule: niet omkeerbaar viaundo. Vraag bevestiging en noem expliciet wat je gaat verwijderen. - Een dag leegmaken —
clear_daygooit alle niet-vergrendelde routes en stops van die datum weg. Er is geen undo (de tool is als onomkeerbaar geregistreerd); enkel vergrendelde routes blijven staan. Noem de datum en vraag bevestiging. - Een dag publiceren —
publish_dayis definitief: er is geen "unpublish", en daarna zijn VRP-runs op die dag geblokkeerd. Bovendien kan het automatische mails in gang zetten. Vraag het eerst. - Een dag wissen / herplannen — een nieuwe
plan_dayvervangt de bestaande planning van die dag. Bevestig de datum vóór je start. Hetzelfde geldt voorplan_weekin de standaardmodus (recompute_all): die herrekent élke niet-vergrendelde dag van het venster. - Een mail versturen —
send_warehouse_loadplanstuurt een echte e-mail naar het magazijn,send_custom_maileen vrije-tekstmail, enrequest_driver_availabilityechte e-mails naar chauffeurs. Controleer datum/periode en selectie en vraag bevestiging.
Omkeerbare wijzigingen (update_order, upsert_planning_rule op een bestaande
regel, lock_route / unlock_route op één route) kun je terugdraaien met undo
op basis van de auditId die de actie teruggaf — maar communiceer ze toch
duidelijk. Let op wat undo níét dekt: bulk_lock_routes, lock_all_routes,
unlock_all_routes (enkel de enkelvoudige lock_route/unlock_route bewaren een
momentopname — de bulk- en alles-varianten wijzigen meerdere routes in één
beweging en doen dat niet), lock_orders_to_driver, pin_orders_to_driver,
unpin_orders, set_driver_availability, create_driver, update_driver,
set_mail_config, set_alternative_rules en de async runs (plan_day,
plan_week) hebben geen schone undo-snapshot. Terugdraaien is daar een
tegengestelde actie: unpin_orders na een pin, unlock_all_routes na een
lock-all (of bulk_lock_routes met lock: false), de route ontgrendelen of
opnieuw plannen na een lock, update_driver met de vorige waarden, of een nieuwe
set_driver_availability. Zeg dat er niet zomaar een undo-knop is vóór je zo'n
actie doet.
De echte tools
Orders & zendingen
list_orders— orders opvragen (filter op datum, status, klant, limiet).create_order— nieuwe leverorder (adres wordt gegeocodeerd; optioneelcontactEmailvoor track & trace-mails). Terug metdelete_order.update_order— eenvoudige order-velden bijwerken (incl.contactEmail). Omkeerbaar viaundo.delete_order— order(s) verwijderen. Niet omkeerbaar — eerst bevestigen.split_order/split_batch— te grote order(s) splitsen. Terug metunmerge_order.unmerge_order— een split ongedaan maken.geocode_missing_orders— adressen zonder coördinaten geocoden (idempotent).synthesize_order_articles— fallback-artikel voor orders zonder artikelen.update_order_articles— volledige artikellijst van een order vervangen.create_shipment/update_shipment/delete_shipment/check_shipment_feasibility.
Planning draaien (async)
plan_day— start een planning-run voor één datum (planningDate) en blokkeert niet: geeft direct eenrunIdterug. Optioneeloptions(afwijkende solver-instellingen, camelCase, bv.{ maxRouteDurationHours: 8 }),unplannedOrderIdsom enkel een gekozen subset ongeplande orders te plannen (reeds-geplande orders blijven altijd in het plan), enadditive: truevoor aanvul-modus (bestaande ritten blijven staan, enkel de ongeplande orders komen erbij). Dit is ook de enige tool die een meerdaagse trip correct plant: het vrije vertrek-/eindpunt komt uit de dagkalender van de chauffeur. Weigert een gepubliceerde dag: zodra er één gepubliceerde route voor die datum bestaat, faalt de tool met "Dag is gepubliceerd — VRP-acties zijn geblokkeerd", en er is geen "unpublish". Plan dus altijd eerst en publiceer daarna (plan_weekslaat gepubliceerde dagen stil over). Moet er ná het publiceren toch nog iets wijzigen, dan kan dat enkel metadd_stop_to_route/remove_stop_from_route(order erbij of eraf) entransfer_route(andere chauffeur/vrachtwagen) — niet met een nieuwe run. Twijfel je of een dag al gepubliceerd is, checkget_publish_status(date)vóór je plant.plan_week— verdeelt orders over een venster van meerdere dagen (from,to, max 14 dagen) in één weekplanning-run, eveneens async. Optioneel:mode(recompute_all= alles vrij herrekenen, default;freeze_insert= bestaande orders blijven op hun dag maar de dagen worden herschreven;freeze_free= bestaande routes bevriezen en enkel nieuwe orders erbij),enabledDays,driverChoice,excludedOrderIds,allowOverflowOrderIds. Gepubliceerde dagen worden automatisch overgeslagen. Meerdaagse trips horen hier NIET. De weekplanning kent geen vrij vertrek-/eindpunt en plant zo'n dag als een gewone depot-dag (vertrek én terugkeer aan het depot), waardoor een fantoom-terugrit in het plan komt. Het antwoord kantripDayWarningsbevatten (welke dag, welke chauffeur, welk veld genegeerd werd) en/oftripDayCheckFailed: true(de tripdagen konden niet nagegaan worden). Vertel die meldingen altijd door aan de gebruiker — een mislukte controle is géén bewijs dat er geen tripdag in het venster zit. Plan trip-dagen dag per dag metplan_day.get_run_status— volg een run op metrunId(ofdatevoor de nieuwste run van die dag) totdoneistrue.get_week_summary— leesbaar week-overzicht van een voltooideplan_week-run (runId): per dag ritten, orders en geladen volume, plus de orders die nergens geplaatst raakten. Werkt pas zinvol zodraget_run_statuscompletedmeldt.cancel_run/retry_run— een run annuleren of opnieuw proberen.
Routes
list_routes— alle routes van een planning-dag (met o.a.vehicleId,baseVehicleId,routeRoundenvehicleNameper route). Wil je ergens een voertuig-id doorgeven (bv.driverChoice.vehicleIds), neem dan altijdbaseVehicleId:vehicleIdkan bij een 2e rit de vorm<uuid>-R2hebben.get_route— één route + zijn stops (parameters:routeId,date).add_stop_to_route— een order als stop aan een bestaande route toevoegen (routeId,orderId, optioneelsequence). De ETA's worden volgorde-behoudend herrekend: stops vóór het invoegpunt houden hun aankomsttijd. Werkt ook op een gepubliceerde dag (de route blijft gepubliceerd). Weigert (422) als de order niet meer past (capaciteit) — voeg ze dan aan een andere route toe; geen automatische 2e rit.remove_stop_from_route— een stop (stopId= route_stops.id) uit een route halen (routeId,stopId). Hernummert + herberekent volgorde-behoudend; de order gaat terug naar "ongepland".transfer_route— een route overdragen aan een andere chauffeur en/of vrachtwagen (routeId, optioneeldriverIden/ofvehicleId;null= loskoppelen). Maakt geen nieuwe route — de route blijft gepubliceerd en zichtbaar; de ETA's herrekenen met het nieuwe truck-profiel maar de stop-volgorde blijft gelijk.
Vloot & chauffeurs
list_drivers— de chauffeurs van jouw klant (naam, startadres, uurtarief, werkduur-override,startsFromHome,planningDisabled,isActive, …).activeOnly: truevoor enkel de actieve. Geeft chauffeur-ids terug, geen voertuig-ids — daarvoor is erlist_vehicles.list_vehicles— de vloot van jouw klant (activeOnly: truevoor enkel de actieve; geen andere argumenten). Antwoordt met{ vehicles: [...] }: per voertuig o.a.id,name,licensePlate,isActive,capacityM3,maxWeightKg, de laadruimte-afmetingen en — het belangrijkste —defaultDriverId+defaultDriverName, de gekoppelde standaardchauffeur. Dit zijn de basis-voertuig-ids dieset_driver_availability(vehicleId)enplan_week(driverChoice.vehicleIds)verwachten (zonder-R<n>-suffix). De samenvatting telt hoeveel voertuigen géén standaardchauffeur hebben — die worden niet ingepland.get_driver— één chauffeur opid.create_driver— nieuwe chauffeur; enkelnameis verplicht, de rest valt terug op de standaardwaarden (o.a. startuur 07:00, uurtarief 70). Geen undo — corrigeren doe je metupdate_driverof via de instellingen.update_driver— bestaande chauffeur bijwerken (driverId+ enkel de velden die je wil wijzigen; de rest blijft ongemoeid). Naast de profielvelden kun je hierstartsFromHomezetten (false = vertrek vanaf het depot i.p.v. het thuisadres) enplanningDisabled(true = chauffeur standaard op alle dagen afwezig, per dag terug in te schakelen). Terugdraaien = opnieuwupdate_drivermet de vorige waarden.get_driver_availability— de afwijkingen op het standaard-chauffeurprofiel voor een periode: afwezigheid en werkvenster-/dag-overrides.fromverplicht,tooptioneel. Gebruik dit vóór je een dag overschrijft — een dag zonder rij betekent gewoon "standaardprofiel".set_driver_availability— de enige tool die een dag-instelling zet, inclusief een tripdag. Zie de semantiek hieronder.request_driver_availability— geselecteerde chauffeurs een persoonlijke (getokende) link sturen waarmee ze per dag hun beschikbaarheid voor een periode doorgeven (schrijft naar de beschikbaarheids-kalender).fromentoverplicht (YYYY-MM-DD); laatdriverIdsweg om alle actieve chauffeurs met een e-mailadres aan te schrijven, of geef exact de chauffeur-ids mee. Dit stuurt echte e-mails — bevestig de periode en de selectie eerst. Deze tool negeert de mail-instellingen: hij verstuurt ook wanneer het mailtypedriver_availability_requestinget_mail_configuit staat. De schakelaar is hier dus geen vangnet — jij bent de poort. Antwoordt met hoeveel aanvragen verstuurd zijn en hoeveel chauffeurs zonder e-mailadres overgeslagen werden.pin_orders_to_driver/unpin_orders/lock_orders_to_driver— zie "Pinnen versus vergrendelen" hieronder.manage_crew_schedule— niet beschikbaar. Er bestaat geen apart, schrijfbaar crew-rooster meer (de week-planning is enkel een afgeleide weergave van de routes); de tool geeft enkel een foutmelding terug die je doorverwijst naarset_driver_availability. Roep hem niet aan.
Pinnen versus vergrendelen (het verschil dat telt)
Dit is de klassieke val: "lock" klínkt als wat je wil, maar doet iets anders.
pin_orders_to_driver(orderIds,driverId) — binden, maar herplanbaar. De orders gaan gewoon mee in de volgende planning-run (ook orders met status "nieuw"), maar de solver mag ze enkel aan díe chauffeur toewijzen. Dit is wat je nodig hebt vóór je plant, bv. om een meerdaagse trip bij één chauffeur te houden. Al écht vergrendelde orders blijven onaangeroerd ("vergrendeld overgeslagen"). Terugdraaien =unpin_orders.unpin_orders(orderIds) — de chauffeur-pin losmaken zodat de solver weer vrij mag toewijzen. Werkt enkel op gepinde (niet-vergrendelde) orders.lock_orders_to_driver(orderIds,driverId) — vergrendelen ná het plannen: de orders worden op één chauffeur gepind én bevroren, zodat een volgende planning-run ze niet meer verplaatst — ze zijn dan uitgesloten van herplanning. Gebruik dit pas als het plan definitief is. Terugdraaien gebeurt door de orders te ontgrendelen of opnieuw te plannen;unpin_ordersraakt ze niet.
Kortom: pin vóór het plannen, lock erna. Geen van beide heeft een undo-snapshot.
Semantiek van set_driver_availability (lees dit vóór je hem gebruikt)
Verplichte argumenten: driverId en date (YYYY-MM-DD) plus status.
statusis verplicht en vervangt altijd de vorige status:available= beschikbaar;sick/leave/unavailable= de solver slaat het voertuig die dag over. Er is geen "status ongewijzigd laten".- Weglaten = behouden voor al de rest. Elk veld dat je niet meegeeft blijft
staan zoals het was — óók
startTime,endTimeenreason. Je hoeft dus niets te herhalen: een tweede aanroep met enkelstartTimelaat een eerder gezet vertrek-/eindpunt gewoon staan. - Expliciet
nullwist die drie velden:startTime=null,endTime=null,reason=null. De per-dag velden hieronder aanvaarden géén null. clearOverrides: truewist de volledige dag-configuratie: alle per-dag afwijkingen (vertrekpunt, eindpunt, open einde, voertuig, snelheid, laad-/lostijd, werkduur, vaste werktijden) vervallen eerst, daarna worden enkel de per-dag velden uit dezelfde aanroep toegepast — zo zet je in één keer "alles weg behalve dit". Het raaktstartTime,endTimeenreasonniet.- Een dag die niets bijzonders meer draagt wordt als rij opgeruimd: status
available, geenstartTime, geenendTimeen geen enkele per-dag afwijking → de server bewaart die rij niet en wist ze, inclusief de reden die er nog op stond. De tool zegt het in het antwoord. Wil je enkel een reden bewaren, hou dan iets anders op die dag staan of gebruik een status ≠available. Uitzondering: bij een chauffeur metplanningDisabled=trueblijft de rij wél bestaan — dat is net de manier om te zeggen "die dag is hij wél inzetbaar". - Reden hoort bij de status: bij een statuswijziging vervalt de oude reden tenzij je in dezelfde aanroep een nieuwe meegeeft; blijft de status dezelfde, dan blijft de reden staan.
- Werkvenster:
startTime/endTimein HH:MM, waarbijendTimeeen absolute klok-cap op het einde van de werkdag is. Geef je er één mee en botst het uur dat er al stond ermee, dan laat de tool dat oude uur vallen en meldt het in het antwoord — lees dat antwoord. - Per-dag profiel-overrides:
startsFromHome,vehicleId(een ander voertuig — de chauffeur leent díe dag de laadruimte/afmetingen van dat voertuig; tarief, snelheid en uren blijven de zijne),speedCoefficient,loadUnloadTimePerM3,maxRouteDurationHoursOverride,fixedStartTime. - Tripdag-velden:
startLat+startLng(vrij vertrekpunt, bv. een hotel — wint vanstartsFromHome),endLat+endLng(de dag eindigt op dat punt; de rit ernaartoe telt mee in de werkdag, en die dag is er geen 2e rit en geen terugrit naar het depot) ofopenEnd: true(de dag stopt bij de laatste klant, zonder terugrit). - Regels op de coördinaten: altijd als paar (
startLatzonderstartLngis een fout), en het punt moet op de gebouwde routekaart liggen. Die kaart bevat België, Luxemburg, Nederland, Frankrijk (vasteland) en Noordrijn-Westfalen. Er zijn twee zeven, in deze volgorde:- Een grove rechthoek (breedtegraad 42,2–53,8, lengtegraad −5,2–9,8). Die loopt niet gelijk met de kaart — hij is enkel de goedkope eerste afwijzing.
- De echte poort: een bereikbaarheidscheck bij de routeserver zelf. Die zoekt de dichtstbijzijnde bekende weg; ligt die tientallen kilometers verderop, dan zit het punt niet op de kaart en wordt het geweigerd. Zo sneuvelt bijvoorbeeld Stuttgart — dat ligt binnen de rechthoek, maar Baden-Württemberg zit niet in de kaartdata. De foutmelding noemt de gedekte gebieden; kies dan een punt daarbinnen of meld aan de gebruiker dat de trip zo niet te plannen is.
- Kon de controle niet uitgevoerd worden (routeserver onbereikbaar of traag),
dan blokkeert dat de planning niet: de dag wordt opgeslagen en het antwoord van
set_driver_availabilitybevat een explicieteLET OP — … kon niet nagegaan worden …-melding. Neem die letterlijk over naar de gebruiker: klopt het punt toch niet, dan zijn de afstanden en reistijden van die dag fout. Een eindpunt en een open einde zijn dezelfde keuze:endLat/endLngsamen metopenEnd: trueis een fout, en zet je er één van, dan vervangt die een eerder gezette andere.openEnd: falsewist een eerder gezet open einde (en mag wél samen metendLat/endLng).
- Alles terug naar standaard voor die dag =
status='available'metstartTime=null,endTime=nullénclearOverrides=true.
Regels & instellingen
list_planning_rules/get_planning_rule— regels opvragen.upsert_planning_rule— een regel aanmaken (laatidleeg) of bijwerken (geefidmee). Bijwerken is omkeerbaar viaundo; een nieuw aangemaakte regel verwijder je metdelete_planning_rule.delete_planning_rule— een regel verwijderen. Niet omkeerbaar — eerst bevestigen.planning_rule_field_values— type-ahead-suggesties (adressen/klantnamen).get_retour_rules— retour-/zending-instellingen opvragen.
Alternatieve regels (alt-regels)
Alt-regels zijn alternatieve scenario's die de solver naast het hoofdplan doorrekent (max 3) — bv. "langere werkdag" of "vol gewicht/volume benutten" — om daarna de beste oplossing te kiezen. Ze zijn per klant instelbaar.
get_alternative_rules— de huidige alt-regels van jouw klant opvragen (geen parameters). Ontbreken ze, dan krijg je de standaard-set terug.set_alternative_rules— de volledige set alt-regels vervangen (max 3). Lees eerstget_alternative_rulesals je er één wil toevoegen/wijzigen zonder de rest te verliezen. Er is geen automatischeundo: het antwoord bevat de vorige regels inprevious— herstel doe je met een nieuweset_alternative_rules-call.
Mails (mail-machine)
De mail-instellingen staan per groep (tier: magazijn/klant/chauffeur/kantoor) en
per soort mail (mailtype) ingesteld: aan/uit, timing (direct bij publicatie of een
vast uur) en ontvanger-adres(sen). Vier mailtypes zijn live en sturen échte
mails: warehouse_load_plan (magazijn-laadplan), customer_track_trace
(klant-track & trace), driver_route_assigned (chauffeur "rit toegewezen") en
driver_availability_request (beschikbaarheidsvraag aan chauffeurs). Enkel
office_daily_summary (dagsamenvatting voor kantoor) is nog een placeholder.
Zet je met set_mail_config een van die vier aan, dan vertrekken er ook echt
mails naar klanten of chauffeurs — behandel dat als een definitieve actie en
bevestig het eerst bij de gebruiker.
De aan/uit-schakelaar geldt niet voor request_driver_availability. Die tool
verstuurt onvoorwaardelijk: de route kijkt niet naar de mail-config (enkel naar
de branding/afzender daarin) en stuurt de mails ook wanneer het mailtype
driver_availability_request uit staat. Vraagt een gebruiker "zet de
chauffeur-mails uit", dan blokkeert dat dus niet de beschikbaarheidsaanvraag —
die stuur jij zelf, en enkel wanneer de gebruiker er expliciet om vraagt.
Publiceren kan automatische mails in gang zetten — maar enkel de ingeschakelde.
Zodra je een dag publiceert (publish_day) gaat het magazijn-laadplan (PDF per
rit) op de achtergrond naar het ingestelde magazijn-adres; dat mailtype staat
standaard aan. De chauffeur-mail "rit toegewezen" is géén automatisch gevolg van
publiceren: driver_route_assigned staat standaard uit (uitgeschakeld, geen
ontvangers) en de achtergrond-poller slaat het hele mailtype over zolang het uit
staat. Ook de klant-track & trace staat standaard uit. Beloof dus nooit dat een
chauffeur of klant vanzelf bericht krijgt — lees eerst get_mail_config en zeg wat
er echt aan staat. Staat een type wél aan, dan vertrekken die mails vanzelf op de
ingeschakelde momenten (publiceren / rit-start / levering / bijna bij u) en hoef je
niets extra te doen.
get_mail_config— de mail-instellingen van jouw klant opvragen (geen parameters).set_mail_config— de volledige mail-config vervangen (geneste tier → mailtypes → regel). Lees eerstget_mail_configals je één regel wil wijzigen zonder de rest te verliezen. Geen automatischeundo: het antwoord bevat de vorige config inprevious— herstel doe je met een nieuweset_mail_config-call.send_warehouse_loadplan— het magazijn-laadplan voor een gepubliceerde dag handmatig (opnieuw) mailen (planningDate, optioneelforce). Dit stuurt een echte e-mail — eerst bevestigen. Zonderforcewordt een al-verstuurde dag overgeslagen (idempotent);force=trueforceert opnieuw versturen. Is de dag niet gepubliceerd of geen ontvanger ingesteld, dan krijg je een nette reden terug i.p.v. een mail.- Chauffeurs zelf hun beschikbaarheid laten doorgeven doe je met
request_driver_availability(zie "Vloot & chauffeurs").
Beschikbaarheid & leverdag-widget
check_availability— leverbaarheid per dag voor een (hypothetische) lading:postcode(BE 4 cijfers / NL "1234 AB") óflat+lng, plusvolumeM3enweightKg; optioneeldays(default 14, max 60). Antwoordt met de volledige slotlijst (recommended | available | tight | full) + vloot-samenvatting.recommended= er rijdt die dag al een rit vlakbij met ruime restcapaciteit; in de klant-widget heet dat "Beschikbaar" met de knop "Reserveren" — alle andere niet-volle dagen zijn daar enkel "Aanvragen".create_booking_link— persoonlijke boekingslink voor een eind-klant:customerName,customerEmail,address(vol adres — wordt gegeocodeerd),volumeM3,weightKg, optioneelorderReference,countryensendMail(default true). Stuurt standaard meteen de uitnodigingsmail "kies je leverdag" naar de klant — bevestig eerst bij de gebruiker, of zetsendMail:falseen geef debookingUrlzelf door. Dit is hetzelfde endpoint dat een webshop (bv. via n8n) bij elke nieuwe bestelling kan aanroepen. Onvindbaar adres → nette fout ("Adres niet gevonden"), er wordt dan géén link aangemaakt.list_booking_invites— de boekingslinks van jouw klant (filterstatus:open | reserved | requested | expired | cancelled;limitmax 50), incl. debookingUrlper link. Er is geen annuleer-tool — annuleren loopt via de beheerder.list_day_requests— leverdag-aanvragen uit de widget (filter opstatus, bv.pendingvoor nog te beslissen aanvragen).decide_day_request— een aanvraag beslissen:requestId+decision:'approve'(maakt meteen de capaciteitsreservering aan en mailt de klant een bevestiging) ofdecision:'reject'+alternativeDates(1–3 unieke toekomstige dagen, verplicht bij reject — die gaan als bevestig-knoppen mee in de afwijzingsmail naar de klant). Onomkeerbaar en stuurt echte klant-mails — eerst bevestigen.link_to_link_order— een widget-reservering (order met status "Te koppelen", eento_link-placeholder) koppelen aan het echte BC-order:placeholderOrderId+targetOrderId. Draagt de leverdatum over naar het echte order en ruimt de placeholder op. Geen undo.get_link_candidates— kandidaat-orders voor zo'n koppeling (zelfde klant, postcode-/referentie-/naam-match), mét de match-redenen per kandidaat.
Het draaiboek erachter: een reservering uit de widget staat als
"Te koppelen"-order op de gekozen dag en telt mee in check_availability
(de capaciteit is dus al ingenomen), maar plan_day/plan_week plannen zo'n
placeholder nooit in. Zodra het echte order uit BC/CSV binnenkomt:
get_link_candidates → link_to_link_order, en de dag-belofte reist mee.
Algemeen
whoami— toont de ingelogde gebruiker + gekoppelde klant.undo— draait een eerder uitgevoerde, omkeerbare actie terug (opauditId).
Een dag plannen — de juiste volgorde
list_orders(datum) om te zien wat er op de dag staat.geocode_missing_ordersals er orders zonder coördinaten zijn — anders vallen ze uit de planning.plan_daymet de datum (geen overrides = de live UI-instellingen). Bewaar derunId. Wil de gebruiker maar een paar van de ongeplande orders inplannen, geef danunplannedOrderIdsmee (ids uit stap 1); de rest blijft ongepland en de bestaande routes blijven behouden.get_run_statusherhaaldelijk totdoneistrue.list_routes(zelfde datum) voor een korte samenvatting: aantal routes, stops, eventuele niet-geplande orders.
Wacht nooit "synchroon" op een run binnen één tool-call — plan_day geeft meteen
terug; jij volgt zelf op met get_run_status.
Een week plannen — de juiste volgorde
list_ordersover het venster;geocode_missing_orderswaar nodig.plan_weekmetfromento(max 14 dagen). Kies bewust eenmode(recompute_allherrekent alles) en beperk desnoods metenabledDays. Wil je voor een bepaalde dag zelf de voertuigen vastleggen, gebruik dandriverChoiceper ISO-datum:{ mode: 'vrp' }(de solver kiest) of{ mode: 'manual', vehicleIds: [...], topUp?: true }. Gebruik daarvoor het basis-voertuig-id: de weekplanning vergelijkt jouwvehicleIdsmet het voertuig-id zónder rit-suffix, dus een id in de vorm<uuid>-R2(de 2e rit van dezelfde vrachtwagen) matcht nooit. Een fout id legt niet één voertuig stil maar de hele vloot van die dag: inmanualzondertopUpzet de weekplanning élk voertuig waarvan het basis-id niet in jouw lijst staat op niet-beschikbaar. Het bedoelde voertuig valt dus samen met alle andere weg, en staan al je ids fout, dan blijft er die dag géén enkel voertuig over — de dag komt leeg terug en alle orders blijven ongepland. Haal de ids daarom bijlist_vehicles(de vlootlijst met de echte basis-ids); als tweede bron kun je uit een reeds geplande dag (list_routes/get_route) het veldbaseVehicleIdnemen (vehicleNamegeeft de leesbare naam), en heb je enkelvehicleId, strip dan zelf het-R<n>-achtervoegsel.list_driversgeeft chauffeur-ids, geen voertuig-ids. Twijfel je over een id, gebruik dantopUp: true: dan blokkeert de weekplanning niets en mag de solver bovenop jouw keuze aanvullen.- Lees het antwoord op tripdagen. Bevat het
tripDayWarnings, meld dan aan de gebruiker welke dag/chauffeur het betreft en dat die dag als een gewone depot-dag gepland wordt (vertrek én terugkeer aan het depot) — het vrije vertrek-/eindpunt verdwijnt uit de berekening. Bevat hettripDayCheckFailed, meld dat als onzekerheid, niet als "geen tripdagen": controleer metget_driver_availabilityen plan die dag opnieuw metplan_day. get_run_statustotdone, daarnaget_week_summary(runId)voor het dag-per-dag overzicht + de niet-geplaatste orders.
Een meerdaagse trip orkestreren
Een meerdaagse trip is een reeks losse dagen die je één voor één plant met
plan_day. Er is geen "trip"-object: de samenhang zit in de leverdatum per order,
de dagkalender van de chauffeur (vertrek- en eindpunt per dag) en de pin van de
orders op die chauffeur. Gebruik hier nooit plan_week — die plant zo'n dag
als een gewone depot-dag.
Harde voorwaarde vooraf: de trip-chauffeur moet de standaardchauffeur van een
ACTIEF voertuig zijn. De solver plant per voertuig en leidt de chauffeur af
uit het voertuig (defaultDriverId) — en hij krijgt enkel de actieve voertuigen
te zien: een voertuig met isActive: false (bv. een truck in onderhoud) valt
volledig uit de planning-run, ook al blijft de chauffeur eraan gekoppeld. Een
chauffeur die van géén enkel actief voertuig de standaardchauffeur is, bestaat voor
de planning simpelweg niet: de pin uit stap 3 verbiedt dan élk voertuig voor die
orders (elke triporder wordt onplanbaar en komt als ongepland terug), en de
hotel-coördinaten uit stap 4 landen nergens omdat de dag-instellingen per
voertuig-met-die-chauffeur worden toegepast. Er komt géén foutmelding — je krijgt
gewoon een lege trip.
Controleer het dus vóór alles met list_vehicles: zoek in vehicles een
voertuig waarvan defaultDriverId jouw chauffeur is (defaultDriverName toont de
naam) én waarvan isActive true is. Roep de tool zonder activeOnly op, dan
zie je ook de inactieve voertuigen staan en kun je het verschil maken tussen "niet
gekoppeld" en "gekoppeld aan een voertuig dat niet meerijdt". Vind je enkel een
inactief voertuig, dan meld je dat als de blokkade. Vind je hem nergens — typisch
bij een chauffeur die je net met create_driver hebt aangemaakt, want dat maakt
géén koppeling — stop dan en vraag de gebruiker om de chauffeur in de app aan een
(actief) voertuig te koppelen (Instellingen → Voertuigen → "Vaste chauffeur"). Er
is geen tool die die koppeling legt of een voertuig weer actief zet.
Stap 1 — chauffeur en voertuig klaarzetten.
list_drivers (of get_driver) om de juiste chauffeur en zijn profiel te vinden.
Staat hij op planningDisabled: true (standaard overal afwezig), dan zet je hem
per tripdag terug aan met een expliciete beschikbaar-rij:
set_driver_availability(driverId, date, status='available', …). Bij zo'n
chauffeur blijft die rij bestaan — dat is precies de bedoeling. Moet hij een
andere vrachtwagen rijden, geef dan vehicleId mee op dezelfde dag-rij (het
basis-id uit list_vehicles). Controleer met get_driver_availability over de
hele tripperiode of er geen oude afwijkingen in de weg staan.
Stap 2 — de orders over de tripdagen verdelen (leverdatum).
plan_day plant uitsluitend de orders waarvan de leverdatum exact die dag is;
een dag zonder orders geeft meteen de fout geen orders voor <datum> om te plannen. Orders uit BC staan doorgaans allemaal op één en dezelfde leverdatum, dus
zonder deze stap propt dag 1 de hele trip vol en falen dag 2 en 3 op een lege dag.
Beslis dus eerst welke orders op welke tripdag horen (geografisch: de klanten
onderweg naar het hotel van die avond) en zet die datum met update_order(id, deliveryDate='YYYY-MM-DD') — één aanroep per order, omkeerbaar via undo. Loop
daarna nog eens list_orders per tripdag om te controleren dat elke dag de
verwachte orders draagt.
update_order weigert een order die op een vergrendelde route staat. Zodra de
route van die order een lock draagt (lock_route, bulk_lock_routes,
lock_all_routes), worden de planningsvelden — leverdatum, tijdvenster en
servicetijd — geweigerd met "Order zit op vergrendelde route …". Ontgrendel dan
eerst met unlock_route (of unlock_all_routes) en zet daarna de datum. Dat raakt
je ook aan het eind van dit draaiboek: vergrendel je de trip achteraf op
routeniveau, dan zit je in precies die toestand — wil je nadien nog een order naar
een andere tripdag schuiven, dan moet die route eerst weer open.
Geocodeer daarna wat nog geen coördinaten heeft — geocode_missing_orders
(optioneel date per tripdag). Een order zonder coördinaten valt gewoon uit de
planning, en bij een buitenlandse trip is dat de meest waarschijnlijke
uitvalsoorzaak: die adressen lopen het vaakst mis. Doe dit vóór stap 5 en lees
het antwoord: naast geocoded staat er een failed-teller, en elk adres dat
daar in zit is een order die je trip niet haalt. Meld die aan de gebruiker in
plaats van door te plannen.
Pinnen en de leverdatum zijn twee losse dingen: de pin zegt WIE de order rijdt (die ene chauffeur), de leverdatum zegt WANNEER hij gereden wordt (welke tripdag). Je hebt ze allebei nodig — een pin zonder juiste leverdatum brengt de order nooit op de juiste dag.
Stap 3 — orders pinnen VÓÓR je plant.
pin_orders_to_driver(orderIds, driverId) voor alle orders van de trip. Pinnen
houdt ze herplanbaar én bindt ze aan die ene chauffeur. Gebruik hier geen
lock_orders_to_driver: vergrendelde orders vallen buiten de planning-run en komen
dus nooit in je tripdagen terecht. Locken kan wél achteraf, als het plan staat.
Stap 4 — per dag het vertrek- en eindpunt zetten.
Eén set_driver_availability per tripdag:
- Dag 1 — vertrek zoals gewoonlijk (thuis of depot: laat
startLat/startLngweg), enendLat+endLng= het hotel waar de dag stopt. - Tussendagen —
startLat+startLng= het hotel van de vorige avond,endLat+endLng= het volgende hotel. Weet je het eindpunt nog niet, dan isopenEnd: truehet alternatief: de dag stopt bij de laatste klant. - Laatste dag —
startLat+startLng= het laatste hotel, en géén eindpunt: geenendLat/endLng, geenopenEnd. Zo eindigt die dag gewoon op het depot. Stond er op die dag al een eerdere tripdag-instelling, geef danclearOverrides: truemee (en herhaal in dezelfde aanroep de per-dag velden die je wél wil houden) — anders blijft het oude eindpunt staan ("weglaten = behouden").
Bewaak daarbij:
- Volume wordt enkel PER DAG bewaakt. De solver controleert de laadruimte van één dag; hij weet niets van "één laadbeurt voor drie dagen". Wil je de hele trip in één keer laden, dan is het jouw verantwoordelijkheid om de som van de order-volumes over alle tripdagen onder de laadcapaciteit te houden. Reken het na en zeg het expliciet tegen de gebruiker.
- Reken met een effectieve vrachtsnelheid van ongeveer 45 à 50 km/u. Een dag
van 500 km is dus ruim tien uur rijden vóór er ook maar één stop gelost is —
dimensioneer de dagen realistisch, en verzet waar nodig de werkdag-limiet per dag
met
maxRouteDurationHoursOverride(of het werkvenster metstartTime/endTime) in dezelfdeset_driver_availability-aanroep. - Een tripdag kent geen tweede rit. Bijladen kan enkel aan het depot, dus een dag met een vrij eindpunt of een open einde krijgt geen 2e rit. Wat die dag niet mee kan, moet naar een andere dag.
- Kaartdekking: sinds 26 juli 2026 dekt de routekaart België, Luxemburg, Nederland, Frankrijk (vasteland) en Noordrijn-Westfalen — die regio's en niets meer. De rechthoek waarmee de kaart is bijgesneden (breedtegraad 42,2–53,8, lengtegraad −5,2–9,8) is ruimer dan de dekking: Stuttgart of Genève vallen er wel in maar zitten niet in de kaartdata. Daarom controleert de app bij het opslaan van een tripdag-coördinaat bij de routeserver of daar écht een weg ligt; zo niet, dan volgt een weigering die de gedekte gebieden opsomt. Plan zo'n punt niet in en meld het aan de gebruiker. Kon die controle niet uitgevoerd worden (routeserver plat), dan wordt de dag wél opgeslagen mét een "kon niet nagegaan worden"-melding in het antwoord — geef die door.
Stap 5 — dag per dag plannen.
Voor elke tripdag in chronologische volgorde: plan_day(planningDate) →
get_run_status(runId) tot done. Wacht een dag af vóór je de volgende start;
zo zie je meteen of een dag te zwaar zit vóór de rest erop verder bouwt.
Stap 6 — het resultaat controleren.
Per dag list_routes(date) en get_route(routeId, date): rijdt de juiste
chauffeur, staan alle gepinde orders erop, en eindigt de dag waar je hem wilde
laten eindigen (hotel, laatste klant, of het depot op de laatste dag)? Blijven er
orders ongepland, meld dat en stel voor om ze te verplaatsen of de werkdag-limiet
op te rekken. Is de trip definitief, dan kun je hem bevriezen met
lock_orders_to_driver — vraag dat eerst.