@flowselections/layout-maker 1.38.4 → 1.45.8

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 (124) hide show
  1. package/README.md +139 -139
  2. package/dist-lib/components/AfdrukKnop.d.ts +19 -19
  3. package/dist-lib/components/AfleverbriefBuilderPage.d.ts +10 -0
  4. package/dist-lib/components/AfleverbriefBuilderPage.d.ts.map +1 -0
  5. package/dist-lib/components/AfleverbriefBuilderPage.js +101 -0
  6. package/dist-lib/components/BlokOntwerperPage.d.ts.map +1 -1
  7. package/dist-lib/components/BlokOntwerperPage.js +8 -3
  8. package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
  9. package/dist-lib/components/ComputersLijst.js +1 -1
  10. package/dist-lib/components/FustKolomVolgorde.d.ts +11 -0
  11. package/dist-lib/components/FustKolomVolgorde.d.ts.map +1 -0
  12. package/dist-lib/components/FustKolomVolgorde.js +52 -0
  13. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  14. package/dist-lib/components/LayoutsPage.js +10 -9
  15. package/dist-lib/components/NetwerkPrintersDialog.d.ts +7 -7
  16. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  17. package/dist-lib/components/PakbonBuilderPage.js +32 -14
  18. package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
  19. package/dist-lib/components/PakbonPreview.js +21 -14
  20. package/dist-lib/components/PakbonSectiesPanel.d.ts +4 -2
  21. package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
  22. package/dist-lib/components/PakbonSectiesPanel.js +5 -3
  23. package/dist-lib/components/PdfMapToestemmingBanner.d.ts +2 -1
  24. package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -1
  25. package/dist-lib/components/PdfMapToestemmingBanner.js +73 -14
  26. package/dist-lib/components/PdfVoorbeeld.d.ts +20 -0
  27. package/dist-lib/components/PdfVoorbeeld.d.ts.map +1 -0
  28. package/dist-lib/components/PdfVoorbeeld.js +95 -0
  29. package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -1
  30. package/dist-lib/components/PrintProgrammaUitleg.js +1 -1
  31. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  32. package/dist-lib/components/PrintQueuePage.js +81 -43
  33. package/dist-lib/components/PrinterSetupWizard.js +3 -3
  34. package/dist-lib/components/PrintersRedirectPage.d.ts +1 -1
  35. package/dist-lib/components/PrintersRedirectPage.js +14 -14
  36. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  37. package/dist-lib/components/PrintplekDetailPage.js +2 -2
  38. package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
  39. package/dist-lib/components/PrintplekWizard.js +6 -2
  40. package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
  41. package/dist-lib/components/ProductiebonBuilderPage.js +13 -7
  42. package/dist-lib/index.d.ts +13 -5
  43. package/dist-lib/index.d.ts.map +1 -1
  44. package/dist-lib/index.js +10 -5
  45. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2008 -118
  46. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  47. package/dist-lib/integrations/supabase/client.server.d.ts +2008 -118
  48. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  49. package/dist-lib/integrations/supabase/client.server.js +1 -1
  50. package/dist-lib/integrations/supabase/moduleClient.d.ts +2008 -118
  51. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  52. package/dist-lib/integrations/supabase/types.d.ts +2031 -99
  53. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  54. package/dist-lib/integrations/supabase/types.js +1 -0
  55. package/dist-lib/lib/aiLayout.functions.d.ts +2008 -118
  56. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  57. package/dist-lib/lib/aiLayout.server.js +9 -9
  58. package/dist-lib/lib/browserPrint.js +1 -1
  59. package/dist-lib/lib/documentVoorbeeld.functions.d.ts +23 -0
  60. package/dist-lib/lib/documentVoorbeeld.functions.d.ts.map +1 -0
  61. package/dist-lib/lib/documentVoorbeeld.functions.js +37 -0
  62. package/dist-lib/lib/fontMetrics.d.ts +15 -0
  63. package/dist-lib/lib/fontMetrics.d.ts.map +1 -0
  64. package/dist-lib/lib/fontMetrics.js +118 -0
  65. package/dist-lib/lib/htmlNaarPdf.server.d.ts +2 -2
  66. package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
  67. package/dist-lib/lib/htmlNaarPdf.server.js +2 -1
  68. package/dist-lib/lib/htmlPdf.server.d.ts +11 -0
  69. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  70. package/dist-lib/lib/htmlPdf.server.js +118 -15
  71. package/dist-lib/lib/layoutPreview.js +7 -7
  72. package/dist-lib/lib/orderData.server.d.ts.map +1 -1
  73. package/dist-lib/lib/orderData.server.js +43 -16
  74. package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts +39 -0
  75. package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts.map +1 -0
  76. package/dist-lib/lib/pakbonBarcodeVerzoek.js +80 -0
  77. package/dist-lib/lib/pakbonBuilder.d.ts +62 -3
  78. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  79. package/dist-lib/lib/pakbonBuilder.js +386 -50
  80. package/dist-lib/lib/pakbonContent.d.ts +41 -0
  81. package/dist-lib/lib/pakbonContent.d.ts.map +1 -0
  82. package/dist-lib/lib/pakbonContent.js +668 -0
  83. package/dist-lib/lib/pakbonDocument.d.ts +199 -0
  84. package/dist-lib/lib/pakbonDocument.d.ts.map +1 -0
  85. package/dist-lib/lib/pakbonDocument.js +735 -0
  86. package/dist-lib/lib/pakbonHtml.d.ts +7 -0
  87. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  88. package/dist-lib/lib/pakbonHtml.js +142 -126
  89. package/dist-lib/lib/pakbonPresentation.d.ts +8 -0
  90. package/dist-lib/lib/pakbonPresentation.d.ts.map +1 -0
  91. package/dist-lib/lib/pakbonPresentation.js +31 -0
  92. package/dist-lib/lib/pakbonScan.d.ts.map +1 -1
  93. package/dist-lib/lib/pakbonScan.js +20 -38
  94. package/dist-lib/lib/pdfJobSaver.d.ts +10 -6
  95. package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -1
  96. package/dist-lib/lib/pdfJobSaver.js +302 -99
  97. package/dist-lib/lib/pdfMap.d.ts +37 -2
  98. package/dist-lib/lib/pdfMap.d.ts.map +1 -1
  99. package/dist-lib/lib/pdfMap.js +120 -7
  100. package/dist-lib/lib/pdfOpslagStatus.d.ts +23 -0
  101. package/dist-lib/lib/pdfOpslagStatus.d.ts.map +1 -0
  102. package/dist-lib/lib/pdfOpslagStatus.js +74 -0
  103. package/dist-lib/lib/printApi.d.ts +31 -0
  104. package/dist-lib/lib/printApi.d.ts.map +1 -1
  105. package/dist-lib/lib/printApi.js +62 -1
  106. package/dist-lib/lib/printQueue.server.d.ts +6 -0
  107. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  108. package/dist-lib/lib/printQueue.server.js +450 -94
  109. package/dist-lib/lib/printService.functions.d.ts +7916 -356
  110. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  111. package/dist-lib/lib/productiebonHtml.js +15 -15
  112. package/dist-lib/lib/profielHtml.d.ts.map +1 -1
  113. package/dist-lib/lib/profielHtml.js +26 -19
  114. package/dist-lib/lib/supabaseAdmin.server.d.ts +5 -5
  115. package/dist-lib/lib/supabaseAdmin.server.js +43 -43
  116. package/dist-lib/lib/testpagina.js +3 -3
  117. package/dist-lib/lib/testprint.js +4 -4
  118. package/dist-lib/lib/useDocumentData.d.ts +8 -0
  119. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  120. package/dist-lib/lib/useDocumentData.js +1 -1
  121. package/dist-lib/lib/voorbeeldPrint.d.ts +3 -0
  122. package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
  123. package/dist-lib/lib/voorbeeldPrint.js +65 -17
  124. package/package.json +158 -151
