@flowselections/layout-maker 1.36.7 → 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 (123) hide show
  1. package/dist-lib/components/AfleverbriefBuilderPage.d.ts +10 -0
  2. package/dist-lib/components/AfleverbriefBuilderPage.d.ts.map +1 -0
  3. package/dist-lib/components/AfleverbriefBuilderPage.js +101 -0
  4. package/dist-lib/components/BlokOntwerperPage.d.ts.map +1 -1
  5. package/dist-lib/components/BlokOntwerperPage.js +8 -3
  6. package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
  7. package/dist-lib/components/ComputersLijst.js +1 -1
  8. package/dist-lib/components/FustKolomVolgorde.d.ts +11 -0
  9. package/dist-lib/components/FustKolomVolgorde.d.ts.map +1 -0
  10. package/dist-lib/components/FustKolomVolgorde.js +52 -0
  11. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  12. package/dist-lib/components/LayoutsPage.js +10 -9
  13. package/dist-lib/components/PaginaDocument.d.ts +4 -1
  14. package/dist-lib/components/PaginaDocument.d.ts.map +1 -1
  15. package/dist-lib/components/PaginaDocument.js +10 -5
  16. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  17. package/dist-lib/components/PakbonBuilderPage.js +34 -14
  18. package/dist-lib/components/PakbonPreview.d.ts +4 -2
  19. package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
  20. package/dist-lib/components/PakbonPreview.js +74 -24
  21. package/dist-lib/components/PakbonSectiesPanel.d.ts +5 -3
  22. package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
  23. package/dist-lib/components/PakbonSectiesPanel.js +8 -5
  24. package/dist-lib/components/PdfMapToestemmingBanner.d.ts +2 -1
  25. package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -1
  26. package/dist-lib/components/PdfMapToestemmingBanner.js +73 -14
  27. package/dist-lib/components/PdfVoorbeeld.d.ts +20 -0
  28. package/dist-lib/components/PdfVoorbeeld.d.ts.map +1 -0
  29. package/dist-lib/components/PdfVoorbeeld.js +95 -0
  30. package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -1
  31. package/dist-lib/components/PrintProgrammaUitleg.js +1 -1
  32. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  33. package/dist-lib/components/PrintQueuePage.js +81 -43
  34. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  35. package/dist-lib/components/PrintplekDetailPage.js +2 -2
  36. package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
  37. package/dist-lib/components/PrintplekWizard.js +6 -2
  38. package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
  39. package/dist-lib/components/ProductiebonBuilderPage.js +13 -7
  40. package/dist-lib/index.d.ts +16 -6
  41. package/dist-lib/index.d.ts.map +1 -1
  42. package/dist-lib/index.js +11 -5
  43. package/dist-lib/integrations/supabase/auth-middleware.d.ts +3585 -1267
  44. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  45. package/dist-lib/integrations/supabase/client.server.d.ts +3585 -1267
  46. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  47. package/dist-lib/integrations/supabase/moduleClient.d.ts +25898 -0
  48. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -0
  49. package/dist-lib/integrations/supabase/moduleClient.js +29 -0
  50. package/dist-lib/integrations/supabase/types.d.ts +3607 -1265
  51. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  52. package/dist-lib/integrations/supabase/types.js +1 -0
  53. package/dist-lib/lib/aiLayout.functions.d.ts +3585 -1267
  54. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  55. package/dist-lib/lib/code128.d.ts +5 -0
  56. package/dist-lib/lib/code128.d.ts.map +1 -0
  57. package/dist-lib/lib/code128.js +51 -0
  58. package/dist-lib/lib/documentVoorbeeld.functions.d.ts +23 -0
  59. package/dist-lib/lib/documentVoorbeeld.functions.d.ts.map +1 -0
  60. package/dist-lib/lib/documentVoorbeeld.functions.js +37 -0
  61. package/dist-lib/lib/fontMetrics.d.ts +15 -0
  62. package/dist-lib/lib/fontMetrics.d.ts.map +1 -0
  63. package/dist-lib/lib/fontMetrics.js +118 -0
  64. package/dist-lib/lib/htmlNaarPdf.server.d.ts +2 -2
  65. package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
  66. package/dist-lib/lib/htmlNaarPdf.server.js +2 -1
  67. package/dist-lib/lib/htmlPdf.server.d.ts +11 -0
  68. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  69. package/dist-lib/lib/htmlPdf.server.js +170 -9
  70. package/dist-lib/lib/layoutPreview.d.ts.map +1 -1
  71. package/dist-lib/lib/layoutPreview.js +6 -3
  72. package/dist-lib/lib/orderData.server.d.ts.map +1 -1
  73. package/dist-lib/lib/orderData.server.js +49 -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 +90 -5
  78. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  79. package/dist-lib/lib/pakbonBuilder.js +455 -58
  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 +21 -2
  87. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  88. package/dist-lib/lib/pakbonHtml.js +144 -36
  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 +44 -0
  93. package/dist-lib/lib/pakbonScan.d.ts.map +1 -0
  94. package/dist-lib/lib/pakbonScan.js +87 -0
  95. package/dist-lib/lib/pdfJobSaver.d.ts +10 -6
  96. package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -1
  97. package/dist-lib/lib/pdfJobSaver.js +302 -99
  98. package/dist-lib/lib/pdfMap.d.ts +37 -2
  99. package/dist-lib/lib/pdfMap.d.ts.map +1 -1
  100. package/dist-lib/lib/pdfMap.js +120 -7
  101. package/dist-lib/lib/pdfOpslagStatus.d.ts +23 -0
  102. package/dist-lib/lib/pdfOpslagStatus.d.ts.map +1 -0
  103. package/dist-lib/lib/pdfOpslagStatus.js +74 -0
  104. package/dist-lib/lib/printApi.d.ts +31 -0
  105. package/dist-lib/lib/printApi.d.ts.map +1 -1
  106. package/dist-lib/lib/printApi.js +62 -1
  107. package/dist-lib/lib/printQueue.server.d.ts +13 -0
  108. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  109. package/dist-lib/lib/printQueue.server.js +673 -96
  110. package/dist-lib/lib/printService.functions.d.ts +11840 -2568
  111. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  112. package/dist-lib/lib/profielHtml.d.ts.map +1 -1
  113. package/dist-lib/lib/profielHtml.js +8 -1
  114. package/dist-lib/lib/supabaseClient.d.ts +1 -3
  115. package/dist-lib/lib/supabaseClient.d.ts.map +1 -1
  116. package/dist-lib/lib/supabaseClient.js +4 -8
  117. package/dist-lib/lib/useDocumentData.d.ts +8 -0
  118. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  119. package/dist-lib/lib/useDocumentData.js +1 -1
  120. package/dist-lib/lib/voorbeeldPrint.d.ts +3 -0
  121. package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
  122. package/dist-lib/lib/voorbeeldPrint.js +65 -17
  123. package/package.json +9 -2
