@flowselections/layout-maker 1.36.7 → 1.38.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/README.md +139 -139
- package/dist-lib/components/AfdrukKnop.d.ts +19 -19
- package/dist-lib/components/NetwerkPrintersDialog.d.ts +7 -7
- package/dist-lib/components/PaginaDocument.d.ts +4 -1
- package/dist-lib/components/PaginaDocument.d.ts.map +1 -1
- package/dist-lib/components/PaginaDocument.js +10 -5
- package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/PakbonBuilderPage.js +4 -2
- package/dist-lib/components/PakbonPreview.d.ts +4 -2
- package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
- package/dist-lib/components/PakbonPreview.js +55 -12
- package/dist-lib/components/PakbonSectiesPanel.d.ts +2 -2
- package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
- package/dist-lib/components/PakbonSectiesPanel.js +3 -2
- package/dist-lib/components/PrinterSetupWizard.js +3 -3
- package/dist-lib/components/PrintersRedirectPage.d.ts +1 -1
- package/dist-lib/components/PrintersRedirectPage.js +14 -14
- package/dist-lib/index.d.ts +4 -2
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +3 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +1240 -812
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +1240 -812
- 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 +24008 -0
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/moduleClient.js +29 -0
- package/dist-lib/integrations/supabase/types.d.ts +1231 -821
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/aiLayout.functions.d.ts +1240 -812
- package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
- package/dist-lib/lib/aiLayout.server.js +9 -9
- package/dist-lib/lib/browserPrint.js +1 -1
- package/dist-lib/lib/code128.d.ts +5 -0
- package/dist-lib/lib/code128.d.ts.map +1 -0
- package/dist-lib/lib/code128.js +51 -0
- package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlPdf.server.js +58 -0
- package/dist-lib/lib/layoutPreview.d.ts.map +1 -1
- package/dist-lib/lib/layoutPreview.js +11 -8
- package/dist-lib/lib/orderData.server.d.ts.map +1 -1
- package/dist-lib/lib/orderData.server.js +6 -0
- package/dist-lib/lib/pakbonBuilder.d.ts +28 -2
- package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
- package/dist-lib/lib/pakbonBuilder.js +69 -8
- package/dist-lib/lib/pakbonHtml.d.ts +14 -2
- package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
- package/dist-lib/lib/pakbonHtml.js +155 -63
- package/dist-lib/lib/pakbonScan.d.ts +44 -0
- package/dist-lib/lib/pakbonScan.d.ts.map +1 -0
- package/dist-lib/lib/pakbonScan.js +105 -0
- package/dist-lib/lib/printQueue.server.d.ts +7 -0
- package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/printQueue.server.js +247 -26
- package/dist-lib/lib/printService.functions.d.ts +4445 -2733
- package/dist-lib/lib/printService.functions.d.ts.map +1 -1
- package/dist-lib/lib/productiebonHtml.js +15 -15
- package/dist-lib/lib/profielHtml.js +18 -18
- package/dist-lib/lib/supabaseAdmin.server.d.ts +5 -5
- package/dist-lib/lib/supabaseAdmin.server.js +43 -43
- package/dist-lib/lib/supabaseClient.d.ts +1 -3
- package/dist-lib/lib/supabaseClient.d.ts.map +1 -1
- package/dist-lib/lib/supabaseClient.js +4 -8
- package/dist-lib/lib/testpagina.js +3 -3
- package/dist-lib/lib/testprint.js +4 -4
- package/package.json +151 -151
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// de juiste printer. Draait alleen op de server (cron / interne aanroep).
|
|
5
5
|
// ============================================================================
|
|
6
6
|
import { maakPakbonOrder, renderPakbonDocument, voorbeeldPakbonOrder, } from "./pakbonHtml.js";
|
|
7
|
+
import { bouwPakbonScanInhoud, bewaarPakbonScanInhoud } from "./pakbonScan.js";
|
|
8
|
+
import { pakbonLayoutVariant } from "./pakbonBuilder.js";
|
|
7
9
|
import { renderProductiebonDocument } from "./productiebonHtml.js";
|
|
8
10
|
import { heeftOrderInhoud, laadOrderVanuitDatabase } from "./orderData.server.js";
|
|
9
11
|
import { profielHeeftInhoud, renderProfielDocument } from "./profielHtml.js";
|
|
@@ -47,6 +49,13 @@ export class GeenDocumentFout extends Error {
|
|
|
47
49
|
this.name = "GeenDocumentFout";
|
|
48
50
|
}
|
|
49
51
|
}
|
|
52
|
+
/** De Engine heeft de taak gepland, maar de layout is nog niet aangeleverd. */
|
|
53
|
+
export class WachtOpLayoutFout extends Error {
|
|
54
|
+
constructor() {
|
|
55
|
+
super(...arguments);
|
|
56
|
+
this.name = "WachtOpLayoutFout";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
50
59
|
/**
|
|
51
60
|
* Oudere/andere benamingen voor hetzelfde document. De Logistiek Engine noemt
|
|
52
61
|
* de afleverbrief bijvoorbeeld nog "verzendbrief"; hier vertalen we dat naar
|
|
@@ -65,6 +74,85 @@ export function normaliseerDocumenttype(type) {
|
|
|
65
74
|
return "document";
|
|
66
75
|
return DOCUMENTTYPE_ALIASSEN[t] ?? t;
|
|
67
76
|
}
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// Contract met de Logistics Engine.
|
|
79
|
+
// De Engine bepaalt documentsoort, variant, layout en printplek; deze module
|
|
80
|
+
// rendert en print alleen. Alles hieronder leest die keuzes uit de opdracht en
|
|
81
|
+
// overruled ze nooit.
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/** Het layout-id zoals de Engine het aanlevert (kolom of payload). */
|
|
84
|
+
export function leesEngineLayoutId(job) {
|
|
85
|
+
const p = (job.payload ?? {});
|
|
86
|
+
const d = (p.data ?? {});
|
|
87
|
+
for (const k of [job.layout_id, p.layout_id, p.layoutId, d.layout_id, d.layoutId]) {
|
|
88
|
+
const v = String(k ?? "").trim();
|
|
89
|
+
if (v)
|
|
90
|
+
return v;
|
|
91
|
+
}
|
|
92
|
+
return "";
|
|
93
|
+
}
|
|
94
|
+
/** Documentsoort zoals de Engine hem noemt (`document_code`). */
|
|
95
|
+
function leesDocumentCode(job) {
|
|
96
|
+
const p = (job.payload ?? {});
|
|
97
|
+
const d = (p.data ?? {});
|
|
98
|
+
for (const k of [job.document_code, p.document_code, p.documentCode, d.document_code]) {
|
|
99
|
+
const v = String(k ?? "").trim();
|
|
100
|
+
if (v)
|
|
101
|
+
return v;
|
|
102
|
+
}
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
/** Is dit een opdracht die door de Logistics Engine is gepland? */
|
|
106
|
+
function isEngineOpdracht(job) {
|
|
107
|
+
const p = (job.payload ?? {});
|
|
108
|
+
if (leesDocumentCode(job))
|
|
109
|
+
return true;
|
|
110
|
+
const bron = String(p.bron_module ?? p.owner_module ?? p.source_module ?? "").toLowerCase();
|
|
111
|
+
return bron.includes("logistic") || bron.includes("engine");
|
|
112
|
+
}
|
|
113
|
+
/** Handmatig opnieuw printen? */
|
|
114
|
+
function isHerprint(job) {
|
|
115
|
+
const p = (job.payload ?? {});
|
|
116
|
+
const d = (p.data ?? {});
|
|
117
|
+
return job.is_herprint === true || p.is_herprint === true || d.is_herprint === true;
|
|
118
|
+
}
|
|
119
|
+
/** De ordersleutel waarop een herprint bij de oorspronkelijke print hoort. */
|
|
120
|
+
function leesOrderRef(job) {
|
|
121
|
+
const p = (job.payload ?? {});
|
|
122
|
+
const d = (p.data ?? {});
|
|
123
|
+
for (const k of [job.order_ref, p.order_ref, p.orderRef, d.order_ref, d.orderRef, job.order_id]) {
|
|
124
|
+
const v = String(k ?? "").trim();
|
|
125
|
+
if (v)
|
|
126
|
+
return v;
|
|
127
|
+
}
|
|
128
|
+
return "";
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Een herprint gebruikt dezelfde layout als de oorspronkelijke print. Stuurt de
|
|
132
|
+
* Engine geen layout mee, dan zoeken we die op bij de laatste geslaagde print
|
|
133
|
+
* van hetzelfde document van dezelfde order.
|
|
134
|
+
*/
|
|
135
|
+
async function zoekHerprintLayoutId(db, job) {
|
|
136
|
+
const orderRef = leesOrderRef(job);
|
|
137
|
+
if (!orderRef)
|
|
138
|
+
return "";
|
|
139
|
+
const type = normaliseerDocumenttype(leesDocumentCode(job) || job.documenttype);
|
|
140
|
+
const { data } = await db
|
|
141
|
+
.from("print_jobs")
|
|
142
|
+
.select("gebruikte_layout_id, documenttype, created_at")
|
|
143
|
+
.eq("order_ref", orderRef)
|
|
144
|
+
.not("gebruikte_layout_id", "is", null)
|
|
145
|
+
.order("created_at", { ascending: false })
|
|
146
|
+
.limit(10);
|
|
147
|
+
for (const rij of arr(data)) {
|
|
148
|
+
if (normaliseerDocumenttype(rij.documenttype) !== type)
|
|
149
|
+
continue;
|
|
150
|
+
const id = String(rij.gebruikte_layout_id ?? "").trim();
|
|
151
|
+
if (id)
|
|
152
|
+
return id;
|
|
153
|
+
}
|
|
154
|
+
return "";
|
|
155
|
+
}
|
|
68
156
|
/**
|
|
69
157
|
* Zoekt de layout die bij de opdracht hoort.
|
|
70
158
|
* Staat er een layout_id op de opdracht (bijv. gezet door de Logistiek
|
|
@@ -94,15 +182,19 @@ function magOntwerpWinnen(layout) {
|
|
|
94
182
|
return String(layout.bron ?? "") !== "floriday";
|
|
95
183
|
}
|
|
96
184
|
async function zoekLayout(db, job) {
|
|
185
|
+
const engineJob = isEngineOpdracht(job);
|
|
97
186
|
const heeftEigenOpmaak = typeof job.render_html === "string" && job.render_html.trim().length > 40;
|
|
98
|
-
|
|
99
|
-
// koppeling: is er opmaak meegestuurd (bijv. een voorbeeldafdruk uit de
|
|
100
|
-
// ontwerper), dan is die opmaak leidend.
|
|
101
|
-
const uitPayload = heeftEigenOpmaak
|
|
187
|
+
const uitPayload = engineJob
|
|
102
188
|
? null
|
|
103
189
|
: (job.payload?.layoutId ?? job.payload?.data?.layoutId ?? job.payload?.layout_id ?? null);
|
|
104
|
-
|
|
105
|
-
|
|
190
|
+
let id = leesEngineLayoutId(job) || job.layout_id || uitPayload;
|
|
191
|
+
if (engineJob && !id && isHerprint(job)) {
|
|
192
|
+
id = await zoekHerprintLayoutId(db, job);
|
|
193
|
+
}
|
|
194
|
+
if (engineJob && !id) {
|
|
195
|
+
throw new WachtOpLayoutFout("Wacht op layout_id van de Logistics Engine. Deze taak wordt niet met een vervangende layout uitgevoerd.");
|
|
196
|
+
}
|
|
197
|
+
const voorbeeld = !engineJob && heeftEigenOpmaak && isVoorbeeldAfdruk(job);
|
|
106
198
|
if (id) {
|
|
107
199
|
const { data } = await db
|
|
108
200
|
.from("document_layouts")
|
|
@@ -113,19 +205,24 @@ async function zoekLayout(db, job) {
|
|
|
113
205
|
throw new GeenDocumentFout("De layout die aan deze opdracht hangt bestaat niet meer. Koppel een geldige layout.");
|
|
114
206
|
}
|
|
115
207
|
const layout = data;
|
|
116
|
-
return {
|
|
208
|
+
return {
|
|
209
|
+
layout,
|
|
210
|
+
// Een Engine-layout is altijd leidend, ook als er render_html is meegestuurd.
|
|
211
|
+
ontwerpWint: engineJob || (!voorbeeld && magOntwerpWinnen(layout)),
|
|
212
|
+
};
|
|
117
213
|
}
|
|
214
|
+
const documenttype = normaliseerDocumenttype(leesDocumentCode(job) || job.documenttype);
|
|
118
215
|
const { data } = await db
|
|
119
216
|
.from("document_layouts")
|
|
120
217
|
.select("*")
|
|
121
|
-
.eq("documenttype",
|
|
218
|
+
.eq("documenttype", documenttype)
|
|
122
219
|
.eq("actief", true)
|
|
123
220
|
.order("is_standaard", { ascending: false })
|
|
124
221
|
.order("updated_at", { ascending: false })
|
|
125
222
|
.limit(1);
|
|
126
223
|
const gevonden = (arr(data)[0] ?? null);
|
|
127
224
|
if (!gevonden && !job.render_html) {
|
|
128
|
-
throw new GeenDocumentFout(`Geen layout gevonden voor documenttype '${
|
|
225
|
+
throw new GeenDocumentFout(`Geen layout gevonden voor documenttype '${documenttype}'. ` +
|
|
129
226
|
"Maak een layout aan en zet die op actief.");
|
|
130
227
|
}
|
|
131
228
|
return { layout: gevonden, ontwerpWint: !voorbeeld && magOntwerpWinnen(gevonden) };
|
|
@@ -148,7 +245,7 @@ async function zoekBronregel(db, job) {
|
|
|
148
245
|
const regel = data;
|
|
149
246
|
if (!regel || regel.bron === "auto")
|
|
150
247
|
return null;
|
|
151
|
-
if (regel.bron === "eigen_layout" && regel.layout_id && !job.layout_id) {
|
|
248
|
+
if (regel.bron === "eigen_layout" && regel.layout_id && !job.layout_id && !isEngineOpdracht(job)) {
|
|
152
249
|
job.layout_id = regel.layout_id;
|
|
153
250
|
}
|
|
154
251
|
return regel.bron;
|
|
@@ -159,6 +256,8 @@ async function zoekBronregel(db, job) {
|
|
|
159
256
|
*/
|
|
160
257
|
async function isFloridayLayoutKeuze(db, job) {
|
|
161
258
|
const payload = (job.payload ?? {});
|
|
259
|
+
if (isEngineOpdracht(job))
|
|
260
|
+
return false;
|
|
162
261
|
const id = job.layout_id ?? payload?.["layoutId"] ?? payload?.["layout_id"] ?? null;
|
|
163
262
|
if (!id)
|
|
164
263
|
return false;
|
|
@@ -329,13 +428,35 @@ async function zoekPrinter(db, job, layout) {
|
|
|
329
428
|
.maybeSingle();
|
|
330
429
|
return data && data.actief !== false ? data : null;
|
|
331
430
|
};
|
|
332
|
-
const type = normaliseerDocumenttype(job.documenttype);
|
|
333
|
-
//
|
|
334
|
-
|
|
431
|
+
const type = normaliseerDocumenttype(leesDocumentCode(job) || job.documenttype);
|
|
432
|
+
// Bij Engine-opdrachten is print_plek_id leidend. Een eventueel oud
|
|
433
|
+
// printer_id mag die keuze niet overschrijven.
|
|
434
|
+
let printer = isEngineOpdracht(job) && leesPrintPlekId(job)
|
|
435
|
+
? null
|
|
436
|
+
: await pak(job.printer_id);
|
|
335
437
|
if (printer)
|
|
336
438
|
return { printer, reden: "" };
|
|
337
439
|
const werkplek = String(job.payload?.werkplek ?? "").trim();
|
|
338
440
|
const pickstation = leesPickstation(job);
|
|
441
|
+
const explicietePlek = leesPrintPlekId(job);
|
|
442
|
+
// Een Engine-printplek is een harde keuze. Nooit terugvallen op computer,
|
|
443
|
+
// layout of bedrijfsregels wanneer de Engine een print_plek_id meegaf.
|
|
444
|
+
if (explicietePlek) {
|
|
445
|
+
const { data: pp } = await db
|
|
446
|
+
.from("document_printplek_printers")
|
|
447
|
+
.select("printer_id")
|
|
448
|
+
.eq("print_plek_id", explicietePlek)
|
|
449
|
+
.eq("documenttype", type)
|
|
450
|
+
.maybeSingle();
|
|
451
|
+
printer = await pak(pp?.printer_id);
|
|
452
|
+
if (printer)
|
|
453
|
+
return { printer, reden: "" };
|
|
454
|
+
const { data: plek } = await db.from("print_plekken").select("naam").eq("id", explicietePlek).maybeSingle();
|
|
455
|
+
return {
|
|
456
|
+
printer: null,
|
|
457
|
+
reden: `Printplek '${String(plek?.naam ?? explicietePlek)}' heeft geen printer voor documenttype '${type}'.`,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
339
460
|
// 2. Regel van de printplek waar de opdracht vandaan komt.
|
|
340
461
|
const plekId = await zoekPrintPlekId(db, job);
|
|
341
462
|
if (plekId) {
|
|
@@ -517,6 +638,13 @@ export async function bouwHtml(db, job, keuze, uitkomst) {
|
|
|
517
638
|
: null;
|
|
518
639
|
if ((pakbonSecties && pakbonSecties.length) || String(layout.documenttype) === "pakbon") {
|
|
519
640
|
const orderBron = p.order ?? p.data?.order ?? p.data ?? p;
|
|
641
|
+
const pakbonMethode = Array.isArray(pakbonSecties)
|
|
642
|
+
? String(pakbonSecties.find((s) => s?.type === "pickmethode")?.opties?.methode ?? "kar")
|
|
643
|
+
: "kar";
|
|
644
|
+
const engineVariant = job.layout_variant ?? p.layout_variant ?? p.layoutVariant ?? p.data?.layout_variant ?? null;
|
|
645
|
+
if (isEngineOpdracht(job) && pakbonMethode === "beide" && !["full_cart", "partial_order"].includes(String(engineVariant ?? ""))) {
|
|
646
|
+
throw new WachtOpLayoutFout("Wacht op layout_variant van de Logistics Engine: kies full_cart of partial_order.");
|
|
647
|
+
}
|
|
520
648
|
const uitDb = heeftOrderInhoud(orderBron) ? null : await laadOrderVanuitDatabase(db, p);
|
|
521
649
|
// Een voorbeeldafdruk zonder ordergegevens krijgt een voorbeeldorder, zodat
|
|
522
650
|
// je ziet hoe het document er in de praktijk uitziet.
|
|
@@ -524,14 +652,82 @@ export async function bouwHtml(db, job, keuze, uitkomst) {
|
|
|
524
652
|
(p.voorbeeld === true && !heeftOrderInhoud(orderBron)
|
|
525
653
|
? voorbeeldPakbonOrder()
|
|
526
654
|
: orderBron);
|
|
527
|
-
|
|
528
|
-
|
|
655
|
+
// Barcode en kargegevens van de Engine mogen niet verloren gaan wanneer
|
|
656
|
+
// de ordergegevens uit een subobject komen.
|
|
657
|
+
const engineBarcode = p.barcode ?? p.data?.cart?.barcode ?? null;
|
|
658
|
+
const engineCart = p.data?.cart ?? null;
|
|
659
|
+
const bronRecord = (bron && typeof bron === "object" ? bron : {});
|
|
660
|
+
// Verwijder order-/payloadbarcodes: bij Engine-opdrachten zijn alleen de
|
|
661
|
+
// twee contractvelden hierboven toegestaan als bron voor de afleverbriefscan.
|
|
662
|
+
const { barcode: _bronBarcode, cart: _bronCart, ...bronZonderEngineBarcode } = bronRecord;
|
|
663
|
+
let order = maakPakbonOrder({
|
|
664
|
+
...bronZonderEngineBarcode,
|
|
665
|
+
...(engineBarcode ? { barcode: engineBarcode } : {}),
|
|
666
|
+
...(engineCart ? { cart: engineCart } : {}),
|
|
667
|
+
});
|
|
668
|
+
if (isEngineOpdracht(job)) {
|
|
669
|
+
const barcode = String(engineBarcode ?? "").trim();
|
|
670
|
+
if (!barcode) {
|
|
671
|
+
throw new WachtOpLayoutFout("Wacht op barcode van de Logistics Engine: iedere kar moet een eigen pakbonbarcode krijgen.");
|
|
672
|
+
}
|
|
673
|
+
const cartId = String(engineCart?.cart_id ?? "").trim();
|
|
674
|
+
const karren = Array.isArray(order.karren) ? order.karren : [];
|
|
675
|
+
const passendeKarren = cartId
|
|
676
|
+
? karren.filter((kar) => String(kar.cart_id ?? "").trim() === cartId)
|
|
677
|
+
: karren;
|
|
678
|
+
// Eén Engine-opdracht staat voor precies één kar en dus één pakbon. Een
|
|
679
|
+
// opdracht met meerdere karren mag niet één barcode aan meerdere karren
|
|
680
|
+
// koppelen; de Engine moet daarvoor afzonderlijke jobs aanmaken.
|
|
681
|
+
if (passendeKarren.length > 1 || (!cartId && karren.length > 1)) {
|
|
682
|
+
throw new WachtOpLayoutFout("Wacht op afzonderlijke kar-opdrachten van de Logistics Engine: maak per kar één print_job met een eigen barcode.");
|
|
683
|
+
}
|
|
684
|
+
if (cartId && passendeKarren.length === 0 && karren.length > 1) {
|
|
685
|
+
throw new WachtOpLayoutFout("De door de Logistics Engine gekozen kar is niet gevonden in de pakbongegevens.");
|
|
686
|
+
}
|
|
687
|
+
const gekozenKar = passendeKarren[0] ?? (karren.length === 1 ? karren[0] : null);
|
|
688
|
+
if (gekozenKar) {
|
|
689
|
+
order = {
|
|
690
|
+
...order,
|
|
691
|
+
cart: {
|
|
692
|
+
...order.cart,
|
|
693
|
+
...engineCart,
|
|
694
|
+
barcode,
|
|
695
|
+
cart_id: cartId || gekozenKar.cart_id,
|
|
696
|
+
cart_label: String(engineCart?.cart_label ?? gekozenKar.cart_label ?? "").trim() || undefined,
|
|
697
|
+
cart_index: Number(engineCart?.cart_index ?? gekozenKar.cart_index ?? 0) || undefined,
|
|
698
|
+
cart_total: Number(engineCart?.cart_total ?? gekozenKar.cart_total ?? 0) || undefined,
|
|
699
|
+
},
|
|
700
|
+
karren: [{ ...gekozenKar, barcode }],
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const html = renderPakbonDocument(layout.config, order, {
|
|
529
705
|
breedteMm,
|
|
530
706
|
hoogteMm,
|
|
531
707
|
margeMm: Number(layout.marge_boven ?? 12),
|
|
532
708
|
titel: job.documentnaam ?? "Document",
|
|
709
|
+
layoutVariant: engineVariant,
|
|
533
710
|
logos: await logosVoor(db, layout),
|
|
534
711
|
});
|
|
712
|
+
// De Engine bepaalt de barcode. De module registreert uitsluitend de
|
|
713
|
+
// gerenderde inhoud onder die bestaande waarde voor de scanner. Als de
|
|
714
|
+
// registratie tijdelijk niet kan, mag dat een afdruk nooit blokkeren.
|
|
715
|
+
const scanInhoud = bouwPakbonScanInhoud(order, {
|
|
716
|
+
barcode: engineBarcode,
|
|
717
|
+
layoutVariant: pakbonLayoutVariant(engineVariant),
|
|
718
|
+
layoutId: String(layout.id ?? "") || null,
|
|
719
|
+
printJobId: String(job.id ?? "") || null,
|
|
720
|
+
isHerprint: isHerprint(job),
|
|
721
|
+
});
|
|
722
|
+
if (scanInhoud) {
|
|
723
|
+
try {
|
|
724
|
+
await bewaarPakbonScanInhoud(db, scanInhoud);
|
|
725
|
+
}
|
|
726
|
+
catch (e) {
|
|
727
|
+
await log(db, job.id, "barcode_inhoud_niet_opgeslagen", e instanceof Error ? e.message : "Registratie van barcode-inhoud mislukt");
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return html;
|
|
535
731
|
}
|
|
536
732
|
// 2) Productiebon-layouts (blokken onder `productiebon.blokken`).
|
|
537
733
|
if (Array.isArray(cfg.productiebon?.blokken) ||
|
|
@@ -623,6 +819,20 @@ function plattePayload(payload) {
|
|
|
623
819
|
loop(payload, "", 0);
|
|
624
820
|
return uit;
|
|
625
821
|
}
|
|
822
|
+
async function wachtOpLayout(db, job, reden) {
|
|
823
|
+
await db
|
|
824
|
+
.from("print_jobs")
|
|
825
|
+
.update({
|
|
826
|
+
status: "wachtend",
|
|
827
|
+
foutmelding: reden.slice(0, 500),
|
|
828
|
+
volgende_poging: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
|
|
829
|
+
opgepakt_op: null,
|
|
830
|
+
voltooid_op: null,
|
|
831
|
+
updated_at: new Date().toISOString(),
|
|
832
|
+
})
|
|
833
|
+
.eq("id", job.id);
|
|
834
|
+
await log(db, job.id, "wacht_op_engine_layout", reden);
|
|
835
|
+
}
|
|
626
836
|
async function mislukt(db, job, reden, terugNaarWachtend) {
|
|
627
837
|
const pogingen = Number(job.pogingen ?? 0);
|
|
628
838
|
const opnieuw = terugNaarWachtend && pogingen < MAX_POGINGEN;
|
|
@@ -650,19 +860,20 @@ async function verwerkJob(db, job) {
|
|
|
650
860
|
// 1) Bronregel: bepaalt of het meegestuurde document wordt gebruikt of dat
|
|
651
861
|
// er altijd een eigen ontwerp wordt opgemaakt.
|
|
652
862
|
let bron = await zoekBronregel(db, job);
|
|
653
|
-
// 1b)
|
|
654
|
-
//
|
|
655
|
-
if (await isFloridayLayoutKeuze(db, job)) {
|
|
863
|
+
// 1b) Legacy Floriday-keuze; Engine-opdrachten volgen uitsluitend hun
|
|
864
|
+
// eigen layout_id en worden nooit teruggezet naar een externe PDF.
|
|
865
|
+
if (!isEngineOpdracht(job) && await isFloridayLayoutKeuze(db, job)) {
|
|
656
866
|
bron = "extern_pdf";
|
|
657
867
|
job.layout_id = null;
|
|
658
868
|
}
|
|
659
|
-
if (bron === "eigen_layout") {
|
|
869
|
+
if (bron === "eigen_layout" || isEngineOpdracht(job)) {
|
|
660
870
|
job.pdf_base64 = null;
|
|
661
871
|
job.pdf_url = null;
|
|
662
872
|
}
|
|
663
|
-
// 2) Kant-en-klare PDF
|
|
664
|
-
|
|
665
|
-
|
|
873
|
+
// 2) Kant-en-klare PDF gaat alleen buiten het Engine-contract ongewijzigd
|
|
874
|
+
// door. De Engine bepaalt altijd de layout, ook als er een PDF aanwezig is.
|
|
875
|
+
const klaar = isEngineOpdracht(job) ? null : await kantEnKlarePdf(db, job);
|
|
876
|
+
if (!klaar && bron === "extern_pdf" && !isEngineOpdracht(job)) {
|
|
666
877
|
await mislukt(db, job, "Floriday-document ontbreekt: voor dit document is ingesteld dat het " +
|
|
667
878
|
"aangeleverde document wordt gebruikt, maar er is geen PDF meegestuurd.", true);
|
|
668
879
|
return "mislukt";
|
|
@@ -777,6 +988,10 @@ async function verwerkJob(db, job) {
|
|
|
777
988
|
return "verstuurd";
|
|
778
989
|
}
|
|
779
990
|
catch (e) {
|
|
991
|
+
if (e instanceof WachtOpLayoutFout) {
|
|
992
|
+
await wachtOpLayout(db, job, e.message);
|
|
993
|
+
return "wachtend";
|
|
994
|
+
}
|
|
780
995
|
// Ontbreekt er een document of layout? Dan heeft opnieuw proberen geen zin.
|
|
781
996
|
const blijvend = e instanceof GeenDocumentFout;
|
|
782
997
|
const tijdelijk = !blijvend && (e instanceof PdfRenderFout || e?.name === "PrintToegangFout");
|
|
@@ -923,10 +1138,13 @@ export async function verwerkWachtrij(db, max = 5) {
|
|
|
923
1138
|
const jobs = [...pdfJobs, ...gewoneJobs];
|
|
924
1139
|
let verstuurd = 0;
|
|
925
1140
|
let mislukteJobs = 0;
|
|
1141
|
+
let wachtend = 0;
|
|
926
1142
|
for (const job of jobs) {
|
|
927
1143
|
const uitkomst = await verwerkJob(db, job);
|
|
928
1144
|
if (uitkomst === "verstuurd")
|
|
929
1145
|
verstuurd++;
|
|
1146
|
+
else if (uitkomst === "wachtend")
|
|
1147
|
+
wachtend++;
|
|
930
1148
|
else
|
|
931
1149
|
mislukteJobs++;
|
|
932
1150
|
}
|
|
@@ -934,6 +1152,7 @@ export async function verwerkWachtrij(db, max = 5) {
|
|
|
934
1152
|
opgepakt: jobs.length,
|
|
935
1153
|
verstuurd,
|
|
936
1154
|
mislukt: mislukteJobs,
|
|
1155
|
+
wachtend,
|
|
937
1156
|
bijgewerkt: await synchroniseerStatussen(db),
|
|
938
1157
|
};
|
|
939
1158
|
}
|
|
@@ -944,16 +1163,18 @@ export async function verwerkWachtrij(db, max = 5) {
|
|
|
944
1163
|
*/
|
|
945
1164
|
export async function bepaalDocumentKeuze(db, job) {
|
|
946
1165
|
let bron = await zoekBronregel(db, job);
|
|
947
|
-
|
|
1166
|
+
// Engine-opdrachten houden hun eigen layout_id; nooit vervangen door een
|
|
1167
|
+
// Floriday-PDF-keuze.
|
|
1168
|
+
if (!isEngineOpdracht(job) && (await isFloridayLayoutKeuze(db, job))) {
|
|
948
1169
|
bron = "extern_pdf";
|
|
949
1170
|
job.layout_id = null;
|
|
950
1171
|
}
|
|
951
|
-
if (bron === "eigen_layout") {
|
|
1172
|
+
if (bron === "eigen_layout" || isEngineOpdracht(job)) {
|
|
952
1173
|
job.pdf_base64 = null;
|
|
953
1174
|
job.pdf_url = null;
|
|
954
1175
|
}
|
|
955
|
-
const klaar = await kantEnKlarePdf(db, job);
|
|
956
|
-
if (!klaar && bron === "extern_pdf") {
|
|
1176
|
+
const klaar = isEngineOpdracht(job) ? null : await kantEnKlarePdf(db, job);
|
|
1177
|
+
if (!klaar && bron === "extern_pdf" && !isEngineOpdracht(job)) {
|
|
957
1178
|
throw new GeenDocumentFout("Voor dit document is ingesteld dat het aangeleverde document wordt " +
|
|
958
1179
|
"gebruikt, maar er is geen PDF meegestuurd.");
|
|
959
1180
|
}
|