@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.
- package/dist-lib/components/AfleverbriefBuilderPage.d.ts +10 -0
- package/dist-lib/components/AfleverbriefBuilderPage.d.ts.map +1 -0
- package/dist-lib/components/AfleverbriefBuilderPage.js +101 -0
- package/dist-lib/components/BlokOntwerperPage.d.ts.map +1 -1
- package/dist-lib/components/BlokOntwerperPage.js +8 -3
- package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
- package/dist-lib/components/ComputersLijst.js +1 -1
- package/dist-lib/components/FustKolomVolgorde.d.ts +11 -0
- package/dist-lib/components/FustKolomVolgorde.d.ts.map +1 -0
- package/dist-lib/components/FustKolomVolgorde.js +52 -0
- package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
- package/dist-lib/components/LayoutsPage.js +10 -9
- package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/PakbonBuilderPage.js +32 -14
- package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
- package/dist-lib/components/PakbonPreview.js +21 -14
- package/dist-lib/components/PakbonSectiesPanel.d.ts +4 -2
- package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
- package/dist-lib/components/PakbonSectiesPanel.js +5 -3
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts +2 -1
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -1
- package/dist-lib/components/PdfMapToestemmingBanner.js +124 -18
- package/dist-lib/components/PdfVoorbeeld.d.ts +20 -0
- package/dist-lib/components/PdfVoorbeeld.d.ts.map +1 -0
- package/dist-lib/components/PdfVoorbeeld.js +95 -0
- package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -1
- package/dist-lib/components/PrintProgrammaUitleg.js +1 -1
- package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
- package/dist-lib/components/PrintQueuePage.js +81 -43
- package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
- package/dist-lib/components/PrintplekDetailPage.js +2 -2
- package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
- package/dist-lib/components/PrintplekWizard.js +6 -2
- package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/ProductiebonBuilderPage.js +13 -7
- package/dist-lib/index.d.ts +13 -5
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +10 -5
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2280 -198
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +2280 -198
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +2280 -198
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2306 -182
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/aiLayout.functions.d.ts +2280 -198
- package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
- package/dist-lib/lib/documentVoorbeeld.functions.d.ts +23 -0
- package/dist-lib/lib/documentVoorbeeld.functions.d.ts.map +1 -0
- package/dist-lib/lib/documentVoorbeeld.functions.js +37 -0
- package/dist-lib/lib/fontMetrics.d.ts +15 -0
- package/dist-lib/lib/fontMetrics.d.ts.map +1 -0
- package/dist-lib/lib/fontMetrics.js +118 -0
- package/dist-lib/lib/htmlNaarPdf.server.d.ts +2 -2
- package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlNaarPdf.server.js +2 -1
- package/dist-lib/lib/htmlPdf.server.d.ts +11 -0
- package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlPdf.server.js +118 -15
- package/dist-lib/lib/orderData.server.d.ts.map +1 -1
- package/dist-lib/lib/orderData.server.js +43 -16
- package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts +39 -0
- package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts.map +1 -0
- package/dist-lib/lib/pakbonBarcodeVerzoek.js +80 -0
- package/dist-lib/lib/pakbonBuilder.d.ts +62 -3
- package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
- package/dist-lib/lib/pakbonBuilder.js +386 -50
- package/dist-lib/lib/pakbonContent.d.ts +41 -0
- package/dist-lib/lib/pakbonContent.d.ts.map +1 -0
- package/dist-lib/lib/pakbonContent.js +668 -0
- package/dist-lib/lib/pakbonDocument.d.ts +199 -0
- package/dist-lib/lib/pakbonDocument.d.ts.map +1 -0
- package/dist-lib/lib/pakbonDocument.js +735 -0
- package/dist-lib/lib/pakbonHtml.d.ts +7 -0
- package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
- package/dist-lib/lib/pakbonHtml.js +89 -73
- package/dist-lib/lib/pakbonPresentation.d.ts +8 -0
- package/dist-lib/lib/pakbonPresentation.d.ts.map +1 -0
- package/dist-lib/lib/pakbonPresentation.js +31 -0
- package/dist-lib/lib/pakbonScan.d.ts.map +1 -1
- package/dist-lib/lib/pakbonScan.js +20 -38
- package/dist-lib/lib/pdfJobSaver.d.ts +10 -6
- package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -1
- package/dist-lib/lib/pdfJobSaver.js +302 -99
- package/dist-lib/lib/pdfMap.d.ts +37 -2
- package/dist-lib/lib/pdfMap.d.ts.map +1 -1
- package/dist-lib/lib/pdfMap.js +120 -7
- package/dist-lib/lib/pdfOpslagStatus.d.ts +23 -0
- package/dist-lib/lib/pdfOpslagStatus.d.ts.map +1 -0
- package/dist-lib/lib/pdfOpslagStatus.js +74 -0
- package/dist-lib/lib/printApi.d.ts +31 -0
- package/dist-lib/lib/printApi.d.ts.map +1 -1
- package/dist-lib/lib/printApi.js +62 -1
- package/dist-lib/lib/printQueue.server.d.ts +6 -0
- package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/printQueue.server.js +450 -94
- package/dist-lib/lib/printService.functions.d.ts +8857 -529
- package/dist-lib/lib/printService.functions.d.ts.map +1 -1
- package/dist-lib/lib/profielHtml.d.ts.map +1 -1
- package/dist-lib/lib/profielHtml.js +8 -1
- package/dist-lib/lib/useDocumentData.d.ts +8 -0
- package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
- package/dist-lib/lib/useDocumentData.js +1 -1
- package/dist-lib/lib/voorbeeldPrint.d.ts +3 -0
- package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
- package/dist-lib/lib/voorbeeldPrint.js +65 -17
- package/package.json +9 -2
|
@@ -75,8 +75,134 @@ export const FUST_VELD_OPTIES = [
|
|
|
75
75
|
{ value: "locatie", label: "Locatie" },
|
|
76
76
|
{ value: "fustsoort", label: "Tray/fustsoort" },
|
|
77
77
|
{ value: "planten_per_fust", label: "Planten per fust" },
|
|
78
|
+
{ value: "fust_aantal", label: "Aantal fusten" },
|
|
78
79
|
{ value: "aantal", label: "Totaal planten" },
|
|
79
80
|
];
|
|
81
|
+
/**
|
|
82
|
+
* Alle velden die op een fustregel van de afleverbrief kunnen staan. De
|
|
83
|
+
* afleverbrief beschrijft één kar, dus kar- en laagnummer horen er ook bij.
|
|
84
|
+
*/
|
|
85
|
+
export const FUSTREGEL_VELD_OPTIES = [
|
|
86
|
+
{ value: "fustsoort", label: "Fustsoort" },
|
|
87
|
+
{ value: "fusthoogte", label: "Fusthoogte" },
|
|
88
|
+
{ value: "belading", label: "Belading" },
|
|
89
|
+
{ value: "karnummer", label: "Karnummer" },
|
|
90
|
+
{ value: "laagnummer", label: "Laag" },
|
|
91
|
+
{ value: "artikelnummer", label: "Artikelnummer" },
|
|
92
|
+
{ value: "artikelnaam", label: "Omschrijving" },
|
|
93
|
+
{ value: "potmaat", label: "Potmaat" },
|
|
94
|
+
{ value: "kleur", label: "Kleur" },
|
|
95
|
+
{ value: "productgroep", label: "Productgroep" },
|
|
96
|
+
{ value: "locatie", label: "Locatie" },
|
|
97
|
+
{ value: "planten_per_fust", label: "Planten per fust" },
|
|
98
|
+
{ value: "fust_aantal", label: "Aantal fusten" },
|
|
99
|
+
{ value: "aantal", label: "Totaal planten" },
|
|
100
|
+
{ value: "gewicht", label: "Gewicht" },
|
|
101
|
+
];
|
|
102
|
+
/** Labels van de fustregelvelden, gedeeld door scherm en afdruk. */
|
|
103
|
+
export const FUSTREGEL_LABELS = Object.fromEntries(FUSTREGEL_VELD_OPTIES.map((o) => [o.value, o.label]));
|
|
104
|
+
/** Velden die rechts uitgelijnd horen te staan. */
|
|
105
|
+
export const FUSTREGEL_RECHTS = new Set([
|
|
106
|
+
"planten_per_fust",
|
|
107
|
+
"fust_aantal",
|
|
108
|
+
"aantal",
|
|
109
|
+
"gewicht",
|
|
110
|
+
]);
|
|
111
|
+
const tekst = (waarde) => String(waarde ?? "").trim();
|
|
112
|
+
/**
|
|
113
|
+
* Zet de karren van een levering om naar losse fustregels. Met `comprimeren`
|
|
114
|
+
* komen identieke fusten (zelfde fustsoort, artikel, potmaat, kleur en aantal
|
|
115
|
+
* planten per fust) op één regel te staan; het aantal fusten wordt opgeteld.
|
|
116
|
+
* Zonder `comprimeren` krijgt elke losse fust een eigen regel.
|
|
117
|
+
*/
|
|
118
|
+
export function fustRegels(karren, opties = {}) {
|
|
119
|
+
const lijst = Array.isArray(karren) ? karren : [];
|
|
120
|
+
const regels = [];
|
|
121
|
+
for (const kar of lijst) {
|
|
122
|
+
const karnummer = tekst(kar?.karnummer ?? kar?.cart_label);
|
|
123
|
+
for (const laag of Array.isArray(kar?.lagen) ? kar.lagen : []) {
|
|
124
|
+
const fusten = Array.isArray(laag?.fusten) ? laag.fusten : [];
|
|
125
|
+
const fustInfo = (soort) => fusten.find((f) => tekst(f?.fusttype ?? f?.fustsoort).toLowerCase() === soort.toLowerCase());
|
|
126
|
+
for (const pr of Array.isArray(laag?.producten) ? laag.producten : []) {
|
|
127
|
+
const fustsoort = tekst(pr?.fustsoort) || "Onbekend";
|
|
128
|
+
const info = fustInfo(fustsoort);
|
|
129
|
+
regels.push({
|
|
130
|
+
fustsoort,
|
|
131
|
+
fusthoogte: tekst(info?.hoogte),
|
|
132
|
+
belading: tekst(pr?.belading ?? info?.belading ?? laag?.belading),
|
|
133
|
+
karnummer,
|
|
134
|
+
laagnummer: tekst(laag?.laagnummer),
|
|
135
|
+
artikelnummer: tekst(pr?.artikelnummer),
|
|
136
|
+
artikelnaam: tekst(pr?.artikelnaam),
|
|
137
|
+
potmaat: tekst(pr?.potmaat ?? laag?.potmaat),
|
|
138
|
+
kleur: tekst(pr?.kleur),
|
|
139
|
+
productgroep: tekst(pr?.productgroep),
|
|
140
|
+
locatie: tekst(pr?.locatie),
|
|
141
|
+
planten_per_fust: Number(pr?.planten_per_fust ?? 0) || 0,
|
|
142
|
+
fust_aantal: Number(pr?.fust_aantal ?? 0) || 0,
|
|
143
|
+
aantal: Number(pr?.aantal ?? 0) || 0,
|
|
144
|
+
gewicht: tekst(pr?.gewicht),
|
|
145
|
+
barcode: tekst(pr?.barcode ?? info?.barcode),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
let uit = regels;
|
|
151
|
+
if (opties.comprimeren !== false) {
|
|
152
|
+
const map = new Map();
|
|
153
|
+
for (const r of regels) {
|
|
154
|
+
const sleutel = [
|
|
155
|
+
r.fustsoort,
|
|
156
|
+
r.fusthoogte,
|
|
157
|
+
r.artikelnummer,
|
|
158
|
+
r.artikelnaam,
|
|
159
|
+
r.potmaat,
|
|
160
|
+
r.kleur,
|
|
161
|
+
r.planten_per_fust,
|
|
162
|
+
]
|
|
163
|
+
.join("|")
|
|
164
|
+
.toLowerCase();
|
|
165
|
+
const bestaand = map.get(sleutel);
|
|
166
|
+
if (bestaand) {
|
|
167
|
+
bestaand.fust_aantal += r.fust_aantal;
|
|
168
|
+
bestaand.aantal += r.aantal;
|
|
169
|
+
// Kar- en laagnummers van samengevoegde regels blijven zichtbaar.
|
|
170
|
+
const lagen = new Set([...bestaand.laagnummer.split(", "), r.laagnummer].filter(Boolean));
|
|
171
|
+
bestaand.laagnummer = [...lagen].join(", ");
|
|
172
|
+
if (!bestaand.locatie)
|
|
173
|
+
bestaand.locatie = r.locatie;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
map.set(sleutel, { ...r });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
uit = [...map.values()];
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// Zonder samenvoegen krijgt elke losse fust een eigen regel, zodat de
|
|
183
|
+
// schakelaar zichtbaar effect heeft: 8 dezelfde fusten worden 8 regels
|
|
184
|
+
// van 1 fust in plaats van één regel met 8.
|
|
185
|
+
const los = [];
|
|
186
|
+
for (const r of regels) {
|
|
187
|
+
const n = r.fust_aantal;
|
|
188
|
+
if (n > 1 && n <= 500) {
|
|
189
|
+
const perFust = r.planten_per_fust > 0 ? r.planten_per_fust : Math.round(r.aantal / n);
|
|
190
|
+
for (let i = 0; i < n; i += 1) {
|
|
191
|
+
los.push({ ...r, fust_aantal: 1, aantal: perFust });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
los.push(r);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
uit = los;
|
|
199
|
+
}
|
|
200
|
+
const sortering = opties.sortering ?? "fustsoort";
|
|
201
|
+
if (sortering !== "eigen") {
|
|
202
|
+
uit = [...uit].sort((a, b) => String(a[sortering] ?? "").localeCompare(String(b[sortering] ?? ""), "nl", { numeric: true }));
|
|
203
|
+
}
|
|
204
|
+
return uit;
|
|
205
|
+
}
|
|
80
206
|
const groepering = {
|
|
81
207
|
key: "groepering",
|
|
82
208
|
label: "Groeperen op",
|
|
@@ -209,6 +335,52 @@ export const SECTIE_REGISTER = [
|
|
|
209
335
|
},
|
|
210
336
|
],
|
|
211
337
|
},
|
|
338
|
+
{
|
|
339
|
+
type: "fustregels",
|
|
340
|
+
label: "Fustregels",
|
|
341
|
+
omschrijving: "Alle fusten van deze kar als regels, met de fustgegevens en het aantal fusten per regel.",
|
|
342
|
+
opties: [
|
|
343
|
+
{
|
|
344
|
+
key: "velden",
|
|
345
|
+
label: "Zichtbare fustgegevens",
|
|
346
|
+
type: "meerkeuze",
|
|
347
|
+
standaard: [
|
|
348
|
+
"fustsoort",
|
|
349
|
+
"artikelnummer",
|
|
350
|
+
"artikelnaam",
|
|
351
|
+
"potmaat",
|
|
352
|
+
"planten_per_fust",
|
|
353
|
+
"fust_aantal",
|
|
354
|
+
"aantal",
|
|
355
|
+
],
|
|
356
|
+
opties: FUSTREGEL_VELD_OPTIES,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
key: "comprimeren",
|
|
360
|
+
label: "Identieke fusten samenvoegen tot één regel",
|
|
361
|
+
type: "schakelaar",
|
|
362
|
+
standaard: true,
|
|
363
|
+
hint: "Twee dezelfde fusten op de kar komen dan op één regel te staan, met 2 bij het aantal fusten.",
|
|
364
|
+
},
|
|
365
|
+
{ key: "toonKoppen", label: "Kolomkoppen tonen", type: "schakelaar", standaard: true },
|
|
366
|
+
{ key: "zebra", label: "Om-en-om arcering", type: "schakelaar", standaard: false },
|
|
367
|
+
{ key: "randen", label: "Randen om cellen", type: "schakelaar", standaard: true },
|
|
368
|
+
{ key: "toonTotaal", label: "Totaalregel tonen", type: "schakelaar", standaard: true },
|
|
369
|
+
{
|
|
370
|
+
key: "sortering",
|
|
371
|
+
label: "Sorteren op",
|
|
372
|
+
type: "keuze",
|
|
373
|
+
standaard: "fustsoort",
|
|
374
|
+
opties: [
|
|
375
|
+
{ value: "eigen", label: "Eigen volgorde" },
|
|
376
|
+
{ value: "fustsoort", label: "Fustsoort" },
|
|
377
|
+
{ value: "artikelnummer", label: "Artikelnummer" },
|
|
378
|
+
{ value: "artikelnaam", label: "Omschrijving" },
|
|
379
|
+
{ value: "locatie", label: "Locatie" },
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
],
|
|
383
|
+
},
|
|
212
384
|
{
|
|
213
385
|
type: "pickmethode",
|
|
214
386
|
label: "Pickmethode",
|
|
@@ -244,6 +416,7 @@ export const SECTIE_REGISTER = [
|
|
|
244
416
|
"locatie",
|
|
245
417
|
"fustsoort",
|
|
246
418
|
"planten_per_fust",
|
|
419
|
+
"fust_aantal",
|
|
247
420
|
"aantal",
|
|
248
421
|
],
|
|
249
422
|
opties: FUST_VELD_OPTIES,
|
|
@@ -483,6 +656,13 @@ export const SECTIE_REGISTER = [
|
|
|
483
656
|
{ key: "label", label: "Bijschrift", type: "tekst", standaard: "Voor ontvangst getekend" },
|
|
484
657
|
{ key: "toonNaam", label: "Naamregel", type: "schakelaar", standaard: true },
|
|
485
658
|
{ key: "toonDatum", label: "Datumregel", type: "schakelaar", standaard: true },
|
|
659
|
+
{
|
|
660
|
+
key: "toonBarcode",
|
|
661
|
+
label: "Barcode onderaan tonen",
|
|
662
|
+
type: "schakelaar",
|
|
663
|
+
standaard: true,
|
|
664
|
+
hint: "De barcode wordt uitsluitend overgenomen uit de Engine-opdracht.",
|
|
665
|
+
},
|
|
486
666
|
],
|
|
487
667
|
},
|
|
488
668
|
{
|
|
@@ -564,20 +744,77 @@ export function standaardPakbonConfig() {
|
|
|
564
744
|
export function leesPakbonConfig(config) {
|
|
565
745
|
// Accepteert zowel de layout-config ({ pakbon: {...} }) als een kale
|
|
566
746
|
// PakbonConfig. Zonder deze tolerantie viel de afdruk terug op de
|
|
567
|
-
// standaardsecties en verdween o.a. het documentlogo.
|
|
747
|
+
// standaardsecties en verdween o.a. het documentlogo. De sleutel
|
|
748
|
+
// "afleverbrief" wordt meegelezen zodat de printpijplijn ook
|
|
749
|
+
// afleverbrief-layouts met hun eigen secties afdrukt.
|
|
568
750
|
const raw = config;
|
|
569
751
|
const c = Array.isArray(raw?.secties)
|
|
570
752
|
? raw
|
|
571
|
-
: raw?.pakbon;
|
|
753
|
+
: (raw?.pakbon ?? raw?.afleverbrief);
|
|
572
754
|
const secties = Array.isArray(c?.secties) ? c.secties : null;
|
|
573
755
|
const logo = c?.logo ?? null;
|
|
574
756
|
const basis = secties && secties.length ? { secties } : standaardPakbonConfig();
|
|
575
757
|
return { ...basis, secties: migreerPickmethode(basis.secties), logo };
|
|
576
758
|
}
|
|
759
|
+
/** Standaardindeling van een afleverbrief: geen kar-, laag- of fustblokken. */
|
|
760
|
+
export function standaardAfleverbriefConfig() {
|
|
761
|
+
return {
|
|
762
|
+
secties: [
|
|
763
|
+
"logo",
|
|
764
|
+
"bedrijfsgegevens",
|
|
765
|
+
"klantgegevens",
|
|
766
|
+
"afleveradres",
|
|
767
|
+
"orderinformatie",
|
|
768
|
+
"transportinformatie",
|
|
769
|
+
"fustregels",
|
|
770
|
+
"totalen",
|
|
771
|
+
"opmerkingen",
|
|
772
|
+
"handtekening",
|
|
773
|
+
].map(nieuweSectie),
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Blokken die op een afleverbrief thuishoren. Een afleverbrief beschrijft
|
|
778
|
+
* altijd precies één kar, dus kar-, laag- en pickmethodeblokken vervallen.
|
|
779
|
+
*/
|
|
780
|
+
export const AFLEVERBRIEF_SECTIE_TYPES = [
|
|
781
|
+
"logo",
|
|
782
|
+
"bedrijfsgegevens",
|
|
783
|
+
"klantgegevens",
|
|
784
|
+
"afleveradres",
|
|
785
|
+
"factuuradres",
|
|
786
|
+
"orderinformatie",
|
|
787
|
+
"transportinformatie",
|
|
788
|
+
"fustregels",
|
|
789
|
+
"totalen",
|
|
790
|
+
"opmerkingen",
|
|
791
|
+
"handtekening",
|
|
792
|
+
"tekstblok",
|
|
793
|
+
"qrcode",
|
|
794
|
+
"barcode",
|
|
795
|
+
"afbeelding",
|
|
796
|
+
];
|
|
797
|
+
/** Leest de sectie-opbouw van een afleverbrief-layout. */
|
|
798
|
+
export function leesAfleverbriefConfig(config) {
|
|
799
|
+
// Eerst de eigen sleutel; oudere afleverbrief-layouts zijn per abuis via de
|
|
800
|
+
// pakbon-opbouw onder "pakbon" opgeslagen en worden hier meegelezen.
|
|
801
|
+
const raw = config;
|
|
802
|
+
const c = Array.isArray(raw?.secties)
|
|
803
|
+
? raw
|
|
804
|
+
: (raw?.afleverbrief ?? raw?.pakbon);
|
|
805
|
+
const secties = Array.isArray(c?.secties) ? c.secties : null;
|
|
806
|
+
const logo = c?.logo ?? null;
|
|
807
|
+
const basis = secties && secties.length ? { secties } : standaardAfleverbriefConfig();
|
|
808
|
+
return { ...basis, secties: basis.secties, logo };
|
|
809
|
+
}
|
|
577
810
|
/** Zet de oude karren-optie "pickmethode" om naar een eigen pickmethode-blok. */
|
|
578
811
|
function migreerPickmethode(secties) {
|
|
812
|
+
// Alleen relevant voor pakbonnen met een karren-blok; een afleverbrief
|
|
813
|
+
// krijgt nooit een pickmethode-kop.
|
|
579
814
|
if (secties.some((s) => s.type === "pickmethode"))
|
|
580
815
|
return secties;
|
|
816
|
+
if (!secties.some((s) => s.type === "karren"))
|
|
817
|
+
return secties;
|
|
581
818
|
const karIndex = secties.findIndex((s) => s.type === "karren");
|
|
582
819
|
const oud = karIndex >= 0 ? String(secties[karIndex].opties?.["pickmethode"] ?? "kar") : "kar";
|
|
583
820
|
const blok = nieuweSectie("pickmethode");
|
|
@@ -902,71 +1139,93 @@ export function karBundelTekst(aantal) {
|
|
|
902
1139
|
export function laagBundelTekst(aantal) {
|
|
903
1140
|
return `Deze laag ${aantal}×`;
|
|
904
1141
|
}
|
|
1142
|
+
const fustSleutel = (waarde) => String(waarde ?? "")
|
|
1143
|
+
.trim()
|
|
1144
|
+
.replace(/\s+/g, " ")
|
|
1145
|
+
.toLowerCase();
|
|
905
1146
|
/**
|
|
906
1147
|
* Verzamellijst met alle fusten van een order, opgeteld per fusttype,
|
|
907
1148
|
* inclusief de producten die in dat fusttype gepickt moeten worden.
|
|
908
|
-
*
|
|
909
|
-
*
|
|
1149
|
+
* Een product hoort uitsluitend bij zijn eigen fustsoort — nooit bij alle
|
|
1150
|
+
* fustgroepen van de laag.
|
|
910
1151
|
*/
|
|
911
1152
|
export function fustVerzamellijst(karren) {
|
|
912
1153
|
const lijst = Array.isArray(karren) ? karren : [];
|
|
913
1154
|
const map = new Map();
|
|
1155
|
+
/** Expliciet door de Engine opgegeven fustaantallen per fusttype. */
|
|
1156
|
+
const opgegevenAantallen = new Map();
|
|
1157
|
+
const zoekGroep = (type, f) => {
|
|
1158
|
+
const sleutel = fustSleutel(type) || "onbekend";
|
|
1159
|
+
let groep = map.get(sleutel);
|
|
1160
|
+
if (!groep) {
|
|
1161
|
+
groep = {
|
|
1162
|
+
fusttype: String(type ?? "").trim() || "Onbekend",
|
|
1163
|
+
aantal: 0,
|
|
1164
|
+
hoogte: String(f?.["hoogte"] ?? ""),
|
|
1165
|
+
belading: String(f?.["belading"] ?? ""),
|
|
1166
|
+
producten: [],
|
|
1167
|
+
};
|
|
1168
|
+
map.set(sleutel, groep);
|
|
1169
|
+
}
|
|
1170
|
+
else if (f) {
|
|
1171
|
+
if (!groep.hoogte && f["hoogte"])
|
|
1172
|
+
groep.hoogte = String(f["hoogte"]);
|
|
1173
|
+
if (!groep.belading && f["belading"])
|
|
1174
|
+
groep.belading = String(f["belading"]);
|
|
1175
|
+
}
|
|
1176
|
+
return groep;
|
|
1177
|
+
};
|
|
914
1178
|
for (const kar of lijst) {
|
|
915
1179
|
for (const laag of Array.isArray(kar?.lagen) ? kar.lagen : []) {
|
|
916
1180
|
const producten = Array.isArray(laag?.producten) ? laag.producten : [];
|
|
917
|
-
// Zonder aparte fustlijst: fusten afleiden uit de producten, zodat een
|
|
918
|
-
// module die alleen orderregels aanlevert toch een verzamellijst krijgt.
|
|
919
1181
|
const opgegeven = Array.isArray(laag?.fusten) ? laag.fusten : [];
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
for (const pr of producten) {
|
|
923
|
-
const soort = String(pr?.fustsoort ?? "").trim() || "Onbekend";
|
|
924
|
-
const aantal = Number(pr?.fust_aantal ?? 0) || 0;
|
|
925
|
-
if (aantal > 0)
|
|
926
|
-
afgeleid.set(soort, (afgeleid.get(soort) ?? 0) + aantal);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
const fusten = opgegeven.length
|
|
930
|
-
? opgegeven
|
|
931
|
-
: Array.from(afgeleid.entries()).map(([fusttype, aantal]) => ({ fusttype, aantal }));
|
|
932
|
-
for (const f of fusten) {
|
|
1182
|
+
// Fustmetadata (hoogte/belading) en expliciete aantallen vastleggen.
|
|
1183
|
+
for (const f of opgegeven) {
|
|
933
1184
|
const type = String(f?.fusttype ?? f?.fustsoort ?? "Onbekend");
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1185
|
+
zoekGroep(type, f);
|
|
1186
|
+
const sleutel = fustSleutel(type) || "onbekend";
|
|
1187
|
+
opgegevenAantallen.set(sleutel, (opgegevenAantallen.get(sleutel) ?? 0) + (Number(f?.aantal ?? 0) || 0));
|
|
1188
|
+
}
|
|
1189
|
+
// Producten bij hun eigen fustsoort plaatsen.
|
|
1190
|
+
for (const pr of producten) {
|
|
1191
|
+
const type = String(pr?.fustsoort ?? "").trim() || "Onbekend";
|
|
1192
|
+
const groep = zoekGroep(type);
|
|
1193
|
+
const nr = String(pr?.artikelnummer ?? "");
|
|
1194
|
+
const naam = String(pr?.artikelnaam ?? "");
|
|
1195
|
+
const bestaand = groep.producten.find((x) => x.artikelnummer === nr && x.artikelnaam === naam);
|
|
1196
|
+
const aantal = Number(pr?.aantal ?? 0) || 0;
|
|
1197
|
+
const fustAantal = Number(pr?.fust_aantal ?? 0) || 0;
|
|
1198
|
+
if (bestaand) {
|
|
1199
|
+
bestaand.aantal += aantal;
|
|
1200
|
+
bestaand.fust_aantal += fustAantal;
|
|
944
1201
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
productgroep: String(pr?.productgroep ?? ""),
|
|
959
|
-
locatie: String(pr?.locatie ?? ""),
|
|
960
|
-
fustsoort: String(pr?.fustsoort ?? ""),
|
|
961
|
-
planten_per_fust: Number(pr?.planten_per_fust ?? 0),
|
|
962
|
-
aantal: Number(pr?.aantal ?? 0),
|
|
963
|
-
});
|
|
964
|
-
}
|
|
1202
|
+
else {
|
|
1203
|
+
groep.producten.push({
|
|
1204
|
+
artikelnummer: nr,
|
|
1205
|
+
artikelnaam: naam,
|
|
1206
|
+
potmaat: String(pr?.potmaat ?? ""),
|
|
1207
|
+
kleur: String(pr?.kleur ?? ""),
|
|
1208
|
+
productgroep: String(pr?.productgroep ?? ""),
|
|
1209
|
+
locatie: String(pr?.locatie ?? ""),
|
|
1210
|
+
fustsoort: String(pr?.fustsoort ?? ""),
|
|
1211
|
+
planten_per_fust: Number(pr?.planten_per_fust ?? 0) || 0,
|
|
1212
|
+
fust_aantal: fustAantal,
|
|
1213
|
+
aantal,
|
|
1214
|
+
});
|
|
965
1215
|
}
|
|
966
1216
|
}
|
|
967
1217
|
}
|
|
968
1218
|
}
|
|
969
|
-
|
|
1219
|
+
const groepen = [...map.entries()].map(([sleutel, groep]) => {
|
|
1220
|
+
const uitProducten = groep.producten.reduce((n, p) => n + p.fust_aantal, 0);
|
|
1221
|
+
const expliciet = opgegevenAantallen.get(sleutel) ?? 0;
|
|
1222
|
+
// Engine-opgave is leidend; anders tellen we de fusten van de producten op.
|
|
1223
|
+
groep.aantal = expliciet > 0 ? expliciet : uitProducten;
|
|
1224
|
+
return groep;
|
|
1225
|
+
});
|
|
1226
|
+
return groepen
|
|
1227
|
+
.filter((g) => g.producten.length > 0 || g.aantal > 0)
|
|
1228
|
+
.sort((a, b) => a.fusttype.localeCompare(b.fusttype));
|
|
970
1229
|
}
|
|
971
1230
|
/**
|
|
972
1231
|
* Voorbeeld van een deelkar (niet-volle kar): alleen een deel van de fusten,
|
|
@@ -984,8 +1243,85 @@ export function deelkarVoorbeeldOrder(order = DEMO_ORDER) {
|
|
|
984
1243
|
{
|
|
985
1244
|
...eerste,
|
|
986
1245
|
gedeeld: true,
|
|
1246
|
+
barcode: "VOORBEELD-DEELKAR",
|
|
987
1247
|
lagen: [{ ...laag, producten: laag.producten.slice(0, 1), fusten: laag.fusten?.slice(0, 1) ?? [] }],
|
|
988
1248
|
},
|
|
989
1249
|
],
|
|
990
1250
|
};
|
|
991
1251
|
}
|
|
1252
|
+
// --- restpakbon (deelkar) ---------------------------------------------------
|
|
1253
|
+
/** Restregels zoals de Logistics Engine ze meestuurt onder `cart.cart_items`. */
|
|
1254
|
+
export function deelkarRegels(order) {
|
|
1255
|
+
const o = (order && typeof order === "object" ? order : {});
|
|
1256
|
+
const cart = (o["cart"] && typeof o["cart"] === "object" ? o["cart"] : {});
|
|
1257
|
+
const lijst = cart["cart_items"] ?? cart["items"];
|
|
1258
|
+
return Array.isArray(lijst) ? lijst : [];
|
|
1259
|
+
}
|
|
1260
|
+
const tekstWaarde = (waarde) => waarde === undefined || waarde === null ? "" : String(waarde).trim();
|
|
1261
|
+
/**
|
|
1262
|
+
* Beperkt een order tot de restregels van één deelkar. Alleen wat de Engine
|
|
1263
|
+
* als `cart.cart_items` meestuurt komt op de restpakbon te staan; nooit de
|
|
1264
|
+
* volledige karinhoud. Wordt gedeeld door voorbeeld, PDF en print, zodat de
|
|
1265
|
+
* drie weergaven niet uiteen kunnen lopen.
|
|
1266
|
+
*/
|
|
1267
|
+
export function beperkTotDeelkar(order) {
|
|
1268
|
+
const regels = deelkarRegels(order);
|
|
1269
|
+
if (!regels.length)
|
|
1270
|
+
return order;
|
|
1271
|
+
const o = (order && typeof order === "object" ? order : {});
|
|
1272
|
+
const cart = (o["cart"] && typeof o["cart"] === "object" ? o["cart"] : {});
|
|
1273
|
+
const karren = Array.isArray(o["karren"]) ? o["karren"] : [];
|
|
1274
|
+
const cartId = tekstWaarde(cart["cart_id"]);
|
|
1275
|
+
const basisKar = (cartId ? karren.find((k) => tekstWaarde(k["cart_id"]) === cartId) : undefined) ??
|
|
1276
|
+
karren[0] ??
|
|
1277
|
+
{};
|
|
1278
|
+
const producten = regels.map((raw) => {
|
|
1279
|
+
const item = raw;
|
|
1280
|
+
return {
|
|
1281
|
+
artikelnummer: tekstWaarde(item["artikelnummer"] ?? item["artikelcode"]),
|
|
1282
|
+
artikelnaam: tekstWaarde(item["artikelnaam"] ?? item["product_name"] ?? item["omschrijving"]),
|
|
1283
|
+
potmaat: tekstWaarde(item["potmaat"]),
|
|
1284
|
+
aantal: Number(item["aantal"] ?? item["quantity"] ?? 0) || 0,
|
|
1285
|
+
belading: tekstWaarde(item["belading"]),
|
|
1286
|
+
barcode: tekstWaarde(item["barcode"]),
|
|
1287
|
+
opmerking: tekstWaarde(item["opmerking"]),
|
|
1288
|
+
locatie: tekstWaarde(item["locatie"]),
|
|
1289
|
+
gewicht: tekstWaarde(item["gewicht"]),
|
|
1290
|
+
productgroep: tekstWaarde(item["productgroep"]),
|
|
1291
|
+
kleur: tekstWaarde(item["kleur"]),
|
|
1292
|
+
fust_aantal: Number(item["fust_aantal"] ?? item["aantal_fusten"] ?? 0) || 0,
|
|
1293
|
+
fustsoort: tekstWaarde(item["fustsoort"] ?? item["fusttype"]),
|
|
1294
|
+
planten_per_fust: Number(item["planten_per_fust"] ?? 0) || 0,
|
|
1295
|
+
};
|
|
1296
|
+
});
|
|
1297
|
+
// Fusten per soort optellen uit dezelfde restregels, zodat de verzamellijst
|
|
1298
|
+
// en de totalen nooit meer tonen dan er nog verzameld moet worden.
|
|
1299
|
+
const fustMap = new Map();
|
|
1300
|
+
for (const pr of producten) {
|
|
1301
|
+
const sleutel = pr.fustsoort.toLowerCase() || "onbekend";
|
|
1302
|
+
const bestaand = fustMap.get(sleutel);
|
|
1303
|
+
if (bestaand)
|
|
1304
|
+
bestaand.aantal += pr.fust_aantal;
|
|
1305
|
+
else
|
|
1306
|
+
fustMap.set(sleutel, {
|
|
1307
|
+
fusttype: pr.fustsoort || "Onbekend",
|
|
1308
|
+
aantal: pr.fust_aantal,
|
|
1309
|
+
hoogte: "",
|
|
1310
|
+
belading: pr.belading,
|
|
1311
|
+
barcode: "",
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
const laag = {
|
|
1315
|
+
laagnummer: 1,
|
|
1316
|
+
belading: "",
|
|
1317
|
+
potmaat: "",
|
|
1318
|
+
gewicht: "",
|
|
1319
|
+
opmerking: "",
|
|
1320
|
+
producten,
|
|
1321
|
+
fusten: [...fustMap.values()].filter((f) => f.aantal > 0),
|
|
1322
|
+
};
|
|
1323
|
+
return {
|
|
1324
|
+
...o,
|
|
1325
|
+
karren: [{ ...basisKar, lagen: [laag] }],
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type DemoOrder, type PakbonConfig } from "./pakbonBuilder.js";
|
|
2
|
+
import { type Flow } from "./pakbonDocument.js";
|
|
3
|
+
export interface PakbonLogo {
|
|
4
|
+
id: string;
|
|
5
|
+
naam?: string;
|
|
6
|
+
viewUrl?: string | null;
|
|
7
|
+
}
|
|
8
|
+
/** Alles wat één renderactie nodig heeft; overal identiek samengesteld. */
|
|
9
|
+
export interface PakbonRenderInput {
|
|
10
|
+
config: PakbonConfig | unknown;
|
|
11
|
+
order: PakbonOrderVorm;
|
|
12
|
+
breedteMm: number;
|
|
13
|
+
hoogteMm: number;
|
|
14
|
+
margeMm: number;
|
|
15
|
+
basisGroottePt: number;
|
|
16
|
+
logos: PakbonLogo[];
|
|
17
|
+
layoutVariant: string | null;
|
|
18
|
+
/** Alleen voor "Voorbeeld printen": hele karren gevolgd door een deelkar. */
|
|
19
|
+
beideVarianten?: boolean;
|
|
20
|
+
zonderPaginavoet?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type PakbonOrderVorm = DemoOrder & {
|
|
23
|
+
barcode?: string;
|
|
24
|
+
cart?: {
|
|
25
|
+
barcode?: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export interface PakbonInhoud {
|
|
29
|
+
flows: Flow[];
|
|
30
|
+
paginaKop: Flow[];
|
|
31
|
+
paginaVoet: Flow[];
|
|
32
|
+
paginanummers: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** Bouwt het complete inhoudsmodel van één pakbon. */
|
|
35
|
+
export declare function bouwPakbonInhoud(input: PakbonRenderInput): PakbonInhoud;
|
|
36
|
+
/**
|
|
37
|
+
* Inhoud voor "Voorbeeld printen": eerst de hele karren, daarna één
|
|
38
|
+
* deelkarpagina — exact zoals het gecombineerde voorbeeld op het scherm.
|
|
39
|
+
*/
|
|
40
|
+
export declare function bouwGecombineerdeInhoud(input: PakbonRenderInput): PakbonInhoud;
|
|
41
|
+
//# sourceMappingURL=pakbonContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pakbonContent.d.ts","sourceRoot":"","sources":["../../src/lib/pakbonContent.ts"],"names":[],"mappings":"AASA,OAAO,EAoBL,KAAK,SAAS,EAEd,KAAK,YAAY,EAGlB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAe,KAAK,IAAI,EAAmC,MAAM,kBAAkB,CAAC;AAE3F,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC;IAC/B,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7B,CAAC;AAomBF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,IAAI,EAAE,CAAC;IAClB,UAAU,EAAE,IAAI,EAAE,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,sDAAsD;AACtD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA+EvE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAmB9E"}
|