@@ -1,6 +1,16 @@
1
1
  import { type DemoOrder, type PakbonConfig } from "./pakbonBuilder.js";
2
- /** Gegevensvorm van een pakbon. Gelijk aan de vorm van het live voorbeeld. */
3
- export type PakbonOrder = DemoOrder;
2
+ /** Gegevensvorm van een pakbon. Engine-metadata blijft naast ordergegevens beschikbaar. */
3
+ export type PakbonOrder = DemoOrder & {
4
+ barcode?: string;
5
+ cart?: {
6
+ cart_label?: string;
7
+ cart_index?: number;
8
+ cart_total?: number;
9
+ cart_id?: string;
10
+ cart_items?: unknown[];
11
+ barcode?: string;
12
+ };
13
+ };
4
14
  export interface PakbonLogo {
5
15
  id: string;
6
16
  naam?: string;
@@ -20,6 +30,15 @@ export interface PakbonRenderOpties {
20
30
  logos?: PakbonLogo[];
21
31
  /** Documentlogo: gebruikt wanneer een logoblok zelf geen logo heeft. */
22
32
  logoId?: string | null;
33
+ /** Variant die uitsluitend door de Logistics Engine wordt bepaald. */
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;
23
42
  }
24
43
  export declare function esc(v: unknown): string;
25
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"pakbonHtml.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonHtml.ts"],"names":[],"mappings":"AAUA,OAAO,EAmBL,KAAK,SAAS,EAEd,KAAK,YAAY,EAGlB,MAAM,iBAAiB,CAAC;AAGzB,8EAA8E;AAC9E,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC;AAEpC,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;CACxB;AAWD,wBAAgB,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAKtC;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAgE3D;AA8oBD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,MAAM,CA8BR;AAgBD,gEAAgE;AAChE,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,GAAG,OAAO,EAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,GAAE,kBAAuB,GAC9B,MAAM,CAmER;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,8 +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, productVeldBreedtes, sectieOnderdrukt, 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
+ import { code128BarsHtml } from "./code128.js";
13
+ import { karMetadata } from "./pakbonPresentation.js";
12
14
  // --- kleine hulpjes ---------------------------------------------------------
