@flowselections/pick-schermen-kwekers 1.0.2 → 1.0.4
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/PickPublicPage.d.ts +7 -0
- package/dist-lib/components/PickPublicPage.d.ts.map +1 -0
- package/dist-lib/components/PickPublicPage.js +19 -0
- package/dist-lib/components/PickstationsPage.d.ts.map +1 -1
- package/dist-lib/components/PickstationsPage.js +57 -14
- package/dist-lib/components/pick/LanguageTiles.d.ts +8 -0
- package/dist-lib/components/pick/LanguageTiles.d.ts.map +1 -0
- package/dist-lib/components/pick/LanguageTiles.js +11 -0
- package/dist-lib/components/pick/PickScherm.d.ts +6 -4
- package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
- package/dist-lib/components/pick/PickScherm.js +145 -61
- package/dist-lib/components/pick/PublicPickRoute.d.ts +6 -0
- package/dist-lib/components/pick/PublicPickRoute.d.ts.map +1 -0
- package/dist-lib/components/pick/PublicPickRoute.js +11 -0
- package/dist-lib/components/pick/QueueTable.d.ts +4 -1
- package/dist-lib/components/pick/QueueTable.d.ts.map +1 -1
- package/dist-lib/components/pick/QueueTable.js +11 -10
- package/dist-lib/hooks/usePickQueue.d.ts +7 -1
- package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
- package/dist-lib/hooks/usePickQueue.js +43 -6
- package/dist-lib/index.d.ts +6 -6
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +7 -12
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +9221 -5284
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +9221 -5284
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +9221 -5284
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +9394 -5387
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/layoutApi.d.ts +23 -0
- package/dist-lib/lib/layoutApi.d.ts.map +1 -0
- package/dist-lib/lib/layoutApi.js +94 -0
- package/dist-lib/lib/layoutMaker/documentProfiles.d.ts +50 -0
- package/dist-lib/lib/layoutMaker/documentProfiles.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/documentProfiles.js +458 -0
- package/dist-lib/lib/layoutMaker/documentTypes.d.ts +123 -0
- package/dist-lib/lib/layoutMaker/documentTypes.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/documentTypes.js +74 -0
- package/dist-lib/lib/layoutMaker/logoLibrary.d.ts +13 -0
- package/dist-lib/lib/layoutMaker/logoLibrary.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/logoLibrary.js +54 -0
- package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts +196 -0
- package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/pakbonBuilder.js +813 -0
- package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts +48 -0
- package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts.map +1 -0
- package/dist-lib/lib/layoutMaker/pakbonHtml.js +703 -0
- package/dist-lib/lib/layoutRenderer.d.ts +7 -0
- package/dist-lib/lib/layoutRenderer.d.ts.map +1 -0
- package/dist-lib/lib/layoutRenderer.js +233 -0
- package/dist-lib/lib/layoutTypes.d.ts +84 -0
- package/dist-lib/lib/layoutTypes.d.ts.map +1 -0
- package/dist-lib/lib/layoutTypes.js +25 -0
- package/dist-lib/lib/logisticsApi.d.ts +54 -0
- package/dist-lib/lib/logisticsApi.d.ts.map +1 -0
- package/dist-lib/lib/logisticsApi.js +72 -0
- package/dist-lib/lib/logisticsTypes.d.ts +34 -0
- package/dist-lib/lib/logisticsTypes.d.ts.map +1 -0
- package/dist-lib/lib/logisticsTypes.js +36 -0
- package/dist-lib/lib/orderContext.d.ts +50 -0
- package/dist-lib/lib/orderContext.d.ts.map +1 -0
- package/dist-lib/lib/orderContext.js +162 -0
- package/dist-lib/lib/pakbonOrderInput.d.ts +8 -0
- package/dist-lib/lib/pakbonOrderInput.d.ts.map +1 -0
- package/dist-lib/lib/pakbonOrderInput.js +150 -0
- package/dist-lib/lib/pickApi.d.ts +24 -1
- package/dist-lib/lib/pickApi.d.ts.map +1 -1
- package/dist-lib/lib/pickApi.js +46 -5
- package/dist-lib/lib/pickI18n.d.ts +14 -0
- package/dist-lib/lib/pickI18n.d.ts.map +1 -0
- package/dist-lib/lib/pickI18n.js +500 -0
- package/dist-lib/lib/pickPrint.d.ts +18 -0
- package/dist-lib/lib/pickPrint.d.ts.map +1 -0
- package/dist-lib/lib/pickPrint.js +184 -0
- package/dist-lib/lib/pickTypes.d.ts +1 -0
- package/dist-lib/lib/pickTypes.d.ts.map +1 -1
- package/package.json +7 -20
- package/dist-lib/components/PickBeheerPage.d.ts +0 -2
- package/dist-lib/components/PickBeheerPage.d.ts.map +0 -1
- package/dist-lib/components/PickBeheerPage.js +0 -84
- package/dist-lib/components/PickDashboardPage.d.ts +0 -2
- package/dist-lib/components/PickDashboardPage.d.ts.map +0 -1
- package/dist-lib/components/PickDashboardPage.js +0 -54
- package/dist-lib/components/PickKioskPage.d.ts +0 -7
- package/dist-lib/components/PickKioskPage.d.ts.map +0 -1
- package/dist-lib/components/PickKioskPage.js +0 -18
- package/dist-lib/components/PickstationDetailPage.d.ts +0 -6
- package/dist-lib/components/PickstationDetailPage.d.ts.map +0 -1
- package/dist-lib/components/PickstationDetailPage.js +0 -25
- package/dist-lib/components/pick/ConfigCrud.d.ts +0 -27
- package/dist-lib/components/pick/ConfigCrud.d.ts.map +0 -1
- package/dist-lib/components/pick/ConfigCrud.js +0 -64
- package/dist-lib/components/pick/CountryTiles.d.ts +0 -9
- package/dist-lib/components/pick/CountryTiles.d.ts.map +0 -1
- package/dist-lib/components/pick/CountryTiles.js +0 -13
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/lib/pakbonBuilder.ts — sectiegebaseerde opbouw van een pakbon
|
|
3
|
+
//
|
|
4
|
+
// Een pakbon bestaat uit secties (blokken). Elke sectie heeft een type uit het
|
|
5
|
+
// SECTIE_REGISTER, een eigen set opties en optionele zichtbaarheidsvoorwaarden.
|
|
6
|
+
// Nieuwe sectiesoort toevoegen = één entry in SECTIE_REGISTER.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// --- kolommen ---------------------------------------------------------------
|
|
9
|
+
export const BESCHIKBARE_KOLOMMEN = [
|
|
10
|
+
{ key: "artikelnummer", label: "Artikelnummer" },
|
|
11
|
+
{ key: "artikelnaam", label: "Artikelnaam" },
|
|
12
|
+
{ key: "potmaat", label: "Potmaat" },
|
|
13
|
+
{ key: "aantal", label: "Aantal" },
|
|
14
|
+
{ key: "belading", label: "Belading" },
|
|
15
|
+
{ key: "barcode", label: "Barcode" },
|
|
16
|
+
{ key: "opmerking", label: "Opmerking" },
|
|
17
|
+
{ key: "locatie", label: "Locatie" },
|
|
18
|
+
{ key: "gewicht", label: "Gewicht" },
|
|
19
|
+
{ key: "productgroep", label: "Productgroep" },
|
|
20
|
+
{ key: "kleur", label: "Kleur" },
|
|
21
|
+
{ key: "fust_aantal", label: "Aantal fusten" },
|
|
22
|
+
{ key: "fustsoort", label: "Fustsoort" },
|
|
23
|
+
{ key: "planten_per_fust", label: "Planten per fust" },
|
|
24
|
+
];
|
|
25
|
+
export function kolomLabel(key) {
|
|
26
|
+
return BESCHIKBARE_KOLOMMEN.find((k) => k.key === key)?.label ?? key;
|
|
27
|
+
}
|
|
28
|
+
export function nieuweKolom(key) {
|
|
29
|
+
return {
|
|
30
|
+
key,
|
|
31
|
+
label: kolomLabel(key),
|
|
32
|
+
breedte: 20,
|
|
33
|
+
uitlijning: key === "aantal" || key === "gewicht" || key === "fust_aantal" || key === "planten_per_fust"
|
|
34
|
+
? "right"
|
|
35
|
+
: "left",
|
|
36
|
+
fontgrootte: 9,
|
|
37
|
+
vet: false,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const STANDAARD_KOLOMKEYS = ["artikelnummer", "artikelnaam", "potmaat", "aantal", "locatie"];
|
|
41
|
+
const groepering = {
|
|
42
|
+
key: "groepering",
|
|
43
|
+
label: "Groeperen op",
|
|
44
|
+
type: "keuze",
|
|
45
|
+
standaard: "order",
|
|
46
|
+
opties: [
|
|
47
|
+
{ value: "order", label: "Per order" },
|
|
48
|
+
{ value: "kar", label: "Per kar" },
|
|
49
|
+
{ value: "laag", label: "Per laag" },
|
|
50
|
+
{ value: "productgroep", label: "Per productgroep" },
|
|
51
|
+
{ value: "afleveradres", label: "Per afleveradres" },
|
|
52
|
+
{ value: "klant", label: "Per klant" },
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
const weergave = {
|
|
56
|
+
key: "weergave",
|
|
57
|
+
label: "Weergave",
|
|
58
|
+
type: "keuze",
|
|
59
|
+
standaard: "tabel",
|
|
60
|
+
opties: [
|
|
61
|
+
{ value: "tabel", label: "In tabelvorm" },
|
|
62
|
+
{ value: "onder", label: "Boven elkaar" },
|
|
63
|
+
{ value: "naast", label: "Naast elkaar" },
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
export const SECTIE_REGISTER = [
|
|
67
|
+
{
|
|
68
|
+
type: "logo",
|
|
69
|
+
label: "Logo",
|
|
70
|
+
omschrijving: "Bedrijfslogo uit de Logo Bibliotheek.",
|
|
71
|
+
opties: [
|
|
72
|
+
{
|
|
73
|
+
key: "uitlijning",
|
|
74
|
+
label: "Uitlijning",
|
|
75
|
+
type: "keuze",
|
|
76
|
+
standaard: "left",
|
|
77
|
+
opties: [
|
|
78
|
+
{ value: "left", label: "Links" },
|
|
79
|
+
{ value: "center", label: "Midden" },
|
|
80
|
+
{ value: "right", label: "Rechts" },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{ key: "hoogte", label: "Hoogte (mm)", type: "getal", standaard: 18 },
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: "bedrijfsgegevens",
|
|
88
|
+
label: "Bedrijfsgegevens",
|
|
89
|
+
omschrijving: "Naam, adres en contactgegevens van het eigen bedrijf.",
|
|
90
|
+
opties: [
|
|
91
|
+
{ key: "toonNaam", label: "Bedrijfsnaam", type: "schakelaar", standaard: true },
|
|
92
|
+
{ key: "toonAdres", label: "Adres", type: "schakelaar", standaard: true },
|
|
93
|
+
{ key: "toonContact", label: "Telefoon / e-mail", type: "schakelaar", standaard: true },
|
|
94
|
+
{ key: "toonKvk", label: "KvK & BTW", type: "schakelaar", standaard: false },
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: "klantgegevens",
|
|
99
|
+
label: "Klantgegevens",
|
|
100
|
+
omschrijving: "Gegevens van de klant.",
|
|
101
|
+
opties: [
|
|
102
|
+
{ key: "toonKlantnummer", label: "Klantnummer", type: "schakelaar", standaard: true },
|
|
103
|
+
{ key: "toonContact", label: "Contactpersoon", type: "schakelaar", standaard: true },
|
|
104
|
+
{ key: "toonReferentie", label: "Klantreferentie", type: "schakelaar", standaard: true },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
type: "afleveradres",
|
|
109
|
+
label: "Afleveradres",
|
|
110
|
+
omschrijving: "Adres waar de zending naartoe gaat.",
|
|
111
|
+
opties: [{ key: "toonLand", label: "Land tonen", type: "schakelaar", standaard: true }],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
type: "factuuradres",
|
|
115
|
+
label: "Factuuradres",
|
|
116
|
+
omschrijving: "Facturatieadres van de klant.",
|
|
117
|
+
opties: [{ key: "toonLand", label: "Land tonen", type: "schakelaar", standaard: true }],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: "orderinformatie",
|
|
121
|
+
label: "Orderinformatie",
|
|
122
|
+
omschrijving: "Ordernummer, datum, referentie.",
|
|
123
|
+
opties: [
|
|
124
|
+
{ key: "toonOrdernummer", label: "Ordernummer", type: "schakelaar", standaard: true },
|
|
125
|
+
{ key: "toonDatum", label: "Orderdatum", type: "schakelaar", standaard: true },
|
|
126
|
+
{ key: "toonLeverdatum", label: "Leverdatum", type: "schakelaar", standaard: true },
|
|
127
|
+
{ key: "toonReferentie", label: "Referentie", type: "schakelaar", standaard: true },
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
type: "transportinformatie",
|
|
132
|
+
label: "Transportinformatie",
|
|
133
|
+
omschrijving: "Transporteur, route en chauffeur.",
|
|
134
|
+
opties: [
|
|
135
|
+
{ key: "toonTransporteur", label: "Transporteur", type: "schakelaar", standaard: true },
|
|
136
|
+
{ key: "toonRoute", label: "Route", type: "schakelaar", standaard: true },
|
|
137
|
+
{ key: "toonChauffeur", label: "Chauffeur", type: "schakelaar", standaard: false },
|
|
138
|
+
{ key: "toonTrack", label: "Track & trace", type: "schakelaar", standaard: false },
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
type: "opmerkingen",
|
|
143
|
+
label: "Opmerkingen",
|
|
144
|
+
omschrijving: "Opmerkingen bij de order.",
|
|
145
|
+
opties: [{ key: "kader", label: "In kader", type: "schakelaar", standaard: true }],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "orderregels",
|
|
149
|
+
label: "Orderregels",
|
|
150
|
+
omschrijving: "De regels van de order, met eigen kolommen en groepering.",
|
|
151
|
+
kolommen: true,
|
|
152
|
+
opties: [
|
|
153
|
+
weergave,
|
|
154
|
+
groepering,
|
|
155
|
+
{ key: "toonKoppen", label: "Kolomkoppen tonen", type: "schakelaar", standaard: true },
|
|
156
|
+
{ key: "zebra", label: "Om-en-om arcering", type: "schakelaar", standaard: false },
|
|
157
|
+
{ key: "randen", label: "Randen om cellen", type: "schakelaar", standaard: true },
|
|
158
|
+
{
|
|
159
|
+
key: "sortering",
|
|
160
|
+
label: "Sorteren op",
|
|
161
|
+
type: "keuze",
|
|
162
|
+
standaard: "eigen",
|
|
163
|
+
opties: [
|
|
164
|
+
{ value: "eigen", label: "Eigen volgorde" },
|
|
165
|
+
{ value: "artikelnummer", label: "Artikelnummer" },
|
|
166
|
+
{ value: "artikelnaam", label: "Naam" },
|
|
167
|
+
{ value: "locatie", label: "Locatie" },
|
|
168
|
+
{ value: "potmaat", label: "Potmaat" },
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
type: "karren",
|
|
175
|
+
label: "Karren",
|
|
176
|
+
omschrijving: "Weergave van karren en de scheiding tussen karren.",
|
|
177
|
+
opties: [
|
|
178
|
+
{
|
|
179
|
+
key: "pickmethode",
|
|
180
|
+
label: "Order pickmethode",
|
|
181
|
+
type: "keuze",
|
|
182
|
+
standaard: "kar",
|
|
183
|
+
opties: [
|
|
184
|
+
{ value: "kar", label: "Order picken per kar" },
|
|
185
|
+
{ value: "fusten", label: "Order picken per fusten (zelf karindeling maken)" },
|
|
186
|
+
],
|
|
187
|
+
hint: "Bij picken per fusten toont de pakbon een verzamellijst met alle fusten en aantallen.",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: "modus",
|
|
191
|
+
label: "Weergave",
|
|
192
|
+
type: "keuze",
|
|
193
|
+
standaard: "pagina",
|
|
194
|
+
opties: [
|
|
195
|
+
{ value: "pagina", label: "1 kar is een pagina" },
|
|
196
|
+
{
|
|
197
|
+
value: "passend",
|
|
198
|
+
label: "Meerdere karren op 1 pagina (alleen als de hele kar past)",
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
key: "bundel_identiek",
|
|
204
|
+
label: "Identieke karren samenvoegen",
|
|
205
|
+
type: "schakelaar",
|
|
206
|
+
standaard: true,
|
|
207
|
+
hint: "Toont de indeling één keer met “Deze kar 5× pakken”. Het karnummer vervalt dan.",
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "velden",
|
|
211
|
+
label: "Zichtbare kargegevens",
|
|
212
|
+
type: "meerkeuze",
|
|
213
|
+
standaard: ["karnummer", "lagen", "producten"],
|
|
214
|
+
opties: [
|
|
215
|
+
{ value: "karnummer", label: "Karnummer" },
|
|
216
|
+
{ value: "lagen", label: "Aantal lagen" },
|
|
217
|
+
{ value: "gewicht", label: "Gewicht" },
|
|
218
|
+
{ value: "producten", label: "Aantal producten" },
|
|
219
|
+
{ value: "barcode", label: "Barcode" },
|
|
220
|
+
{ value: "qrcode", label: "QR-code" },
|
|
221
|
+
{ value: "chauffeur", label: "Chauffeur" },
|
|
222
|
+
{ value: "route", label: "Route" },
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
key: "scheiding",
|
|
227
|
+
label: "Scheiding tussen karren",
|
|
228
|
+
type: "keuze",
|
|
229
|
+
standaard: "kop",
|
|
230
|
+
opties: [
|
|
231
|
+
{ value: "geen", label: "Geen scheiding" },
|
|
232
|
+
{ value: "lijn", label: "Horizontale lijn" },
|
|
233
|
+
{ value: "balk", label: "Dikke scheidingsbalk" },
|
|
234
|
+
{ value: "pagina", label: "Nieuwe pagina" },
|
|
235
|
+
{ value: "kop", label: "Groot kopblok" },
|
|
236
|
+
{ value: "kleur", label: "Gekleurde achtergrond" },
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
key: "koptekst",
|
|
241
|
+
label: "Koptekst kar",
|
|
242
|
+
type: "tekst",
|
|
243
|
+
hint: "Gebruik {kar}, {route}, {chauffeur}, {lagen}, {producten}",
|
|
244
|
+
standaard: "KAR {kar}",
|
|
245
|
+
},
|
|
246
|
+
{ key: "kleur", label: "Achtergrondkleur kop", type: "kleur", standaard: "#e8eef7" },
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
type: "lagen",
|
|
251
|
+
label: "Lagen",
|
|
252
|
+
omschrijving: "Weergave van de lagen binnen een kar.",
|
|
253
|
+
opties: [
|
|
254
|
+
{
|
|
255
|
+
key: "modus",
|
|
256
|
+
label: "Weergave",
|
|
257
|
+
type: "keuze",
|
|
258
|
+
standaard: "apart",
|
|
259
|
+
opties: [
|
|
260
|
+
{ value: "apart", label: "Iedere laag apart" },
|
|
261
|
+
{ value: "gebundeld", label: "Dezelfde lagen combineren" },
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
key: "velden",
|
|
266
|
+
label: "Zichtbare laaggegevens",
|
|
267
|
+
type: "meerkeuze",
|
|
268
|
+
standaard: ["laagnummer", "belading", "producten"],
|
|
269
|
+
opties: [
|
|
270
|
+
{ value: "laagnummer", label: "Laagnummer" },
|
|
271
|
+
{ value: "belading", label: "Belading" },
|
|
272
|
+
{ value: "potmaat", label: "Potmaat" },
|
|
273
|
+
{ value: "producten", label: "Aantal producten" },
|
|
274
|
+
{ value: "fusten", label: "Aantal fusten" },
|
|
275
|
+
{ value: "gewicht", label: "Gewicht" },
|
|
276
|
+
{ value: "opmerking", label: "Opmerking" },
|
|
277
|
+
],
|
|
278
|
+
},
|
|
279
|
+
{ key: "koptekst", label: "Koptekst laag", type: "tekst", standaard: "Laag {laag}" },
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
type: "producten",
|
|
284
|
+
label: "Producten op een laag",
|
|
285
|
+
omschrijving: "Hoe producten binnen een laag worden getoond.",
|
|
286
|
+
opties: [
|
|
287
|
+
weergave,
|
|
288
|
+
{
|
|
289
|
+
key: "velden",
|
|
290
|
+
label: "Zichtbare productgegevens",
|
|
291
|
+
type: "meerkeuze",
|
|
292
|
+
standaard: ["artikelnummer", "artikelnaam", "potmaat", "aantal"],
|
|
293
|
+
opties: BESCHIKBARE_KOLOMMEN.map((k) => ({ value: k.key, label: k.label })).concat([
|
|
294
|
+
{ value: "foto", label: "Foto" },
|
|
295
|
+
{ value: "qrcode", label: "QR-code" },
|
|
296
|
+
]),
|
|
297
|
+
},
|
|
298
|
+
{ key: "groeperen", label: "Gelijke producten groeperen", type: "schakelaar", standaard: false },
|
|
299
|
+
{
|
|
300
|
+
key: "kop_eenmalig",
|
|
301
|
+
label: "Kolomkoppen maar één keer tonen",
|
|
302
|
+
type: "schakelaar",
|
|
303
|
+
standaard: true,
|
|
304
|
+
hint: "Toont de kolomnamen alleen bij de eerste laag in plaats van boven elke laag.",
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
key: "sortering",
|
|
308
|
+
label: "Sorteren op",
|
|
309
|
+
type: "keuze",
|
|
310
|
+
standaard: "eigen",
|
|
311
|
+
opties: [
|
|
312
|
+
{ value: "eigen", label: "Eigen volgorde" },
|
|
313
|
+
{ value: "artikelnummer", label: "Artikelnummer" },
|
|
314
|
+
{ value: "artikelnaam", label: "Naam" },
|
|
315
|
+
{ value: "locatie", label: "Locatie" },
|
|
316
|
+
{ value: "potmaat", label: "Potmaat" },
|
|
317
|
+
],
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
type: "fusten",
|
|
323
|
+
label: "Fusten",
|
|
324
|
+
omschrijving: "Weergave van fusten.",
|
|
325
|
+
opties: [
|
|
326
|
+
{
|
|
327
|
+
key: "modus",
|
|
328
|
+
label: "Weergave",
|
|
329
|
+
type: "keuze",
|
|
330
|
+
standaard: "totaal",
|
|
331
|
+
opties: [
|
|
332
|
+
{ value: "geen", label: "Niet tonen" },
|
|
333
|
+
{ value: "totaal", label: "Alleen totaal tonen" },
|
|
334
|
+
{ value: "laag", label: "Per laag tonen" },
|
|
335
|
+
{ value: "product", label: "Per product tonen" },
|
|
336
|
+
{ value: "kar", label: "Per kar tonen" },
|
|
337
|
+
],
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
key: "velden",
|
|
341
|
+
label: "Zichtbare fustgegevens",
|
|
342
|
+
type: "meerkeuze",
|
|
343
|
+
standaard: ["fusttype", "aantal"],
|
|
344
|
+
opties: [
|
|
345
|
+
{ value: "fusttype", label: "Fusttype" },
|
|
346
|
+
{ value: "aantal", label: "Aantal" },
|
|
347
|
+
{ value: "hoogte", label: "Hoogte" },
|
|
348
|
+
{ value: "belading", label: "Belading" },
|
|
349
|
+
{ value: "barcode", label: "Barcode" },
|
|
350
|
+
],
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
type: "totalen",
|
|
356
|
+
label: "Totalen",
|
|
357
|
+
omschrijving: "Totaaloverzicht onderaan de pakbon.",
|
|
358
|
+
opties: [
|
|
359
|
+
{
|
|
360
|
+
key: "velden",
|
|
361
|
+
label: "Zichtbare totalen",
|
|
362
|
+
type: "meerkeuze",
|
|
363
|
+
standaard: ["producten", "karren", "lagen"],
|
|
364
|
+
opties: [
|
|
365
|
+
{ value: "producten", label: "Totaal aantal producten" },
|
|
366
|
+
{ value: "lagen", label: "Totaal aantal lagen" },
|
|
367
|
+
{ value: "fusten", label: "Totaal aantal fusten" },
|
|
368
|
+
{ value: "karren", label: "Totaal aantal karren" },
|
|
369
|
+
{ value: "gewicht", label: "Totaal gewicht" },
|
|
370
|
+
{ value: "volume", label: "Totaal volume" },
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
key: "uitlijning",
|
|
375
|
+
label: "Uitlijning",
|
|
376
|
+
type: "keuze",
|
|
377
|
+
standaard: "right",
|
|
378
|
+
opties: [
|
|
379
|
+
{ value: "left", label: "Links" },
|
|
380
|
+
{ value: "right", label: "Rechts" },
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
key: "elke_pagina",
|
|
385
|
+
label: "Onderaan elke pagina tonen",
|
|
386
|
+
type: "schakelaar",
|
|
387
|
+
standaard: false,
|
|
388
|
+
hint: "De totalen komen als voettekst onder iedere pagina te staan.",
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
key: "toon_paginanummer",
|
|
392
|
+
label: "Paginanummer tonen",
|
|
393
|
+
type: "schakelaar",
|
|
394
|
+
standaard: false,
|
|
395
|
+
hint: "Toont bijvoorbeeld 'Pagina 1 van 3' in de voettekst.",
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
type: "handtekening",
|
|
401
|
+
label: "Handtekening",
|
|
402
|
+
omschrijving: "Ruimte voor naam en handtekening.",
|
|
403
|
+
opties: [
|
|
404
|
+
{ key: "label", label: "Bijschrift", type: "tekst", standaard: "Voor ontvangst getekend" },
|
|
405
|
+
{ key: "toonNaam", label: "Naamregel", type: "schakelaar", standaard: true },
|
|
406
|
+
{ key: "toonDatum", label: "Datumregel", type: "schakelaar", standaard: true },
|
|
407
|
+
],
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
type: "tekstblok",
|
|
411
|
+
label: "Vrij tekstblok",
|
|
412
|
+
omschrijving: "Eigen tekst, veldcodes toegestaan.",
|
|
413
|
+
opties: [
|
|
414
|
+
{ key: "tekst", label: "Tekst", type: "tekst", standaard: "Bedankt voor uw bestelling." },
|
|
415
|
+
{ key: "fontgrootte", label: "Tekstgrootte", type: "getal", standaard: 9 },
|
|
416
|
+
{ key: "kader", label: "In kader", type: "schakelaar", standaard: false },
|
|
417
|
+
],
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
type: "qrcode",
|
|
421
|
+
label: "QR-code",
|
|
422
|
+
omschrijving: "QR-code met orderwaarde.",
|
|
423
|
+
opties: [
|
|
424
|
+
{ key: "waarde", label: "Inhoud", type: "tekst", standaard: "{{order.nummer}}" },
|
|
425
|
+
{ key: "grootte", label: "Grootte (mm)", type: "getal", standaard: 25 },
|
|
426
|
+
],
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
type: "barcode",
|
|
430
|
+
label: "Barcode",
|
|
431
|
+
omschrijving: "Barcode met orderwaarde.",
|
|
432
|
+
opties: [
|
|
433
|
+
{ key: "waarde", label: "Inhoud", type: "tekst", standaard: "{{order.nummer}}" },
|
|
434
|
+
{ key: "hoogte", label: "Hoogte (mm)", type: "getal", standaard: 15 },
|
|
435
|
+
],
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
type: "afbeelding",
|
|
439
|
+
label: "Eigen afbeelding",
|
|
440
|
+
omschrijving: "Afbeelding via URL of uit de bibliotheek.",
|
|
441
|
+
opties: [
|
|
442
|
+
{ key: "url", label: "Afbeelding-URL", type: "tekst", standaard: "" },
|
|
443
|
+
{ key: "hoogte", label: "Hoogte (mm)", type: "getal", standaard: 25 },
|
|
444
|
+
],
|
|
445
|
+
},
|
|
446
|
+
];
|
|
447
|
+
export function sectieDef(type) {
|
|
448
|
+
return SECTIE_REGISTER.find((s) => s.type === type) ?? SECTIE_REGISTER[0];
|
|
449
|
+
}
|
|
450
|
+
let teller = 0;
|
|
451
|
+
export function nieuweSectie(type) {
|
|
452
|
+
const def = sectieDef(type);
|
|
453
|
+
const opties = {};
|
|
454
|
+
for (const o of def.opties)
|
|
455
|
+
opties[o.key] = o.standaard;
|
|
456
|
+
teller += 1;
|
|
457
|
+
return {
|
|
458
|
+
id: `${type}-${Date.now().toString(36)}-${teller}`,
|
|
459
|
+
type,
|
|
460
|
+
titel: def.label,
|
|
461
|
+
zichtbaar: true,
|
|
462
|
+
opties,
|
|
463
|
+
kolommen: def.kolommen ? STANDAARD_KOLOMKEYS.map(nieuweKolom) : undefined,
|
|
464
|
+
condities: [],
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
export function standaardPakbonConfig() {
|
|
468
|
+
return {
|
|
469
|
+
secties: [
|
|
470
|
+
"logo",
|
|
471
|
+
"bedrijfsgegevens",
|
|
472
|
+
"klantgegevens",
|
|
473
|
+
"afleveradres",
|
|
474
|
+
"orderinformatie",
|
|
475
|
+
"karren",
|
|
476
|
+
"lagen",
|
|
477
|
+
"producten",
|
|
478
|
+
"fusten",
|
|
479
|
+
"totalen",
|
|
480
|
+
"handtekening",
|
|
481
|
+
].map(nieuweSectie),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
export function leesPakbonConfig(config) {
|
|
485
|
+
// Accepteert zowel de layout-config ({ pakbon: {...} }) als een kale
|
|
486
|
+
// PakbonConfig. Zonder deze tolerantie viel de afdruk terug op de
|
|
487
|
+
// standaardsecties en verdween o.a. het documentlogo.
|
|
488
|
+
const raw = config;
|
|
489
|
+
const c = Array.isArray(raw?.secties)
|
|
490
|
+
? raw
|
|
491
|
+
: raw?.pakbon;
|
|
492
|
+
const secties = Array.isArray(c?.secties) ? c.secties : null;
|
|
493
|
+
const logo = c?.logo ?? null;
|
|
494
|
+
const basis = secties && secties.length ? { secties } : standaardPakbonConfig();
|
|
495
|
+
return { ...basis, logo };
|
|
496
|
+
}
|
|
497
|
+
const p = (nr, naam, potmaat, aantal, locatie, groep, kleur) => ({
|
|
498
|
+
artikelnummer: nr,
|
|
499
|
+
artikelnaam: naam,
|
|
500
|
+
potmaat,
|
|
501
|
+
aantal,
|
|
502
|
+
belading: `${aantal} st/laag`,
|
|
503
|
+
barcode: `87${nr}`,
|
|
504
|
+
opmerking: "",
|
|
505
|
+
locatie,
|
|
506
|
+
gewicht: `${(aantal * 0.6).toFixed(1)} kg`,
|
|
507
|
+
productgroep: groep,
|
|
508
|
+
kleur,
|
|
509
|
+
fust_aantal: Math.max(1, Math.ceil(aantal / 12)),
|
|
510
|
+
planten_per_fust: Math.min(aantal, 12),
|
|
511
|
+
fustsoort: groep === "Groen" ? "Fust 566" : groep === "Orchidee" ? "Tray 577" : "Fust 588",
|
|
512
|
+
});
|
|
513
|
+
export const DEMO_ORDER = {
|
|
514
|
+
order: {
|
|
515
|
+
nummer: "ORD-2026-004512",
|
|
516
|
+
datum: "29-07-2026",
|
|
517
|
+
leverdatum: "31-07-2026",
|
|
518
|
+
referentie: "Week 31 – Zuid",
|
|
519
|
+
opmerking: "Karren gestapeld aanleveren, deur 4.",
|
|
520
|
+
},
|
|
521
|
+
bedrijf: {
|
|
522
|
+
naam: "Flow Selections B.V.",
|
|
523
|
+
adres: "Handelsweg 12",
|
|
524
|
+
plaats: "2665 JK Bleiswijk",
|
|
525
|
+
telefoon: "+31 10 123 45 67",
|
|
526
|
+
email: "orders@flowselections.nl",
|
|
527
|
+
kvk: "KvK 12345678",
|
|
528
|
+
btw: "BTW NL001234567B01",
|
|
529
|
+
},
|
|
530
|
+
klant: {
|
|
531
|
+
naam: "Bloemenhuis De Zonnebloem",
|
|
532
|
+
nummer: "KL-10482",
|
|
533
|
+
contact: "M. de Vries",
|
|
534
|
+
referentie: "PO-88213",
|
|
535
|
+
},
|
|
536
|
+
afleveradres: {
|
|
537
|
+
naam: "De Zonnebloem – Filiaal Zuid",
|
|
538
|
+
adres: "Marktplein 3",
|
|
539
|
+
plaats: "5611 AA Eindhoven",
|
|
540
|
+
land: "Nederland",
|
|
541
|
+
},
|
|
542
|
+
factuuradres: {
|
|
543
|
+
naam: "Bloemenhuis De Zonnebloem",
|
|
544
|
+
adres: "Postbus 120",
|
|
545
|
+
plaats: "5600 AC Eindhoven",
|
|
546
|
+
land: "Nederland",
|
|
547
|
+
},
|
|
548
|
+
transport: {
|
|
549
|
+
transporteur: "DHL Fresh",
|
|
550
|
+
route: "Route Zuid",
|
|
551
|
+
chauffeur: "J. Bakker",
|
|
552
|
+
track: "3SDHL8842190",
|
|
553
|
+
},
|
|
554
|
+
karren: [
|
|
555
|
+
{
|
|
556
|
+
karnummer: 5,
|
|
557
|
+
route: "Route Zuid",
|
|
558
|
+
chauffeur: "J. Bakker",
|
|
559
|
+
gewicht: "142 kg",
|
|
560
|
+
lagen: [
|
|
561
|
+
{
|
|
562
|
+
laagnummer: 1,
|
|
563
|
+
belading: "8 × 12",
|
|
564
|
+
potmaat: "12 cm",
|
|
565
|
+
gewicht: "48 kg",
|
|
566
|
+
opmerking: "Onderin plaatsen",
|
|
567
|
+
producten: [
|
|
568
|
+
p("A1001", "Phalaenopsis wit 2-tak", "12 cm", 96, "A-03", "Orchidee", "Wit"),
|
|
569
|
+
p("A1042", "Phalaenopsis roze 2-tak", "12 cm", 48, "A-04", "Orchidee", "Roze"),
|
|
570
|
+
],
|
|
571
|
+
fusten: [
|
|
572
|
+
{ fusttype: "Deense tray", aantal: 8, hoogte: "22 cm", belading: "12 st", barcode: "FT-8801" },
|
|
573
|
+
],
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
laagnummer: 2,
|
|
577
|
+
belading: "6 × 10",
|
|
578
|
+
potmaat: "17 cm",
|
|
579
|
+
gewicht: "52 kg",
|
|
580
|
+
opmerking: "",
|
|
581
|
+
producten: [
|
|
582
|
+
p("B2201", "Ficus Lyrata", "17 cm", 60, "B-11", "Groen", "Groen"),
|
|
583
|
+
p("B2210", "Monstera Deliciosa", "17 cm", 30, "B-12", "Groen", "Groen"),
|
|
584
|
+
],
|
|
585
|
+
fusten: [{ fusttype: "Plateau", aantal: 6, hoogte: "18 cm", belading: "10 st", barcode: "FT-9120" }],
|
|
586
|
+
},
|
|
587
|
+
],
|
|
588
|
+
},
|
|
589
|
+
// Karren 6, 7 en 8 hebben exact dezelfde indeling: in het voorbeeld worden
|
|
590
|
+
// ze samengevoegd tot één blok met "Deze kar 3× pakken".
|
|
591
|
+
...[6, 7, 8].map((nr) => ({
|
|
592
|
+
karnummer: nr,
|
|
593
|
+
route: "Route Zuid",
|
|
594
|
+
chauffeur: "J. Bakker",
|
|
595
|
+
gewicht: "118 kg",
|
|
596
|
+
lagen: [1, 2].map((laagnr) => ({
|
|
597
|
+
laagnummer: laagnr,
|
|
598
|
+
belading: "10 × 8",
|
|
599
|
+
potmaat: "9 cm",
|
|
600
|
+
gewicht: "38 kg",
|
|
601
|
+
opmerking: "",
|
|
602
|
+
producten: [
|
|
603
|
+
p("C3300", "Kalanchoë mix", "9 cm", 80, "C-02", "Bloeiend", "Mix"),
|
|
604
|
+
p("C3311", "Succulenten mix", "9 cm", 80, "C-05", "Bloeiend", "Mix"),
|
|
605
|
+
],
|
|
606
|
+
fusten: [
|
|
607
|
+
{ fusttype: "Deense tray", aantal: 10, hoogte: "22 cm", belading: "8 st", barcode: "FT-8802" },
|
|
608
|
+
],
|
|
609
|
+
})),
|
|
610
|
+
})),
|
|
611
|
+
],
|
|
612
|
+
};
|
|
613
|
+
export function alleProducten(order) {
|
|
614
|
+
return order.karren.flatMap((k) => k.lagen.flatMap((l) => l.producten));
|
|
615
|
+
}
|
|
616
|
+
export function totalen(order) {
|
|
617
|
+
const producten = alleProducten(order);
|
|
618
|
+
const lagen = order.karren.reduce((n, k) => n + k.lagen.length, 0);
|
|
619
|
+
const fusten = order.karren.reduce((n, k) => n + k.lagen.reduce((m, l) => m + l.fusten.reduce((x, f) => x + f.aantal, 0), 0), 0);
|
|
620
|
+
const stuks = producten.reduce((n, p2) => n + p2.aantal, 0);
|
|
621
|
+
const gewicht = producten.reduce((n, p2) => n + parseFloat(p2.gewicht), 0);
|
|
622
|
+
return {
|
|
623
|
+
producten: `${stuks} stuks`,
|
|
624
|
+
lagen: `${lagen} lagen`,
|
|
625
|
+
fusten: `${fusten} fusten`,
|
|
626
|
+
karren: `${order.karren.length} karren`,
|
|
627
|
+
gewicht: `${gewicht.toFixed(1)} kg`,
|
|
628
|
+
volume: `${(lagen * 0.42).toFixed(2)} m³`,
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
// --- condities --------------------------------------------------------------
|
|
632
|
+
export const CONDITIE_VELDEN = [
|
|
633
|
+
{ value: "aantal_karren", label: "Aantal karren" },
|
|
634
|
+
{ value: "aantal_lagen", label: "Aantal lagen" },
|
|
635
|
+
{ value: "aantal_fusten", label: "Aantal fusten" },
|
|
636
|
+
{ value: "aantal_producten", label: "Aantal producten" },
|
|
637
|
+
{ value: "transporteur", label: "Transporteur" },
|
|
638
|
+
{ value: "documentsoort", label: "Documentsoort" },
|
|
639
|
+
{ value: "klant", label: "Klant" },
|
|
640
|
+
{ value: "route", label: "Route" },
|
|
641
|
+
];
|
|
642
|
+
export function conditieContext(order) {
|
|
643
|
+
const t = totalen(order);
|
|
644
|
+
return {
|
|
645
|
+
aantal_karren: String(order.karren.length),
|
|
646
|
+
aantal_lagen: String(order.karren.reduce((n, k) => n + k.lagen.length, 0)),
|
|
647
|
+
aantal_fusten: t.fusten.replace(/\D/g, ""),
|
|
648
|
+
aantal_producten: t.producten.replace(/\D/g, ""),
|
|
649
|
+
transporteur: order.transport.transporteur,
|
|
650
|
+
documentsoort: "pakbon",
|
|
651
|
+
klant: order.klant.naam,
|
|
652
|
+
route: order.transport.route,
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
export function sectieZichtbaar(sectie, ctx) {
|
|
656
|
+
if (!sectie.zichtbaar)
|
|
657
|
+
return false;
|
|
658
|
+
return (sectie.condities ?? []).every((c) => {
|
|
659
|
+
const w = ctx[c.veld] ?? "";
|
|
660
|
+
switch (c.operator) {
|
|
661
|
+
case "=":
|
|
662
|
+
return w === c.waarde;
|
|
663
|
+
case "!=":
|
|
664
|
+
return w !== c.waarde;
|
|
665
|
+
case ">":
|
|
666
|
+
return Number(w) > Number(c.waarde);
|
|
667
|
+
case "<":
|
|
668
|
+
return Number(w) < Number(c.waarde);
|
|
669
|
+
case "bevat":
|
|
670
|
+
return w.toLowerCase().includes(c.waarde.toLowerCase());
|
|
671
|
+
case "leeg":
|
|
672
|
+
return w === "";
|
|
673
|
+
case "niet_leeg":
|
|
674
|
+
return w !== "";
|
|
675
|
+
default:
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
export function sorteerProducten(items, sortering) {
|
|
681
|
+
if (!sortering || sortering === "eigen")
|
|
682
|
+
return items;
|
|
683
|
+
const key = sortering;
|
|
684
|
+
return [...items].sort((a, b) => String(a[key]).localeCompare(String(b[key]), "nl"));
|
|
685
|
+
}
|
|
686
|
+
// --- veldcodes --------------------------------------------------------------
|
|
687
|
+
/** Vervangt {{groep.veld}} codes door waarden uit de (voorbeeld)order. */
|
|
688
|
+
export function vulVeldcodes(tekst, order) {
|
|
689
|
+
if (!tekst)
|
|
690
|
+
return "";
|
|
691
|
+
const bron = order;
|
|
692
|
+
return tekst.replace(/\{\{\s*([a-zA-Z_]+)\.([a-zA-Z_]+)\s*\}\}/g, (heel, groep, veld) => {
|
|
693
|
+
const waarde = bron[groep]?.[veld];
|
|
694
|
+
return waarde === undefined || waarde === null ? heel : String(waarde);
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
// --- identieke karren en lagen bundelen -------------------------------------
|
|
698
|
+
//
|
|
699
|
+
// Wanneer meerdere karren (of lagen) exact dezelfde indeling hebben, hoeft die
|
|
700
|
+
// indeling maar één keer op de pakbon te staan. Boven het blok komt dan
|
|
701
|
+
// "Deze kar 5× pakken" of "Deze laag 4×".
|
|
702
|
+
function laagVingerafdruk(l) {
|
|
703
|
+
const producten = (l.producten ?? [])
|
|
704
|
+
.map((p) => [p.artikelnummer, p.artikelnaam, p.potmaat, p.aantal, p.belading, p.locatie, p.fust_aantal, p.fustsoort, p.planten_per_fust].join("|"))
|
|
705
|
+
.join(";");
|
|
706
|
+
const fusten = (l.fusten ?? [])
|
|
707
|
+
.map((f) => [f.fusttype, f.aantal, f.hoogte, f.belading].join("|"))
|
|
708
|
+
.join(";");
|
|
709
|
+
// laagnummer bewust niet meegenomen: alleen de indeling telt
|
|
710
|
+
return [l.belading, l.potmaat, l.gewicht, l.opmerking, producten, fusten].join("#");
|
|
711
|
+
}
|
|
712
|
+
function karVingerafdruk(k) {
|
|
713
|
+
// karnummer bewust niet meegenomen: alleen de indeling telt
|
|
714
|
+
return [k.route, k.chauffeur, k.gewicht, (k.lagen ?? []).map(laagVingerafdruk).join("~")].join("#");
|
|
715
|
+
}
|
|
716
|
+
/** Groepeert identieke karren. Bij `aan = false` blijft elke kar los. */
|
|
717
|
+
export function groepeerIdentiekeKarren(karren, aan) {
|
|
718
|
+
const lijst = Array.isArray(karren) ? karren : [];
|
|
719
|
+
if (!aan)
|
|
720
|
+
return lijst.map((kar) => ({ kar, aantal: 1, nummers: [kar.karnummer] }));
|
|
721
|
+
const map = new Map();
|
|
722
|
+
for (const kar of lijst) {
|
|
723
|
+
const sleutel = karVingerafdruk(kar);
|
|
724
|
+
const bestaand = map.get(sleutel);
|
|
725
|
+
if (bestaand) {
|
|
726
|
+
bestaand.aantal += 1;
|
|
727
|
+
bestaand.nummers.push(kar.karnummer);
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
map.set(sleutel, { kar, aantal: 1, nummers: [kar.karnummer] });
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return [...map.values()];
|
|
734
|
+
}
|
|
735
|
+
/** Groepeert identieke lagen binnen één kar. */
|
|
736
|
+
export function groepeerIdentiekeLagen(lagen, aan) {
|
|
737
|
+
const lijst = Array.isArray(lagen) ? lagen : [];
|
|
738
|
+
if (!aan)
|
|
739
|
+
return lijst.map((laag) => ({ laag, aantal: 1, nummers: [laag.laagnummer] }));
|
|
740
|
+
const map = new Map();
|
|
741
|
+
for (const laag of lijst) {
|
|
742
|
+
const sleutel = laagVingerafdruk(laag);
|
|
743
|
+
const bestaand = map.get(sleutel);
|
|
744
|
+
if (bestaand) {
|
|
745
|
+
bestaand.aantal += 1;
|
|
746
|
+
bestaand.nummers.push(laag.laagnummer);
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
map.set(sleutel, { laag, aantal: 1, nummers: [laag.laagnummer] });
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return [...map.values()];
|
|
753
|
+
}
|
|
754
|
+
/** Tekst boven een gebundelde kar, bijv. "Deze kar 5× pakken". */
|
|
755
|
+
export function karBundelTekst(aantal) {
|
|
756
|
+
return `Deze kar ${aantal}× pakken`;
|
|
757
|
+
}
|
|
758
|
+
/** Tekst boven een gebundelde laag, bijv. "Deze laag 4×". */
|
|
759
|
+
export function laagBundelTekst(aantal) {
|
|
760
|
+
return `Deze laag ${aantal}×`;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Verzamellijst met alle fusten van een order, opgeteld per fusttype,
|
|
764
|
+
* inclusief de producten die in dat fusttype gepickt moeten worden.
|
|
765
|
+
* Gebruikt wanneer er per fust gepickt wordt en de gebruiker zelf de
|
|
766
|
+
* karindeling maakt.
|
|
767
|
+
*/
|
|
768
|
+
export function fustVerzamellijst(karren) {
|
|
769
|
+
const lijst = Array.isArray(karren) ? karren : [];
|
|
770
|
+
const map = new Map();
|
|
771
|
+
for (const kar of lijst) {
|
|
772
|
+
for (const laag of Array.isArray(kar?.lagen) ? kar.lagen : []) {
|
|
773
|
+
const fusten = Array.isArray(laag?.fusten) ? laag.fusten : [];
|
|
774
|
+
const producten = Array.isArray(laag?.producten) ? laag.producten : [];
|
|
775
|
+
for (const f of fusten) {
|
|
776
|
+
const type = String(f?.fusttype ?? f?.fustsoort ?? "Onbekend");
|
|
777
|
+
let groep = map.get(type);
|
|
778
|
+
if (!groep) {
|
|
779
|
+
groep = {
|
|
780
|
+
fusttype: type,
|
|
781
|
+
aantal: 0,
|
|
782
|
+
hoogte: String(f?.hoogte ?? ""),
|
|
783
|
+
belading: String(f?.belading ?? ""),
|
|
784
|
+
producten: [],
|
|
785
|
+
};
|
|
786
|
+
map.set(type, groep);
|
|
787
|
+
}
|
|
788
|
+
groep.aantal += Number(f?.aantal ?? 0);
|
|
789
|
+
for (const pr of producten) {
|
|
790
|
+
const nr = String(pr?.artikelnummer ?? "");
|
|
791
|
+
const bestaand = groep.producten.find((x) => x.artikelnummer === nr);
|
|
792
|
+
if (bestaand) {
|
|
793
|
+
bestaand.aantal += Number(pr?.aantal ?? 0);
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
groep.producten.push({
|
|
797
|
+
artikelnummer: nr,
|
|
798
|
+
artikelnaam: String(pr?.artikelnaam ?? ""),
|
|
799
|
+
potmaat: String(pr?.potmaat ?? ""),
|
|
800
|
+
kleur: String(pr?.kleur ?? ""),
|
|
801
|
+
productgroep: String(pr?.productgroep ?? ""),
|
|
802
|
+
locatie: String(pr?.locatie ?? ""),
|
|
803
|
+
fustsoort: String(pr?.fustsoort ?? ""),
|
|
804
|
+
planten_per_fust: Number(pr?.planten_per_fust ?? 0),
|
|
805
|
+
aantal: Number(pr?.aantal ?? 0),
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return [...map.values()].sort((a, b) => a.fusttype.localeCompare(b.fusttype));
|
|
813
|
+
}
|