@flowselections/logistiek-engine 1.0.34 → 1.0.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +24 -24
  2. package/dist-lib/components/FlowCanvas.d.ts +28 -0
  3. package/dist-lib/components/FlowCanvas.d.ts.map +1 -0
  4. package/dist-lib/components/FlowCanvas.js +429 -0
  5. package/dist-lib/components/FlowOrders.d.ts +8 -0
  6. package/dist-lib/components/FlowOrders.d.ts.map +1 -0
  7. package/dist-lib/components/FlowOrders.js +125 -0
  8. package/dist-lib/components/FlowPage.d.ts +2 -0
  9. package/dist-lib/components/FlowPage.d.ts.map +1 -0
  10. package/dist-lib/components/FlowPage.js +141 -0
  11. package/dist-lib/components/InklapbaarVenster.d.ts +9 -0
  12. package/dist-lib/components/InklapbaarVenster.d.ts.map +1 -0
  13. package/dist-lib/components/InklapbaarVenster.js +10 -0
  14. package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
  15. package/dist-lib/components/LogistiekEnginePage.js +9 -3
  16. package/dist-lib/components/LogistiekEngineQueuePage.d.ts +2 -0
  17. package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -0
  18. package/dist-lib/components/LogistiekEngineQueuePage.js +11 -0
  19. package/dist-lib/components/NodeTracePanel.d.ts +11 -0
  20. package/dist-lib/components/NodeTracePanel.d.ts.map +1 -0
  21. package/dist-lib/components/NodeTracePanel.js +40 -0
  22. package/dist-lib/components/OrderJourneyBar.d.ts +9 -0
  23. package/dist-lib/components/OrderJourneyBar.d.ts.map +1 -0
  24. package/dist-lib/components/OrderJourneyBar.js +26 -0
  25. package/dist-lib/components/OrderLogboek.d.ts +10 -0
  26. package/dist-lib/components/OrderLogboek.d.ts.map +1 -0
  27. package/dist-lib/components/OrderLogboek.js +92 -0
  28. package/dist-lib/components/OrderStopBanner.d.ts +5 -0
  29. package/dist-lib/components/OrderStopBanner.d.ts.map +1 -0
  30. package/dist-lib/components/OrderStopBanner.js +22 -0
  31. package/dist-lib/components/OrderTraceDetails.d.ts +22 -0
  32. package/dist-lib/components/OrderTraceDetails.d.ts.map +1 -0
  33. package/dist-lib/components/OrderTraceDetails.js +87 -0
  34. package/dist-lib/components/RegiePage.d.ts.map +1 -1
  35. package/dist-lib/components/RegiePage.js +11 -69
  36. package/dist-lib/components/WerktijdenCard.d.ts +2 -0
  37. package/dist-lib/components/WerktijdenCard.d.ts.map +1 -0
  38. package/dist-lib/components/WerktijdenCard.js +37 -0
  39. package/dist-lib/components/WerkwijzeHerindelingCard.d.ts.map +1 -1
  40. package/dist-lib/components/WerkwijzeHerindelingCard.js +100 -6
  41. package/dist-lib/hooks/useLogisticsTrace.d.ts +78 -0
  42. package/dist-lib/hooks/useLogisticsTrace.d.ts.map +1 -0
  43. package/dist-lib/hooks/useLogisticsTrace.js +152 -0
  44. package/dist-lib/hooks/useOrderNodeTrace.d.ts +11 -0
  45. package/dist-lib/hooks/useOrderNodeTrace.d.ts.map +1 -0
  46. package/dist-lib/hooks/useOrderNodeTrace.js +26 -0
  47. package/dist-lib/hooks/useOrderTrace.d.ts +74 -0
  48. package/dist-lib/hooks/useOrderTrace.d.ts.map +1 -0
  49. package/dist-lib/hooks/useOrderTrace.js +134 -0
  50. package/dist-lib/hooks/useOrderVersies.d.ts +47 -0
  51. package/dist-lib/hooks/useOrderVersies.d.ts.map +1 -0
  52. package/dist-lib/hooks/useOrderVersies.js +180 -0
  53. package/dist-lib/hooks/useRuleEngine.d.ts +1 -0
  54. package/dist-lib/hooks/useRuleEngine.d.ts.map +1 -1
  55. package/dist-lib/hooks/useRuleEngine.js +1 -0
  56. package/dist-lib/hooks/useShippingNoteStatus.d.ts +29 -0
  57. package/dist-lib/hooks/useShippingNoteStatus.d.ts.map +1 -0
  58. package/dist-lib/hooks/useShippingNoteStatus.js +107 -0
  59. package/dist-lib/hooks/useWerktijden.d.ts +33 -0
  60. package/dist-lib/hooks/useWerktijden.d.ts.map +1 -0
  61. package/dist-lib/hooks/useWerktijden.js +88 -0
  62. package/dist-lib/hooks/useWerkwijzeStatus.d.ts +12 -1
  63. package/dist-lib/hooks/useWerkwijzeStatus.d.ts.map +1 -1
  64. package/dist-lib/hooks/useWerkwijzeStatus.js +60 -4
  65. package/dist-lib/index.d.ts +13 -0
  66. package/dist-lib/index.d.ts.map +1 -1
  67. package/dist-lib/index.js +13 -0
  68. package/dist-lib/integrations/supabase/auth-middleware.d.ts +1600 -54
  69. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  70. package/dist-lib/integrations/supabase/client.server.d.ts +1600 -54
  71. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  72. package/dist-lib/integrations/supabase/client.server.js +1 -1
  73. package/dist-lib/integrations/supabase/moduleClient.d.ts +1600 -54
  74. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  75. package/dist-lib/integrations/supabase/types.d.ts +1618 -50
  76. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  77. package/dist-lib/lib/cartPlanRequests.server.d.ts +1 -1
  78. package/dist-lib/lib/cartPlanRequests.server.d.ts.map +1 -1
  79. package/dist-lib/lib/cartPlanRequests.server.js +49 -8
  80. package/dist-lib/lib/floridayDocuments.functions.d.ts +4644 -6
  81. package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
  82. package/dist-lib/lib/floridayDocuments.functions.js +1 -1
  83. package/dist-lib/lib/floridayDocuments.server.d.ts +14 -0
  84. package/dist-lib/lib/floridayDocuments.server.d.ts.map +1 -1
  85. package/dist-lib/lib/floridayDocuments.server.js +58 -0
  86. package/dist-lib/lib/floridayGuard.server.d.ts +1 -1
  87. package/dist-lib/lib/floridayGuard.server.d.ts.map +1 -1
  88. package/dist-lib/lib/floridayGuard.server.js +6 -3
  89. package/dist-lib/lib/floridayPush.functions.d.ts +1600 -54
  90. package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
  91. package/dist-lib/lib/floridayPush.functions.js +1 -1
  92. package/dist-lib/lib/flowGraph.d.ts +43 -0
  93. package/dist-lib/lib/flowGraph.d.ts.map +1 -0
  94. package/dist-lib/lib/flowGraph.js +153 -0
  95. package/dist-lib/lib/flowNodes.d.ts +23 -0
  96. package/dist-lib/lib/flowNodes.d.ts.map +1 -0
  97. package/dist-lib/lib/flowNodes.js +58 -0
  98. package/dist-lib/lib/flowRoute.d.ts +107 -0
  99. package/dist-lib/lib/flowRoute.d.ts.map +1 -0
  100. package/dist-lib/lib/flowRoute.js +280 -0
  101. package/dist-lib/lib/flowTree.d.ts +64 -0
  102. package/dist-lib/lib/flowTree.d.ts.map +1 -0
  103. package/dist-lib/lib/flowTree.js +519 -0
  104. package/dist-lib/lib/handlers/index.d.ts +1 -0
  105. package/dist-lib/lib/handlers/index.d.ts.map +1 -1
  106. package/dist-lib/lib/handlers/index.js +1 -0
  107. package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts +3 -0
  108. package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts.map +1 -0
  109. package/dist-lib/lib/handlers/logistics-shipping-note-now.server.js +100 -0
  110. package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
  111. package/dist-lib/lib/handlers/logistics-tick.server.js +97 -2
  112. package/dist-lib/lib/loadCarrierPlanner.d.ts +2 -0
  113. package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
  114. package/dist-lib/lib/loadCarrierPlanner.js +18 -0
  115. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +7740 -10
  116. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
  117. package/dist-lib/lib/loadCarrierPlanning.functions.js +1 -1
  118. package/dist-lib/lib/loadCarrierPlanning.server.d.ts +9 -0
  119. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  120. package/dist-lib/lib/loadCarrierPlanning.server.js +44 -17
  121. package/dist-lib/lib/logisticsPlanner.d.ts.map +1 -1
  122. package/dist-lib/lib/logisticsPlanner.js +14 -2
  123. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +3096 -4
  124. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
  125. package/dist-lib/lib/logisticsRecalcJob.functions.js +1 -1
  126. package/dist-lib/lib/logisticsRecalculate.functions.d.ts +1600 -54
  127. package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
  128. package/dist-lib/lib/logisticsRecalculate.functions.js +1 -1
  129. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  130. package/dist-lib/lib/modulePrompts.js +3459 -2677
  131. package/dist-lib/lib/nodeTrace.d.ts +61 -0
  132. package/dist-lib/lib/nodeTrace.d.ts.map +1 -0
  133. package/dist-lib/lib/nodeTrace.js +191 -0
  134. package/dist-lib/lib/pickQueueCleanup.server.d.ts +14 -0
  135. package/dist-lib/lib/pickQueueCleanup.server.d.ts.map +1 -0
  136. package/dist-lib/lib/pickQueueCleanup.server.js +80 -0
  137. package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
  138. package/dist-lib/lib/planQueue.server.js +140 -0
  139. package/dist-lib/lib/ruleEngineImpact.d.ts.map +1 -1
  140. package/dist-lib/lib/ruleEngineImpact.js +11 -4
  141. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  142. package/dist-lib/lib/ruleEngineSchema.js +50 -6
  143. package/dist-lib/lib/ruleEngineWizard.d.ts.map +1 -1
  144. package/dist-lib/lib/ruleEngineWizard.js +3 -1
  145. package/dist-lib/lib/shippingNoteQueue.server.d.ts +18 -0
  146. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -0
  147. package/dist-lib/lib/shippingNoteQueue.server.js +304 -0
  148. package/dist-lib/lib/trace.server.d.ts +75 -0
  149. package/dist-lib/lib/trace.server.d.ts.map +1 -0
  150. package/dist-lib/lib/trace.server.js +75 -0
  151. package/dist-lib/lib/vakUitleg.d.ts +19 -0
  152. package/dist-lib/lib/vakUitleg.d.ts.map +1 -0
  153. package/dist-lib/lib/vakUitleg.js +132 -0
  154. package/package.json +26 -2
  155. package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts +0 -2
  156. package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts.map +0 -1
  157. package/dist-lib/components/rule-engine/FloridayConnectionBanner.js +0 -41
  158. package/dist-lib/integrations/supabase/client.d.ts +0 -20293
  159. package/dist-lib/integrations/supabase/client.d.ts.map +0 -1
  160. package/dist-lib/integrations/supabase/client.js +0 -13