13
15
  const arr = (v) => (Array.isArray(v) ? v : []);
14
16
  const opt = (s, key, fallback) => s.opties?.[key] ?? fallback;
@@ -24,6 +26,24 @@ const cel = (p, veld) => {
24
26
  return "";
25
27
  return String(p[veld] ?? "");
26
28
  };
29
+ /** Rendert uitsluitend een bestaande barcodewaarde uit de Engine-payload. */
30
+ function barcodeHtml(value, hoogteMm = 15) {
31
+ const tekst = String(value ?? "").trim();
32
+ if (!tekst)
33
+ return "";
34
+ const hoogte = Number.isFinite(hoogteMm) && hoogteMm > 0 ? hoogteMm : 15;
35
+ return `<div class="barcode"><div class="barcode-bars" data-barcode="${esc(tekst)}" style="height:${hoogte}mm">${code128BarsHtml(tekst)}</div><div>${esc(tekst)}</div></div>`;
36
+ }
37
+ /** Barcode van één pakbon; bij één geselecteerde kar mag diens Engine-barcode worden gebruikt. */
38
+ function pakbonBarcode(order) {
39
+ const direct = String(order.barcode ?? order.cart?.barcode ?? "").trim();
40
+ if (direct)
41
+ return direct;
42
+ const karren = Array.isArray(order.karren) ? order.karren : [];
43
+ if (karren.length !== 1)
44
+ return undefined;
45
+ return String(karren[0]?.barcode ?? "").trim() || undefined;
46
+ }
27
47
  /**
28
48
  * Vult ontbrekende onderdelen aan met veilige lege waarden, zodat een module
29
49
  * die maar een deel van de gegevens heeft nooit een lege of stukke pakbon
@@ -38,11 +58,21 @@ export function maakPakbonOrder(input) {
38
58
  out[v] = b[v] === undefined || b[v] === null ? "" : String(b[v]);
39
59
  return out;
40
60
  };
61
+ const cart = (bron["cart"] && typeof bron["cart"] === "object" ? bron["cart"] : {});
62
+ const topBarcode = String(bron["barcode"] ?? cart["barcode"] ?? "").trim();
41
63
  const karren = arr(bron["karren"]).map((k, i) => ({
42
64
  karnummer: Number(k["karnummer"] ?? i + 1),
65
+ barcode: String(k["barcode"] ?? "").trim() || undefined,
43
66
  route: String(k["route"] ?? ""),
44
67
  chauffeur: String(k["chauffeur"] ?? ""),
45
68
  gewicht: String(k["gewicht"] ?? ""),
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,
46
76
  gedeeld: k["gedeeld"] === true,
47
77
  lagen: arr(k["lagen"]).map((l, j) => ({
48
78
  laagnummer: Number(l["laagnummer"] ?? j + 1),
@@ -89,6 +119,17 @@ export function maakPakbonOrder(input) {
89
119
  afleveradres: groep("afleveradres", ["naam", "adres", "plaats", "land"]),
90
120
  factuuradres: groep("factuuradres", ["naam", "adres", "plaats", "land"]),
91
121
  transport: groep("transport", ["transporteur", "route", "chauffeur", "track"]),
122
+ barcode: topBarcode || undefined,
123
+ cart: Object.keys(cart).length ? {
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,
131
+ barcode: String(cart["barcode"] ?? "").trim() || undefined,
132
+ } : undefined,
92
133
  karren,
93
134
  };
94
135
  }
@@ -310,19 +351,7 @@ function karKop(s, kar, velden, bundelTekst = "") {
310
351
  .replace(/\{chauffeur\}/g, kar.chauffeur)
311
352
  .replace(/\{lagen\}/g, String(kar.lagen.length))
312
353
  .replace(/\{producten\}/g, String(kar.lagen.reduce((n, l) => n + l.producten.length, 0)));
313
- const info = [];
314
- if (velden.includes("lagen"))
315
- info.push(`${kar.lagen.length} lagen`);
316
- if (velden.includes("producten"))
317
- info.push(`${kar.lagen.reduce((n, l) => n + l.producten.reduce((m, p) => m + p.aantal, 0), 0)} producten`);
318
- if (velden.includes("gewicht") && kar.gewicht)
319
- info.push(kar.gewicht);
320
- if (velden.includes("chauffeur") && kar.chauffeur)
321
- info.push(kar.chauffeur);
322
- if (velden.includes("route") && kar.route)
323
- info.push(kar.route);
324
- if (kar.gedeeld)
325
- info.push("gedeelde kar");
354
+ const info = karMetadata(kar, velden);
326
355
  const toonNummer = velden.includes("karnummer");
327
356
  if (!toonNummer && !info.length && !bundelTekst)
328
357
  return "";
@@ -340,9 +369,7 @@ function karKop(s, kar, velden, bundelTekst = "") {
340
369
  ]
341
370
  .filter(Boolean)
342
371
  .join(" ");
343
- return `<div class="karkop" style="${stijl}"><span>${links}</span><span class="meta">${info
344
- .map((t) => `<span>${esc(t)}</span>`)
345
- .join("")}</span></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>`;
346
373
  }
347
374
  function laagKop(s, laag, velden, compact, bundelTekst = "") {
348
375
  const tekst = optS(s, "koptekst", "Laag {laag}").replace(/\{laag\}/g, String(laag.laagnummer));
@@ -361,20 +388,26 @@ function laagKop(s, laag, velden, compact, bundelTekst = "") {
361
388
  info.push(laag.opmerking);
362
389
  if (!velden.includes("laagnummer") && !info.length && !bundelTekst)
363
390
  return "";
364
- 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>`;
365
392
  }
366
393
  function bundelMelding(tekst) {
367
394
  return `<div class="bundel">${esc(tekst)}</div>`;
368
395
  }
369
396
  function karBlok(s, kar, lagen, zoek, omkaderd, aantal = 1) {
370
- // Bij samenvoegen van identieke karren vervalt het unieke karnummer.
371
- const bundelt = opt(s, "bundel_identiek", true) !== false;
397
+ // Alleen bij écht samengevoegde karren vervalt het unieke karnummer; een
398
+ // losse kar (bijv. met eigen Engine-barcode) houdt zijn eigen gegevens.
399
+ const bundelt = opt(s, "bundel_identiek", true) !== false && aantal > 1;
372
400
  const velden = lijst(s, "velden").filter((v) => !(bundelt && (v === "karnummer" || v === "barcode" || v === "qrcode")));
373
401
  const lagenSectie = zoek("lagen");
374
402
  const productSectie = zoek("producten");
375
403
  const fustSectie = zoek("fusten");
376
404
  const lagenModus = lagenSectie ? optS(lagenSectie, "modus", "apart") : "geen";
377
405
  let inhoud = karKop(s, kar, velden, karBundelTekst(aantal));
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);
378
411
  if (lagen.length && lagenSectie && lagenModus !== "geen") {
379
412
  const lVelden = lijst(lagenSectie, "velden");
380
413
  const toonProducten = lagenModus !== "nummer" && lagenModus !== "regel";
@@ -403,9 +436,10 @@ const FUST_KOLOM_LABELS = {
403
436
  locatie: "Locatie",
404
437
  fustsoort: "Tray/fust",
405
438
  planten_per_fust: "Pl./fust",
439
+ fust_aantal: "Fusten",
406
440
  aantal: "Planten",
407
441
  };
408
- const FUST_RECHTS = new Set(["planten_per_fust", "aantal"]);
442
+ const FUST_RECHTS = new Set(["planten_per_fust", "fust_aantal", "aantal"]);
409
443
  /** Verzamellijst met alle te picken fusten per fusttype. */