@@ -32,6 +32,13 @@ export interface PakbonRenderOpties {
32
32
  logoId?: string | null;
33
33
  /** Variant die uitsluitend door de Logistics Engine wordt bepaald. */
34
34
  layoutVariant?: string | null;
35
+ /** Laat de vaste paginavoet weg (voor een tweede voorbeeldvariant). */
36
+ zonderPaginavoet?: boolean;
37
+ /**
38
+ * Alleen voor "Voorbeeld printen": toont na de hele-karpagina's ook een
39
+ * deelkarpagina, net als het voorbeeld op het scherm.
40
+ */
41
+ voorbeeldBeideVarianten?: boolean;
35
42
  }
36
43
  export declare function esc(v: unknown): string;
37
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"pakbonHtml.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonHtml.ts"],"names":[],"mappings":"AAUA,OAAO,EAoBL,KAAK,SAAS,EAEd,KAAK,YAAY,EAGlB,MAAM,iBAAiB,CAAC;AAKzB,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAWD,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAKtC;AAyBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAiF3D;AAgrBD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,MAAM,CA+CR;AAgBD,gEAAgE;AAChE,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,MAAM,CAoER;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,IAAI,WAAW,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,IAAI,CAsCN;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAUf"}
1
+ {"version":3,"file":"pakbonHtml.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonHtml.ts"],"names":[],"mappings":"AAUA,OAAO,EAwBL,KAAK,SAAS,EAEd,KAAK,YAAY,EAGlB,MAAM,iBAAiB,CAAC;AAMzB,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAWD,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAKtC;AAyBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAqF3D;AA4rBD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,MAAM,CAyDR;AAgBD,gEAAgE;AAChE,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,MAAM,CAkFR;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,IAAI,WAAW,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,IAAI,CAsCN;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAUf"}
@@ -7,9 +7,10 @@
7
7
  // layoutconfiguratie en de echte ordergegevens. Zo tonen het live voorbeeld en
8
8
  // de afdruk altijd exact dezelfde secties — inclusief de orderregels.
9
9
  // ============================================================================
10
- import { DEMO_ORDER, conditieContext, groepeerIdentiekeKarren, groepeerIdentiekeLagen, karBundelTekst, fustVerzamellijst, pickMethode, pakbonLayoutVariant, productVeldBreedtes, sectieOnderdruktVoorVariant, laagBundelTekst, leesPakbonConfig, sectieZichtbaar, sorteerProducten, totalen, vulVeldcodes, } from "./pakbonBuilder.js";
10
+ import { DEMO_ORDER, deelkarVoorbeeldOrder, conditieContext, groepeerIdentiekeKarren, groepeerIdentiekeLagen, karBundelTekst, fustVerzamellijst, fustRegels, FUSTREGEL_LABELS, FUSTREGEL_RECHTS, pickMethode, pakbonLayoutVariant, productVeldBreedtes, sectieOnderdruktVoorVariant, laagBundelTekst, leesPakbonConfig, sectieZichtbaar, sorteerProducten, totalen, vulVeldcodes, } from "./pakbonBuilder.js";
11
11
  import { haalPrintLogos } from "./logoLibrary.js";
12
12
  import { code128BarsHtml } from "./code128.js";
13
+ import { karMetadata } from "./pakbonPresentation.js";
13
14
  // --- kleine hulpjes ---------------------------------------------------------
14
15
  const arr = (v) => (Array.isArray(v) ? v : []);
15
16
  const opt = (s, key, fallback) => s.opties?.[key] ?? fallback;