@@ -30,6 +30,20 @@ export const RULE_STEPS = [
30
30
  description: "Bepaal wanneer een order in een gecombineerde order (orderbuffer) terechtkomt.",
31
31
  supportsConditions: true,
32
32
  groups: [
33
+ {
34
+ id: "herkomst",
35
+ label: "Herkomst van bestellingen",
36
+ description: "Bestellingen komen binnen uit Floriday, de mailbox voor bestellingen, de actiemail of handmatige invoer.",
37
+ fields: [
38
+ {
39
+ key: "floriday_merge_lines",
40
+ label: "Floriday-bestelregels samenvoegen tot \u00e9\u00e9n bestelling",
41
+ type: "toggle",
42
+ default: true,
43
+ description: "Floriday levert elke bestelregel als een eigen verkooporder. Staat dit aan, dan worden regels van dezelfde klant, hetzelfde levermoment en dezelfde afleverlocatie samengevoegd tot \u00e9\u00e9n order met \u00e9\u00e9n ordernummer (het laagste FO-nummer). Orders die al zijn ingedeeld, geprint of gecontroleerd blijven ongewijzigd.",
44
+ },
45
+ ],
46
+ },
33
47
  {
34
48
  id: "orderbuffer",
35
49
  label: "Orderbuffer",
@@ -232,6 +246,27 @@ export const RULE_STEPS = [
232
246
  dependsOn: { key: "mode", in: ["auto"] },
233
247
  },
234
248
  { key: "max_customers", label: "Maximaal aantal klanten per ladingdrager", type: "number", min: 1, max: 99, default: 2, dependsOn: [{ key: "mode", in: ["auto"] }, { key: "fill_customers_as_much_as_fits", in: [false] }] },
249
+ {
250
+ key: "max_customers_per_layer",
251
+ label: "Maximaal aantal klanten op een laag",
252
+ type: "number",
253
+ min: 1,
254
+ max: 99,
255
+ default: 1,
256
+ description: "Staat dit op 1, dan mogen op één laag alleen producten van dezelfde klant staan. Meerdere bestellingen van dezelfde klant mogen wel samen op een laag.",
257
+ dependsOn: { key: "mode", in: ["auto"] },
258
+ },
259
+ {
260
+ key: "cart_plan_freeze",
261
+ label: "Wanneer ligt de karrenindeling vast?",
262
+ type: "select",
263
+ default: "per_cart",
264
+ options: [
265
+ { value: "per_cart", label: "Als de pakbon is uitgeprint" },
266
+ { value: "first_packing_slip", label: "Als de eerste pakbon van de order of buffer is uitgeprint" },
267
+ ],
268
+ description: "Per kar: alleen de kar met een geprinte pakbon blijft staan, de rest mag nog opnieuw ingedeeld worden. Eerste pakbon: zodra de eerste pakbon van de order of buffer is geprint, ligt de hele indeling vast en komen er hoogstens karren bij.",
269
+ },
235
270
  {
236
271
  key: "fill_layers_as_much_as_fits",
237
272
  label: "Lagen: zoveel als past",
@@ -538,8 +573,8 @@ export const RULE_STEPS = [
538
573
  },
539
574
  {
540
575
  value: "manual_approval",
541
- label: "Wachten op handmatige goedkeuring",
542
- description: "De Engine past de planning niet aan totdat een gebruiker de wijziging heeft goedgekeurd.",
576
+ label: "Handmatig herinplannen",
577
+ description: "De Engine doet niets met vertraagde orders: de nieuwe leverdag wordt handmatig in de Afhandeling-module bepaald.",
543
578
  },
544
579
  ],
545
580
  },
@@ -782,7 +817,7 @@ export const RULE_STEPS = [
782
817
  options: [
783
818
  { value: "after_checkin", label: "Na het aanmeldmoment van het transport" },
784
819
  { value: "after_scan", label: "Automatisch afdrukken nadat een kar is gescand" },
785
- { value: "with_packing_slip", label: "Gelijktijdig met de pakbon" },
820
+ { value: "with_packing_slip", label: "Als de pakbon wordt uitgeprint" },
786
821
  { value: "manual_approval", label: "Pas na handmatige goedkeuring op een pickstation" },
787
822
  ],
788
823
  },
@@ -883,16 +918,18 @@ export const RULE_STEPS = [
883
918
  type: "select",
884
919
  default: "scanner",
885
920
  options: [
886
- { value: "scanner", label: "Scancontrole" },
921
+ { value: "scanner", label: "Scancontrole met verzendbrief uitprinten" },
922
+ { value: "scan_only", label: "Scannen voor afmelden" },
887
923
  { value: "paper", label: "Papieren controle" },
888
924
  { value: "skip", label: "Controle overslaan" },
889
925
  ],
926
+ description: "Bij 'Scannen voor afmelden' scant de medewerker alleen de pakbon; die ene scan meldt de hele kar direct af. Er wordt dan niets geprint.",
890
927
  },
891
928
  {
892
929
  key: "control_scanner_id",
893
930
  label: "Scanner",
894
931
  type: "scanner",
895
- dependsOn: [{ key: "control_mode", in: ["scanner"] }],
932
+ dependsOn: [{ key: "control_mode", in: ["scanner", "scan_only"] }],
896
933
  description: "De scanner die bij deze controlepost hoort. Alle pakbonnen die gecontroleerd moeten worden, komen bij deze scanner binnen.",
897
934
  },
898
935
  {
@@ -920,6 +957,13 @@ export const RULE_STEPS = [
920
957
  default: false,
921
958
  description: "Staat dit uit, dan verstuurt de Logistics Engine geen enkele statuswijziging naar Floriday. Staat dit aan, dan wordt een order pas op afgehandeld gezet nadat de karrencontrole is goedgekeurd.",
922
959
  },
960
+ {
961
+ key: "floriday_delivery_note_create",
962
+ label: "Verzendbrief laten aanmaken in Floriday",
963
+ type: "toggle",
964
+ default: false,
965
+ description: "Staat dit aan, dan laat de Engine bij een Floriday-order een officiele verzendbrief aanmaken zodra de pakbon naar het pickstation gaat, en haalt dat document daarna op. De order wordt hierdoor niet afgemeld; dat blijft aan de controlescan.",
966
+ },
923
967
  {
924
968
  key: "floriday_stock_updates",
925
969
  label: "Voorraad doorgeven aan Floriday",
@@ -935,7 +979,7 @@ export const RULE_STEPS = [
935
979
  max: 100,
936
980
  default: 100,
937
981
  unit: "%",
938
- dependsOn: { key: "control_mode", in: ["scanner", "paper"] },
982
+ dependsOn: { key: "control_mode", in: ["scanner", "scan_only", "paper"] },
939
983
  },
940
984
  ],
941
985
  },
@@ -1 +1 @@
1
- {"version":3,"file":"ruleEngineWizard.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineWizard.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAC;CACzB;AAeD,eAAO,MAAM,YAAY,EAAE,UAAU,EAsDpC,CAAC;AA+BF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEzD;AAkED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAE9D;AAyCD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAStF"}
1
+ {"version":3,"file":"ruleEngineWizard.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineWizard.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAC;CACzB;AAeD,eAAO,MAAM,YAAY,EAAE,UAAU,EAsDpC,CAAC;AA+BF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEzD;AAwED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAE9D;AAyCD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAStF"}
@@ -114,6 +114,8 @@ const EXTRA_HELP = {
114
114
  multi_order: "Aan: orders van meerdere bestellingen mogen op dezelfde drager staan.",
115
115
  max_orders: "Meer orders op één drager betekent minder karren, maar wel meer sorteerwerk.",
116
116
  max_customers: "Handig als klanten hun eigen kar willen ontvangen.",
117
+ max_customers_per_layer: "Op 1 komen er nooit twee verschillende klanten op dezelfde laag; meerdere bestellingen van dezelfde klant mogen wel samen.",
118
+ cart_plan_freeze: "Bepaalt hoe streng een eenmaal geprinte indeling vaststaat. Per kar blijft alleen de geprinte kar staan; bij 'eerste pakbon' ligt de hele order of buffer vast zodra er één pakbon uit de printer is.",
117
119
  max_layers: "Het aantal lagen dat je fysiek op een kar of container kwijt kunt.",
118
120
  max_boxes_per_pallet: "Het aantal dozen dat je fysiek op één pallet kwijt kunt.",
119
121
  optimal_fill: "Aan: het systeem zoekt de indeling waarbij de minste dragers nodig zijn.",
@@ -144,7 +146,7 @@ const EXTRA_HELP = {
144
146
  shipping_note_layout: "\u00c9\u00e9n layout voor de verzend-, aflever- en veilingbrief van BVO orders.",
145
147
  production_note_release: "Bepaalt op welk moment de productiebon beschikbaar komt.",
146
148
  production_note_station: "Het pickstation waar de productiebon uitgeprint wordt.",
147
- control_mode: "Hoe je controleert of de kar klopt voordat hij weggaat.",
149
+ control_mode: "Hoe je controleert of de kar klopt voordat hij weggaat. Bij 'Scannen voor afmelden' is één pakbonscan genoeg en wordt de hele kar direct afgemeld.",
148
150
  control_print_items: "Welke papieren de medewerker bij de controle krijgt.",
149
151
  sample_percentage: "100% betekent alles controleren; lager betekent steekproefsgewijs.",
150
152
  pick_reserve_minutes: "Extra tijd die je altijd vrijhoudt vóór de vervoerder komt.",
@@ -0,0 +1,18 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export interface ShippingNoteRun {
3
+ /** Het aantal aanvragen dat deze ronde is opgepakt. */
4
+ claimed: number;
5
+ /** Aantal aangemaakte verzendbrief-printopdrachten. */
6
+ printed: number;
7
+ /** Aantal aanvragen dat wacht op het officiële Floriday-document. */
8
+ waiting: number;
9
+ /** Aantal aanvragen dat door een tijdelijke storing opnieuw wordt geprobeerd. */
10
+ retrying: number;
11
+ /** Aantal aanvragen met een definitieve fout. */
12
+ failed: number;
13
+ errors: string[];
14
+ }
15
+ export declare function runShippingNoteQueue(sb: SupabaseClient, options?: {
16
+ limit?: number;
17
+ }): Promise<ShippingNoteRun>;
18
+ //# sourceMappingURL=shippingNoteQueue.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shippingNoteQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/shippingNoteQueue.server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAqCD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CAmU1B"}
@@ -0,0 +1,304 @@
1
+ // ============================================================================
2
+ // src/lib/shippingNoteQueue.server.ts
3
+ // Verzendbrief bij het printen van een kar.
4
+ //
5
+ // De pakbon is de enige bron voor kar en printer. De wachtrijregel bewaart
6
+ // alleen de verwijzing naar de pakbon; op het moment dat de printopdracht
7
+ // wordt aangemaakt worden kar en printer uit die pakbon gelezen.
8
+ //
9
+ // BVO-orders krijgen hun eigen layout al vanuit de database. FO-orders (Floriday)
10
+ // komen hier langs: alleen het officiële Floriday-document mag worden geprint.
11
+ // Er wordt niets bevestigd of afgehandeld, en er komen geen omgevings- of
12
+ // klantwaarden in deze code.
13
+ // ============================================================================
14
+ import { trace, newTraceId, classifyError } from "./trace.server.js";
15
+ import { FLOW_NODE } from "./flowNodes.js";
16
+ /** Na dit aantal pogingen is een aanvraag definitief mislukt. */
17
+ const MAX_ATTEMPTS = 60;
18
+ function pickPdf(result) {
19
+ const base64 = result["pdfBase64"] ??
20
+ result["base64"] ??
21
+ result["pdf"] ??
22
+ null;
23
+ const url = result["url"] ??
24
+ result["pdfUrl"] ??
25
+ result["documentUrl"] ??
26
+ null;
27
+ return { base64: base64 ?? null, url: url ?? null };
28
+ }
29
+ /** Bepaalt of een Floriday-antwoord tijdelijk is of "nog niet beschikbaar". */
30
+ function classifyFloridayReason(message) {
31
+ const tijdelijk = /(timeout|time-out|tijdelijk|netwerk|network|rate.?limit|429|50\d|service unavailable|unavailable|opnieuw)/i;
32
+ return tijdelijk.test(message) ? "tijdelijk" : "nog_niet_beschikbaar";
33
+ }
34
+ export async function runShippingNoteQueue(sb, options = {}) {
35
+ const run = {
36
+ claimed: 0,
37
+ printed: 0,
38
+ waiting: 0,
39
+ retrying: 0,
40
+ failed: 0,
41
+ errors: [],
42
+ };
43
+ const { data, error } = await sb.rpc("logistics_slip_note_claim", {
44
+ _limit: options.limit ?? 10,
45
+ _lease_seconds: 120,
46
+ });
47
+ if (error) {
48
+ run.errors.push(`Verzendbrieven niet leesbaar: ${error.message}`);
49
+ return run;
50
+ }
51
+ const rows = Array.isArray(data) ? data : [];
52
+ run.claimed = rows.length;
53
+ if (rows.length === 0)
54
+ return run;
55
+ const { getFlorydayDocument } = await import("./floridayDocuments.server.js");
56
+ for (const row of rows) {
57
+ const attempts = Number(row.attempts ?? 0);
58
+ const traceId = newTraceId();
59
+ const basis = {
60
+ traceId,
61
+ orderRef: row.order_number ?? row.order_id ?? null,
62
+ orderSource: "floriday",
63
+ cartRef: row.cart_id ?? null,
64
+ slipRef: row.slip_job_id ?? null,
65
+ phase: "verzendbrief",
66
+ actor: "logistiek-engine:verzendbriefwachtrij",
67
+ attempts,
68
+ nodeId: FLOW_NODE.stations,
69
+ };
70
+ await trace(sb, {
71
+ ...basis,
72
+ step: "Verzendbriefaanvraag opgepakt",
73
+ status: "geslaagd",
74
+ input: { aanvraagId: row.id, pakbonJobId: row.slip_job_id, pogingen: attempts },
75
+ nextStep: "Officiële Floriday-verzendbrief ophalen",
76
+ });
77
+ const faal = async (code, reden, fulfillmentOrderId) => {
78
+ await sb.rpc("logistics_slip_note_finish", {
79
+ _id: row.id,
80
+ _ok: false,
81
+ _status: "mislukt",
82
+ _fulfillment_order_id: fulfillmentOrderId ?? null,
83
+ _error_code: code,
84
+ _error: reden,
85
+ });
86
+ run.failed++;
87
+ await trace(sb, {
88
+ ...basis,
89
+ step: "Verzendbrief definitief mislukt",
90
+ status: "mislukt",
91
+ decision: code,
92
+ reason: reden,
93
+ error: reden,
94
+ errorClass: classifyError(code, reden),
95
+ nextStep: "Handmatig oplossen; de Engine probeert het niet meer.",
96
+ calc: { values: { pogingen: attempts, maximaal: MAX_ATTEMPTS }, conclusion: reden },
97
+ ...(fulfillmentOrderId ? { externalRef: fulfillmentOrderId } : {}),
98
+ });
99
+ };
100
+ const wacht = async (reden, klasse) => {
101
+ if (attempts >= MAX_ATTEMPTS) {
102
+ await faal("wachten_verlopen", `Na ${attempts} pogingen is er nog steeds geen officiële verzendbrief. Laatste reden: ${reden}`);
103
+ return;
104
+ }
105
+ await sb.rpc("logistics_slip_note_keep_waiting", {
106
+ _id: row.id,
107
+ _reason: reden,
108
+ _class: klasse,
109
+ });
110
+ if (klasse === "tijdelijk")
111
+ run.retrying++;
112
+ else
113
+ run.waiting++;
114
+ await trace(sb, {
115
+ ...basis,
116
+ step: "Wachten op officiële Floriday-verzendbrief",
117
+ status: "wachtend",
118
+ decision: klasse,
119
+ reason: reden,
120
+ errorClass: "extern",
121
+ rule: "FO-orders krijgen uitsluitend het officiële Floriday-document",
122
+ nextStep: "Automatisch opnieuw proberen",
123
+ calc: {
124
+ setting: "Maximaal aantal pogingen voor de verzendbrief",
125
+ values: { poging: attempts, maximaal: MAX_ATTEMPTS },
126
+ conclusion: `Nog ${Math.max(MAX_ATTEMPTS - attempts, 0)} poging(en) over.`,
127
+ },
128
+ });
129
+ };
130
+ try {
131
+ if (!row.order_number) {
132
+ await faal("geen_ordernummer", "Bij deze kar hoort geen ordernummer; de verzendbrief kan niet worden opgehaald.");
133
+ continue;
134
+ }
135
+ // Een verzendbrief ophalen is een leesactie. Wacht daarom niet op de
136
+ // status-/afhandelpush: die is bewust geblokkeerd tot na de controlescan.
137
+ const { data: order, error: orderError } = await sb
138
+ .from("orders")
139
+ .select("floriday_sales_order_id")
140
+ .eq("id", row.order_id ?? "")
141
+ .maybeSingle();
142
+ if (orderError) {
143
+ await wacht(`De Floriday-order kon niet worden gelezen: ${orderError.message}`, "tijdelijk");
144
+ continue;
145
+ }
146
+ const salesOrderId = String(order?.["floriday_sales_order_id"] ?? "").trim();
147
+ if (!salesOrderId) {
148
+ await faal("sales_order_ontbreekt", "Bij deze FO-order ontbreekt het Floriday sales-order-ID; de verzendbrief kan niet worden opgehaald.");
149
+ continue;
150
+ }
151
+ // Stap 1: zorg dat Floriday een officiele verzendbrief heeft. Bestaat er
152
+ // al een fulfillment-order voor deze pakbon, dan wordt er geen tweede
153
+ // aangemaakt.
154
+ let bestaandeFo = String(row.fulfillment_order_id ?? "").trim() || null;
155
+ if (!bestaandeFo) {
156
+ const { createFlorydayDeliveryNote } = await import("./floridayDocuments.server.js");
157
+ const startAanmaak = Date.now();
158
+ const aangemaakt = await createFlorydayDeliveryNote(sb, row.order_number);
159
+ await trace(sb, {
160
+ ...basis,
161
+ step: "Floriday: verzendbrief aanvragen",
162
+ status: aangemaakt.fulfillmentOrderId ? "geslaagd" : aangemaakt.ok ? "wachtend" : "mislukt",
163
+ externalSystem: "floriday",
164
+ externalAction: "fulfillment-order aanmaken",
165
+ ...(aangemaakt.fulfillmentOrderId ? { externalRef: aangemaakt.fulfillmentOrderId } : {}),
166
+ externalResponse: aangemaakt,
167
+ durationMs: Date.now() - startAanmaak,
168
+ ...(aangemaakt.error ? { error: aangemaakt.error } : {}),
169
+ });
170
+ if (aangemaakt.fulfillmentOrderId) {
171
+ bestaandeFo = aangemaakt.fulfillmentOrderId;
172
+ await sb
173
+ .from("logistics_slip_shipping_note")
174
+ .update({ fulfillment_order_id: bestaandeFo })
175
+ .eq("id", row.id)
176
+ .is("fulfillment_order_id", null);
177
+ }
178
+ else if (!aangemaakt.ok) {
179
+ await wacht(`Wachten op Floriday-verzendbrief: ${aangemaakt.error ?? "Floriday heeft het document nog niet aangemaakt."}`, aangemaakt.skipped ? "nog_niet_beschikbaar" : classifyFloridayReason(aangemaakt.error ?? ""));
180
+ continue;
181
+ }
182
+ }
183
+ // Stap 2: het officiele document ophalen.
184
+ const startOphalen = Date.now();
185
+ const doc = (await getFlorydayDocument(sb, {
186
+ kind: "delivery-note",
187
+ salesOrderId,
188
+ ...(bestaandeFo ? { fulfillmentOrderId: bestaandeFo } : {}),
189
+ }));
190
+ await trace(sb, {
191
+ ...basis,
192
+ step: "Floriday: verzendbrief ophalen",
193
+ status: doc["ok"] ? "geslaagd" : "wachtend",
194
+ externalSystem: "floriday",
195
+ externalAction: "delivery-note ophalen",
196
+ ...(bestaandeFo ? { externalRef: bestaandeFo } : {}),
197
+ externalResponse: {
198
+ ok: doc["ok"] ?? false,
199
+ error: doc["error"] ?? null,
200
+ heeftBestand: Boolean(doc["pdfBase64"] ?? doc["base64"] ?? doc["pdf"] ?? doc["url"]),
201
+ },
202
+ durationMs: Date.now() - startOphalen,
203
+ });
204
+ if (!doc["ok"]) {
205
+ const message = String(doc["error"] ?? "") ||
206
+ "Wachten op officiële Floriday-afleverbrief: Floriday heeft het document nog niet aangemaakt.";
207
+ await wacht(message, classifyFloridayReason(message));
208
+ continue;
209
+ }
210
+ const fulfillmentOrderId = String(doc["fulfillmentOrderId"] ?? doc["fulfillment_order_id"] ?? "").trim() ||
211
+ bestaandeFo;
212
+ const { base64, url } = pickPdf(doc);
213
+ if (!base64 && !url) {
214
+ // Nooit een leeg of zelfgemaakt document printen.
215
+ await wacht("Wachten op officiële Floriday-afleverbrief: Floriday gaf nog geen bruikbaar bestand terug.", "nog_niet_beschikbaar");
216
+ continue;
217
+ }
218
+ // De pakbon is de bron voor printer en kar.
219
+ const { data: slip } = await sb
220
+ .from("print_jobs")
221
+ .select("payload, printer_id, documentnaam, is_herprint")
222
+ .eq("id", row.slip_job_id)
223
+ .maybeSingle();
224
+ const slipRow = (slip ?? null);
225
+ if (!slipRow) {
226
+ await faal("pakbon_verdwenen", "De bijbehorende pakbon bestaat niet meer; er wordt geen losse verzendbrief gemaakt.", fulfillmentOrderId);
227
+ continue;
228
+ }
229
+ const slipPayload = slipRow["payload"] ?? {};
230
+ const printerId = slipRow["printer_id"] ?? null;
231
+ const cartId = slipPayload["cart_id"] ?? row.cart_id;
232
+ if (!printerId) {
233
+ await wacht("De pakbon heeft nog geen printer toegewezen gekregen; de verzendbrief wacht op dezelfde printer.", "tijdelijk");
234
+ continue;
235
+ }
236
+ const idempotentie = `verzendbrief-bij-pakbon:${row.slip_job_id}`;
237
+ const { data: bestaand } = await sb
238
+ .from("print_jobs")
239
+ .select("id")
240
+ .eq("idempotentie_sleutel", idempotentie)
241
+ .maybeSingle();
242
+ let jobId = bestaand?.["id"] ?? null;
243
+ if (!jobId) {
244
+ const { data: job, error: jobError } = await sb
245
+ .from("print_jobs")
246
+ .insert({
247
+ printer_id: printerId,
248
+ documenttype: "afleverbrief",
249
+ documentnaam: `Verzendbrief ${row.order_number}`,
250
+ status: "wachtend",
251
+ idempotentie_sleutel: idempotentie,
252
+ pdf_base64: base64,
253
+ pdf_url: url,
254
+ herkomst: "logistiek-engine",
255
+ gebruiker_naam: "Pickstation",
256
+ is_herprint: Boolean(slipRow["is_herprint"] ?? false),
257
+ payload: {
258
+ ...slipPayload,
259
+ source: "pickstation",
260
+ document_type_code: "verzendbrief",
261
+ documentType: "verzendbrief",
262
+ trigger: "with_packing_slip",
263
+ is_floriday: true,
264
+ packing_slip_job_id: row.slip_job_id,
265
+ print_batch_key: row.batch_key ?? `kar-print:${row.slip_job_id}`,
266
+ order_id: row.order_id,
267
+ order_number: row.order_number,
268
+ cart_id: cartId,
269
+ fulfillment_order_id: fulfillmentOrderId,
270
+ },
271
+ })
272
+ .select("id")
273
+ .maybeSingle();
274
+ if (jobError) {
275
+ await wacht(`De verzendbrief kon nog niet worden klaargezet om te printen: ${jobError.message}`, "tijdelijk");
276
+ continue;
277
+ }
278
+ jobId = job?.["id"] ?? null;
279
+ }
280
+ await sb.rpc("logistics_slip_note_finish", {
281
+ _id: row.id,
282
+ _ok: true,
283
+ _status: "geprint",
284
+ _print_job_id: jobId,
285
+ _fulfillment_order_id: fulfillmentOrderId,
286
+ });
287
+ run.printed++;
288
+ await trace(sb, {
289
+ ...basis,
290
+ step: "Verzendbrief klaargezet om te printen",
291
+ status: "geslaagd",
292
+ decision: "samen met de pakbon naar dezelfde printer",
293
+ ...(fulfillmentOrderId ? { externalRef: fulfillmentOrderId } : {}),
294
+ output: { printJobId: jobId, printerId, cartId },
295
+ });
296
+ }
297
+ catch (e) {
298
+ const message = String(e?.message ?? e);
299
+ run.errors.push(message);
300
+ await wacht(`Onverwachte fout bij het ophalen van de verzendbrief: ${message}`, "tijdelijk");
301
+ }
302
+ }
303
+ return run;
304
+ }
@@ -0,0 +1,75 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export type TraceStatus = "geslaagd" | "wachtend" | "waarschuwing" | "overgeslagen" | "mislukt";
3
+ /**
4
+ * Foutsoort — zodat het logboek onderscheid maakt tussen een storing en een
5
+ * bewuste regel.
6
+ * technisch = database/API/printer/integratie ging stuk
7
+ * ontbrekende_gegevens = de order of stamgegevens missen iets
8
+ * configuratie = een instelling of koppeling staat niet goed
9
+ * regel = de Engine mag bewust niet verder (business rule)
10
+ * extern = een extern systeem heeft (nog) niet geleverd
11
+ */
12
+ export type TraceErrorClass = "technisch" | "ontbrekende_gegevens" | "configuratie" | "regel" | "extern";
13
+ /** Berekening achter een beslissing, in begrijpelijke stappen. */
14
+ export interface TraceCalc {
15
+ /** Welke instelling(en) meespeelden. */
16
+ setting?: string;
17
+ /** De gebruikte waarden, bijv. { lagen: 7, maxPerKar: 5 }. */
18
+ values?: Record<string, unknown>;
19
+ /** De rekenstap zelf, bijv. "7 / 5". */
20
+ formula?: string;
21
+ /** De uitkomst, bijv. "1 volle kar + 1 deelkar". */
22
+ result?: string;
23
+ /** Conclusie in gewone taal. */
24
+ conclusion?: string;
25
+ }
26
+ export interface TraceEvent {
27
+ traceId?: string | null;
28
+ orderRef?: string | null;
29
+ orderSource?: "floriday" | "eigen" | null;
30
+ cartRef?: string | null;
31
+ slipRef?: string | null;
32
+ phase: string;
33
+ step: string;
34
+ status: TraceStatus;
35
+ actor?: string;
36
+ /** Vakje in de flowkaart waar deze stap hoort (id uit flowTree). */
37
+ nodeId?: string;
38
+ input?: unknown;
39
+ output?: unknown;
40
+ reads?: unknown;
41
+ decision?: string;
42
+ reason?: string;
43
+ values?: unknown;
44
+ rule?: string;
45
+ /** Berekening achter de beslissing. */
46
+ calc?: TraceCalc;
47
+ /** Wat de order hierna gaat doen. */
48
+ nextStep?: string;
49
+ errorClass?: TraceErrorClass;
50
+ dbTable?: string;
51
+ dbRecord?: string;
52
+ dbAction?: string;
53
+ dbOld?: unknown;
54
+ dbNew?: unknown;
55
+ externalSystem?: string;
56
+ externalAction?: string;
57
+ externalRef?: string;
58
+ externalStatus?: string;
59
+ externalResponse?: unknown;
60
+ error?: string;
61
+ attempts?: number;
62
+ nextAttemptAt?: string | null;
63
+ durationMs?: number;
64
+ }
65
+ /** Bepaalt de foutsoort uit een reden-code of foutmelding. */
66
+ export declare function classifyError(reasonCode?: string | null, message?: string | null): TraceErrorClass;
67
+ /** Nieuw trace-id voor één volledige verwerkingsronde van een order. */
68
+ export declare function newTraceId(): string;
69
+ /** Eén gebeurtenis vastleggen. Faalt nooit hard. */
70
+ export declare function trace(sb: SupabaseClient, event: TraceEvent): Promise<void>;
71
+ /** Meerdere gebeurtenissen in één keer vastleggen. */
72
+ export declare function traceBatch(sb: SupabaseClient, events: TraceEvent[]): Promise<void>;
73
+ /** Meet de duur van een stap en legt uitkomst of fout vast. */
74
+ export declare function traced<T>(sb: SupabaseClient, event: Omit<TraceEvent, "status">, run: () => Promise<T>): Promise<T>;
75
+ //# sourceMappingURL=trace.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.server.d.ts","sourceRoot":"","sources":["../../src/lib/trace.server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ // ============================================================================
2
+ // src/lib/trace.server.ts — audittrail vanuit de Engine zelf
3
+ // ============================================================================
4
+ // Elke stap, beslissing, databasewijziging en externe aanvraag wordt hier
5
+ // vastgelegd via public.logistics_trace. Loggen mag de verwerking nooit
6
+ // blokkeren: fouten worden bewust ingeslikt.
7
+ // ============================================================================
8
+ /** Bepaalt de foutsoort uit een reden-code of foutmelding. */
9
+ export function classifyError(reasonCode, message) {
10
+ const t = `${reasonCode ?? ""} ${message ?? ""}`.toLowerCase();
11
+ if (/afmeting|ontbreek|onbekend|geen regels|mist|niet gevuld|leeg/.test(t))
12
+ return "ontbrekende_gegevens";
13
+ if (/instelling|configurat|layout|mapping|niet ingesteld|werktijden/.test(t))
14
+ return "configuratie";
15
+ if (/kargrens|regel|niet toegestaan|geblokkeerd|vrijgave|aanmeldmoment|bevroren/.test(t))
16
+ return "regel";
17
+ if (/floriday|api|http|timeout|extern|printer/.test(t))
18
+ return "extern";
19
+ return "technisch";
20
+ }
21
+ /** Nieuw trace-id voor één volledige verwerkingsronde van een order. */
22
+ export function newTraceId() {
23
+ return globalThis.crypto?.randomUUID?.() ?? "";
24
+ }
25
+ function clean(event) {
26
+ const out = {};
27
+ for (const [key, value] of Object.entries(event)) {
28
+ if (value !== undefined && value !== null && value !== "")
29
+ out[key] = value;
30
+ }
31
+ return out;
32
+ }
33
+ /** Eén gebeurtenis vastleggen. Faalt nooit hard. */
34
+ export async function trace(sb, event) {
35
+ try {
36
+ await sb.rpc("logistics_trace", { p: clean(event) });
37
+ }
38
+ catch {
39
+ /* loggen mag de verwerking niet blokkeren */
40
+ }
41
+ }
42
+ /** Meerdere gebeurtenissen in één keer vastleggen. */
43
+ export async function traceBatch(sb, events) {
44
+ if (!Array.isArray(events) || events.length === 0)
45
+ return;
46
+ try {
47
+ await sb.rpc("logistics_trace_batch", { p: events.map(clean) });
48
+ }
49
+ catch {
50
+ /* loggen mag de verwerking niet blokkeren */
51
+ }
52
+ }
53
+ /** Meet de duur van een stap en legt uitkomst of fout vast. */
54
+ export async function traced(sb, event, run) {
55
+ const start = Date.now();
56
+ try {
57
+ const result = await run();
58
+ await trace(sb, {
59
+ ...event,
60
+ status: "geslaagd",
61
+ durationMs: Date.now() - start,
62
+ output: event.output ?? result,
63
+ });
64
+ return result;
65
+ }
66
+ catch (e) {
67
+ await trace(sb, {
68
+ ...event,
69
+ status: "mislukt",
70
+ durationMs: Date.now() - start,
71
+ error: String(e?.message ?? e),
72
+ });
73
+ throw e;
74
+ }
75
+ }
@@ -0,0 +1,19 @@
1
+ import { type NodeTraceGroep } from "./nodeTrace";
2
+ export interface VakUitleg {
3
+ /** Welke keuze de Engine hier maakte. */
4
+ beslissing: string;
5
+ /** Waarom die keuze is gemaakt. */
6
+ waarom: string | null;
7
+ /** De bepalende gegevens en instellingen, als korte paren. */
8
+ feiten: string[];
9
+ /** Regel/instelling waarop de keuze steunt. */
10
+ regel: string | null;
11
+ /** Is dit afgeleid uit de registraties in plaats van vastgelegd? */
12
+ afgeleid: boolean;
13
+ }
14
+ /**
15
+ * Maakt van de gebeurtenissen van één vakje een vaste uitleg:
16
+ * welke keuze is gemaakt, waarom, en welke gegevens dat bepaalden.
17
+ */
18
+ export declare function vakUitleg(groep: NodeTraceGroep): VakUitleg;
19
+ //# sourceMappingURL=vakUitleg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vakUitleg.d.ts","sourceRoot":"","sources":["../../src/lib/vakUitleg.ts"],"names":[],"mappings":"AASA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEjE,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;CACnB;AA6DD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,CAoD1D"}