410
444
  function fustVerzamellijstHtml(order, s) {
411
445
  const groepen = fustVerzamellijst(order?.karren);
@@ -442,7 +476,9 @@ function fustVerzamellijstHtml(order, s) {
442
476
  : "";
443
477
  return `${kopTekst ? `<div class="sectitel">${esc(kopTekst)}</div>` : ""}${blokken}${totaalHtml}`;
444
478
  }
445
- 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 = "") {
446
482
  const modus = optS(s, "modus", "pagina");
447
483
  if (modus === "geen")
448
484
  return "";
@@ -466,13 +502,13 @@ function karrenHtml(s, order, zoek) {
466
502
  const laagGroepen = groepeerIdentiekeLagen(lagen, String(lagenModus) === "gebundeld");
467
503
  laagGroepen.forEach((lg, j) => {
468
504
  const breek = i > 0 || j > 0;
469
- 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>`);
470
506
  });
471
507
  return;
472
508
  }
473
509
  const breek = i > 0 && perPagina;
474
510
  const scheider = i > 0 && !perPagina ? scheidingHtml(scheiding) : "";
475
- 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>`);
476
512
  });
477
513
  return delen.join("");
478
514
  }
@@ -557,8 +593,38 @@ function sectieHtml(s, order, zoek, opties) {
557
593
  .join("");
558
594
  return titelHtml(s) + body;
559
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
+ }
560
626
  case "pickmethode":
