@flowselections/layout-maker 1.38.4 → 1.45.9

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 (110) 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/PakbonBuilderPage.d.ts.map +1 -1
  14. package/dist-lib/components/PakbonBuilderPage.js +32 -14
  15. package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
  16. package/dist-lib/components/PakbonPreview.js +21 -14
  17. package/dist-lib/components/PakbonSectiesPanel.d.ts +4 -2
  18. package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
  19. package/dist-lib/components/PakbonSectiesPanel.js +5 -3
  20. package/dist-lib/components/PdfMapToestemmingBanner.d.ts +2 -1
  21. package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -1
  22. package/dist-lib/components/PdfMapToestemmingBanner.js +124 -18
  23. package/dist-lib/components/PdfVoorbeeld.d.ts +20 -0
  24. package/dist-lib/components/PdfVoorbeeld.d.ts.map +1 -0
  25. package/dist-lib/components/PdfVoorbeeld.js +95 -0
  26. package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -1
  27. package/dist-lib/components/PrintProgrammaUitleg.js +1 -1
  28. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  29. package/dist-lib/components/PrintQueuePage.js +81 -43
  30. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  31. package/dist-lib/components/PrintplekDetailPage.js +2 -2
  32. package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
  33. package/dist-lib/components/PrintplekWizard.js +6 -2
  34. package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
  35. package/dist-lib/components/ProductiebonBuilderPage.js +13 -7
  36. package/dist-lib/index.d.ts +13 -5
  37. package/dist-lib/index.d.ts.map +1 -1
  38. package/dist-lib/index.js +10 -5
  39. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2280 -198
  40. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  41. package/dist-lib/integrations/supabase/client.server.d.ts +2280 -198
  42. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  43. package/dist-lib/integrations/supabase/client.server.js +1 -1
  44. package/dist-lib/integrations/supabase/moduleClient.d.ts +2280 -198
  45. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  46. package/dist-lib/integrations/supabase/types.d.ts +2306 -182
  47. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  48. package/dist-lib/integrations/supabase/types.js +1 -0
  49. package/dist-lib/lib/aiLayout.functions.d.ts +2280 -198
  50. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  51. package/dist-lib/lib/documentVoorbeeld.functions.d.ts +23 -0
  52. package/dist-lib/lib/documentVoorbeeld.functions.d.ts.map +1 -0
  53. package/dist-lib/lib/documentVoorbeeld.functions.js +37 -0
  54. package/dist-lib/lib/fontMetrics.d.ts +15 -0
  55. package/dist-lib/lib/fontMetrics.d.ts.map +1 -0
  56. package/dist-lib/lib/fontMetrics.js +118 -0
  57. package/dist-lib/lib/htmlNaarPdf.server.d.ts +2 -2
  58. package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
  59. package/dist-lib/lib/htmlNaarPdf.server.js +2 -1
  60. package/dist-lib/lib/htmlPdf.server.d.ts +11 -0
  61. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  62. package/dist-lib/lib/htmlPdf.server.js +118 -15
  63. package/dist-lib/lib/orderData.server.d.ts.map +1 -1
  64. package/dist-lib/lib/orderData.server.js +43 -16
  65. package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts +39 -0
  66. package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts.map +1 -0
  67. package/dist-lib/lib/pakbonBarcodeVerzoek.js +80 -0
  68. package/dist-lib/lib/pakbonBuilder.d.ts +62 -3
  69. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  70. package/dist-lib/lib/pakbonBuilder.js +386 -50
  71. package/dist-lib/lib/pakbonContent.d.ts +41 -0
  72. package/dist-lib/lib/pakbonContent.d.ts.map +1 -0
  73. package/dist-lib/lib/pakbonContent.js +668 -0
  74. package/dist-lib/lib/pakbonDocument.d.ts +199 -0
  75. package/dist-lib/lib/pakbonDocument.d.ts.map +1 -0
  76. package/dist-lib/lib/pakbonDocument.js +735 -0
  77. package/dist-lib/lib/pakbonHtml.d.ts +7 -0
  78. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  79. package/dist-lib/lib/pakbonHtml.js +89 -73
  80. package/dist-lib/lib/pakbonPresentation.d.ts +8 -0
  81. package/dist-lib/lib/pakbonPresentation.d.ts.map +1 -0
  82. package/dist-lib/lib/pakbonPresentation.js +31 -0
  83. package/dist-lib/lib/pakbonScan.d.ts.map +1 -1
  84. package/dist-lib/lib/pakbonScan.js +20 -38
  85. package/dist-lib/lib/pdfJobSaver.d.ts +10 -6
  86. package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -1
  87. package/dist-lib/lib/pdfJobSaver.js +302 -99
  88. package/dist-lib/lib/pdfMap.d.ts +37 -2
  89. package/dist-lib/lib/pdfMap.d.ts.map +1 -1
  90. package/dist-lib/lib/pdfMap.js +120 -7
  91. package/dist-lib/lib/pdfOpslagStatus.d.ts +23 -0
  92. package/dist-lib/lib/pdfOpslagStatus.d.ts.map +1 -0
  93. package/dist-lib/lib/pdfOpslagStatus.js +74 -0
  94. package/dist-lib/lib/printApi.d.ts +31 -0
  95. package/dist-lib/lib/printApi.d.ts.map +1 -1
  96. package/dist-lib/lib/printApi.js +62 -1
  97. package/dist-lib/lib/printQueue.server.d.ts +6 -0
  98. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  99. package/dist-lib/lib/printQueue.server.js +450 -94
  100. package/dist-lib/lib/printService.functions.d.ts +8857 -529
  101. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  102. package/dist-lib/lib/profielHtml.d.ts.map +1 -1
  103. package/dist-lib/lib/profielHtml.js +8 -1
  104. package/dist-lib/lib/useDocumentData.d.ts +8 -0
  105. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  106. package/dist-lib/lib/useDocumentData.js +1 -1
  107. package/dist-lib/lib/voorbeeldPrint.d.ts +3 -0
  108. package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
  109. package/dist-lib/lib/voorbeeldPrint.js +65 -17
  110. package/package.json +9 -2
