@flowselections/layout-maker 1.55.2 → 1.57.1
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/LayoutVerwijzingenKaart.d.ts +4 -0
- package/dist-lib/components/LayoutVerwijzingenKaart.d.ts.map +1 -0
- package/dist-lib/components/LayoutVerwijzingenKaart.js +59 -0
- package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
- package/dist-lib/components/LayoutsPage.js +4 -13
- package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
- package/dist-lib/components/PrintQueuePage.js +16 -1
- package/dist-lib/components/PrintenInstellenWizard.d.ts +6 -0
- package/dist-lib/components/PrintenInstellenWizard.d.ts.map +1 -0
- package/dist-lib/components/PrintenInstellenWizard.js +89 -0
- package/dist-lib/components/PrintenPage.d.ts +3 -1
- package/dist-lib/components/PrintenPage.d.ts.map +1 -1
- package/dist-lib/components/PrintenPage.js +4 -2
- package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
- package/dist-lib/components/PrintplekDetailPage.js +2 -0
- package/dist-lib/components/TestprintDialog.js +2 -2
- package/dist-lib/components/WerkplekOmzettingStap.d.ts +10 -0
- package/dist-lib/components/WerkplekOmzettingStap.d.ts.map +1 -0
- package/dist-lib/components/WerkplekOmzettingStap.js +46 -0
- package/dist-lib/components/WerkplekVraag.d.ts +4 -0
- package/dist-lib/components/WerkplekVraag.d.ts.map +1 -0
- package/dist-lib/components/WerkplekVraag.js +26 -0
- package/dist-lib/components/WerkplekkenTab.d.ts +7 -0
- package/dist-lib/components/WerkplekkenTab.d.ts.map +1 -0
- package/dist-lib/components/WerkplekkenTab.js +143 -0
- package/dist-lib/index.d.ts +15 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +12 -0
- package/dist-lib/integrations/supabase/types.d.ts +415 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/beheerder.d.ts +2 -0
- package/dist-lib/lib/beheerder.d.ts.map +1 -0
- package/dist-lib/lib/beheerder.js +18 -0
- package/dist-lib/lib/etiketControle.d.ts +36 -0
- package/dist-lib/lib/etiketControle.d.ts.map +1 -0
- package/dist-lib/lib/etiketControle.js +89 -0
- package/dist-lib/lib/layoutVerwijzingen.d.ts +50 -0
- package/dist-lib/lib/layoutVerwijzingen.d.ts.map +1 -0
- package/dist-lib/lib/layoutVerwijzingen.js +101 -0
- package/dist-lib/lib/papierFormaten.d.ts +3 -3
- package/dist-lib/lib/papierFormaten.d.ts.map +1 -1
- package/dist-lib/lib/papierFormaten.js +6 -6
- package/dist-lib/lib/printQueue.server.d.ts +6 -0
- package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/printQueue.server.js +149 -23
- package/dist-lib/lib/printRoutering.d.ts +14 -1
- package/dist-lib/lib/printRoutering.d.ts.map +1 -1
- package/dist-lib/lib/printRoutering.js +6 -0
- package/dist-lib/lib/printnodeStatusTekst.d.ts +2 -0
- package/dist-lib/lib/printnodeStatusTekst.d.ts.map +1 -0
- package/dist-lib/lib/printnodeStatusTekst.js +13 -0
- package/dist-lib/lib/productiebonHtml.js +1 -1
- package/dist-lib/lib/testprint.d.ts +6 -0
- package/dist-lib/lib/testprint.d.ts.map +1 -1
- package/dist-lib/lib/testprint.js +11 -7
- package/dist-lib/lib/waaromPrinter.d.ts +7 -0
- package/dist-lib/lib/waaromPrinter.d.ts.map +1 -0
- package/dist-lib/lib/waaromPrinter.js +35 -0
- package/dist-lib/lib/werkplekOmzetting.d.ts +22 -0
- package/dist-lib/lib/werkplekOmzetting.d.ts.map +1 -0
- package/dist-lib/lib/werkplekOmzetting.js +42 -0
- package/dist-lib/lib/werkplekken.d.ts +73 -0
- package/dist-lib/lib/werkplekken.d.ts.map +1 -0
- package/dist-lib/lib/werkplekken.js +156 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beheerder.d.ts","sourceRoot":"","sources":["../../src/lib/beheerder.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,IAAI,OAAO,GAAG,IAAI,CAiB/C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Dezelfde beheerderscontrole als de Shell: has_role admin (en superadmin).
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { supabase } from "./supabaseClient.js";
|
|
4
|
+
export function useIsBeheerder() {
|
|
5
|
+
const [beheerder, setBeheerder] = useState(null);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
void (async () => {
|
|
8
|
+
const { data } = await supabase.auth.getUser();
|
|
9
|
+
const uid = data?.user?.id;
|
|
10
|
+
if (!uid)
|
|
11
|
+
return setBeheerder(false);
|
|
12
|
+
const rpc = supabase.rpc;
|
|
13
|
+
const r = await Promise.all(["admin", "superadmin"].map((rol) => rpc.call(supabase, "has_role", { _user_id: uid, _role: rol }).then((x) => x.data === true)));
|
|
14
|
+
setBeheerder(r.some(Boolean));
|
|
15
|
+
})();
|
|
16
|
+
}, []);
|
|
17
|
+
return beheerder;
|
|
18
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface GeladenEtiket {
|
|
2
|
+
/** Naam zoals PrintNode het formaat kent (gaat mee als optie `paper`). */
|
|
3
|
+
naam: string;
|
|
4
|
+
breedte_mm: number;
|
|
5
|
+
hoogte_mm: number;
|
|
6
|
+
}
|
|
7
|
+
export type EtiketUitkomst = {
|
|
8
|
+
ok: true;
|
|
9
|
+
paper: string;
|
|
10
|
+
rotate: 0 | 90;
|
|
11
|
+
uitleg: string;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
code: "FORMAAT_PAST_NIET" | "GEEN_GELADEN_ETIKET";
|
|
15
|
+
bericht: string;
|
|
16
|
+
};
|
|
17
|
+
export declare const maatTekst: (b: number, h: number) => string;
|
|
18
|
+
/** Leest een opgeslagen geladen etiket; ongeldig = null. */
|
|
19
|
+
export declare function leesGeladenEtiket(v: unknown): GeladenEtiket | null;
|
|
20
|
+
/** PrintNode-formaten (tienden mm) als keuzelijst in mm, zonder lege maten. */
|
|
21
|
+
export declare function etiketOpties(papers: unknown): GeladenEtiket[];
|
|
22
|
+
/**
|
|
23
|
+
* Past een document van breedte×hoogte (mm) op het geladen etiket? Draaien
|
|
24
|
+
* mag (liggend etiket, staande layout of andersom), schalen nooit.
|
|
25
|
+
*/
|
|
26
|
+
export declare function etiketPast(doc: {
|
|
27
|
+
breedte_mm: number;
|
|
28
|
+
hoogte_mm: number;
|
|
29
|
+
soortLabel: string;
|
|
30
|
+
}, geladen: GeladenEtiket | null, printerNaam: string): EtiketUitkomst;
|
|
31
|
+
/** Leest de paginagrootte (mm) van de eerste pagina uit een PDF (MediaBox). */
|
|
32
|
+
export declare function pdfPaginaMm(pdfBase64: string): {
|
|
33
|
+
breedte_mm: number;
|
|
34
|
+
hoogte_mm: number;
|
|
35
|
+
} | null;
|
|
36
|
+
//# sourceMappingURL=etiketControle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"etiketControle.d.ts","sourceRoot":"","sources":["../../src/lib/etiketControle.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,mBAAmB,GAAG,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAKtF,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,WAA2B,CAAC;AAE1E,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAQlE;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,aAAa,EAAE,CAW7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAClE,OAAO,EAAE,aAAa,GAAG,IAAI,EAC7B,WAAW,EAAE,MAAM,GAClB,cAAc,CAgChB;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAa/F"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/lib/etiketControle.ts — past het document op het geladen etiket?
|
|
3
|
+
//
|
|
4
|
+
// PrintNode meldt per printer alle formaten die de driver kent
|
|
5
|
+
// (capabilities.papers, in tienden van een millimeter). Dat zegt niets over de
|
|
6
|
+
// rol die er écht in zit. Daarom kiest de beheerder per labelprinter het
|
|
7
|
+
// "geladen etiket" en controleren we daartegen. Nooit stil schalen.
|
|
8
|
+
// ============================================================================
|
|
9
|
+
const MARGE_MM = 2;
|
|
10
|
+
const mm = (n) => Math.round(n * 10) / 10;
|
|
11
|
+
export const maatTekst = (b, h) => `${mm(b)}×${mm(h)} mm`;
|
|
12
|
+
/** Leest een opgeslagen geladen etiket; ongeldig = null. */
|
|
13
|
+
export function leesGeladenEtiket(v) {
|
|
14
|
+
if (!v || typeof v !== "object")
|
|
15
|
+
return null;
|
|
16
|
+
const r = v;
|
|
17
|
+
const b = Number(r.breedte_mm);
|
|
18
|
+
const h = Number(r.hoogte_mm);
|
|
19
|
+
const naam = String(r.naam ?? "").trim();
|
|
20
|
+
if (!naam || !(b > 0) || !(h > 0))
|
|
21
|
+
return null;
|
|
22
|
+
return { naam, breedte_mm: b, hoogte_mm: h };
|
|
23
|
+
}
|
|
24
|
+
/** PrintNode-formaten (tienden mm) als keuzelijst in mm, zonder lege maten. */
|
|
25
|
+
export function etiketOpties(papers) {
|
|
26
|
+
if (!papers || typeof papers !== "object" || Array.isArray(papers))
|
|
27
|
+
return [];
|
|
28
|
+
const uit = [];
|
|
29
|
+
for (const [naam, maat] of Object.entries(papers)) {
|
|
30
|
+
if (!Array.isArray(maat) || maat.length < 2)
|
|
31
|
+
continue;
|
|
32
|
+
const b = Number(maat[0]);
|
|
33
|
+
const h = Number(maat[1]);
|
|
34
|
+
if (!(b > 0) || !(h > 0))
|
|
35
|
+
continue;
|
|
36
|
+
uit.push({ naam: naam.trim() ? naam : naam, breedte_mm: b / 10, hoogte_mm: h / 10 });
|
|
37
|
+
}
|
|
38
|
+
return uit.sort((a, b) => a.breedte_mm * a.hoogte_mm - b.breedte_mm * b.hoogte_mm);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Past een document van breedte×hoogte (mm) op het geladen etiket? Draaien
|
|
42
|
+
* mag (liggend etiket, staande layout of andersom), schalen nooit.
|
|
43
|
+
*/
|
|
44
|
+
export function etiketPast(doc, geladen, printerNaam) {
|
|
45
|
+
if (!geladen) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
code: "GEEN_GELADEN_ETIKET",
|
|
49
|
+
bericht: `Stel eerst het geladen etiket in voor labelprinter ${printerNaam}.`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const { breedte_mm: b, hoogte_mm: h } = doc;
|
|
53
|
+
const recht = b <= geladen.breedte_mm + MARGE_MM && h <= geladen.hoogte_mm + MARGE_MM;
|
|
54
|
+
const gedraaid = b <= geladen.hoogte_mm + MARGE_MM && h <= geladen.breedte_mm + MARGE_MM;
|
|
55
|
+
if (!recht && !gedraaid) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
code: "FORMAAT_PAST_NIET",
|
|
59
|
+
bericht: `${doc.soortLabel} ${maatTekst(b, h)} past niet op het geladen etiket ${maatTekst(geladen.breedte_mm, geladen.hoogte_mm)} van labelprinter ${printerNaam}.`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const docLiggend = b > h;
|
|
63
|
+
const etiketLiggend = geladen.breedte_mm > geladen.hoogte_mm;
|
|
64
|
+
const rotate = !recht || docLiggend !== etiketLiggend ? 90 : 0;
|
|
65
|
+
return {
|
|
66
|
+
ok: true,
|
|
67
|
+
paper: geladen.naam,
|
|
68
|
+
rotate,
|
|
69
|
+
uitleg: `geladen etiket ${geladen.naam.trim()} (${maatTekst(geladen.breedte_mm, geladen.hoogte_mm)})${rotate ? ", gedraaid" : ""}`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Leest de paginagrootte (mm) van de eerste pagina uit een PDF (MediaBox). */
|
|
73
|
+
export function pdfPaginaMm(pdfBase64) {
|
|
74
|
+
try {
|
|
75
|
+
const bin = atob(pdfBase64.slice(0, 400000));
|
|
76
|
+
const m = /\/MediaBox\s*\[\s*([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)\s*\]/.exec(bin);
|
|
77
|
+
if (!m)
|
|
78
|
+
return null;
|
|
79
|
+
const w = Math.abs(Number(m[3]) - Number(m[1]));
|
|
80
|
+
const h = Math.abs(Number(m[4]) - Number(m[2]));
|
|
81
|
+
if (!(w > 0) || !(h > 0))
|
|
82
|
+
return null;
|
|
83
|
+
const pt = 25.4 / 72;
|
|
84
|
+
return { breedte_mm: w * pt, hoogte_mm: h * pt };
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface LayoutGebruik {
|
|
2
|
+
id: string;
|
|
3
|
+
naam: string;
|
|
4
|
+
documenttype: string;
|
|
5
|
+
bron: string;
|
|
6
|
+
actief: boolean;
|
|
7
|
+
is_standaard: boolean;
|
|
8
|
+
gebruik: Record<string, number>;
|
|
9
|
+
}
|
|
10
|
+
export interface LayoutVerwijzing {
|
|
11
|
+
tabel: string;
|
|
12
|
+
kolom: string;
|
|
13
|
+
pad: string[];
|
|
14
|
+
rij_id: string;
|
|
15
|
+
rij_naam: string | null;
|
|
16
|
+
rij_actief: boolean | null;
|
|
17
|
+
layout_id: string;
|
|
18
|
+
}
|
|
19
|
+
/** Tabellen die bij deze module horen: alleen die mag je hier omzetten. */
|
|
20
|
+
export declare const EIGEN_TABELLEN: readonly ["print_rules", "printer_mappings", "document_bronregels"];
|
|
21
|
+
export declare const isEigenVerwijzing: (v: Pick<LayoutVerwijzing, "tabel">) => boolean;
|
|
22
|
+
export interface VerwijzingPlek {
|
|
23
|
+
module: string;
|
|
24
|
+
scherm: string;
|
|
25
|
+
/** Relatieve link binnen de Shell; geen vast adres. */
|
|
26
|
+
link: string | null;
|
|
27
|
+
bekend: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function plekVanVerwijzing(v: Pick<LayoutVerwijzing, "tabel" | "kolom" | "pad">): VerwijzingPlek;
|
|
30
|
+
export interface SoortOverzicht {
|
|
31
|
+
documenttype: string;
|
|
32
|
+
layouts: (LayoutGebruik & {
|
|
33
|
+
verwijzingen: LayoutVerwijzing[];
|
|
34
|
+
totaal30: number;
|
|
35
|
+
})[];
|
|
36
|
+
/** Er zijn meerdere actieve layouts, of instellingen wijzen naar verschillende layouts. */
|
|
37
|
+
conflict: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Bouwt per documentsoort het overzicht. Kiest nooit zelf een standaard. */
|
|
40
|
+
export declare function bouwOverzicht(layoutsIn: unknown, verwijzingenIn: unknown): SoortOverzicht[];
|
|
41
|
+
export declare function useLayoutVerwijzingen(): {
|
|
42
|
+
overzicht: SoortOverzicht[];
|
|
43
|
+
loading: boolean;
|
|
44
|
+
fout: string | null;
|
|
45
|
+
reload: () => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
/** Zet één verwijzing van deze module om. De database weigert andere modules. */
|
|
48
|
+
export declare function zetVerwijzingOm(v: LayoutVerwijzing, nieuwLayoutId: string): Promise<void>;
|
|
49
|
+
export declare const BRON_LABEL: Record<string, string>;
|
|
50
|
+
//# sourceMappingURL=layoutVerwijzingen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layoutVerwijzingen.d.ts","sourceRoot":"","sources":["../../src/lib/layoutVerwijzingen.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2EAA2E;AAC3E,eAAO,MAAM,cAAc,qEAAsE,CAAC;AAClG,eAAO,MAAM,iBAAiB,GAAI,GAAG,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,YACX,CAAC;AAyB1D,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC,GAAG,cAAc,CAUtG;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,CAAC,aAAa,GAAG;QAAE,YAAY,EAAE,gBAAgB,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IACpF,2FAA2F;IAC3F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,GAAG,cAAc,EAAE,CAoB3F;AAED,wBAAgB,qBAAqB;;;;;EAiBpC;AAED,iFAAiF;AACjF,wBAAsB,eAAe,CAAC,CAAC,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM/F;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM7C,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// src/lib/layoutVerwijzingen.ts — welke instellingen (op id) naar welke layout
|
|
3
|
+
// wijzen, en hoe vaak elke layout de laatste 30 dagen is gebruikt. Alleen
|
|
4
|
+
// verwijzingen van Layouts en printers zelf mogen hier worden omgezet;
|
|
5
|
+
// instellingen van andere modules worden alleen getoond met een link.
|
|
6
|
+
// ============================================================================
|
|
7
|
+
import { useCallback, useEffect, useState } from "react";
|
|
8
|
+
import { supabase } from "./supabaseClient.js";
|
|
9
|
+
const db = supabase;
|
|
10
|
+
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
11
|
+
/** Tabellen die bij deze module horen: alleen die mag je hier omzetten. */
|
|
12
|
+
export const EIGEN_TABELLEN = ["print_rules", "printer_mappings", "document_bronregels"];
|
|
13
|
+
export const isEigenVerwijzing = (v) => EIGEN_TABELLEN.includes(v.tabel);
|
|
14
|
+
/** Eigenaar per tabelvoorvoegsel. Alleen structuur, geen gegevens van een Shell. */
|
|
15
|
+
const MODULES = [
|
|
16
|
+
{ voorvoegsel: "logistics_", info: { module: "Logistiek Engine", moduleId: "logistiek-engine" } },
|
|
17
|
+
{ voorvoegsel: "pick_station", info: { module: "Pickstations", moduleId: "pickstations" } },
|
|
18
|
+
{ voorvoegsel: "print_", info: { module: "Layouts en printers", moduleId: "layouts-printers" } },
|
|
19
|
+
{ voorvoegsel: "printer_", info: { module: "Layouts en printers", moduleId: "layouts-printers" } },
|
|
20
|
+
{ voorvoegsel: "document_", info: { module: "Layouts en printers", moduleId: "layouts-printers" } },
|
|
21
|
+
];
|
|
22
|
+
/** Bekende schermnamen per JSON-pad. Onbekend → tabel en veld tonen. */
|
|
23
|
+
const SCHERMEN = {
|
|
24
|
+
"logistics_rule_configs:pickstations.fields.shipping_note_layout": "Werkwijze › Pickstations › Verzendbrief voor BVO orders",
|
|
25
|
+
"logistics_rule_configs:pickstations.fields.packing_slip_layout": "Werkwijze › Pickstations › Pakbon",
|
|
26
|
+
"logistics_rule_configs:pickstations.fields.packing_slip_partial_layout": "Werkwijze › Pickstations › Restpakbon",
|
|
27
|
+
"logistics_rule_configs:pickstations.fields.production_note_layout": "Werkwijze › Pickstations › Productiebon",
|
|
28
|
+
"logistics_rule_configs:pickstations.fields.sticker_layout": "Werkwijze › Pickstations › Sticker",
|
|
29
|
+
"printer_mappings:layout_id": "Printen › Standaardregels",
|
|
30
|
+
"print_rules:layout_id": "Printen › Printregels",
|
|
31
|
+
"document_bronregels:layout_id": "Documenten › Bronregels",
|
|
32
|
+
};
|
|
33
|
+
export function plekVanVerwijzing(v) {
|
|
34
|
+
const info = MODULES.find((m) => v.tabel.startsWith(m.voorvoegsel))?.info ?? { module: "Andere module", moduleId: null };
|
|
35
|
+
const sleutel = `${v.tabel}:${v.pad.length ? v.pad.join(".") : v.kolom}`;
|
|
36
|
+
const scherm = SCHERMEN[sleutel];
|
|
37
|
+
return {
|
|
38
|
+
module: info.module,
|
|
39
|
+
scherm: scherm ?? `${v.tabel} › ${[v.kolom, ...v.pad].join(".")}`,
|
|
40
|
+
link: info.moduleId ? `/${info.moduleId}` : null,
|
|
41
|
+
bekend: Boolean(scherm),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Bouwt per documentsoort het overzicht. Kiest nooit zelf een standaard. */
|
|
45
|
+
export function bouwOverzicht(layoutsIn, verwijzingenIn) {
|
|
46
|
+
const layouts = arr(layoutsIn);
|
|
47
|
+
// Verwijzingen van de module zelf naar de standaardregels zijn geen keuze
|
|
48
|
+
// van een andere module; ze tellen wel mee in de lijst, niet als conflict.
|
|
49
|
+
const verw = arr(verwijzingenIn).map((v) => ({ ...v, pad: arr(v.pad) }));
|
|
50
|
+
const perSoort = new Map();
|
|
51
|
+
for (const l of layouts) {
|
|
52
|
+
const s = perSoort.get(l.documenttype) ?? { documenttype: l.documenttype, layouts: [], conflict: false };
|
|
53
|
+
const eigen = verw.filter((v) => v.layout_id === l.id);
|
|
54
|
+
const gebruik = l.gebruik && typeof l.gebruik === "object" ? l.gebruik : {};
|
|
55
|
+
s.layouts.push({ ...l, gebruik, verwijzingen: eigen, totaal30: Object.values(gebruik).reduce((a, b) => a + Number(b || 0), 0) });
|
|
56
|
+
perSoort.set(l.documenttype, s);
|
|
57
|
+
}
|
|
58
|
+
for (const s of perSoort.values()) {
|
|
59
|
+
const actief = s.layouts.filter((l) => l.actief);
|
|
60
|
+
const metModuleVerwijzing = s.layouts.filter((l) => l.verwijzingen.some((v) => !isEigenVerwijzing(v) && v.rij_actief !== false));
|
|
61
|
+
s.conflict = actief.length > 1 || metModuleVerwijzing.length > 1;
|
|
62
|
+
s.layouts.sort((a, b) => Number(b.actief) - Number(a.actief) || b.totaal30 - a.totaal30 || a.naam.localeCompare(b.naam));
|
|
63
|
+
}
|
|
64
|
+
return [...perSoort.values()].filter((s) => s.conflict).sort((a, b) => a.documenttype.localeCompare(b.documenttype));
|
|
65
|
+
}
|
|
66
|
+
export function useLayoutVerwijzingen() {
|
|
67
|
+
const [overzicht, setOverzicht] = useState([]);
|
|
68
|
+
const [loading, setLoading] = useState(true);
|
|
69
|
+
const [fout, setFout] = useState(null);
|
|
70
|
+
const reload = useCallback(async () => {
|
|
71
|
+
setLoading(true);
|
|
72
|
+
const { data, error } = await db.rpc("layout_verwijzingen");
|
|
73
|
+
if (error)
|
|
74
|
+
setFout(error.message);
|
|
75
|
+
else {
|
|
76
|
+
setFout(null);
|
|
77
|
+
const d = (data ?? {});
|
|
78
|
+
setOverzicht(bouwOverzicht(d.layouts, d.verwijzingen));
|
|
79
|
+
}
|
|
80
|
+
setLoading(false);
|
|
81
|
+
}, []);
|
|
82
|
+
useEffect(() => { void reload(); }, [reload]);
|
|
83
|
+
return { overzicht, loading, fout, reload };
|
|
84
|
+
}
|
|
85
|
+
/** Zet één verwijzing van deze module om. De database weigert andere modules. */
|
|
86
|
+
export async function zetVerwijzingOm(v, nieuwLayoutId) {
|
|
87
|
+
if (!isEigenVerwijzing(v))
|
|
88
|
+
throw new Error("Deze instelling hoort bij een andere module en wordt hier niet gewijzigd.");
|
|
89
|
+
const { error } = await db.rpc("layout_verwijzing_omzetten", {
|
|
90
|
+
_tabel: v.tabel, _rij_id: v.rij_id, _oud: v.layout_id, _nieuw: nieuwLayoutId,
|
|
91
|
+
});
|
|
92
|
+
if (error)
|
|
93
|
+
throw new Error(error.message);
|
|
94
|
+
}
|
|
95
|
+
export const BRON_LABEL = {
|
|
96
|
+
eigen_layout: "eigen layout",
|
|
97
|
+
extern_pdf: "Floriday-document",
|
|
98
|
+
render_html: "aangeleverde opmaak",
|
|
99
|
+
klantlayout: "klantlayout",
|
|
100
|
+
onbekend: "onbekend",
|
|
101
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Papierformaten van een printer: naam -> [breedte, hoogte] in 0,
|
|
1
|
+
/** Papierformaten van een printer: naam -> [breedte, hoogte] in 0,1 mm. */
|
|
2
2
|
export type PrinterFormaten = Record<string, [number, number] | number[]>;
|
|
3
3
|
export interface FormaatKeuze {
|
|
4
4
|
/** Naam zoals de printer die kent, of null als er geen match is. */
|
|
@@ -9,8 +9,8 @@ export interface FormaatKeuze {
|
|
|
9
9
|
uitleg: string;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* Zoekt de papiernaam die
|
|
13
|
-
*
|
|
12
|
+
* Zoekt de papiernaam die exact bij de gevraagde maat past (afronding max 1 mm per zijde).
|
|
13
|
+
* Geen exacte match -> geen papiernaam. Draaiing telt mee (liggend papier mag ook).
|
|
14
14
|
*/
|
|
15
15
|
export declare function kiesPapier(formaten: PrinterFormaten | null | undefined, breedteMm: number, hoogteMm: number, margeMm?: number): FormaatKeuze;
|
|
16
16
|
export interface PrinterFormaatOptie {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"papierFormaten.d.ts","sourceRoot":"","sources":["../../src/lib/papierFormaten.ts"],"names":[],"mappings":"AAWA,
|
|
1
|
+
{"version":3,"file":"papierFormaten.d.ts","sourceRoot":"","sources":["../../src/lib/papierFormaten.ts"],"names":[],"mappings":"AAWA,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC;AAE1E,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iDAAiD;IACjD,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC;IACf,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;CAChB;AAUD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,EAC5C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,SAAI,GACV,YAAY,CAyCd;AAQD,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAe5F;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GAC3C,mBAAmB,EAAE,CAuBvB"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// src/lib/papierFormaten.ts — het juiste papierformaat van de printer kiezen.
|
|
3
3
|
//
|
|
4
4
|
// De printdienst levert per printer een lijst met papierformaten die die
|
|
5
|
-
// printer aankan, met naam en afmeting in
|
|
5
|
+
// printer aankan, met naam en afmeting in tienden van een millimeter
|
|
6
6
|
// (A4 = [2100, 2970]). Hier zoeken we de naam die past bij de maat van onze
|
|
7
7
|
// layout, zodat de opdracht op het juiste papier uitkomt.
|
|
8
8
|
// ============================================================================
|
|
@@ -10,13 +10,13 @@ import { PAPIERFORMATEN } from "./documentTypes.js";
|
|
|
10
10
|
const arrGetal = (v) => Array.isArray(v) ? v.map((n) => Number(n)).filter((n) => Number.isFinite(n)) : [];
|
|
11
11
|
/** Zet een waarde uit de printerlijst om naar millimeters. */
|
|
12
12
|
function naarMm(waarde) {
|
|
13
|
-
return waarde /
|
|
13
|
+
return waarde / 10;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Zoekt de papiernaam die
|
|
17
|
-
*
|
|
16
|
+
* Zoekt de papiernaam die exact bij de gevraagde maat past (afronding max 1 mm per zijde).
|
|
17
|
+
* Geen exacte match -> geen papiernaam. Draaiing telt mee (liggend papier mag ook).
|
|
18
18
|
*/
|
|
19
|
-
export function kiesPapier(formaten, breedteMm, hoogteMm, margeMm =
|
|
19
|
+
export function kiesPapier(formaten, breedteMm, hoogteMm, margeMm = 1) {
|
|
20
20
|
const liggend = breedteMm > hoogteMm;
|
|
21
21
|
const rotate = liggend ? 90 : 0;
|
|
22
22
|
if (!formaten || typeof formaten !== "object" || Array.isArray(formaten)) {
|
|
@@ -37,7 +37,7 @@ export function kiesPapier(formaten, breedteMm, hoogteMm, margeMm = 2) {
|
|
|
37
37
|
const kort = Math.min(naarMm(m[0]), naarMm(m[1]));
|
|
38
38
|
const lang = Math.max(naarMm(m[0]), naarMm(m[1]));
|
|
39
39
|
const afwijking = Math.abs(kort - doelKort) + Math.abs(lang - doelLang);
|
|
40
|
-
if (
|
|
40
|
+
if (Math.abs(kort - doelKort) <= margeMm && Math.abs(lang - doelLang) <= margeMm && (!beste || afwijking < beste.afwijking)) {
|
|
41
41
|
beste = { naam, afwijking };
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -40,6 +40,12 @@ export type BronUitkomst = {
|
|
|
40
40
|
export declare function normaliseerDocumenttype(type: unknown): string;
|
|
41
41
|
/** Het layout-id zoals de Engine het aanlevert (kolom of payload). */
|
|
42
42
|
export declare function leesEngineLayoutId(job: Job): string;
|
|
43
|
+
/** Testprint: alleen de eigen testvlag telt (geen kar, geen barcode). */
|
|
44
|
+
export declare function isTestprintJob(job: {
|
|
45
|
+
payload?: unknown;
|
|
46
|
+
}): boolean;
|
|
47
|
+
/** Verwijdert elke barcode (order en karren), zodat het barcode-element leeg blijft. */
|
|
48
|
+
export declare function zonderBarcodes<T>(order: T): T;
|
|
43
49
|
/**
|
|
44
50
|
* Herkent een ondertekende downloadlink naar de EIGEN bestandsopslag (adres
|
|
45
51
|
* uit de omgeving, niets vast in code) en geeft map + pad terug. Zo werkt een
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"printQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/printQueue.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,9 @@ import { bouwDocumentHtml, voorbeeldContext } from "./layoutPreview.js";
|
|
|
14
14
|
import { htmlNaarPdfServer, PdfRenderFout } from "./htmlNaarPdf.server.js";
|
|
15
15
|
import { stuurPdfNaarPrinter, opdrachtStatusDetail, vervaltijdVoor } from "./printService.server.js";
|
|
16
16
|
import { kiesPapier } from "./papierFormaten.js";
|
|
17
|
+
import { waaromDezePrinter } from "./waaromPrinter.js";
|
|
18
|
+
import { etiketPast, leesGeladenEtiket, pdfPaginaMm } from "./etiketControle.js";
|
|
19
|
+
import { documentTypeLabel as documentTypeLabelVoor } from "./documentTypes.js";
|
|
17
20
|
import { PAPIERFORMATEN } from "./documentTypes.js";
|
|
18
21
|
const MAX_POGINGEN = 3;
|
|
19
22
|
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
@@ -167,6 +170,29 @@ function isEngineOpdracht(job) {
|
|
|
167
170
|
const bron = String(p.bron_module ?? p.owner_module ?? p.source_module ?? "").toLowerCase();
|
|
168
171
|
return bron.includes("logistic") || bron.includes("engine");
|
|
169
172
|
}
|
|
173
|
+
/** Testprint: alleen de eigen testvlag telt (geen kar, geen barcode). */
|
|
174
|
+
export function isTestprintJob(job) {
|
|
175
|
+
const p = (job.payload ?? {});
|
|
176
|
+
return p["is_testprint"] === true || p["is_testprint"] === "true";
|
|
177
|
+
}
|
|
178
|
+
/** Verwijdert elke barcode (order en karren), zodat het barcode-element leeg blijft. */
|
|
179
|
+
export function zonderBarcodes(order) {
|
|
180
|
+
const o = { ...order };
|
|
181
|
+
delete o.barcode;
|
|
182
|
+
if (o.cart && typeof o.cart === "object") {
|
|
183
|
+
const { barcode: _b, ...rest } = o.cart;
|
|
184
|
+
o.cart = rest;
|
|
185
|
+
}
|
|
186
|
+
if (Array.isArray(o.karren)) {
|
|
187
|
+
o.karren = o.karren.map((k) => {
|
|
188
|
+
if (!k || typeof k !== "object")
|
|
189
|
+
return k;
|
|
190
|
+
const { barcode: _b, ...rest } = k;
|
|
191
|
+
return rest;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return o;
|
|
195
|
+
}
|
|
170
196
|
/** Handmatig opnieuw printen? */
|
|
171
197
|
function isHerprint(job) {
|
|
172
198
|
const p = (job.payload ?? {});
|
|
@@ -607,7 +633,7 @@ async function zoekPrinter(db, job, layout) {
|
|
|
607
633
|
return null;
|
|
608
634
|
const { data } = await db
|
|
609
635
|
.from("printers")
|
|
610
|
-
.select("id, naam, extern_printer_id, actief, papierformaat, ondersteunde_formaten, ondersteunde_laden, formaten_bijgewerkt_op, afdrukmethode")
|
|
636
|
+
.select("id, naam, weergavenaam, extern_printer_id, actief, papierformaat, ondersteunde_formaten, ondersteunde_laden, formaten_bijgewerkt_op, afdrukmethode, geladen_etiket")
|
|
611
637
|
.eq("id", id)
|
|
612
638
|
.maybeSingle();
|
|
613
639
|
return data && data.actief !== false ? data : null;
|
|
@@ -657,10 +683,18 @@ async function zoekPrinter(db, job, layout) {
|
|
|
657
683
|
_werkplek: werkplek || null,
|
|
658
684
|
_layout_id: layout?.id ?? null,
|
|
659
685
|
_papierformaat: layout?.papierformaat ?? null,
|
|
686
|
+
...(leesWerkplekId(job) ? { _werkplek_id: leesWerkplekId(job) } : {}),
|
|
660
687
|
});
|
|
661
688
|
printer = await pak(route?.printer_id);
|
|
662
|
-
if (printer)
|
|
689
|
+
if (printer) {
|
|
690
|
+
try {
|
|
691
|
+
const plekNaam = plekId ? await printplekNaamVoorJob(db, job) : null;
|
|
692
|
+
const r = (route ?? {});
|
|
693
|
+
await log(db, job.id, "waarom", waaromDezePrinter({ bron: r.bron, papierformaat: r.papierformaat ?? null, werkplek_naam: r.werkplek_naam, printer_rol: r.printer_rol, werkplek: r.werkplek }, String(printer.weergavenaam || printer.naam || "Printer"), plekNaam));
|
|
694
|
+
}
|
|
695
|
+
catch { /* uitleg is informatief */ }
|
|
663
696
|
return { printer, reden: "" };
|
|
697
|
+
}
|
|
664
698
|
if (plekId) {
|
|
665
699
|
const naam = (await printplekNaamVoorJob(db, job)) ?? "onbekend";
|
|
666
700
|
return {
|
|
@@ -819,9 +853,15 @@ export async function bouwHtml(db, job, keuze, uitkomst) {
|
|
|
819
853
|
}
|
|
820
854
|
// Barcode en kargegevens van de Engine mogen niet verloren gaan wanneer
|
|
821
855
|
// de ordergegevens uit een subobject komen.
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
856
|
+
// Een testpakbon heeft geen kar en geen barcode: het barcode-element blijft
|
|
857
|
+
// leeg, er gaat geen barcodeverzoek naar de Engine en er wordt niets
|
|
858
|
+
// geregistreerd voor de scanner.
|
|
859
|
+
const isTestpakbon = isTestprintJob(job);
|
|
860
|
+
const herprintBron = isTestpakbon ? null : await zoekHerprintBarcodeBron(db, job);
|
|
861
|
+
const engineBarcode = isTestpakbon
|
|
862
|
+
? null
|
|
863
|
+
: (p.barcode ?? p.data?.cart?.barcode ?? p.cart?.barcode ?? herprintBron?.barcode ?? null);
|
|
864
|
+
const ruweEngineCart = isTestpakbon ? null : (p.data?.cart ?? p.cart ?? herprintBron?.cart ?? null);
|
|
825
865
|
const engineCart = ruweEngineCart && typeof ruweEngineCart === "object"
|
|
826
866
|
? {
|
|
827
867
|
...ruweEngineCart,
|
|
@@ -858,7 +898,9 @@ export async function bouwHtml(db, job, keuze, uitkomst) {
|
|
|
858
898
|
...(engineBarcode ? { barcode: engineBarcode } : {}),
|
|
859
899
|
...(engineCart ? { cart: engineCart } : {}),
|
|
860
900
|
});
|
|
861
|
-
if (
|
|
901
|
+
if (isTestpakbon)
|
|
902
|
+
order = zonderBarcodes(order);
|
|
903
|
+
if (isEngineOpdracht(job) && !isTestpakbon) {
|
|
862
904
|
let barcode = String(engineBarcode ?? "").trim();
|
|
863
905
|
if (!barcode) {
|
|
864
906
|
// De Engine heeft (nog) geen barcode meegestuurd. Heeft zij er
|
|
@@ -979,13 +1021,15 @@ export async function bouwHtml(db, job, keuze, uitkomst) {
|
|
|
979
1021
|
// De Engine bepaalt de barcode. De module registreert uitsluitend de
|
|
980
1022
|
// gerenderde inhoud onder die bestaande waarde voor de scanner. Als de
|
|
981
1023
|
// registratie tijdelijk niet kan, mag dat een afdruk nooit blokkeren.
|
|
982
|
-
const scanInhoud =
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1024
|
+
const scanInhoud = isTestpakbon
|
|
1025
|
+
? null
|
|
1026
|
+
: bouwPakbonScanInhoud(order, {
|
|
1027
|
+
barcode: order?.cart?.barcode ?? engineBarcode,
|
|
1028
|
+
layoutVariant: pakbonLayoutVariant(engineVariant),
|
|
1029
|
+
layoutId: String(layout.id ?? "") || null,
|
|
1030
|
+
printJobId: String(job.id ?? "") || null,
|
|
1031
|
+
isHerprint: isHerprint(job),
|
|
1032
|
+
});
|
|
989
1033
|
if (scanInhoud) {
|
|
990
1034
|
try {
|
|
991
1035
|
await bewaarPakbonScanInhoud(db, scanInhoud);
|
|
@@ -1292,6 +1336,20 @@ async function verwerkJob(db, job) {
|
|
|
1292
1336
|
await log(db, job.id, "annulering_bevestigd", "Niet afgeleverd: opdracht was geannuleerd.");
|
|
1293
1337
|
return "wachtend";
|
|
1294
1338
|
}
|
|
1339
|
+
// Labelprinter: het geladen etiket is leidend (punt "geladen etiket").
|
|
1340
|
+
const label = await labelControleVoorbereiden(db, printer);
|
|
1341
|
+
const isTest = (job.payload ?? {})["is_testprint"] === true;
|
|
1342
|
+
if (label && isTest && label.etiket) {
|
|
1343
|
+
// Een testprint gebruikt het formaat dat echt in de printer zit.
|
|
1344
|
+
const p = (job.payload ?? {});
|
|
1345
|
+
p["voorbeeld_formaat"] = {
|
|
1346
|
+
breedte_mm: label.etiket.breedte_mm,
|
|
1347
|
+
hoogte_mm: label.etiket.hoogte_mm,
|
|
1348
|
+
orientatie: label.etiket.breedte_mm > label.etiket.hoogte_mm ? "landscape" : "portrait",
|
|
1349
|
+
marge_boven: 2,
|
|
1350
|
+
};
|
|
1351
|
+
job.payload = p;
|
|
1352
|
+
}
|
|
1295
1353
|
// Uitkomst van de opmaakkeuze; wordt na verzending vastgelegd naast de
|
|
1296
1354
|
// aangeleverde invoer, zodat achteraf zichtbaar is wat er gekozen is.
|
|
1297
1355
|
const uitkomst = { bron: floriday ? "floriday_1op1" : "extern_pdf" };
|
|
@@ -1324,17 +1382,48 @@ async function verwerkJob(db, job) {
|
|
|
1324
1382
|
const vfPapier = (job.payload ?? {})["voorbeeld_formaat"];
|
|
1325
1383
|
const breedteMm = Number(layout?.breedte_mm ?? vfPapier?.["breedte_mm"] ?? standaardMaat(printer).breedte);
|
|
1326
1384
|
const hoogteMm = Number(layout?.hoogte_mm ?? vfPapier?.["hoogte_mm"] ?? standaardMaat(printer).hoogte);
|
|
1327
|
-
|
|
1385
|
+
let papier = kiesPapier(formaten, breedteMm, hoogteMm);
|
|
1386
|
+
if (label) {
|
|
1387
|
+
const maat = (klaar ? pdfPaginaMm(pdfBase64) : null) ?? { breedte_mm: breedteMm, hoogte_mm: hoogteMm };
|
|
1388
|
+
const uit = etiketPast({ ...maat, soortLabel: documentTypeLabelVoor(String(job.documenttype ?? "Document")) }, label.etiket, label.naam);
|
|
1389
|
+
if (!uit.ok) {
|
|
1390
|
+
await mislukt(db, job, `${uit.code}: ${uit.bericht}`, true);
|
|
1391
|
+
return "mislukt";
|
|
1392
|
+
}
|
|
1393
|
+
papier = { paper: uit.paper, rotate: uit.rotate, uitleg: uit.uitleg };
|
|
1394
|
+
await log(db, job.id, "etiket", `Labelprinter ${label.naam}: ${uit.uitleg}.`);
|
|
1395
|
+
}
|
|
1328
1396
|
const verloopt = vervaltijdVoor(String(job.documenttype ?? ""));
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1397
|
+
// Eén fysieke printer via meerdere computers: probeer de routes op
|
|
1398
|
+
// volgorde; valt de eerste weg, dan automatisch de volgende.
|
|
1399
|
+
const routes = await printerRoutes(db, String(printer.id), String(printer.extern_printer_id));
|
|
1400
|
+
let externJobId = "";
|
|
1401
|
+
let laatsteFout = null;
|
|
1402
|
+
for (const [i, route] of routes.entries()) {
|
|
1403
|
+
try {
|
|
1404
|
+
externJobId = await stuurPdfNaarPrinter({
|
|
1405
|
+
jobId: String(job.id),
|
|
1406
|
+
expireAfter: verloopt,
|
|
1407
|
+
externPrinterId: route.extern,
|
|
1408
|
+
documentnaam: String(job.documentnaam ?? "Document"),
|
|
1409
|
+
pdfBase64,
|
|
1410
|
+
kopieen: Number(job.kopieen ?? 1),
|
|
1411
|
+
opties: { paper: papier.paper, rotate: papier.rotate, fitToPage: false },
|
|
1412
|
+
});
|
|
1413
|
+
if (i > 0) {
|
|
1414
|
+
await log(db, job.id, "route", `Verstuurd via computer ${route.computer ?? "andere route"}: de eerste computer was niet bereikbaar.`);
|
|
1415
|
+
}
|
|
1416
|
+
laatsteFout = null;
|
|
1417
|
+
break;
|
|
1418
|
+
}
|
|
1419
|
+
catch (e) {
|
|
1420
|
+
laatsteFout = e;
|
|
1421
|
+
if (!(e instanceof Error) || i === routes.length - 1 || e.name === "AlOntvangenFout")
|
|
1422
|
+
throw e;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
if (laatsteFout)
|
|
1426
|
+
throw laatsteFout;
|
|
1338
1427
|
if (await isJobGeannuleerd(db, String(job.id))) {
|
|
1339
1428
|
const { annuleerExternePrintOpdracht } = await import("./printService.server.js");
|
|
1340
1429
|
await annuleerExternePrintOpdracht(externJobId).catch(() => undefined);
|
|
@@ -1699,3 +1788,40 @@ export async function bepaalDocumentKeuze(db, job) {
|
|
|
1699
1788
|
: await zoekLayout(db, job);
|
|
1700
1789
|
return { keuze, klaarPdf: klaar };
|
|
1701
1790
|
}
|
|
1791
|
+
/**
|
|
1792
|
+
* Is dit een labelprinter? Ja als er een geladen etiket is ingesteld, of als
|
|
1793
|
+
* een werkplek hem als labelprinter gebruikt. Alleen dan geldt de controle,
|
|
1794
|
+
* zodat bestaande printers zonder werkplek precies blijven werken als nu.
|
|
1795
|
+
*/
|
|
1796
|
+
async function labelControleVoorbereiden(db, printer) {
|
|
1797
|
+
const etiket = leesGeladenEtiket(printer?.geladen_etiket);
|
|
1798
|
+
const naam = String(printer?.weergavenaam || printer?.naam || "onbekend");
|
|
1799
|
+
if (etiket)
|
|
1800
|
+
return { naam, etiket };
|
|
1801
|
+
const { data } = await db
|
|
1802
|
+
.from("print_werkplekken")
|
|
1803
|
+
.select("id")
|
|
1804
|
+
.eq("label_printer_id", printer.id)
|
|
1805
|
+
.eq("actief", true)
|
|
1806
|
+
.limit(1);
|
|
1807
|
+
return Array.isArray(data) && data.length ? { naam, etiket: null } : null;
|
|
1808
|
+
}
|
|
1809
|
+
/** Routes van een printer, op prioriteit; zonder routes de printer zelf. */
|
|
1810
|
+
async function printerRoutes(db, printerId, eigen) {
|
|
1811
|
+
const { data } = await db
|
|
1812
|
+
.from("printer_routes")
|
|
1813
|
+
.select("extern_printer_id, computer_naam, prioriteit")
|
|
1814
|
+
.eq("printer_id", printerId)
|
|
1815
|
+
.order("prioriteit", { ascending: true });
|
|
1816
|
+
const lijst = (Array.isArray(data) ? data : [])
|
|
1817
|
+
.map((r) => ({ extern: String(r.extern_printer_id ?? ""), computer: r.computer_naam ?? null }))
|
|
1818
|
+
.filter((r) => r.extern);
|
|
1819
|
+
if (!lijst.some((r) => r.extern === eigen))
|
|
1820
|
+
lijst.unshift({ extern: eigen, computer: null });
|
|
1821
|
+
return lijst;
|
|
1822
|
+
}
|
|
1823
|
+
/** Werkplek uit het nieuwe model (op id), meegestuurd in de payload. */
|
|
1824
|
+
function leesWerkplekId(job) {
|
|
1825
|
+
const v = String((job.payload ?? {})["werkplek_id"] ?? "").trim();
|
|
1826
|
+
return /^[0-9a-f-]{36}$/i.test(v) ? v : null;
|
|
1827
|
+
}
|