561
- if (optS(s, "methode", "kar") !== "fusten")
627
+ if (optS(s, "methode", "kar") === "kar")
562
628
  return "";
563
629
  return fustVerzamellijstHtml(order, s);
564
630
  case "karren":
@@ -591,8 +657,11 @@ function sectieHtml(s, order, zoek, opties) {
591
657
  return `<div class="${opt(s, "kader", false) ? "kader" : ""}" style="font-size:${Number(opt(s, "fontgrootte", 9))}pt">${esc(vulVeldcodes(optS(s, "tekst", ""), order))}</div>`;
592
658
  case "qrcode":
593
659
  return `<div><div class="qr" style="width:${Number(opt(s, "grootte", 25))}mm;height:${Number(opt(s, "grootte", 25))}mm"></div><div class="klein">${esc(vulVeldcodes(optS(s, "waarde", ""), order))}</div></div>`;
594
- case "barcode":
595
- return `<div><div class="streepjes" style="height:${Number(opt(s, "hoogte", 15))}mm"></div><div>${esc(vulVeldcodes(optS(s, "waarde", ""), order))}</div></div>`;
660
+ case "barcode": {
661
+ // Alleen de Engine-waarde mag op de pakbon komen; nooit een lokaal
662
+ // gegenereerde orderwaarde of een layout-default als barcode gebruiken.
663
+ return barcodeHtml(pakbonBarcode(order), Number(opt(s, "hoogte", 15)));
664
+ }
596
665
  case "afbeelding": {
597
666
  const url = optS(s, "url", "");
598
667
  return url
@@ -610,20 +679,44 @@ export function renderPakbonBody(config, order, opties = {}) {
610
679
  const ctx = conditieContext(order);
611
680
  const alleSecties = arr(cfg.secties);
612
681
  const methode = pickMethode(alleSecties);
613
- const secties = alleSecties.filter((s) => sectieZichtbaar(s, ctx) && !sectieOnderdrukt(s.type, methode));
682
+ const variant = pakbonLayoutVariant(opties.layoutVariant);
683
+ const secties = alleSecties.filter((s) => sectieZichtbaar(s, ctx) && !sectieOnderdruktVoorVariant(s.type, methode, variant));
684
+ const heeftKarBarcodes = secties.some((s) => s.type === "karren") &&
685
+ (Array.isArray(order.karren) ? order.karren : []).some((kar) => Boolean(String(kar.barcode ?? "").trim()));
614
686
  const zoek = (t) => secties.find((s) => s.type === t);
615
687
  const opts = { ...opties, logoId: opties.logoId ?? cfg.logo?.logoId ?? null };
616
- const kop = documentLogoHtml(cfg.logo, opts);
688
+ const variantKop = variant
689
+ ? `<div class="pakbonvariant">${variant === "full_cart" ? "HELE KAR" : "DEELKAR"}</div>`
690
+ : "";
691
+ const kop = variantKop + documentLogoHtml(cfg.logo, opts);
617
692
  const totalenSectie = zoek("totalen");
618
693
  const totalenElkePagina = !!totalenSectie && opt(totalenSectie, "elke_pagina", false) === true;
619
694
  const inhoud = secties
620
695
  .filter((s) => !(s.type === "totalen" && totalenElkePagina))
621
- .map((s) => s.type === "karren" ? karrenHtml(s, order, zoek) : blokFrame(s, sectieHtml(s, order, zoek, opts)))
696
+ .filter((s) => !(s.type === "barcode" && heeftKarBarcodes))
697
+ .map((s) => s.type === "karren"
698
+ ? karrenHtml(s, order, zoek, variantKop)
699
+ : blokFrame(s, sectieHtml(s, order, zoek, opts)))
622
700
  .join("");
623
- const voet = totalenElkePagina && totalenSectie
701
+ const pickSectie = alleSecties.find((s) => s.type === "pickmethode");
702
+ const pickInstellingen = pickSectie ?? alleSecties[0];
703
+ // Elke pakbon krijgt de Engine-barcode wanneer die is aangeleverd. Een
704
+ // expliciet barcodeblok rendert hem zelf; anders voegen we hem één keer
705
+ // automatisch toe. Zonder Engine-barcode wordt nooit een waarde verzonnen.
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");
713
+ const barcode = automatischeBarcode
714
+ ? barcodeHtml(pakbonBarcode(order), Number(pickInstellingen ? opt(pickInstellingen, "barcodeHoogte", 15) : 15))
715
+ : "";
716
+ const voet = totalenElkePagina && totalenSectie && !opties.zonderPaginavoet
624
717
  ? `<div class="paginavoet">${sectieHtml(totalenSectie, order, zoek, opts)}</div>`
625
718
  : "";
626
- return kop + inhoud + voet;
719
+ return kop + inhoud + (barcode ? `<div class="blok">${barcode}</div>` : "") + voet;
627
720
  }
628
721
  /** Het documentlogo bovenaan de pakbon. */
629
722
  function documentLogoHtml(logoCfg, opties) {
@@ -642,7 +735,18 @@ export function renderPakbonDocument(config, order, opties = {}) {
642
735
  const marge = opties.margeMm ?? 12;
643
736
  const font = opties.lettertype ?? 'Arial, Helvetica, "Segoe UI", sans-serif';
644
737
  const grootte = opties.lettergrootte ?? 8.5;
645
- 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
+ }
646
750
  // De layout bepaalt of er paginanummers op de afdruk komen; de PDF-motor
647
751
  // leest dit uit de meta, zodat de wachtrij niets extra hoeft door te geven.
648
752
  const totalen = arr(leesPakbonConfig(config).secties).find((s) => s.type === "totalen");
@@ -656,6 +760,7 @@ export function renderPakbonDocument(config, order, opties = {}) {
656
760
  * { box-sizing: border-box; }
657
761
  html, body { margin: 0; padding: 0; }
658
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; }
659
764
  .blok { margin-bottom: 2mm; }
660
765
  .sectitel { font-size: 90%; font-weight: 600; text-transform: uppercase; color: #6b7280; margin-bottom: 0.6mm; }
661
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; }
@@ -681,10 +786,13 @@ tr.zebra td { background: #f3f4f6; }
681
786
  .tweekolom { display: grid; grid-template-columns: 1fr 1fr; gap: 3mm; }
682
787
  .karblok { margin-bottom: 2mm; }
683
788
  .karblok.omkaderd { border: 0.25mm solid #d1d5db; border-radius: 1mm; padding: 1.5mm; }
684
- .karkop { display: flex; justify-content: space-between; align-items: center; padding: 0.8mm 1.5mm; border-radius: 1mm; margin-bottom: 1mm; }
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; }
685
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%; }
686
793
  .laag { margin-bottom: 1.5mm; }
687
- .laagkop { display: flex; justify-content: space-between; font-weight: 500; border-bottom: 0.2mm solid #d1d5db; padding-bottom: 0.4mm; margin-bottom: 0.6mm; }
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; }
688
796
  .laagkop.compact { border-bottom: none; }
689
797
  .meta { display: flex; gap: 3mm; font-size: 88%; font-weight: 400; color: #4b5563; }
690
798
  .totalen { display: flex; flex-wrap: wrap; gap: 5mm; border-top: 0.25mm solid #d1d5db; padding-top: 1.2mm; font-weight: 500; }
@@ -695,7 +803,7 @@ tr.zebra td { background: #f3f4f6; }
695
803
  .lijn { border-top: 0.25mm solid #d1d5db; margin: 1.5mm 0; }
696
804
  .balk { height: 1mm; background: #374151; margin: 1.5mm 0; }
697
805
  .qr { border: 0.25mm dashed #9ca3af; }
698
- .streepjes { width: 45mm; background: repeating-linear-gradient(to right, #111827 0 2px, transparent 2px 5px); }
806
+ .barcode { display:flex; flex-direction:column; align-items:center; gap:0.8mm; } .barcode-bars { width:45mm; display:flex; background:#fff; }
699
807
  .klein { font-size: 85%; color: #6b7280; }
700
808
  .breekvoor { break-before: page; page-break-before: always; }
701
809
  .heelhouden { break-inside: avoid; page-break-inside: avoid; }
@@ -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
+ }
@@ -0,0 +1,44 @@
1
+ import { type PakbonLayoutVariant } from "./pakbonBuilder.js";
2
+ export interface PakbonScanRegel {
3
+ artikelnummer: string;
4
+ artikelnaam: string;
5
+ potmaat: string;
6
+ kleur: string;
7
+ fustsoort: string;
8
+ planten_per_fust: number;
9
+ aantal: number;
10
+ fust_aantal: number;
11
+ }
12
+ export interface PakbonScanInhoud {
13
+ barcode: string;
14
+ order_ref: string | null;
15
+ order_nummer: string | null;
16
+ klant_naam: string | null;
17
+ klant_nummer: string | null;
18
+ cart_id: string | null;
19
+ cart_label: string | null;
20
+ cart_index: number | null;
21
+ cart_total: number | null;
22
+ layout_variant: PakbonLayoutVariant | null;
23
+ layout_id: string | null;
24
+ print_job_id: string | null;
25
+ is_herprint: boolean;
26
+ regels: PakbonScanRegel[];
27
+ }
28
+ /**
29
+ * Bouwt de scanregel uit de order zoals die op de pakbon is gerenderd.
30
+ * Bij een deelkar (`partial_order`) staan uitsluitend de fusten van die
31
+ * deelkar op de pakbon, dus ook uitsluitend die regels in de registratie.
32
+ */
33
+ export declare function bouwPakbonScanInhoud(order: unknown, opties: {
34
+ barcode: unknown;
35
+ layoutVariant?: PakbonLayoutVariant | null;
36
+ layoutId?: string | null;
37
+ printJobId?: string | null;
38
+ isHerprint?: boolean;
39
+ }): PakbonScanInhoud | null;
40
+ /** Slaat de scaninhoud op; een herprint werkt dezelfde barcode bij. */
41
+ export declare function bewaarPakbonScanInhoud(db: {
42
+ from: (tabel: string) => any;
43
+ }, inhoud: PakbonScanInhoud | null): Promise<void>;
44
+ //# sourceMappingURL=pakbonScan.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,87 @@
1
+ // ============================================================================
2
+ // src/lib/pakbonScan.ts — registreert wat er achter een pakbonbarcode zit
3
+ // ----------------------------------------------------------------------------
4
+ // De barcodewaarde blijft eigendom van de Logistics Engine: deze module
5
+ // genereert of wijzigt nooit een barcode. Wel legt zij vast WAT er op de
6
+ // gedrukte pakbon staat, zodat een scanner daaruit een afleverbrief kan
7
+ // opbouwen: order, klant, kar en de gedrukte regels.
8
+ // ============================================================================
9
+ import { beperkTotDeelkar, fustVerzamellijst } from "./pakbonBuilder.js";
10
+ function tekst(waarde) {
11
+ return waarde === undefined || waarde === null ? "" : String(waarde).trim();
12
+ }
13
+ function getal(waarde) {
14
+ const n = Number(waarde);
15
+ return Number.isFinite(n) && n !== 0 ? n : null;
16
+ }
17
+ /**
18
+ * Bouwt de scanregel uit de order zoals die op de pakbon is gerenderd.
19
+ * Bij een deelkar (`partial_order`) staan uitsluitend de fusten van die
20
+ * deelkar op de pakbon, dus ook uitsluitend die regels in de registratie.
21
+ */
22
+ export function bouwPakbonScanInhoud(order, opties) {
23
+ const barcode = tekst(opties.barcode);
24
+ if (!barcode)
25
+ return null;
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);
30
+ const alleKarren = Array.isArray(o["karren"]) ? o["karren"] : [];
31
+ const cart = (o["cart"] && typeof o["cart"] === "object" ? o["cart"] : {});
32
+ const cartId = tekst(cart["cart_id"]);
33
+ // Een order kan meerdere karren bevatten. Voor een deelkar mag de scanner
34
+ // nooit de inhoud van de andere karren terugkrijgen: selecteer dus eerst op
35
+ // het door de Engine meegestuurde cart_id.
36
+ const passendeKarren = cartId
37
+ ? alleKarren.filter((kar) => tekst(kar["cart_id"]) === cartId)
38
+ : alleKarren;
39
+ const karren = passendeKarren.length ? passendeKarren : alleKarren;
40
+ const eersteKar = (karren[0] ?? {});
41
+ const regels = [];
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;
48
+ }
49
+ regels.push({
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,
58
+ });
59
+ }
60
+ }
61
+ return {
62
+ barcode,
63
+ order_ref: tekst(o["order"]?.referentie) || null,
64
+ order_nummer: tekst(o["order"]?.nummer) || null,
65
+ klant_naam: tekst(o["klant"]?.naam) || null,
66
+ klant_nummer: tekst(o["klant"]?.nummer) || null,
67
+ cart_id: tekst(cart["cart_id"] ?? eersteKar["cart_id"]) || null,
68
+ cart_label: tekst(cart["cart_label"] ?? eersteKar["cart_label"]) || null,
69
+ cart_index: getal(cart["cart_index"] ?? eersteKar["cart_index"]),
70
+ cart_total: getal(cart["cart_total"] ?? eersteKar["cart_total"]),
71
+ layout_variant: opties.layoutVariant ?? null,
72
+ layout_id: opties.layoutId ?? null,
73
+ print_job_id: opties.printJobId ?? null,
74
+ is_herprint: opties.isHerprint === true,
75
+ regels,
76
+ };
77
+ }
78
+ /** Slaat de scaninhoud op; een herprint werkt dezelfde barcode bij. */
79
+ export async function bewaarPakbonScanInhoud(db, inhoud) {
80
+ if (!inhoud)
81
+ return;
82
+ const { error } = await db
83
+ .from("pakbon_barcode_inhoud")
84
+ .upsert({ ...inhoud, updated_at: new Date().toISOString() }, { onConflict: "barcode" });
85
+ if (error)
86
+ throw new Error(error.message ?? "Opslaan van pakbon-scaninhoud mislukt");
87
+ }
@@ -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"}