@@ -0,0 +1,23 @@
1
+ export interface VoorbeeldPdfInvoer {
2
+ html: string;
3
+ breedteMm: number;
4
+ hoogteMm: number;
5
+ margeMm: number;
6
+ paginanummers?: boolean;
7
+ }
8
+ /**
9
+ * Rendert print-HTML met exact dezelfde servercode als de printwachtrij, zodat
10
+ * het voorbeeld in de editor letterlijk de PDF is die straks wordt geprint.
11
+ * Er wordt niets opgeslagen en geen printopdracht aangemaakt.
12
+ */
13
+ export declare const maakVoorbeeldPdf: import("@tanstack/start-client-core").RequiredFetcher<undefined, (invoer: VoorbeeldPdfInvoer) => {
14
+ html: string;
15
+ breedteMm: number;
16
+ hoogteMm: number;
17
+ margeMm: number;
18
+ paginanummers: boolean | undefined;
19
+ }, Promise<{
20
+ pdfBase64: string;
21
+ bytes: number;
22
+ }>>;
23
+ //# sourceMappingURL=documentVoorbeeld.functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentVoorbeeld.functions.d.ts","sourceRoot":"","sources":["../../src/lib/documentVoorbeeld.functions.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,4EACF,kBAAkB;;;;;;;;;GA2BzC,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { createServerFn } from "@tanstack/react-start";
2
+ /**
3
+ * Rendert print-HTML met exact dezelfde servercode als de printwachtrij, zodat
4
+ * het voorbeeld in de editor letterlijk de PDF is die straks wordt geprint.
5
+ * Er wordt niets opgeslagen en geen printopdracht aangemaakt.
6
+ */
7
+ export const maakVoorbeeldPdf = createServerFn({ method: "POST" })
8
+ .inputValidator((invoer) => {
9
+ const html = String(invoer?.html ?? "");
10
+ if (!html.trim())
11
+ throw new Error("Voorbeeld kan niet worden gemaakt: geen HTML aangeleverd.");
12
+ // Pakbonnen met ingesloten logo's/barcodes (data-URI's) worden snel groot;
13
+ // de grens is er alleen om echt onwerkbare invoer te weren.
14
+ if (html.length > 40000000)
15
+ throw new Error("Voorbeeld te groot om te renderen.");
16
+ const breedteMm = Number(invoer?.breedteMm);
17
+ const hoogteMm = Number(invoer?.hoogteMm);
18
+ const margeMm = Number(invoer?.margeMm);
19
+ if (!Number.isFinite(breedteMm) || breedteMm <= 0 || !Number.isFinite(hoogteMm) || hoogteMm <= 0) {
20
+ throw new Error("Voorbeeld kan niet worden gemaakt: papierformaat ontbreekt.");
21
+ }
22
+ if (!Number.isFinite(margeMm) || margeMm < 0 || margeMm * 2 >= Math.min(breedteMm, hoogteMm)) {
23
+ throw new Error("Voorbeeld kan niet worden gemaakt: de ingestelde paginamarge is ongeldig.");
24
+ }
25
+ return { html, breedteMm, hoogteMm, margeMm, paginanummers: invoer?.paginanummers };
26
+ })
27
+ .handler(async ({ data }) => {
28
+ const { htmlNaarPdfBytes, bytesNaarBase64 } = await import("./htmlPdf.server.js");
29
+ const bytes = await htmlNaarPdfBytes({
30
+ html: data.html,
31
+ breedteMm: data.breedteMm,
32
+ hoogteMm: data.hoogteMm,
33
+ margeMm: data.margeMm,
34
+ ...(typeof data.paginanummers === "boolean" ? { paginanummers: data.paginanummers } : {}),
35
+ });
36
+ return { pdfBase64: bytesNaarBase64(bytes), bytes: bytes.length };
37
+ });
@@ -0,0 +1,15 @@
1
+ /** Breedte van tekst in punten bij een gegeven fontgrootte. */
2
+ export declare function tekstBreedtePt(tekst: string, groottePt: number, vet?: boolean): number;
3
+ /** Verhouding regelhoogte / fontgrootte; overal identiek. */
4
+ export declare const REGELHOOGTE_FACTOR = 1.25;
5
+ /** Regelhoogte in punten. */
6
+ export declare function regelHoogtePt(groottePt: number): number;
7
+ /**
8
+ * Breekt tekst af op woordgrenzen binnen een maximale breedte. Woorden die
9
+ * zelf te lang zijn worden hard afgebroken (net als overflow-wrap: anywhere).
10
+ * De uitkomst is de definitieve regelverdeling: renderers wrappen nooit zelf.
11
+ */
12
+ export declare function breekAf(tekst: string, maxBreedtePt: number, groottePt: number, vet?: boolean): string[];
13
+ /** Kort tekst af tot één regel met beletselteken. */
14
+ export declare function kortAf(tekst: string, maxBreedtePt: number, groottePt: number, vet?: boolean): string;
15
+ //# sourceMappingURL=fontMetrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fontMetrics.d.ts","sourceRoot":"","sources":["../../src/lib/fontMetrics.ts"],"names":[],"mappings":"AA+CA,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,MAAM,CAKpF;AAED,6DAA6D;AAC7D,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,MAAM,EAAE,CA2CrG;AAED,qDAAqD;AACrD,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,MAAM,CAMlG"}
@@ -0,0 +1,118 @@
1
+ // ============================================================================
2
+ // src/lib/fontMetrics.ts — centrale fontmetriek voor de pakbon-layoutengine.
3
+ // ----------------------------------------------------------------------------
4
+ // Zowel het live voorbeeld (browser) als de PDF-motor (server) meten tekst met
5
+ // EXACT deze tabellen. Daardoor breekt tekst overal op dezelfde plek af en
6
+ // staan kolommen overal even breed. De waarden zijn de glyph-breedtes van
7
+ // Helvetica / Helvetica-Bold in duizendsten van de fontgrootte (WinAnsi,
8
+ // tekencodes 32 t/m 255) — precies wat de PDF-renderer gebruikt.
9
+ // ============================================================================
10
+ /** Eerste tekencode in de tabellen. */
11
+ const EERSTE = 32;
12
+ const HELVETICA = [
13
+ 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556,
14
+ 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
15
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556,
16
+ 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
17
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
18
+ 0, 0, 0, 0, 0, 0, 0, 0, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333,
19
+ 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722,
20
+ 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
21
+ 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584,
22
+ 611, 556, 556, 556, 556, 500, 556, 500,
23
+ ];
24
+ const HELVETICA_BOLD = [
25
+ 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556,
26
+ 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
27
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611,
28
+ 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
29
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30
+ 0, 0, 0, 0, 0, 0, 0, 0, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333,
31
+ 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722,
32
+ 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
33
+ 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584,
34
+ 611, 611, 611, 611, 611, 556, 611, 556,
35
+ ];
36
+ const ONBEKEND = 556; // breedte van "?" als terugval
37
+ function glyphBreedte(code, vet) {
38
+ const tabel = vet ? HELVETICA_BOLD : HELVETICA;
39
+ const w = tabel[code - EERSTE];
40
+ return typeof w === "number" && w > 0 ? w : ONBEKEND;
41
+ }
42
+ /** Breedte van tekst in punten bij een gegeven fontgrootte. */
43
+ export function tekstBreedtePt(tekst, groottePt, vet = false) {
44
+ let som = 0;
45
+ const s = String(tekst ?? "");
46
+ for (let i = 0; i < s.length; i++)
47
+ som += glyphBreedte(s.charCodeAt(i), vet);
48
+ return (som / 1000) * groottePt;
49
+ }
50
+ /** Verhouding regelhoogte / fontgrootte; overal identiek. */
51
+ export const REGELHOOGTE_FACTOR = 1.25;
52
+ /** Regelhoogte in punten. */
53
+ export function regelHoogtePt(groottePt) {
54
+ return groottePt * REGELHOOGTE_FACTOR;
55
+ }
56
+ /**
57
+ * Breekt tekst af op woordgrenzen binnen een maximale breedte. Woorden die
58
+ * zelf te lang zijn worden hard afgebroken (net als overflow-wrap: anywhere).
59
+ * De uitkomst is de definitieve regelverdeling: renderers wrappen nooit zelf.
60
+ */
61
+ export function breekAf(tekst, maxBreedtePt, groottePt, vet = false) {
62
+ const bron = String(tekst ?? "").replace(/\s+/g, " ").trim();
63
+ if (!bron)
64
+ return [""];
65
+ if (maxBreedtePt <= 0)
66
+ return [bron];
67
+ const regels = [];
68
+ let huidig = "";
69
+ const duwHard = (woord) => {
70
+ let rest = woord;
71
+ while (rest.length) {
72
+ let n = rest.length;
73
+ while (n > 1 && tekstBreedtePt(rest.slice(0, n), groottePt, vet) > maxBreedtePt)
74
+ n--;
75
+ regels.push(rest.slice(0, n));
76
+ rest = rest.slice(n);
77
+ }
78
+ };
79
+ for (const woord of bron.split(" ")) {
80
+ const kandidaat = huidig ? `${huidig} ${woord}` : woord;
81
+ if (tekstBreedtePt(kandidaat, groottePt, vet) <= maxBreedtePt) {
82
+ huidig = kandidaat;
83
+ continue;
84
+ }
85
+ if (huidig) {
86
+ regels.push(huidig);
87
+ huidig = "";
88
+ }
89
+ if (tekstBreedtePt(woord, groottePt, vet) <= maxBreedtePt)
90
+ huidig = woord;
91
+ else {
92
+ const stukken = [];
93
+ let rest = woord;
94
+ while (rest.length) {
95
+ let n = rest.length;
96
+ while (n > 1 && tekstBreedtePt(rest.slice(0, n), groottePt, vet) > maxBreedtePt)
97
+ n--;
98
+ stukken.push(rest.slice(0, n));
99
+ rest = rest.slice(n);
100
+ }
101
+ huidig = stukken.pop() ?? "";
102
+ regels.push(...stukken);
103
+ }
104
+ }
105
+ if (huidig)
106
+ regels.push(huidig);
107
+ return regels.length ? regels : [""];
108
+ }
109
+ /** Kort tekst af tot één regel met beletselteken. */
110
+ export function kortAf(tekst, maxBreedtePt, groottePt, vet = false) {
111
+ const s = String(tekst ?? "");
112
+ if (tekstBreedtePt(s, groottePt, vet) <= maxBreedtePt)
113
+ return s;
114
+ let n = s.length;
115
+ while (n > 1 && tekstBreedtePt(`${s.slice(0, n)}…`, groottePt, vet) > maxBreedtePt)
116
+ n--;
117
+ return `${s.slice(0, n)}…`;
118
+ }
@@ -1,6 +1,6 @@
1
1
  export declare class PdfRenderFout extends Error {
2
- code: "niet_ingesteld" | "mislukt";
3
- constructor(code: "niet_ingesteld" | "mislukt", boodschap: string);
2
+ code: "niet_ingesteld" | "mislukt" | "afwijking";
3
+ constructor(code: "niet_ingesteld" | "mislukt" | "afwijking", boodschap: string);
4
4
  }