@@ -65,11 +66,13 @@ export function maakPakbonOrder(input) {
65
66
  route: String(k["route"] ?? ""),
66
67
  chauffeur: String(k["chauffeur"] ?? ""),
67
68
  gewicht: String(k["gewicht"] ?? ""),
68
- cart_label: String(k["cart_label"] ?? cart["cart_label"] ?? "").trim() || undefined,
69
- cart_index: Number(k["cart_index"] ?? cart["cart_index"] ?? 0) || undefined,
70
- cart_total: Number(k["cart_total"] ?? cart["cart_total"] ?? 0) || undefined,
71
- cart_id: String(k["cart_id"] ?? cart["cart_id"] ?? "").trim() || undefined,
72
- cart_items: Array.isArray(k["cart_items"] ?? cart["cart_items"]) ? (k["cart_items"] ?? cart["cart_items"]) : undefined,
69
+ cart_label: String(k["cart_label"] ?? k["cartLabel"] ?? cart["cart_label"] ?? cart["cartLabel"] ?? "").trim() || undefined,
70
+ cart_index: Number(k["cart_index"] ?? k["cartIndex"] ?? cart["cart_index"] ?? cart["cartIndex"] ?? 0) || undefined,
71
+ cart_total: Number(k["cart_total"] ?? k["cartTotal"] ?? cart["cart_total"] ?? cart["cartTotal"] ?? 0) || undefined,
72
+ cart_id: String(k["cart_id"] ?? k["cartId"] ?? cart["cart_id"] ?? cart["cartId"] ?? "").trim() || undefined,
73
+ cart_items: Array.isArray(k["cart_items"] ?? k["items"] ?? cart["cart_items"] ?? cart["items"])
74
+ ? (k["cart_items"] ?? k["items"] ?? cart["cart_items"] ?? cart["items"])
75
+ : undefined,
73
76
  gedeeld: k["gedeeld"] === true,
74
77
  lagen: arr(k["lagen"]).map((l, j) => ({
75
78
  laagnummer: Number(l["laagnummer"] ?? j + 1),
@@ -118,11 +121,13 @@ export function maakPakbonOrder(input) {
118
121
  transport: groep("transport", ["transporteur", "route", "chauffeur", "track"]),
119
122
  barcode: topBarcode || undefined,
120
123
  cart: Object.keys(cart).length ? {
121
- cart_label: String(cart["cart_label"] ?? "").trim() || undefined,
122
- cart_index: Number(cart["cart_index"] ?? 0) || undefined,
123
- cart_total: Number(cart["cart_total"] ?? 0) || undefined,
124
- cart_id: String(cart["cart_id"] ?? "").trim() || undefined,
125
- cart_items: Array.isArray(cart["cart_items"]) ? cart["cart_items"] : undefined,
124
+ cart_label: String(cart["cart_label"] ?? cart["cartLabel"] ?? "").trim() || undefined,
125
+ cart_index: Number(cart["cart_index"] ?? cart["cartIndex"] ?? 0) || undefined,
126
+ cart_total: Number(cart["cart_total"] ?? cart["cartTotal"] ?? 0) || undefined,
127
+ cart_id: String(cart["cart_id"] ?? cart["cartId"] ?? "").trim() || undefined,
128
+ cart_items: Array.isArray(cart["cart_items"] ?? cart["items"])
129
+ ? (cart["cart_items"] ?? cart["items"])
130
+ : undefined,
126
131
  barcode: String(cart["barcode"] ?? "").trim() || undefined,
127
132
  } : undefined,
128
133
  karren,
@@ -346,27 +351,7 @@ function karKop(s, kar, velden, bundelTekst = "") {
346
351
  .replace(/\{chauffeur\}/g, kar.chauffeur)
347
352
  .replace(/\{lagen\}/g, String(kar.lagen.length))
348
353
  .replace(/\{producten\}/g, String(kar.lagen.reduce((n, l) => n + l.producten.length, 0)));
349
- const info = [];
350
- if (velden.includes("lagen"))
351
- info.push(`${kar.lagen.length} lagen`);
352
- if (velden.includes("producten"))
353
- info.push(`${kar.lagen.reduce((n, l) => n + l.producten.reduce((m, p) => m + p.aantal, 0), 0)} producten`);
354
- if (velden.includes("gewicht") && kar.gewicht)
355
- info.push(kar.gewicht);
356
- if (velden.includes("chauffeur") && kar.chauffeur)
357
- info.push(kar.chauffeur);
358
- if (velden.includes("route") && kar.route)
359
- info.push(kar.route);
360
- if (kar.gedeeld)
361
- info.push("gedeelde kar");
362
- const cartLabel = kar.cart_label ||
363
- (kar.cart_index && kar.cart_total ? `Kar ${kar.cart_index} van ${kar.cart_total}` : "");
364
- if (cartLabel)
365
- info.push(cartLabel);
366
- if (kar.cart_id)
367
- info.push(`ID ${kar.cart_id}`);
368
- if (kar.cart_items?.length)
369
- info.push(`${kar.cart_items.length} karregels`);
354
+ const info = karMetadata(kar, velden);
370
355
  const toonNummer = velden.includes("karnummer");
371
356
  if (!toonNummer && !info.length && !bundelTekst)
372
357
  return "";
@@ -384,31 +369,7 @@ function karKop(s, kar, velden, bundelTekst = "") {
384
369
  ]
385
370
  .filter(Boolean)
386
371
  .join(" ");
387
- return `<div class="karkop" style="${stijl}"><span>${links}</span><span class="meta">${info
388
- .map((t) => `<span>${esc(t)}</span>`)
389
- .join("")}</span></div>`;
390
- }
391
- function cartRegelsHtml(kar) {
392
- const regels = arr(kar.cart_items);
393
- if (!regels.length)
394
- return "";
395
- const velden = [
396
- ["artikelnummer", "Artikel"],
397
- ["artikelnaam", "Omschrijving"],
398
- ["omschrijving", "Omschrijving"],
399
- ["aantal", "Aantal"],
400
- ["eenheid", "Eenheid"],
401
- ];
402
- const rijen = regels.map((regel) => {
403
- const waarden = velden
404
- .map(([sleutel]) => String(regel[sleutel] ?? "").trim())
405
- .filter(Boolean);
406
- const tekst = waarden.length
407
- ? waarden.map((waarde) => `<span>${esc(waarde)}</span>`).join(" ")
408
- : Object.values(regel).map((waarde) => `<span>${esc(String(waarde ?? ""))}</span>`).join(" ");
409
- return `<div class="cartregel">${tekst}</div>`;
410
- });
411
- return `<div class="cartregels"><div class="vet">Karregels</div>${rijen.join("")}</div>`;
372
+ return `<div class="karkop" style="${stijl}"><div class="karkop-titel">${links}</div>${info.length ? `<div class="karkop-meta">${esc(info.join(" · "))}</div>` : ""}</div>`;
412
373
  }
413
374
  function laagKop(s, laag, velden, compact, bundelTekst = "") {
414
375
  const tekst = optS(s, "koptekst", "Laag {laag}").replace(/\{laag\}/g, String(laag.laagnummer));
@@ -427,7 +388,7 @@ function laagKop(s, laag, velden, compact, bundelTekst = "") {
427
388
  info.push(laag.opmerking);
428
389
  if (!velden.includes("laagnummer") && !info.length && !bundelTekst)
429
390
  return "";
430
- return `<div class="laagkop${compact ? " compact" : ""}"><span>${velden.includes("laagnummer") ? esc(tekst) : ""}${bundelTekst ? ` <span class="bundel">${esc(bundelTekst)}</span>` : ""}</span><span class="meta">${info.map((t) => `<span>${esc(t)}</span>`).join("")}</span></div>`;
391
+ return `<div class="laagkop${compact ? " compact" : ""}"><div class="laagkop-titel">${velden.includes("laagnummer") ? esc(tekst) : ""}${bundelTekst ? ` <span class="bundel">${esc(bundelTekst)}</span>` : ""}</div>${info.length ? `<div class="laagkop-meta">${esc(info.join(" · "))}</div>` : ""}</div>`;
431
392
  }
432
393
  function bundelMelding(tekst) {
433
394
  return `<div class="bundel">${esc(tekst)}</div>`;
@@ -442,7 +403,11 @@ function karBlok(s, kar, lagen, zoek, omkaderd, aantal = 1) {
442
403
  const fustSectie = zoek("fusten");
443
404
  const lagenModus = lagenSectie ? optS(lagenSectie, "modus", "apart") : "geen";
444
405
  let inhoud = karKop(s, kar, velden, karBundelTekst(aantal));
445
- inhoud += cartRegelsHtml(kar);
406
+ // De Engine-cartregels zijn selectie-/controlegegevens. De zichtbare
407
+ // productregels komen uitsluitend uit de ingestelde lagen/productsectie,
408
+ // net als in het live voorbeeld.
409
+ if (kar.barcode)
410
+ inhoud += barcodeHtml(kar.barcode);
446
411
  if (lagen.length && lagenSectie && lagenModus !== "geen") {
447
412
  const lVelden = lijst(lagenSectie, "velden");
448
413
  const toonProducten = lagenModus !== "nummer" && lagenModus !== "regel";
@@ -460,10 +425,6 @@ function karBlok(s, kar, lagen, zoek, omkaderd, aantal = 1) {
460
425
  }
461
426
  if (fustSectie && optS(fustSectie, "modus", "totaal") === "kar")
462
427
  inhoud += fustTabel(lijst(fustSectie, "velden"), lagen.flatMap((l) => l.fusten), `Fusten kar ${kar.karnummer}`);
463
- // Een volle-karpakbon kan meerdere karren/pagina's bevatten. De barcode
464
- // hoort daarom in het eigen karblok en niet één keer onderaan de serie.
465
- if (kar.barcode)
466
- inhoud += barcodeHtml(kar.barcode);
467
428
  return `<div class="karblok${omkaderd ? " omkaderd" : ""}">${inhoud}</div>`;
468
429
  }
469
430
  const FUST_KOLOM_LABELS = {
@@ -475,9 +436,10 @@ const FUST_KOLOM_LABELS = {
475
436
  locatie: "Locatie",
476
437
  fustsoort: "Tray/fust",
477
438
  planten_per_fust: "Pl./fust",
439
+ fust_aantal: "Fusten",
478
440
  aantal: "Planten",
479
441
  };
480
- const FUST_RECHTS = new Set(["planten_per_fust", "aantal"]);
442
+ const FUST_RECHTS = new Set(["planten_per_fust", "fust_aantal", "aantal"]);
481
443
  /** Verzamellijst met alle te picken fusten per fusttype. */
482
444
  function fustVerzamellijstHtml(order, s) {
483
445
  const groepen = fustVerzamellijst(order?.karren);
@@ -514,7 +476,9 @@ function fustVerzamellijstHtml(order, s) {
514
476
  : "";
515
477
  return `${kopTekst ? `<div class="sectitel">${esc(kopTekst)}</div>` : ""}${blokken}${totaalHtml}`;
516
478
  }
517
- function karrenHtml(s, order, zoek) {
479
+ function karrenHtml(s, order, zoek,
480
+ /** Kop die op iedere nieuwe karpagina wordt herhaald (HELE KAR / DEELKAR). */
481
+ paginaKop = "") {
518
482
  const modus = optS(s, "modus", "pagina");
519
483
  if (modus === "geen")
520
484
  return "";
@@ -538,13 +502,13 @@ function karrenHtml(s, order, zoek) {
538
502
  const laagGroepen = groepeerIdentiekeLagen(lagen, String(lagenModus) === "gebundeld");
539
503
  laagGroepen.forEach((lg, j) => {
540
504
  const breek = i > 0 || j > 0;
541
- delen.push(`<div class="${breek ? "breekvoor" : ""}">${blokFrame(s, karBlok(s, kar, [lg.laag], zoek, modus === "blok" || modus === "passend", groep.aantal))}</div>`);
505
+ delen.push(`<div class="${breek ? "breekvoor" : ""}">${breek ? paginaKop : ""}${blokFrame(s, karBlok(s, kar, [lg.laag], zoek, modus === "blok" || modus === "passend", groep.aantal))}</div>`);
542
506
  });
543
507
  return;
544
508
  }
545
509
  const breek = i > 0 && perPagina;
546
510
  const scheider = i > 0 && !perPagina ? scheidingHtml(scheiding) : "";
547
- delen.push(`<div class="${breek ? "breekvoor" : ""} ${modus === "passend" ? "heelhouden" : ""}">${scheider}${blokFrame(s, karBlok(s, kar, lagen, zoek, modus === "blok" || modus === "passend", groep.aantal))}</div>`);
511
+ delen.push(`<div class="${breek ? "breekvoor" : ""} ${modus === "passend" ? "heelhouden" : ""}">${breek ? paginaKop : ""}${scheider}${blokFrame(s, karBlok(s, kar, lagen, zoek, modus === "blok" || modus === "passend", groep.aantal))}</div>`);
548
512
  });
549
513
  return delen.join("");
550
514
  }
@@ -629,6 +593,36 @@ function sectieHtml(s, order, zoek, opties) {
629
593
  .join("");
630
594
  return titelHtml(s) + body;
631
595
  }
596
+ case "fustregels": {
597
+ const velden = lijst(s, "velden").filter((v) => FUSTREGEL_LABELS[v]);
598
+ if (!velden.length)
599
+ return "";
600
+ const regels = fustRegels(order.karren, {
601
+ comprimeren: opt(s, "comprimeren", true) !== false,
602
+ sortering: optS(s, "sortering", "fustsoort"),
603
+ });
604
+ if (!regels.length)
605
+ return "";
606
+ const randen = opt(s, "randen", true) !== false;
607
+ const zebra = !!opt(s, "zebra", false);
608
+ const cls = randen ? "onder" : "";
609
+ const kop = opt(s, "toonKoppen", true) !== false
610
+ ? `<tr>${velden
611
+ .map((v) => `<th class="${cls}"${FUSTREGEL_RECHTS.has(v) ? ' style="text-align:right"' : ""}>${esc(FUSTREGEL_LABELS[v])}</th>`)
612
+ .join("")}</tr>`
613
+ : "";
614
+ const rijen = regels
615
+ .map((r, i) => `<tr${zebra && i % 2 === 1 ? ' style="background:#f4f4f4"' : ""}>${velden
616
+ .map((v) => `<td class="${cls}"${FUSTREGEL_RECHTS.has(v) ? ' style="text-align:right"' : ""}>${esc(String(r[v] ?? ""))}</td>`)
617
+ .join("")}</tr>`)
618
+ .join("");
619
+ const totaalFusten = regels.reduce((n, r) => n + r.fust_aantal, 0);
620
+ const totaalPlanten = regels.reduce((n, r) => n + r.aantal, 0);
621
+ const totaal = opt(s, "toonTotaal", true) !== false
622
+ ? `<div class="totalen" style="justify-content:flex-end"><span>${totaalFusten} fusten</span><span>${totaalPlanten} planten</span></div>`
623
+ : "";
624
+ return `${titelHtml(s)}<table class="regels">${kop}${rijen}</table>${totaal}`;
625
+ }
632
626
  case "pickmethode":
633
627
  if (optS(s, "methode", "kar") === "kar")
634
628
  return "";
@@ -700,18 +694,26 @@ export function renderPakbonBody(config, order, opties = {}) {
700
694
  const inhoud = secties
701
695
  .filter((s) => !(s.type === "totalen" && totalenElkePagina))
702
696
  .filter((s) => !(s.type === "barcode" && heeftKarBarcodes))
703
- .map((s) => s.type === "karren" ? karrenHtml(s, order, zoek) : blokFrame(s, sectieHtml(s, order, zoek, opts)))
697
+ .map((s) => s.type === "karren"
698
+ ? karrenHtml(s, order, zoek, variantKop)
699
+ : blokFrame(s, sectieHtml(s, order, zoek, opts)))
704
700
  .join("");
705
701
  const pickSectie = alleSecties.find((s) => s.type === "pickmethode");
706
702
  const pickInstellingen = pickSectie ?? alleSecties[0];
707
703
  // Elke pakbon krijgt de Engine-barcode wanneer die is aangeleverd. Een
708
704
  // expliciet barcodeblok rendert hem zelf; anders voegen we hem één keer
709
705
  // automatisch toe. Zonder Engine-barcode wordt nooit een waarde verzonnen.
710
- const automatischeBarcode = !heeftKarBarcodes && !secties.some((s) => s.type === "barcode");
706
+ // De schakelaar staat op het pickmethodeblok (pakbon) of het
707
+ // handtekeningblok (afleverbrief); standaard staat de barcode aan.
708
+ const barcodeSchakelaarSectie = pickSectie ?? alleSecties.find((s) => s.type === "handtekening");
709
+ const barcodeAan = barcodeSchakelaarSectie
710
+ ? opt(barcodeSchakelaarSectie, "toonBarcode", true) !== false
711
+ : true;
712
+ const automatischeBarcode = barcodeAan && !heeftKarBarcodes && !secties.some((s) => s.type === "barcode");
711
713
  const barcode = automatischeBarcode
712
714
  ? barcodeHtml(pakbonBarcode(order), Number(pickInstellingen ? opt(pickInstellingen, "barcodeHoogte", 15) : 15))
713
715
  : "";
714
- const voet = totalenElkePagina && totalenSectie
716
+ const voet = totalenElkePagina && totalenSectie && !opties.zonderPaginavoet
715
717
  ? `<div class="paginavoet">${sectieHtml(totalenSectie, order, zoek, opts)}</div>`
716
718
  : "";
717
719
  return kop + inhoud + (barcode ? `<div class="blok">${barcode}</div>` : "") + voet;
@@ -733,66 +735,80 @@ export function renderPakbonDocument(config, order, opties = {}) {
733
735
  const marge = opties.margeMm ?? 12;
734
736
  const font = opties.lettertype ?? 'Arial, Helvetica, "Segoe UI", sans-serif';
735
737
  const grootte = opties.lettergrootte ?? 8.5;
736
- const body = renderPakbonBody(config, order, opties);
738
+ let body = renderPakbonBody(config, order, opties);
739
+ if (opties.voorbeeldBeideVarianten) {
740
+ // Zelfde opbouw als het voorbeeld op het scherm: eerst de hele karren,
741
+ // daarna één deelkarpagina zonder karindeling.
742
+ const deel = renderPakbonBody(config, deelkarVoorbeeldOrder(order), {
743
+ ...opties,
744
+ layoutVariant: "partial_order",
745
+ zonderPaginavoet: true,
746
+ });
747
+ body = renderPakbonBody(config, order, { ...opties, layoutVariant: "full_cart" }) +
748
+ `<div class="breekvoor">${deel}</div>`;
749
+ }
737
750
  // De layout bepaalt of er paginanummers op de afdruk komen; de PDF-motor
738
751
  // leest dit uit de meta, zodat de wachtrij niets extra hoeft door te geven.
739
752
  const totalen = arr(leesPakbonConfig(config).secties).find((s) => s.type === "totalen");
740
753
  const paginanummers = !!totalen && opt(totalen, "toon_paginanummer", false) === true;
741
- return `<!doctype html><html lang="nl"><head><meta charset="utf-8" />
742
- <meta name="pdf-paginanummers" content="${paginanummers ? "ja" : "nee"}" />
743
- <title>${esc(opties.titel ?? "Pakbon")}</title>
744
-
745
- <style>
746
- @page { size: ${b}mm ${h}mm; margin: ${marge}mm; }
747
- * { box-sizing: border-box; }
748
- html, body { margin: 0; padding: 0; }
749
- body { font-family: ${font}; font-size: ${grootte}pt; color: #111827; line-height: 1.35; }
750
- .pakbonvariant { border-top: 0.6mm solid #111827; border-bottom: 0.6mm solid #111827; padding: 2mm 1mm; margin-bottom: 2mm; text-align: center; font-size: 15pt; font-weight: 800; line-height: 1.1; }
751
- .blok { margin-bottom: 2mm; }
752
- .sectitel { font-size: 90%; font-weight: 600; text-transform: uppercase; color: #6b7280; margin-bottom: 0.6mm; }
753
- .fustgroepkop { display: flex; justify-content: space-between; font-weight: 600; color: #111827; border-bottom: 0.45mm solid #111827; padding-bottom: 0.5mm; margin-bottom: 0.6mm; }
754
-
755
- .vet { font-weight: 600; }
756
- .kv { display: flex; justify-content: space-between; gap: 3mm; }
757
- .kv .k { color: #6b7280; }
758
- .kv .v { font-weight: 500; }
759
- .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 6mm; }
760
- .kader { border: 0.25mm solid #d1d5db; border-radius: 1mm; padding: 1.5mm; }
761
- table.regels { width: 100%; border-collapse: collapse; }
762
- table.regels.vast { table-layout: fixed; }
763
- table.regels.vast td, table.regels.vast th { overflow-wrap: anywhere; }
764
- table.regels th, table.regels td { padding: 0.7mm 1mm; vertical-align: top; }
765
- table.regels th { font-size: 90%; text-transform: uppercase; color: #6b7280; font-weight: 600; text-align: left; }
766
- .rand { border: 0.2mm solid #d1d5db; }
767
- .onder { border-bottom: 0.2mm solid #d1d5db; }
768
- table.regels.compact th, table.regels.compact td { padding: 0.3mm 0.8mm; }
769
- tr.zebra td { background: #f3f4f6; }
770
- .plijst { margin: 0; padding-left: 4mm; }
771
- .groep { margin-bottom: 1.5mm; }
772
- .regelrij { display: flex; gap: 2mm; }
773
- .tweekolom { display: grid; grid-template-columns: 1fr 1fr; gap: 3mm; }
774
- .karblok { margin-bottom: 2mm; }
775
- .karblok.omkaderd { border: 0.25mm solid #d1d5db; border-radius: 1mm; padding: 1.5mm; }
776
- .karkop { display: flex; justify-content: space-between; align-items: center; padding: 0.8mm 1.5mm; border-radius: 1mm; margin-bottom: 1mm; }
777
- .bundel { display: inline-block; border: 0.3mm dashed #6b7280; border-radius: 1mm; padding: 0.4mm 1.5mm; margin-bottom: 1mm; font-weight: 700; text-transform: uppercase; letter-spacing: 0.2mm; font-size: 90%; }
778
- .laag { margin-bottom: 1.5mm; }
779
- .laagkop { display: flex; justify-content: space-between; font-weight: 500; border-bottom: 0.2mm solid #d1d5db; padding-bottom: 0.4mm; margin-bottom: 0.6mm; }
780
- .laagkop.compact { border-bottom: none; }
781
- .meta { display: flex; gap: 3mm; font-size: 88%; font-weight: 400; color: #4b5563; }
782
- .totalen { display: flex; flex-wrap: wrap; gap: 5mm; border-top: 0.25mm solid #d1d5db; padding-top: 1.2mm; font-weight: 500; }
783
- .paginavoet { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; border-top: 0.35mm solid #9ca3af; padding-top: 1mm; }
784
- .handtekening { margin-top: 3mm; }
785
- .lijnveld { margin-top: 4mm; border-bottom: 0.25mm solid #6b7280; padding-bottom: 3mm; }
786
- .lijnveld.hoog { padding-bottom: 10mm; }
787
- .lijn { border-top: 0.25mm solid #d1d5db; margin: 1.5mm 0; }
788
- .balk { height: 1mm; background: #374151; margin: 1.5mm 0; }
789
- .qr { border: 0.25mm dashed #9ca3af; }
790
- .barcode { display:flex; flex-direction:column; align-items:center; gap:0.8mm; } .barcode-bars { width:45mm; display:flex; background:#fff; }
791
- .klein { font-size: 85%; color: #6b7280; }
792
- .breekvoor { break-before: page; page-break-before: always; }
793
- .heelhouden { break-inside: avoid; page-break-inside: avoid; }
794
- img { max-width: 100%; }
795
- </style></head>
754
+ return `<!doctype html><html lang="nl"><head><meta charset="utf-8" />
755
+ <meta name="pdf-paginanummers" content="${paginanummers ? "ja" : "nee"}" />
756
+ <title>${esc(opties.titel ?? "Pakbon")}</title>
757
+
758
+ <style>
759
+ @page { size: ${b}mm ${h}mm; margin: ${marge}mm; }
760
+ * { box-sizing: border-box; }
761
+ html, body { margin: 0; padding: 0; }
762
+ body { font-family: ${font}; font-size: ${grootte}pt; color: #111827; line-height: 1.35; }
763
+ .pakbonvariant { border-top: 0.6mm solid #111827; border-bottom: 0.6mm solid #111827; padding: 2mm 1mm; margin-bottom: 2mm; text-align: center; font-size: 15pt; font-weight: 800; line-height: 1.1; }
764
+ .blok { margin-bottom: 2mm; }
765
+ .sectitel { font-size: 90%; font-weight: 600; text-transform: uppercase; color: #6b7280; margin-bottom: 0.6mm; }
766
+ .fustgroepkop { display: flex; justify-content: space-between; font-weight: 600; color: #111827; border-bottom: 0.45mm solid #111827; padding-bottom: 0.5mm; margin-bottom: 0.6mm; }
767
+
768
+ .vet { font-weight: 600; }
769
+ .kv { display: flex; justify-content: space-between; gap: 3mm; }
770
+ .kv .k { color: #6b7280; }
771
+ .kv .v { font-weight: 500; }
772
+ .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 6mm; }
773
+ .kader { border: 0.25mm solid #d1d5db; border-radius: 1mm; padding: 1.5mm; }
774
+ table.regels { width: 100%; border-collapse: collapse; }
775
+ table.regels.vast { table-layout: fixed; }
776
+ table.regels.vast td, table.regels.vast th { overflow-wrap: anywhere; }
777
+ table.regels th, table.regels td { padding: 0.7mm 1mm; vertical-align: top; }
778
+ table.regels th { font-size: 90%; text-transform: uppercase; color: #6b7280; font-weight: 600; text-align: left; }
779
+ .rand { border: 0.2mm solid #d1d5db; }
780
+ .onder { border-bottom: 0.2mm solid #d1d5db; }
781
+ table.regels.compact th, table.regels.compact td { padding: 0.3mm 0.8mm; }
782
+ tr.zebra td { background: #f3f4f6; }
783
+ .plijst { margin: 0; padding-left: 4mm; }
784
+ .groep { margin-bottom: 1.5mm; }
785
+ .regelrij { display: flex; gap: 2mm; }
786
+ .tweekolom { display: grid; grid-template-columns: 1fr 1fr; gap: 3mm; }
787
+ .karblok { margin-bottom: 2mm; }
788
+ .karblok.omkaderd { border: 0.25mm solid #d1d5db; border-radius: 1mm; padding: 1.5mm; }
789
+ .karkop { display: block; padding: 0.8mm 1.5mm; border-radius: 1mm; margin-bottom: 1mm; overflow-wrap: anywhere; }
790
+ .karkop-titel { font-weight: 700; }
791
+ .karkop-meta { margin-top: 0.4mm; font-size: 78%; font-weight: 400; color: #4b5563; overflow-wrap: anywhere; }
792
+ .bundel { display: inline-block; border: 0.3mm dashed #6b7280; border-radius: 1mm; padding: 0.4mm 1.5mm; margin-bottom: 1mm; font-weight: 700; text-transform: uppercase; letter-spacing: 0.2mm; font-size: 90%; }
793
+ .laag { margin-bottom: 1.5mm; }
794
+ .laagkop { display: block; font-weight: 500; border-bottom: 0.2mm solid #d1d5db; padding-bottom: 0.4mm; margin-bottom: 0.6mm; overflow-wrap: anywhere; }
795
+ .laagkop-meta { margin-top: 0.25mm; font-size: 82%; font-weight: 400; color: #4b5563; overflow-wrap: anywhere; }
796
+ .laagkop.compact { border-bottom: none; }
797
+ .meta { display: flex; gap: 3mm; font-size: 88%; font-weight: 400; color: #4b5563; }
798
+ .totalen { display: flex; flex-wrap: wrap; gap: 5mm; border-top: 0.25mm solid #d1d5db; padding-top: 1.2mm; font-weight: 500; }
799
+ .paginavoet { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; border-top: 0.35mm solid #9ca3af; padding-top: 1mm; }
800
+ .handtekening { margin-top: 3mm; }
801
+ .lijnveld { margin-top: 4mm; border-bottom: 0.25mm solid #6b7280; padding-bottom: 3mm; }
802
+ .lijnveld.hoog { padding-bottom: 10mm; }
803
+ .lijn { border-top: 0.25mm solid #d1d5db; margin: 1.5mm 0; }
804
+ .balk { height: 1mm; background: #374151; margin: 1.5mm 0; }
805
+ .qr { border: 0.25mm dashed #9ca3af; }
806
+ .barcode { display:flex; flex-direction:column; align-items:center; gap:0.8mm; } .barcode-bars { width:45mm; display:flex; background:#fff; }
807
+ .klein { font-size: 85%; color: #6b7280; }
808
+ .breekvoor { break-before: page; page-break-before: always; }
809
+ .heelhouden { break-inside: avoid; page-break-inside: avoid; }
810
+ img { max-width: 100%; }
811
+ </style></head>
796
812
  <body>${body}</body></html>`;
797
813
  }
798
814
  /** Handig voor testen: het document met de voorbeeldgegevens. */
@@ -0,0 +1,8 @@
1
+ import type { DemoKar } from "./pakbonBuilder.js";
2
+ /**
3
+ * Canonieke zichtbare metadata van een kar. Zowel het live voorbeeld als de
4
+ * print-renderer gebruiken deze lijst, zodat geen van beide zelf regels kan
5
+ * toevoegen of in een andere volgorde kan zetten.
6
+ */
7
+ export declare function karMetadata(kar: DemoKar, velden: string[]): string[];
8
+ //# sourceMappingURL=pakbonPresentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pakbonPresentation.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonPresentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAqBpE"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Canonieke zichtbare metadata van een kar. Zowel het live voorbeeld als de
3
+ * print-renderer gebruiken deze lijst, zodat geen van beide zelf regels kan
4
+ * toevoegen of in een andere volgorde kan zetten.
5
+ */
6
+ export function karMetadata(kar, velden) {
7
+ const info = [];
8
+ if (velden.includes("lagen"))
9
+ info.push(`${kar.lagen.length} lagen`);
10
+ if (velden.includes("producten")) {
11
+ const aantal = kar.lagen.reduce((totaal, laag) => totaal + laag.producten.reduce((som, product) => som + product.aantal, 0), 0);
12
+ info.push(`${aantal} producten`);
13
+ }
14
+ if (velden.includes("gewicht") && kar.gewicht)
15
+ info.push(kar.gewicht);
16
+ if (velden.includes("chauffeur") && kar.chauffeur)
17
+ info.push(kar.chauffeur);
18
+ if (velden.includes("route") && kar.route)
19
+ info.push(kar.route);
20
+ if (kar.gedeeld)
21
+ info.push("gedeelde kar");
22
+ const label = kar.cart_label ||
23
+ (kar.cart_index && kar.cart_total ? `Kar ${kar.cart_index} van ${kar.cart_total}` : "");
24
+ if (label)
25
+ info.push(label);
26
+ if (kar.cart_id)
27
+ info.push(`ID ${kar.cart_id}`);
28
+ if (kar.cart_items?.length)
29
+ info.push(`${kar.cart_items.length} karregels`);
30
+ return info;
31
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"pakbonScan.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonScan.ts"],"names":[],"mappings":"AASA,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAWD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE;IACN,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACA,gBAAgB,GAAG,IAAI,CA8EzB;AAED,uEAAuE;AACvE,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE;IAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAAE,EACpC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CAMf"}
1
+ {"version":3,"file":"pakbonScan.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonScan.ts"],"names":[],"mappings":"AASA,OAAO,EAAuC,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEhG,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAWD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE;IACN,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACA,gBAAgB,GAAG,IAAI,CA8DzB;AAED,uEAAuE;AACvE,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE;IAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAAE,EACpC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -6,7 +6,7 @@
6
6
  // gedrukte pakbon staat, zodat een scanner daaruit een afleverbrief kan
7
7
  // opbouwen: order, klant, kar en de gedrukte regels.
8
8
  // ============================================================================
9
- import { fustVerzamellijst } from "./pakbonBuilder.js";
9
+ import { beperkTotDeelkar, fustVerzamellijst } from "./pakbonBuilder.js";
10
10
  function tekst(waarde) {
11
11
  return waarde === undefined || waarde === null ? "" : String(waarde).trim();
12
12
  }
@@ -23,7 +23,10 @@ export function bouwPakbonScanInhoud(order, opties) {
23
23
  const barcode = tekst(opties.barcode);
24
24
  if (!barcode)
25
25
  return null;
26
- const o = (order && typeof order === "object" ? order : {});
26
+ const ruw = (order && typeof order === "object" ? order : {});
27
+ // Restpakbon: precies dezelfde beperking als bij het afdrukken, zodat de
28
+ // scanner nooit meer regels terugkrijgt dan er op het vel staan.
29
+ const o = (opties.layoutVariant === "partial_order" ? beperkTotDeelkar(ruw) : ruw);
27
30
  const alleKarren = Array.isArray(o["karren"]) ? o["karren"] : [];
28
31
  const cart = (o["cart"] && typeof o["cart"] === "object" ? o["cart"] : {});
29
32
  const cartId = tekst(cart["cart_id"]);
@@ -33,46 +36,25 @@ export function bouwPakbonScanInhoud(order, opties) {
33
36
  const passendeKarren = cartId
34
37
  ? alleKarren.filter((kar) => tekst(kar["cart_id"]) === cartId)
35
38
  : alleKarren;
36
- // Bij partial_order is cart_items de autoritatieve inhoud van deze deelkar.
37
- // Alleen als die lijst ontbreekt, gebruiken we de passende karregels.
38
- const cartItems = Array.isArray(cart["cart_items"]) ? cart["cart_items"] : [];
39
- const karren = passendeKarren;
39
+ const karren = passendeKarren.length ? passendeKarren : alleKarren;
40
40
  const eersteKar = (karren[0] ?? {});
41
41
  const regels = [];
42
- if (opties.layoutVariant !== "partial_order" || !cartItems.length) {
43
- for (const groep of fustVerzamellijst(karren)) {
44
- for (const pr of groep.producten) {
45
- const bestaand = regels.find((r) => r.artikelnummer === pr.artikelnummer && r.fustsoort === (pr.fustsoort || groep.fusttype));
46
- if (bestaand) {
47
- bestaand.aantal += Number(pr.aantal) || 0;
48
- continue;
49
- }
50
- regels.push({
51
- artikelnummer: pr.artikelnummer,
52
- artikelnaam: pr.artikelnaam,
53
- potmaat: pr.potmaat,
54
- kleur: pr.kleur,
55
- fustsoort: pr.fustsoort || groep.fusttype,
56
- planten_per_fust: Number(pr.planten_per_fust) || 0,
57
- aantal: Number(pr.aantal) || 0,
58
- fust_aantal: Number(groep.aantal) || 0,
59
- });
42
+ for (const groep of fustVerzamellijst(karren)) {
43
+ for (const pr of groep.producten) {
44
+ const bestaand = regels.find((r) => r.artikelnummer === pr.artikelnummer && r.fustsoort === (pr.fustsoort || groep.fusttype));
45
+ if (bestaand) {
46
+ bestaand.aantal += Number(pr.aantal) || 0;
47
+ continue;
60
48
  }
61
- }
62
- }
63
- // De Engine kan de deelkarinhoud direct als cart_items meesturen. Die lijst
64
- // wint bij partial_order en bevat dan uitsluitend deze barcode-kar.
65
- if (opties.layoutVariant === "partial_order" && cartItems.length) {
66
- for (const item of cartItems) {
67
49
  regels.push({
68
- artikelnummer: tekst(item["artikelnummer"] ?? item["artikelcode"]),
69
- artikelnaam: tekst(item["artikelnaam"] ?? item["product_name"] ?? item["omschrijving"]),
70
- potmaat: tekst(item["potmaat"]),
71
- kleur: tekst(item["kleur"]),
72
- fustsoort: tekst(item["fustsoort"] ?? item["fusttype"]),
73
- planten_per_fust: Number(item["planten_per_fust"] ?? 0) || 0,
74
- aantal: Number(item["aantal"] ?? item["quantity"] ?? 0) || 0,
75
- fust_aantal: Number(item["fust_aantal"] ?? item["aantal_fusten"] ?? 0) || 0,
50
+ artikelnummer: pr.artikelnummer,
51
+ artikelnaam: pr.artikelnaam,
52
+ potmaat: pr.potmaat,
53
+ kleur: pr.kleur,
54
+ fustsoort: pr.fustsoort || groep.fusttype,
55
+ planten_per_fust: Number(pr.planten_per_fust) || 0,
56
+ aantal: Number(pr.aantal) || 0,
57
+ fust_aantal: Number(pr.fust_aantal) || Number(groep.aantal) || 0,
76
58
  });
77
59
  }
78
60
  }
@@ -1,20 +1,24 @@
1
+ import { supabase } from "./supabaseClient.js";
1
2
  type PdfServiceState = {
2
3
  gestart: boolean;
3
4
  bezig: boolean;
4
5
  interval: number | null;
5
6
  gemeldePrinters: Set<string>;
7
+ writerId: string;
8
+ kanaal?: ReturnType<typeof supabase.channel> | null;
6
9
  };
7
10
  declare global {
8
11
  interface Window {
9
12
  __layoutMakerPdfService?: PdfServiceState;
10
13
  }
11
14
  }
12
- /** Start één permanente lokale PDF-afhandelaar voor de volledige shell. */
15
+ /** Herstelt uitsluitend de lokale aflevering van een reeds gerenderde PDF. */
16
+ export declare function bewaarPdfJobOpnieuw(jobId: string): Promise<boolean>;
17
+ /** Downloadt exact het opgeslagen artefact; legacy jobs vallen terug op base64. */
18
+ export declare function downloadPdfJob(jobId: string, documentnaam: string): Promise<void>;
19
+ export declare function controleerPdfMap(printerId: string): Promise<"ok" | "map_ontbreekt" | "geen_rechten">;
13
20
  export declare function startPdfMapService(): void;
14
- /**
15
- * Wacht na een printactie op de server-PDF en schrijft hem vervolgens direct
16
- * naar de map die op deze computer voor de virtuele printer is gekozen.
17
- */
18
- export declare function bewaarPdfJobZodraKlaar(jobId: string, printerId: string): Promise<boolean>;
21
+ /** Wacht alleen op het eindresultaat; de singleton met databaseclaim schrijft. */
22
+ export declare function bewaarPdfJobZodraKlaar(jobId: string, _printerId: string): Promise<boolean>;
19
23
  export {};
20
24
  //# sourceMappingURL=pdfJobSaver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pdfJobSaver.d.ts","sourceRoot":"","sources":["../../src/lib/pdfJobSaver.ts"],"names":[],"mappings":"AA2BA,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC9B,CAAC;AAEF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,uBAAuB,CAAC,EAAE,eAAe,CAAC;KAC3C;CACF;AA8HD,2EAA2E;AAC3E,wBAAgB,kBAAkB,IAAI,IAAI,CAyBzC;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAyB/F"}
1
+ {"version":3,"file":"pdfJobSaver.d.ts","sourceRoot":"","sources":["../../src/lib/pdfJobSaver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAgC5C,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CACrD,CAAC;AAEF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,uBAAuB,CAAC,EAAE,eAAe,CAAC;KAC3C;CACF;AAiND,8EAA8E;AAC9E,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCzE;AAED,mFAAmF;AACnF,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBvF;AAED,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,eAAe,GAAG,cAAc,CAAC,CAI1G;AAoCD,wBAAgB,kBAAkB,IAAI,IAAI,CA+BzC;AAED,kFAAkF;AAClF,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAehG"}