@flowselections/layout-maker 1.32.0 → 1.36.7
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/ComputersLijst.d.ts.map +1 -1
- package/dist-lib/components/ComputersLijst.js +5 -5
- package/dist-lib/components/DocumentenPage.d.ts.map +1 -1
- package/dist-lib/components/DocumentenPage.js +3 -2
- package/dist-lib/components/LayoutPrinterSelect.d.ts +8 -0
- package/dist-lib/components/LayoutPrinterSelect.d.ts.map +1 -0
- package/dist-lib/components/LayoutPrinterSelect.js +23 -0
- package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
- package/dist-lib/components/LayoutsPage.js +16 -3
- package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/PakbonBuilderPage.js +3 -1
- package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
- package/dist-lib/components/PakbonSectiesPanel.js +6 -2
- package/dist-lib/components/PdfMapAutoSaver.d.ts +6 -0
- package/dist-lib/components/PdfMapAutoSaver.d.ts.map +1 -0
- package/dist-lib/components/PdfMapAutoSaver.js +12 -0
- package/dist-lib/components/PdfMapGlobaleBanner.d.ts +12 -0
- package/dist-lib/components/PdfMapGlobaleBanner.d.ts.map +1 -0
- package/dist-lib/components/PdfMapGlobaleBanner.js +30 -0
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts +7 -0
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -0
- package/dist-lib/components/PdfMapToestemmingBanner.js +139 -0
- package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
- package/dist-lib/components/PrintQueuePage.js +42 -3
- package/dist-lib/components/PrintenPage.d.ts.map +1 -1
- package/dist-lib/components/PrintenPage.js +3 -2
- package/dist-lib/components/PrinterSetupWizard.d.ts.map +1 -1
- package/dist-lib/components/PrinterSetupWizard.js +25 -2
- package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
- package/dist-lib/components/PrintplekDetailPage.js +30 -4
- package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
- package/dist-lib/components/PrintplekWizard.js +81 -3
- package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/ProductiebonBuilderPage.js +3 -1
- package/dist-lib/index.d.ts +6 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +11 -1
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +242 -1
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +242 -1
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +244 -1
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/aiLayout.functions.d.ts +242 -1
- package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
- package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlPdf.server.js +43 -6
- package/dist-lib/lib/orderData.server.d.ts.map +1 -1
- package/dist-lib/lib/orderData.server.js +117 -10
- package/dist-lib/lib/pdfJobSaver.d.ts +20 -0
- package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -0
- package/dist-lib/lib/pdfJobSaver.js +173 -0
- package/dist-lib/lib/pdfMap.d.ts +48 -0
- package/dist-lib/lib/pdfMap.d.ts.map +1 -0
- package/dist-lib/lib/pdfMap.js +219 -0
- package/dist-lib/lib/pdfPrinter.d.ts +9 -0
- package/dist-lib/lib/pdfPrinter.d.ts.map +1 -0
- package/dist-lib/lib/pdfPrinter.js +34 -0
- package/dist-lib/lib/previewPdf.d.ts.map +1 -1
- package/dist-lib/lib/previewPdf.js +41 -9
- package/dist-lib/lib/printApi.d.ts.map +1 -1
- package/dist-lib/lib/printApi.js +9 -1
- package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/printQueue.server.js +99 -26
- package/dist-lib/lib/printService.functions.d.ts +968 -4
- package/dist-lib/lib/printService.functions.d.ts.map +1 -1
- package/dist-lib/lib/useDocumentData.d.ts +10 -0
- package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
- package/dist-lib/lib/useDocumentData.js +19 -0
- package/dist-lib/lib/voorbeeldPrint.d.ts +4 -0
- package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
- package/dist-lib/lib/voorbeeldPrint.js +13 -2
- package/package.json +1 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/lib/pdfMap.ts — keuze van de map op de eigen computer waarin PDF's van
|
|
3
|
+
// de virtuele "Opslaan als PDF"-printer worden bewaard. De maphandle blijft
|
|
4
|
+
// lokaal in IndexedDB staan (per printer); de servers zien alleen de naam.
|
|
5
|
+
// ============================================================================
|
|
6
|
+
const DB_NAAM = "layout-maker-pdfmap";
|
|
7
|
+
const STORE = "handles";
|
|
8
|
+
const BEWAARD_SLEUTEL = "layout-maker-pdf-bewaard";
|
|
9
|
+
const GLOBALE_HANDLE_SLEUTEL = "__gekozen_pdf_map__";
|
|
10
|
+
const PDF_MAP_GEWIJZIGD_EVENT = "layout-maker:pdf-map-gewijzigd";
|
|
11
|
+
export function mapKiezenMogelijk() {
|
|
12
|
+
return typeof window !== "undefined" && "showDirectoryPicker" in window;
|
|
13
|
+
}
|
|
14
|
+
function openDb() {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const req = indexedDB.open(DB_NAAM, 1);
|
|
17
|
+
req.onupgradeneeded = () => {
|
|
18
|
+
if (!req.result.objectStoreNames.contains(STORE))
|
|
19
|
+
req.result.createObjectStore(STORE);
|
|
20
|
+
};
|
|
21
|
+
req.onsuccess = () => resolve(req.result);
|
|
22
|
+
req.onerror = () => reject(req.error);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function bewaarHandle(printerId, handle) {
|
|
26
|
+
const db = await openDb();
|
|
27
|
+
await new Promise((resolve, reject) => {
|
|
28
|
+
const tx = db.transaction(STORE, "readwrite");
|
|
29
|
+
const store = tx.objectStore(STORE);
|
|
30
|
+
// De map hoort bij deze browser/computer, niet bij een database-printer-id.
|
|
31
|
+
// Bewaar daarom ook onder één vaste sleutel. Dit voorkomt dat een nieuwe of
|
|
32
|
+
// dubbele virtuele PDF-printer de reeds goedgekeurde map onzichtbaar maakt.
|
|
33
|
+
store.put(handle, GLOBALE_HANDLE_SLEUTEL);
|
|
34
|
+
store.put(handle, printerId);
|
|
35
|
+
tx.oncomplete = () => resolve();
|
|
36
|
+
tx.onerror = () => reject(tx.error);
|
|
37
|
+
});
|
|
38
|
+
window.dispatchEvent(new CustomEvent(PDF_MAP_GEWIJZIGD_EVENT, { detail: { printerId } }));
|
|
39
|
+
}
|
|
40
|
+
export function luisterNaarPdfMapWijziging(handler) {
|
|
41
|
+
if (typeof window === "undefined")
|
|
42
|
+
return () => undefined;
|
|
43
|
+
window.addEventListener(PDF_MAP_GEWIJZIGD_EVENT, handler);
|
|
44
|
+
return () => window.removeEventListener(PDF_MAP_GEWIJZIGD_EVENT, handler);
|
|
45
|
+
}
|
|
46
|
+
async function leesHandle(printerId) {
|
|
47
|
+
try {
|
|
48
|
+
const db = await openDb();
|
|
49
|
+
const lees = (sleutel) => new Promise((resolve, reject) => {
|
|
50
|
+
const tx = db.transaction(STORE, "readonly");
|
|
51
|
+
const req = tx.objectStore(STORE).get(sleutel);
|
|
52
|
+
req.onsuccess = () => resolve(req.result ?? null);
|
|
53
|
+
req.onerror = () => reject(req.error);
|
|
54
|
+
});
|
|
55
|
+
const globaal = await lees(GLOBALE_HANDLE_SLEUTEL);
|
|
56
|
+
if (globaal)
|
|
57
|
+
return globaal;
|
|
58
|
+
const direct = await lees(printerId);
|
|
59
|
+
if (direct) {
|
|
60
|
+
await bewaarHandle(printerId, direct);
|
|
61
|
+
return direct;
|
|
62
|
+
}
|
|
63
|
+
const gevonden = await new Promise((resolve, reject) => {
|
|
64
|
+
const tx = db.transaction(STORE, "readonly");
|
|
65
|
+
const store = tx.objectStore(STORE);
|
|
66
|
+
const cursor = store.openCursor();
|
|
67
|
+
cursor.onsuccess = () => {
|
|
68
|
+
const rij = cursor.result;
|
|
69
|
+
if (!rij) {
|
|
70
|
+
resolve(null);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const handle = rij.value;
|
|
74
|
+
if (handle?.name && typeof handle.getFileHandle === "function") {
|
|
75
|
+
resolve(handle);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
rij.continue();
|
|
79
|
+
};
|
|
80
|
+
cursor.onerror = () => reject(cursor.error);
|
|
81
|
+
});
|
|
82
|
+
if (gevonden)
|
|
83
|
+
await bewaarHandle(printerId, gevonden);
|
|
84
|
+
return gevonden;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Browsers blokkeren showDirectoryPicker in een cross-origin iframe (zoals de
|
|
92
|
+
* Lovable-preview). De aanroeper kan dan aanbieden om de app in een eigen
|
|
93
|
+
* tabblad te openen, waar de verkenner wel werkt.
|
|
94
|
+
*/
|
|
95
|
+
export function draaitInIframe() {
|
|
96
|
+
try {
|
|
97
|
+
return typeof window !== "undefined" && window.self !== window.top;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Opent de huidige pagina in een eigen tabblad (buiten het preview-iframe). */
|
|
104
|
+
export function openInEigenTabblad() {
|
|
105
|
+
window.open(window.location.href, "_blank", "noopener");
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Opent de mappenverkenner van het besturingssysteem zodat de gebruiker een
|
|
109
|
+
* map kan selecteren. Start in Downloads zodat het pad snel te vinden is.
|
|
110
|
+
* Geeft terug wat er is gebeurd zodat de aanroeper gericht kan reageren.
|
|
111
|
+
*/
|
|
112
|
+
export async function kiesPdfMap(printerId) {
|
|
113
|
+
if (!mapKiezenMogelijk())
|
|
114
|
+
return { status: "niet-ondersteund" };
|
|
115
|
+
try {
|
|
116
|
+
const handle = (await window.showDirectoryPicker({
|
|
117
|
+
mode: "readwrite",
|
|
118
|
+
startIn: "downloads",
|
|
119
|
+
}));
|
|
120
|
+
await bewaarHandle(printerId, handle);
|
|
121
|
+
// Een nieuwe mapkeuze is ook een expliciete opdracht om reeds voltooide
|
|
122
|
+
// PDF-jobs opnieuw naar deze map te schrijven.
|
|
123
|
+
try {
|
|
124
|
+
localStorage.removeItem(BEWAARD_SLEUTEL);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Lokale opslag kan door browserbeleid uitgeschakeld zijn.
|
|
128
|
+
}
|
|
129
|
+
return { status: "gekozen", naam: handle.name };
|
|
130
|
+
}
|
|
131
|
+
catch (fout) {
|
|
132
|
+
// De gebruiker drukt op Annuleren in de verkenner → AbortError, geen fout.
|
|
133
|
+
if (fout instanceof DOMException && fout.name === "AbortError") {
|
|
134
|
+
return { status: "geannuleerd" };
|
|
135
|
+
}
|
|
136
|
+
// Cross-origin iframe → SecurityError ("Cross origin sub frames aren't
|
|
137
|
+
// allowed to show a file picker"). Aparte status zodat de UI een
|
|
138
|
+
// "open in eigen tabblad"-knop kan tonen.
|
|
139
|
+
if (fout instanceof DOMException &&
|
|
140
|
+
(fout.name === "SecurityError" || /cross.?origin/i.test(fout.message))) {
|
|
141
|
+
return { status: "iframe-geblokkeerd" };
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
status: "fout",
|
|
145
|
+
melding: fout instanceof Error ? fout.message : "Onbekende fout",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Is er voor deze printer een map gekozen op deze computer? */
|
|
150
|
+
export async function heeftPdfMap(printerId) {
|
|
151
|
+
return (await leesHandle(printerId)) !== null;
|
|
152
|
+
}
|
|
153
|
+
/** Naam van de gekozen map (voor meldingen), of null. */
|
|
154
|
+
export async function pdfMapNaam(printerId) {
|
|
155
|
+
const h = await leesHandle(printerId);
|
|
156
|
+
return h?.name ?? null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Probeert het bestand rechtstreeks in de gekozen map te zetten. Lukt dat niet
|
|
160
|
+
* (andere computer, geen toestemming, browser zonder ondersteuning), dan geeft
|
|
161
|
+
* de functie false terug en kan de aanroeper gewoon downloaden.
|
|
162
|
+
*/
|
|
163
|
+
export async function bewaarInPdfMap(printerId, bestandsnaam, blob) {
|
|
164
|
+
const handle = await leesHandle(printerId);
|
|
165
|
+
if (!handle)
|
|
166
|
+
return false;
|
|
167
|
+
try {
|
|
168
|
+
const toestemming = (await handle.queryPermission?.({ mode: "readwrite" })) ?? "granted";
|
|
169
|
+
if (toestemming !== "granted") {
|
|
170
|
+
const nieuw = await handle.requestPermission?.({ mode: "readwrite" });
|
|
171
|
+
if (nieuw !== "granted")
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const bestand = await handle.getFileHandle(bestandsnaam, { create: true });
|
|
175
|
+
const writable = await bestand.createWritable();
|
|
176
|
+
await writable.write(blob);
|
|
177
|
+
await writable.close();
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
catch (fout) {
|
|
181
|
+
console.error("[layout-maker] PDF kon niet lokaal worden opgeslagen", fout);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Controleert toestemming zonder een bestandsactie te starten. */
|
|
186
|
+
export async function pdfMapToestemming(printerId) {
|
|
187
|
+
const handle = await leesHandle(printerId);
|
|
188
|
+
if (!handle)
|
|
189
|
+
return "ontbreekt";
|
|
190
|
+
try {
|
|
191
|
+
return ((await handle.queryPermission?.({ mode: "readwrite" })) ?? "granted");
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return "denied";
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Vraagt vanuit een expliciete gebruikersklik opnieuw schrijftoestemming voor
|
|
199
|
+
* een eerder gekozen map. Achtergrondtaken mogen deze browserprompt niet zelf
|
|
200
|
+
* openen, omdat browsers daarvoor een actieve gebruikershandeling vereisen.
|
|
201
|
+
*/
|
|
202
|
+
export async function herstelPdfMapToestemming(printerId) {
|
|
203
|
+
const handle = await leesHandle(printerId);
|
|
204
|
+
if (!handle)
|
|
205
|
+
return "ontbreekt";
|
|
206
|
+
try {
|
|
207
|
+
// requestPermission moet rechtstreeks in deze klik-callstack plaatsvinden;
|
|
208
|
+
// een voorafgaande await kan de tijdelijke gebruikersactivatie laten verlopen.
|
|
209
|
+
if (handle.requestPermission) {
|
|
210
|
+
const nieuw = await handle.requestPermission({ mode: "readwrite" });
|
|
211
|
+
return nieuw === "granted" ? "granted" : "denied";
|
|
212
|
+
}
|
|
213
|
+
const huidig = (await handle.queryPermission?.({ mode: "readwrite" })) ?? "granted";
|
|
214
|
+
return huidig === "granted" ? "granted" : "denied";
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return "denied";
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zorgt dat de virtuele PDF-printer bestaat. Geeft true terug als de printer
|
|
3
|
+
* er na afloop is (bestaand of net aangemaakt), en welke melding past.
|
|
4
|
+
*/
|
|
5
|
+
export declare function zorgVoorPdfPrinter(): Promise<{
|
|
6
|
+
ok: boolean;
|
|
7
|
+
alAanwezig: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=pdfPrinter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdfPrinter.d.ts","sourceRoot":"","sources":["../../src/lib/pdfPrinter.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC;IAClD,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC,CAsBD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/lib/pdfPrinter.ts — gedeelde helper voor de virtuele "Opslaan als
|
|
3
|
+
// PDF"-printer. Documenten die hierheen gaan worden niet geprint maar als
|
|
4
|
+
// downloadbare PDF in de printwachtrij bewaard. Er is maar één PDF-printer
|
|
5
|
+
// nodig; een tweede wordt niet aangemaakt.
|
|
6
|
+
// ============================================================================
|
|
7
|
+
import { supabase } from "./supabaseClient.js";
|
|
8
|
+
/**
|
|
9
|
+
* Zorgt dat de virtuele PDF-printer bestaat. Geeft true terug als de printer
|
|
10
|
+
* er na afloop is (bestaand of net aangemaakt), en welke melding past.
|
|
11
|
+
*/
|
|
12
|
+
export async function zorgVoorPdfPrinter() {
|
|
13
|
+
const { data: bestaand } = await supabase
|
|
14
|
+
.from("printers")
|
|
15
|
+
.select("id")
|
|
16
|
+
.eq("afdrukmethode", "pdf")
|
|
17
|
+
.eq("actief", true)
|
|
18
|
+
.limit(1);
|
|
19
|
+
if ((bestaand ?? []).length > 0)
|
|
20
|
+
return { ok: true, alAanwezig: true };
|
|
21
|
+
const { error } = await supabase
|
|
22
|
+
.from("printers")
|
|
23
|
+
.insert({
|
|
24
|
+
naam: "Opslaan als PDF",
|
|
25
|
+
omschrijving: "Virtuele printer: documenten worden als PDF in de printwachtrij bewaard.",
|
|
26
|
+
actief: true,
|
|
27
|
+
online: true,
|
|
28
|
+
afdrukmethode: "pdf",
|
|
29
|
+
papierformaat: "A4",
|
|
30
|
+
});
|
|
31
|
+
if (error)
|
|
32
|
+
throw error;
|
|
33
|
+
return { ok: true, alAanwezig: false };
|
|
34
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"previewPdf.d.ts","sourceRoot":"","sources":["../../src/lib/previewPdf.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"previewPdf.d.ts","sourceRoot":"","sources":["../../src/lib/previewPdf.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAqFxC;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoM1F"}
|
|
@@ -24,24 +24,39 @@ function leesSleutel(request) {
|
|
|
24
24
|
}
|
|
25
25
|
/** Mag deze aanroeper voorbeelden opvragen? Zelfde regels als de queue-tick. */
|
|
26
26
|
async function magAanroepen(request, db) {
|
|
27
|
+
const geprobeerd = [];
|
|
28
|
+
const ontbrekend = [];
|
|
27
29
|
const meegegeven = leesSleutel(request);
|
|
28
|
-
if (!meegegeven)
|
|
29
|
-
|
|
30
|
+
if (!meegegeven) {
|
|
31
|
+
ontbrekend.push("toegangsbewijs in de apikey- of authorization-header");
|
|
32
|
+
return { ok: false, geprobeerd, ontbrekend };
|
|
33
|
+
}
|
|
34
|
+
geprobeerd.push("runner-sleutel");
|
|
30
35
|
const { isRunnerSleutel } = await import("./runnerRegistry.server.js");
|
|
31
36
|
if (await isRunnerSleutel(db, meegegeven))
|
|
32
|
-
return true;
|
|
37
|
+
return { ok: true, geprobeerd, ontbrekend };
|
|
38
|
+
geprobeerd.push("publishable-key");
|
|
33
39
|
const projectSleutel = process.env["SUPABASE_PUBLISHABLE_KEY"] ??
|
|
34
40
|
process.env["VITE_SUPABASE_PUBLISHABLE_KEY"] ??
|
|
35
41
|
"";
|
|
36
|
-
if (projectSleutel
|
|
37
|
-
|
|
42
|
+
if (!projectSleutel)
|
|
43
|
+
ontbrekend.push("SUPABASE_PUBLISHABLE_KEY");
|
|
44
|
+
else if (gelijk(projectSleutel, meegegeven))
|
|
45
|
+
return { ok: true, geprobeerd, ontbrekend };
|
|
46
|
+
geprobeerd.push("gebruikerstoken");
|
|
38
47
|
try {
|
|
39
48
|
const { data } = await db.auth.getUser(meegegeven);
|
|
40
|
-
|
|
49
|
+
if (data?.user?.id)
|
|
50
|
+
return { ok: true, geprobeerd, ontbrekend };
|
|
41
51
|
}
|
|
42
52
|
catch {
|
|
43
|
-
|
|
53
|
+
/* val door naar weigering */
|
|
44
54
|
}
|
|
55
|
+
return { ok: false, geprobeerd, ontbrekend };
|
|
56
|
+
}
|
|
57
|
+
/** Herkent een databaseweigering (de server mag niet) los van "jij mag niet". */
|
|
58
|
+
function isRechtenFout(melding, code) {
|
|
59
|
+
return code === "42501" || /permission denied|must be owner|not allowed/i.test(melding);
|
|
45
60
|
}
|
|
46
61
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
47
62
|
/** Legt een weigering vindbaar vast; faalt nooit hard. */
|
|
@@ -68,8 +83,15 @@ export async function behandelPreviewPdf(request, supabase) {
|
|
|
68
83
|
if (!supabase) {
|
|
69
84
|
return Response.json({ ok: false, code: "geen_database", fout: "De server kreeg geen databaseverbinding." }, { status: 500 });
|
|
70
85
|
}
|
|
71
|
-
|
|
72
|
-
|
|
86
|
+
const toegang = await magAanroepen(request, supabase);
|
|
87
|
+
if (!toegang.ok) {
|
|
88
|
+
return Response.json({
|
|
89
|
+
ok: false,
|
|
90
|
+
code: "geen_toegang",
|
|
91
|
+
fout: "Het voorbeeld weigerde het verzoek: geen geldig toegangsbewijs meegestuurd (dit is een aanroeper-probleem, geen databaserechten-probleem).",
|
|
92
|
+
geprobeerd: toegang.geprobeerd,
|
|
93
|
+
ontbrekend: toegang.ontbrekend,
|
|
94
|
+
}, { status: 401 });
|
|
73
95
|
}
|
|
74
96
|
let body = {};
|
|
75
97
|
try {
|
|
@@ -91,6 +113,13 @@ export async function behandelPreviewPdf(request, supabase) {
|
|
|
91
113
|
_venster_sec: VENSTER_SEC,
|
|
92
114
|
});
|
|
93
115
|
if (tempoFout) {
|
|
116
|
+
if (isRechtenFout(String(tempoFout.message ?? ""), tempoFout.code)) {
|
|
117
|
+
return Response.json({
|
|
118
|
+
ok: false,
|
|
119
|
+
code: "server_geen_rechten",
|
|
120
|
+
fout: "De server mag print_preview_toestaan niet uitvoeren. De route draait niet met de service-role sleutel of het EXECUTE-recht ontbreekt.",
|
|
121
|
+
}, { status: 503 });
|
|
122
|
+
}
|
|
94
123
|
return weiger(supabase, station, queueItem, "render_mislukt", `Voorbeeld niet mogelijk: ${tempoFout.message}`, 500);
|
|
95
124
|
}
|
|
96
125
|
const toestemming = (tempo ?? {});
|
|
@@ -110,6 +139,9 @@ export async function behandelPreviewPdf(request, supabase) {
|
|
|
110
139
|
});
|
|
111
140
|
if (rpcFout) {
|
|
112
141
|
const melding = String(rpcFout.message ?? "");
|
|
142
|
+
if (isRechtenFout(melding, rpcFout.code)) {
|
|
143
|
+
return weiger(supabase, station, queueItem, "server_geen_rechten", "De server mag pick_preview_job niet uitvoeren. De route draait niet met de service-role sleutel of het EXECUTE-recht ontbreekt.", 503);
|
|
144
|
+
}
|
|
113
145
|
// Ontbreekt de functie zelf (Engine nog niet bijgewerkt)? Dat is geen
|
|
114
146
|
// stationprobleem maar een installatieprobleem.
|
|
115
147
|
if (/could not find the function|does not exist/i.test(melding)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printApi.d.ts","sourceRoot":"","sources":["../../src/lib/printApi.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"printApi.d.ts","sourceRoot":"","sources":["../../src/lib/printApi.ts"],"names":[],"mappings":"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"}
|
package/dist-lib/lib/printApi.js
CHANGED
|
@@ -7,6 +7,7 @@ import { supabase } from "./supabaseClient.js";
|
|
|
7
7
|
import { printerVoorWerkplekDocument } from "./documentRoutering.js";
|
|
8
8
|
import { printerVoorPrintplek, printplekNaam, printplekVoorComputer } from "./printplekken.js";
|
|
9
9
|
import { bronVoorDocument } from "./documentBron.js";
|
|
10
|
+
import { bewaarPdfJobZodraKlaar } from "./pdfJobSaver.js";
|
|
10
11
|
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
11
12
|
/** Zoekt de te gebruiken layout: expliciet, anders standaard, anders de nieuwste. */
|
|
12
13
|
async function bepaalLayout(documenttype, layoutId) {
|
|
@@ -104,8 +105,15 @@ async function zetInWachtrij(rij) {
|
|
|
104
105
|
const id = data?.id ?? null;
|
|
105
106
|
// Direct laten verwerken; wacht niet op de cron-ronde. Mislukt dit, dan
|
|
106
107
|
// blijft de opdracht gewoon wachtend staan voor een volgende poging.
|
|
107
|
-
if (id)
|
|
108
|
+
if (id) {
|
|
108
109
|
void startWachtrijVerwerking();
|
|
110
|
+
const printerId = typeof rij.printer_id === "string" ? rij.printer_id : null;
|
|
111
|
+
// Bij de virtuele PDF-printer blijft deze browser wachten op de gemaakte
|
|
112
|
+
// PDF en schrijft hem meteen naar de lokaal gekozen map. Voor gewone
|
|
113
|
+
// printers stopt de helper direct omdat daar geen maphandle voor bestaat.
|
|
114
|
+
if (printerId)
|
|
115
|
+
void bewaarPdfJobZodraKlaar(id, printerId);
|
|
116
|
+
}
|
|
109
117
|
return id;
|
|
110
118
|
}
|
|
111
119
|
/** Fout wanneer een identieke aanvraag kort geleden al is aangemaakt. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/printQueue.server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAsB5D,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE/B,mFAAmF;AACnF,MAAM,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEpD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAW1E;AAUD,2EAA2E;AAC3E,qBAAa,gBAAiB,SAAQ,KAAK;IAChC,IAAI,SAAsB;CACpC;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvE,yEAAyE;AACzE,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,aAAa,GAAG,aAAa,CAAC;AAE1F,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAcnD,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAI7D;AAkHD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BnF;
|
|
1
|
+
{"version":3,"file":"printQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/printQueue.server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAsB5D,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE/B,mFAAmF;AACnF,MAAM,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEpD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAW1E;AAUD,2EAA2E;AAC3E,qBAAa,gBAAiB,SAAQ,KAAK;IAChC,IAAI,SAAsB;CACpC;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvE,yEAAyE;AACzE,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,aAAa,GAAG,aAAa,CAAC;AAE1F,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAcnD,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAI7D;AAkHD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BnF;AAwQD;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,OAAO,EACX,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,WAAW,EAClB,QAAQ,CAAC,EAAE,YAAY,GACtB,OAAO,CAAC,MAAM,CAAC,CA8IjB;AAGD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAY1D;AAmVD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,SAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAwCtF;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,OAAO,EACX,GAAG,EAAE,GAAG,GACP,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA0B1D"}
|
|
@@ -324,7 +324,7 @@ async function zoekPrinter(db, job, layout) {
|
|
|
324
324
|
return null;
|
|
325
325
|
const { data } = await db
|
|
326
326
|
.from("printers")
|
|
327
|
-
.select("id, naam, extern_printer_id, actief, papierformaat, ondersteunde_formaten, ondersteunde_laden, formaten_bijgewerkt_op")
|
|
327
|
+
.select("id, naam, extern_printer_id, actief, papierformaat, ondersteunde_formaten, ondersteunde_laden, formaten_bijgewerkt_op, afdrukmethode")
|
|
328
328
|
.eq("id", id)
|
|
329
329
|
.maybeSingle();
|
|
330
330
|
return data && data.actief !== false ? data : null;
|
|
@@ -414,24 +414,31 @@ async function zoekPrinter(db, job, layout) {
|
|
|
414
414
|
reden: `Documenttype '${type}' heeft geen standaardprinter. Stel dit in bij Printen > Standaardregels.`,
|
|
415
415
|
};
|
|
416
416
|
}
|
|
417
|
+
/** Verzamelt elk logo-id ergens in de layoutconfiguratie (op elke diepte). */
|
|
418
|
+
function verzamelLogoIds(waarde, uit, diepte = 0) {
|
|
419
|
+
if (diepte > 8 || waarde === null || typeof waarde !== "object")
|
|
420
|
+
return;
|
|
421
|
+
if (Array.isArray(waarde)) {
|
|
422
|
+
for (const item of waarde)
|
|
423
|
+
verzamelLogoIds(item, uit, diepte + 1);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
for (const [sleutel, val] of Object.entries(waarde)) {
|
|
427
|
+
if ((sleutel === "logoId" || sleutel === "logo_id") && typeof val === "string" && val) {
|
|
428
|
+
uit.add(val);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
verzamelLogoIds(val, uit, diepte + 1);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
417
435
|
/** Haalt de logo's op die in de layout gebruikt worden, met tijdelijke URL. */
|
|
418
436
|
async function logosVoor(db, layout) {
|
|
419
437
|
const config = layout?.config ?? null;
|
|
420
438
|
const ids = new Set();
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
// Ook logo's die als blok in de ontwerper staan meenemen.
|
|
425
|
-
for (const sectie of Array.isArray(config?.sections) ? config.sections : []) {
|
|
426
|
-
const id = sectie?.opties?.logoId ?? sectie?.logoId;
|
|
427
|
-
if (id)
|
|
428
|
-
ids.add(String(id));
|
|
429
|
-
}
|
|
430
|
-
for (const blok of Array.isArray(config?.blokken) ? config.blokken : []) {
|
|
431
|
-
const id = blok?.opties?.logoId ?? blok?.logoId;
|
|
432
|
-
if (id)
|
|
433
|
-
ids.add(String(id));
|
|
434
|
-
}
|
|
439
|
+
// Logo's staan op verschillende plekken in de configuratie: als documentlogo,
|
|
440
|
+
// als blok in de ontwerper, of binnen `pakbon.secties` / `productiebon.blokken`.
|
|
441
|
+
verzamelLogoIds(config, ids);
|
|
435
442
|
if (!ids.size)
|
|
436
443
|
return [];
|
|
437
444
|
const { data } = await db
|
|
@@ -664,7 +671,9 @@ async function verwerkJob(db, job) {
|
|
|
664
671
|
const layout = keuze.layout;
|
|
665
672
|
const printerKeuze = await zoekPrinter(db, job, layout);
|
|
666
673
|
const printer = printerKeuze.printer;
|
|
667
|
-
|
|
674
|
+
// Virtuele PDF-printer: geen PrintNode nodig; de PDF wordt bewaard.
|
|
675
|
+
const isPdfPrinter = String(printer?.afdrukmethode ?? "") === "pdf";
|
|
676
|
+
if (!printer || (!isPdfPrinter && !printer.extern_printer_id)) {
|
|
668
677
|
await mislukt(db, job, printerKeuze.reden ||
|
|
669
678
|
`Printer '${printer?.naam ?? "onbekend"}' is niet aan PrintNode gekoppeld.`, true);
|
|
670
679
|
return "mislukt";
|
|
@@ -679,18 +688,69 @@ async function verwerkJob(db, job) {
|
|
|
679
688
|
throw new GeenDocumentFout("Het document was leeg: er zijn geen gegevens gevonden om af te drukken. " +
|
|
680
689
|
"Controleer of de layout blokken bevat en of de order gegevens heeft.");
|
|
681
690
|
}
|
|
682
|
-
|
|
691
|
+
// Een voorbeeldafdruk koppelt bewust geen layout (het meegestuurde
|
|
692
|
+
// ontwerp is leidend), maar geeft wél het papierformaat van de bewerkte
|
|
693
|
+
// layout mee. Zonder dit zou het voorbeeld altijd op A4 uitkomen.
|
|
694
|
+
const vf = (job.payload ?? {})["voorbeeld_formaat"];
|
|
695
|
+
const liggend = String(layout?.orientatie ?? vf?.["orientatie"] ?? "portrait") === "landscape";
|
|
683
696
|
pdfBase64 = await htmlNaarPdfServer({
|
|
684
697
|
html,
|
|
685
|
-
breedteMm: Number(layout?.breedte_mm ?? 210),
|
|
686
|
-
hoogteMm: Number(layout?.hoogte_mm ?? 297),
|
|
687
|
-
margeMm: Number(layout?.marge_boven ?? 10),
|
|
698
|
+
breedteMm: Number(layout?.breedte_mm ?? vf?.["breedte_mm"] ?? 210),
|
|
699
|
+
hoogteMm: Number(layout?.hoogte_mm ?? vf?.["hoogte_mm"] ?? 297),
|
|
700
|
+
margeMm: Number(layout?.marge_boven ?? vf?.["marge_boven"] ?? 10),
|
|
688
701
|
landschap: liggend,
|
|
689
702
|
});
|
|
690
703
|
}
|
|
704
|
+
// Virtuele PDF-printer: niets gaat naar een fysieke printer; de opgemaakte
|
|
705
|
+
// PDF wordt op de opdracht bewaard en is daarna te downloaden in de
|
|
706
|
+
// wachtrij. De opdracht is meteen voltooid.
|
|
707
|
+
if (isPdfPrinter) {
|
|
708
|
+
// In twee stappen: eerst de status (klein en altijd betrouwbaar), daarna
|
|
709
|
+
// pas de PDF zelf. Een grote PDF kan door de databaselimiet geweigerd
|
|
710
|
+
// worden; de opdracht mag daar nooit door blijven hangen op 'bezig'.
|
|
711
|
+
const { error: statusFout } = await db
|
|
712
|
+
.from("print_jobs")
|
|
713
|
+
.update({
|
|
714
|
+
printer_id: printer.id,
|
|
715
|
+
gebruikte_layout_id: uitkomst.bron === "extern_pdf" ? null : (layout?.id ?? null),
|
|
716
|
+
gebruikte_bron: uitkomst.bron,
|
|
717
|
+
status: "voltooid",
|
|
718
|
+
lokale_pdf_status: "gereed",
|
|
719
|
+
lokale_pdf_fout: null,
|
|
720
|
+
lokaal_opgeslagen_op: null,
|
|
721
|
+
foutmelding: null,
|
|
722
|
+
volgende_poging: null,
|
|
723
|
+
voltooid_op: new Date().toISOString(),
|
|
724
|
+
updated_at: new Date().toISOString(),
|
|
725
|
+
})
|
|
726
|
+
.eq("id", job.id);
|
|
727
|
+
if (statusFout) {
|
|
728
|
+
await mislukt(db, job, `Opdracht afronden mislukt: ${statusFout.message}`, true);
|
|
729
|
+
return "mislukt";
|
|
730
|
+
}
|
|
731
|
+
const { error: pdfFout } = await db
|
|
732
|
+
.from("print_jobs")
|
|
733
|
+
.update({ resultaat_pdf_base64: pdfBase64 })
|
|
734
|
+
.eq("id", job.id);
|
|
735
|
+
if (pdfFout) {
|
|
736
|
+
await db
|
|
737
|
+
.from("print_jobs")
|
|
738
|
+
.update({
|
|
739
|
+
lokale_pdf_status: "fout",
|
|
740
|
+
lokale_pdf_fout: `PDF kon niet bewaard worden: ${pdfFout.message}`.slice(0, 500),
|
|
741
|
+
updated_at: new Date().toISOString(),
|
|
742
|
+
})
|
|
743
|
+
.eq("id", job.id);
|
|
744
|
+
await log(db, job.id, "mislukt", `PDF bewaren mislukt: ${pdfFout.message}`);
|
|
745
|
+
return "verstuurd";
|
|
746
|
+
}
|
|
747
|
+
await log(db, job.id, "pdf_gereed", `PDF gereed voor lokale opslag via ${printer.naam ?? "PDF-printer"}.`);
|
|
748
|
+
return "verstuurd";
|
|
749
|
+
}
|
|
691
750
|
const formaten = await zorgVoorFormaten(db, printer);
|
|
692
|
-
const
|
|
693
|
-
const
|
|
751
|
+
const vfPapier = (job.payload ?? {})["voorbeeld_formaat"];
|
|
752
|
+
const breedteMm = Number(layout?.breedte_mm ?? vfPapier?.["breedte_mm"] ?? standaardMaat(printer).breedte);
|
|
753
|
+
const hoogteMm = Number(layout?.hoogte_mm ?? vfPapier?.["hoogte_mm"] ?? standaardMaat(printer).hoogte);
|
|
694
754
|
const papier = kiesPapier(formaten, breedteMm, hoogteMm);
|
|
695
755
|
const externJobId = await stuurPdfNaarPrinter({
|
|
696
756
|
externPrinterId: String(printer.extern_printer_id),
|
|
@@ -812,6 +872,7 @@ async function vervalControle(db) {
|
|
|
812
872
|
.select("id, pogingen")
|
|
813
873
|
.eq("status", "bezig")
|
|
814
874
|
.is("extern_job_id", null)
|
|
875
|
+
.neq("lokale_pdf_status", "gereed")
|
|
815
876
|
.or(`opgepakt_op.lt.${grensClaim},and(opgepakt_op.is.null,updated_at.lt.${grensClaim})`)
|
|
816
877
|
.limit(50);
|
|
817
878
|
for (const job of arr(vastgelopen)) {
|
|
@@ -844,10 +905,22 @@ export async function verwerkWachtrij(db, max = 5) {
|
|
|
844
905
|
catch (e) {
|
|
845
906
|
console.warn(`[printwachtrij] vervalcontrole mislukt: ${e instanceof Error ? e.message : "onbekend"}`);
|
|
846
907
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
const
|
|
908
|
+
// PDF-opdrachten hebben een eigen claimroute. Daardoor kunnen oudere
|
|
909
|
+
// gepubliceerde moduleversies, die een PDF-printer nog als PrintNode-printer
|
|
910
|
+
// behandelen, deze opdrachten niet meer vóór de actuele runner oppakken.
|
|
911
|
+
const { data: pdfData, error: pdfError } = await db.rpc("claim_pdf_print_jobs", { _max: max });
|
|
912
|
+
if (pdfError)
|
|
913
|
+
throw new Error(pdfError.message);
|
|
914
|
+
const pdfJobs = arr(pdfData);
|
|
915
|
+
const resterend = Math.max(0, max - pdfJobs.length);
|
|
916
|
+
let gewoneJobs = [];
|
|
917
|
+
if (resterend > 0) {
|
|
918
|
+
const { data, error } = await db.rpc("claim_cloud_print_jobs", { _max: resterend });
|
|
919
|
+
if (error)
|
|
920
|
+
throw new Error(error.message);
|
|
921
|
+
gewoneJobs = arr(data);
|
|
922
|
+
}
|
|
923
|
+
const jobs = [...pdfJobs, ...gewoneJobs];
|
|
851
924
|
let verstuurd = 0;
|
|
852
925
|
let mislukteJobs = 0;
|
|
853
926
|
for (const job of jobs) {
|