5
5
  export interface PdfOpties {
6
6
  html: string;
@@ -1 +1 @@
1
- {"version":3,"file":"htmlNaarPdf.server.d.ts","sourceRoot":"","sources":["../../src/lib/htmlNaarPdf.server.ts"],"names":[],"mappings":"AAQA,qBAAa,aAAc,SAAQ,KAAK;IAE7B,IAAI,EAAE,gBAAgB,GAAG,SAAS;gBAAlC,IAAI,EAAE,gBAAgB,GAAG,SAAS,EACzC,SAAS,EAAE,MAAM;CAKpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,4DAA4D;AAC5D,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB1E"}
1
+ {"version":3,"file":"htmlNaarPdf.server.d.ts","sourceRoot":"","sources":["../../src/lib/htmlNaarPdf.server.ts"],"names":[],"mappings":"AAQA,qBAAa,aAAc,SAAQ,KAAK;IAE7B,IAAI,EAAE,gBAAgB,GAAG,SAAS,GAAG,WAAW;gBAAhD,IAAI,EAAE,gBAAgB,GAAG,SAAS,GAAG,WAAW,EACvD,SAAS,EAAE,MAAM;CAKpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,4DAA4D;AAC5D,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB1E"}
@@ -29,6 +29,7 @@ export async function htmlNaarPdfServer(opties) {
29
29
  return bytesNaarBase64(bytes);
30
30
  }
31
31
  catch (e) {
32
- throw new PdfRenderFout("mislukt", e instanceof Error ? `PDF maken mislukte: ${e.message}` : "PDF maken mislukte.");
32
+ const melding = e instanceof Error ? e.message : "PDF maken mislukte.";
33
+ throw new PdfRenderFout(melding.startsWith("Afdrukafwijking gevonden:") ? "afwijking" : "mislukt", melding.startsWith("Afdrukafwijking gevonden:") ? melding : `PDF maken mislukte: ${melding}`);
33
34
  }
34
35
  }
@@ -41,6 +41,17 @@ export interface DocumentPdfOpties {
41
41
  /** Voettekst met paginanummers ("Pagina 1 van 3"). */
42
42
  paginanummers?: boolean;
43
43
  }
44
+ export interface PdfRenderDiagnostiek {
45
+ geldig: boolean;
46
+ fouten: string[];
47
+ }
48
+ /**
49
+ * Bewaakt constructies die de eigen PDF-motor niet hetzelfde kan uitleggen als
50
+ * een browser. @page is toegestaan: papier en marge komen uit de canonieke
51
+ * DocumentPdfOpties. Andere at-rules en complexe selectors worden geweigerd in
52
+ * plaats van stilletjes genegeerd.
53
+ */
54
+ export declare function controleerPdfOpmaak(html: string): PdfRenderDiagnostiek;
44
55
  /** Zet print-HTML om naar een PDF en levert die als base64 (zonder prefix). */
45
56
  export declare function htmlNaarPdfBytes(opties: DocumentPdfOpties): Promise<Uint8Array>;
46
57
  export declare function bytesNaarBase64(bytes: Uint8Array): string;
@@ -1 +1 @@
1
- {"version":3,"file":"htmlPdf.server.d.ts","sourceRoot":"","sources":["../../src/lib/htmlPdf.server.ts"],"names":[],"mappings":"AAYA,OAAO,EAOL,KAAK,GAAG,EACT,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,EAAE,oBAAoB,CAAC;AAIpC,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuBD,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAuC/C;AAUD,UAAU,SAAS;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AACD,UAAU,QAAQ;IAChB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpD;AA2BD,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,CAgClD;AAqBD,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAiBlE;AAKD,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AA4mCD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,+EAA+E;AAC/E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CA+DrF;AA0BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAQzD"}
1
+ {"version":3,"file":"htmlPdf.server.d.ts","sourceRoot":"","sources":["../../src/lib/htmlPdf.server.ts"],"names":[],"mappings":"AAYA,OAAO,EAOL,KAAK,GAAG,EACT,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,EAAE,oBAAoB,CAAC;AAIpC,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuBD,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAuC/C;AAUD,UAAU,SAAS;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AACD,UAAU,QAAQ;IAChB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpD;AA2BD,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,CAgClD;AAqBD,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAiBlE;AAKD,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAypCD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CA8BtE;AAED,+EAA+E;AAC/E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CA6ErF;AA0BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAQzD"}
@@ -525,6 +525,16 @@ async function meetHoogte(ctx, n, vak, s) {
525
525
  await tekenKinderen(meetCtx, { tag: "div", attrs: {}, kinderen: [n] }, vak, s);
526
526
  });
527
527
  }
528
+ /**
529
+ * Meet uitsluitend de inhoud van een blok. Het blok zelf meemeten telt padding
530
+ * en marges dubbel; dan valt een achtergrondvlak zichtbaar te ver door.
531
+ */
532
+ async function meetInhoud(ctx, n, vak, s) {
533
+ const meetCtx = { ...ctx, meten: true };
534
+ return ctx.tk.meet(async () => {
535
+ await tekenKinderen(meetCtx, n, vak, s);
536
+ });
537
+ }
528
538
  function rijenVan(tabel) {
529
539
  const rijen = [];
530
540
  const loop = (k) => {
@@ -562,12 +572,23 @@ async function tekenBlok(ctx, n, vak, ouderStijl) {
562
572
  const s = stijlVan(n, ouderStijl);
563
573
  const st = eig(n);
564
574
  const cl = klassen(n);
565
- const barcode = zoekBarcodeWaarde(n);
575
+ const barcode = eigenBarcodeWaarde(n);
566
576
  if (barcode) {
567
- const h = lengte(st["height"]) ?? 15 * MM;
568
- tk.zorgVoor(h + 1 * MM);
569
- tekenBarcode(tk, barcode, vak.x, vak.breedte, h);
570
- tk.y -= h + 1 * MM;
577
+ const balkNode = zoekDirecteBarcodeNode(n);
578
+ const h = lengte(balkNode ? eig(balkNode)["height"] : st["height"]) ?? 15 * MM;
579
+ const onderschrift = heeft(n, "barcode") ? plattTekst(n).trim() : "";
580
+ const onderschriftStijl = { ...s, grootte: Math.min(s.grootte, 7), uitlijning: "center" };
581
+ const tekstHoogte = onderschrift ? regelHoogte(onderschriftStijl) : 0;
582
+ const barcodeBreedte = Math.min(45 * MM, vak.breedte);
583
+ const barcodeX = vak.x + Math.max(0, (vak.breedte - barcodeBreedte) / 2);
584
+ tk.zorgVoor(h + tekstHoogte + 1 * MM);
585
+ tekenBarcode(tk, barcode, barcodeX, barcodeBreedte, h);
586
+ tk.y -= h;
587
+ if (onderschrift) {
588
+ tk.y -= tekstHoogte;
589
+ tekenRegel(tk, onderschrift, vak.x, vak.breedte, tk.y + onderschriftStijl.grootte * 0.25, onderschriftStijl);
590
+ }
591
+ tk.y -= 1 * MM;
571
592
  return;
572
593
  }
573
594
  if (n.tag === "#tekst") {
@@ -695,7 +716,7 @@ async function tekenBlok(ctx, n, vak, ouderStijl) {
695
716
  const heelHouden = cl.includes("heelhouden") || /avoid/.test(st["break-inside"] ?? st["page-break-inside"] ?? "");
696
717
  const binnenVak = { x: vak.x + padding, breedte: vak.breedte - padding * 2 };
697
718
  if (!ctx.meten && (heelHouden || achtergrond)) {
698
- const nodig = (await meetHoogte(ctx, n, binnenVak, s)) + padding * 2;
719
+ const nodig = (await meetInhoud(ctx, n, binnenVak, s)) + padding * 2;
699
720
  if (heelHouden && nodig > tk.ruimte && nodig < tk.hoogte - tk.marge * 2) {
700
721
  tk.nieuwePagina();
701
722
  }
@@ -816,7 +837,18 @@ async function tekenTabel(ctx, tabel, vak, s) {
816
837
  const cellen = rij.kinderen.filter((c) => c.tag === "td" || c.tag === "th");
817
838
  const celBreedte = (i) => Math.max(4, (breedtes[i] ?? 20) - padX * 2);
818
839
  const celTekst = cellen.map((c) => plattTekst(c));
819
- const cellenStijl = cellen.map((c, i) => passendeStijl(tk, celTekst[i], stijlVan(c, s), celBreedte(i)));
840
+ // Eén verkleiningsfactor voor de hele rij: losse cellen die elk hun eigen
841
+ // maat kiezen leveren een rommelige, ongelijke kop- en gegevensregel op.
842
+ const ruwStijl = cellen.map((c) => stijlVan(c, s));
843
+ const factor = cellen.reduce((laagste, _c, i) => {
844
+ const basis = ruwStijl[i];
845
+ const passend = passendeStijl(tk, celTekst[i], basis, celBreedte(i));
846
+ return Math.min(laagste, passend.grootte / basis.grootte);
847
+ }, 1);
848
+ const cellenStijl = ruwStijl.map((st) => ({
849
+ ...st,
850
+ grootte: Math.round(st.grootte * factor * 10) / 10,
851
+ }));
820
852
  const teksten = cellen.map((_, i) => breekAf(tk, celTekst[i], cellenStijl[i], celBreedte(i)));
821
853
  const hoogte = Math.max(regelHoogte(s), ...teksten.map((t, i) => Math.max(1, t.length) * regelHoogte(cellenStijl[i] ?? s))) + padY * 2;
822
854
  if (hoogte > tk.ruimte) {
@@ -895,7 +927,7 @@ async function tekenAbsoluut(ctx, n, s) {
895
927
  const hoogte = lengte(st["height"]) ?? regelHoogte(eigen);
896
928
  const yBoven = tk.hoogte - top;
897
929
  const yOnder = yBoven - hoogte;
898
- const barcode = zoekBarcodeWaarde(n);
930
+ const barcode = eigenBarcodeWaarde(n);
899
931
  if (barcode) {
900
932
  const barcodeHoogte = Math.max(5 * MM, hoogte * 0.72);
901
933
  tekenBarcode(tk, barcode, x, breedte, barcodeHoogte, yBoven);
@@ -1063,6 +1095,24 @@ function zoekBarcodeWaarde(n) {
1063
1095
  }
1064
1096
  return null;
1065
1097
  }
1098
+ /** Barcode alleen wanneer dit element zelf de barcode of barcodecontainer is. */
1099
+ function eigenBarcodeWaarde(n) {
1100
+ const eigen = String(n.attrs["data-barcode"] ?? "").trim();
1101
+ if (eigen)
1102
+ return eigen;
1103
+ if (!heeft(n, "barcode"))
1104
+ return null;
1105
+ return zoekBarcodeWaarde(n);
1106
+ }
1107
+ function zoekDirecteBarcodeNode(n) {
1108
+ if (String(n.attrs["data-barcode"] ?? "").trim())
1109
+ return n;
1110
+ for (const kind of n.kinderen) {
1111
+ if (String(kind.attrs["data-barcode"] ?? "").trim())
1112
+ return kind;
1113
+ }
1114
+ return null;
1115
+ }
1066
1116
  /** Zoekt een streepjes- of blokjespatroon (barcode/QR) in de knoop of kinderen. */
1067
1117
  function zoekGradient(n) {
1068
1118
  const css = `${eig(n)["background"] ?? ""} ${eig(n)["background-image"] ?? ""}`;
@@ -1107,8 +1157,6 @@ async function tekenKinderen(ctx, n, vak, s) {
1107
1157
  (/grid/.test(display) && kolommen.trim().split(/\s+/).length === 2);
1108
1158
  const rijModus = /flex/.test(display) ||
1109
1159
  cl.includes("kv") ||
1110
- cl.includes("karkop") ||
1111
- cl.includes("laagkop") ||
1112
1160
  cl.includes("meta") ||
1113
1161
  cl.includes("totalen") ||
1114
1162
  cl.includes("regelrij");
@@ -1146,8 +1194,7 @@ async function tekenKinderen(ctx, n, vak, s) {
1146
1194
  const spreiden = stukken.length > 1 &&
1147
1195
  (verdeel === "space-between" ||
1148
1196
  verdeel === "space-around" ||
1149
- ((!verdeel || verdeel === "normal") &&
1150
- (cl.includes("kv") || cl.includes("karkop") || cl.includes("laagkop"))));
1197
+ ((!verdeel || verdeel === "normal") && cl.includes("kv")));
1151
1198
  const rechtsUit = verdeel === "flex-end" || verdeel === "right" || verdeel === "end";
1152
1199
  if (spreiden) {
1153
1200
  let x = vak.x;
@@ -1253,11 +1300,64 @@ async function laadAfbeeldingen(pdf, wortel) {
1253
1300
  }));
1254
1301
  return { beelden, fouten };
1255
1302
  }
1303
+ /**
1304
+ * Bewaakt constructies die de eigen PDF-motor niet hetzelfde kan uitleggen als
1305
+ * een browser. @page is toegestaan: papier en marge komen uit de canonieke
1306
+ * DocumentPdfOpties. Andere at-rules en complexe selectors worden geweigerd in
1307
+ * plaats van stilletjes genegeerd.
1308
+ */
1309
+ export function controleerPdfOpmaak(html) {
1310
+ const css = leesStylesheets(html).replace(/\/\*[\s\S]*?\*\//g, "");
1311
+ const fouten = new Set();
1312
+ for (const match of css.matchAll(/@([\w-]+)/g)) {
1313
+ const naam = String(match[1] ?? "").toLowerCase();
1314
+ if (naam !== "page")
1315
+ fouten.add(`CSS-regel @${naam} wordt niet ondersteund door de afdrukmotor.`);
1316
+ }
1317
+ let i = 0;
1318
+ while (i < css.length) {
1319
+ const open = css.indexOf("{", i);
1320
+ if (open < 0)
1321
+ break;
1322
+ const kop = css.slice(i, open).trim();
1323
+ let diepte = 0;
1324
+ let einde = open;
1325
+ for (; einde < css.length; einde += 1) {
1326
+ if (css[einde] === "{")
1327
+ diepte += 1;
1328
+ else if (css[einde] === "}") {
1329
+ diepte -= 1;
1330
+ if (!diepte)
1331
+ break;
1332
+ }
1333
+ }
1334
+ i = einde + 1;
1335
+ if (!kop || kop.startsWith("@"))
1336
+ continue;
1337
+ for (const selector of kop.split(",")) {
1338
+ if (!leesSelector(selector)) {
1339
+ fouten.add(`CSS-selector '${selector.trim()}' wordt niet ondersteund door de afdrukmotor.`);
1340
+ }
1341
+ }
1342
+ }
1343
+ return { geldig: fouten.size === 0, fouten: [...fouten] };
1344
+ }
1256
1345
  /** Zet print-HTML om naar een PDF en levert die als base64 (zonder prefix). */
1257
1346
  export async function htmlNaarPdfBytes(opties) {
1258
1347
  const bMm = Number(opties.breedteMm ?? 210);
1259
1348
  const hMm = Number(opties.hoogteMm ?? 297);
1260
- const marge = Number(opties.margeMm ?? 10) * MM;
1349
+ const margeMm = Number(opties.margeMm ?? 10);
1350
+ if (!Number.isFinite(bMm) || !Number.isFinite(hMm) || bMm <= 0 || hMm <= 0) {
1351
+ throw new Error("Het papierformaat is ongeldig.");
1352
+ }
1353
+ if (!Number.isFinite(margeMm) || margeMm < 0 || margeMm * 2 >= Math.min(bMm, hMm)) {
1354
+ throw new Error("De paginamarge is ongeldig.");
1355
+ }
1356
+ const diagnostiek = controleerPdfOpmaak(opties.html);
1357
+ if (!diagnostiek.geldig) {
1358
+ throw new Error(`Afdrukafwijking gevonden: ${diagnostiek.fouten.join(" ")}`);
1359
+ }
1360
+ const marge = margeMm * MM;
1261
1361
  const breedte = (opties.landschap ? Math.max(bMm, hMm) : Math.min(bMm, hMm)) * MM;
1262
1362
  const hoogte = (opties.landschap ? Math.min(bMm, hMm) : Math.max(bMm, hMm)) * MM;
1263
1363
  const pdf = await PDFDocument.create();
@@ -1268,6 +1368,9 @@ export async function htmlNaarPdfBytes(opties) {
1268
1368
  // het document er hetzelfde uitziet als in het voorbeeld op het scherm.
1269
1369
  stempelCss(wortel, ontleedCss(leesStylesheets(opties.html)));
1270
1370
  const { beelden: afbeeldingen, fouten: beeldFouten } = await laadAfbeeldingen(pdf, wortel);
1371
+ if (beeldFouten.size) {
1372
+ throw new Error(`Afdrukafwijking gevonden: ${[...beeldFouten.values()].join(" ")}`);
1373
+ }
1271
1374
  const basis = basisGrootte(opties.html);
1272
1375
  const tk = new Tekenaar(pdf, breedte, hoogte, marge, normaal, vet);
1273
1376
  const ctx = { tk, afbeeldingen, beeldFouten };
@@ -1292,8 +1395,8 @@ export async function htmlNaarPdfBytes(opties) {
1292
1395
  }
1293
1396
  // De layout bepaalt of paginanummers meegaan; zonder voorkeur alleen bij
1294
1397
  // meerdere pagina's.
1295
- const uitMeta = /name=["']pdf-paginanummers["']\s+content=["']ja["']/i.test(opties.html);
1296
- const nummers = opties.paginanummers ?? (uitMeta ? true : tk.paginas.length > 1);
1398
+ const meta = /name=["']pdf-paginanummers["']\s+content=["'](ja|nee)["']/i.exec(opties.html)?.[1];
1399
+ const nummers = opties.paginanummers ?? (meta ? meta === "ja" : tk.paginas.length > 1);
1297
1400
  if (nummers) {
1298
1401
  tk.paginas.forEach((p, i) => {
1299
1402
  const t = `Pagina ${i + 1} van ${tk.paginas.length}`;
@@ -1 +1 @@
1
- {"version":3,"file":"orderData.server.d.ts","sourceRoot":"","sources":["../../src/lib/orderData.server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE/B,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAwBtD,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAKvD;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG;IACrD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAgCA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG;IAC7C,KAAK,EAAE,WAAW,CAAC;IACnB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAMA;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,MAAM,EAAE;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7E,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CA8XrB;AA+DD;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAGhG"}
1
+ {"version":3,"file":"orderData.server.d.ts","sourceRoot":"","sources":["../../src/lib/orderData.server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE/B,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAwBtD,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAKvD;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG;IACrD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAgCA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG;IAC7C,KAAK,EAAE,WAAW,CAAC;IACnB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAMA;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,MAAM,EAAE;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7E,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CA8ZrB;AA+DD;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAGhG"}
@@ -334,22 +334,49 @@ export async function laadPakbonData(db, opties) {
334
334
  const items = karItems.filter((i) => i["cart_id"] === kar["id"]);
335
335
  const maxLagen = Math.max(1, num(kar["max_layers"]) || 0) || 1;
336
336
  const lagen = [];
337
- let huidige = null;
338
- for (const item of items) {
339
- const fusten = num(item["crates"]);
340
- const perFust = num(item["plants_per_crate"]);
341
- const perLaag = num(item["crates_per_layer"]);
342
- const deel = num(item["layer_fraction"]) ||
343
- (perLaag > 0 ? fusten / perLaag : 0) ||
344
- (num(item["layer_share_pct"]) ? num(item["layer_share_pct"]) / 100 : 0) ||
345
- 1;
346
- const product = maakProduct(item, fusten * perFust || num(item["boxes"]), fusten, perFust);
347
- if (!huidige || huidige.ruimte + deel > 1.0001) {
348
- huidige = { producten: [], ruimte: 0 };
349
- lagen.push(huidige);
337
+ // De Logistiek Engine geeft per karregel het laagnummer door. Zodra dat
338
+ // aanwezig is volgen we die indeling exact — nooit zelf herverdelen.
339
+ const engineLagen = items.some((i) => num(i["layer_index"]) > 0);
340
+ if (engineLagen) {
341
+ const perLaag = new Map();
342
+ for (const item of items) {
343
+ const fusten = num(item["crates"]);
344
+ const perFust = num(item["plants_per_crate"]);
345
+ const nummer = Math.max(1, num(item["layer_index"]) || 1);
346
+ const capaciteit = num(item["crates_per_layer"]);
347
+ const inLaag = num(item["crates_in_layer"]) || fusten;
348
+ const deel = capaciteit > 0 ? inLaag / capaciteit : num(item["layer_fraction"]) || 0;
349
+ let laag = perLaag.get(nummer);
350
+ if (!laag) {
351
+ laag = { producten: [], ruimte: 0 };
352
+ perLaag.set(nummer, laag);
353
+ }
354
+ laag.producten.push(maakProduct(item, fusten * perFust || num(item["boxes"]), fusten, perFust));
355
+ laag.ruimte += deel;
356
+ }
357
+ const hoogste = Math.max(maxLagen, ...perLaag.keys());
358
+ for (let n = 1; n <= hoogste; n++) {
359
+ lagen.push(perLaag.get(n) ?? { producten: [], ruimte: 0 });
360
+ }
361
+ }
362
+ else {
363
+ let huidige = null;
364
+ for (const item of items) {
365
+ const fusten = num(item["crates"]);
366
+ const perFust = num(item["plants_per_crate"]);
367
+ const perLaag = num(item["crates_per_layer"]);
368
+ const deel = num(item["layer_fraction"]) ||
369
+ (perLaag > 0 ? fusten / perLaag : 0) ||
370
+ (num(item["layer_share_pct"]) ? num(item["layer_share_pct"]) / 100 : 0) ||
371
+ 1;
372
+ const product = maakProduct(item, fusten * perFust || num(item["boxes"]), fusten, perFust);
373
+ if (!huidige || huidige.ruimte + deel > 1.0001) {
374
+ huidige = { producten: [], ruimte: 0 };
375
+ lagen.push(huidige);
376
+ }
377
+ huidige.producten.push(product);
378
+ huidige.ruimte += deel;
350
379
  }
351
- huidige.producten.push(product);
352
- huidige.ruimte += deel;
353
380
  }
354
381
  if (!lagen.length)
355
382
  lagen.push({ producten: [], ruimte: 0 });
@@ -365,7 +392,7 @@ export async function laadPakbonData(db, opties) {
365
392
  gewicht: kar["weight_kg"] ? `${num(kar["weight_kg"]).toFixed(1)} kg` : "",
366
393
  gedeeld: kar["__gedeeld"] === true,
367
394
  opmerking: String(kar["notes"] ?? ""),
368
- lagen: lagen.slice(0, Math.max(maxLagen, lagen.length)).map((laag, j) => {
395
+ lagen: lagen.map((laag, j) => {
369
396
  const potmaten = uniek(laag.producten.map((product) => product["potmaat"]));
370
397
  return {
371
398
  laagnummer: j + 1,
@@ -0,0 +1,39 @@
1
+ export interface PakbonBarcodeVerzoek {
2
+ print_job_id: string;
3
+ documentnaam: string | null;
4
+ order_nummer: string | null;
5
+ order_ref: string | null;
6
+ klant_naam: string | null;
7
+ klant_nummer: string | null;
8
+ cart_id: string | null;
9
+ cart_label: string | null;
10
+ cart_index: number | null;
11
+ cart_total: number | null;
12
+ layout_variant: string | null;
13
+ layout_id: string | null;
14
+ is_herprint: boolean;
15
+ }
16
+ type Db = {
17
+ from: (tabel: string) => any;
18
+ };
19
+ /**
20
+ * Kijkt of de Engine inmiddels een barcode heeft geleverd voor deze opdracht.
21
+ * Geeft `null` terug zolang dat niet zo is. Er wordt nooit een waarde bedacht.
22
+ */
23
+ export declare function geleverdeBarcodeVoorJob(db: Db, printJobId: string): Promise<string | null>;
24
+ /**
25
+ * Legt (of ververst) het openstaande verzoek vast. Mislukt het wegschrijven,
26
+ * dan mag dat de wachtrij niet breken: de opdracht blijft gewoon wachten.
27
+ */
28
+ export declare function vraagPakbonBarcodeAan(db: Db, verzoek: PakbonBarcodeVerzoek): Promise<void>;
29
+ /** Bouwt het verzoek uit de order zoals die op de pakbon zou komen. */
30
+ export declare function bouwPakbonBarcodeVerzoek(order: unknown, opties: {
31
+ printJobId: string;
32
+ documentnaam?: unknown;
33
+ cart?: Record<string, any> | null;
34
+ layoutVariant?: string | null;
35
+ layoutId?: string | null;
36
+ isHerprint?: boolean;
37
+ }): PakbonBarcodeVerzoek;
38
+ export {};
39
+ //# sourceMappingURL=pakbonBarcodeVerzoek.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pakbonBarcodeVerzoek.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonBarcodeVerzoek.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,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,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,KAAK,EAAE,GAAG;IAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAAE,CAAC;AAY3C;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAShG;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAwBf;AAED,uEAAuE;AACvE,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE;IACN,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACA,oBAAoB,CAkBtB"}