@flowselections/pick-schermen-kwekers 1.0.2 → 1.0.3

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.
Files changed (94) hide show
  1. package/dist-lib/components/PickPublicPage.d.ts +7 -0
  2. package/dist-lib/components/PickPublicPage.d.ts.map +1 -0
  3. package/dist-lib/components/PickPublicPage.js +19 -0
  4. package/dist-lib/components/PickstationsPage.d.ts.map +1 -1
  5. package/dist-lib/components/PickstationsPage.js +57 -14
  6. package/dist-lib/components/pick/LanguageTiles.d.ts +8 -0
  7. package/dist-lib/components/pick/LanguageTiles.d.ts.map +1 -0
  8. package/dist-lib/components/pick/LanguageTiles.js +11 -0
  9. package/dist-lib/components/pick/PickScherm.d.ts +6 -4
  10. package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
  11. package/dist-lib/components/pick/PickScherm.js +145 -61
  12. package/dist-lib/components/pick/QueueTable.d.ts +4 -1
  13. package/dist-lib/components/pick/QueueTable.d.ts.map +1 -1
  14. package/dist-lib/components/pick/QueueTable.js +11 -10
  15. package/dist-lib/hooks/usePickQueue.d.ts +7 -1
  16. package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
  17. package/dist-lib/hooks/usePickQueue.js +43 -6
  18. package/dist-lib/index.d.ts +5 -6
  19. package/dist-lib/index.d.ts.map +1 -1
  20. package/dist-lib/index.js +6 -12
  21. package/dist-lib/integrations/supabase/auth-middleware.d.ts +8929 -5189
  22. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  23. package/dist-lib/integrations/supabase/client.d.ts +8929 -5189
  24. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  25. package/dist-lib/integrations/supabase/client.server.d.ts +8929 -5189
  26. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  27. package/dist-lib/integrations/supabase/types.d.ts +9245 -5437
  28. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  29. package/dist-lib/lib/layoutApi.d.ts +23 -0
  30. package/dist-lib/lib/layoutApi.d.ts.map +1 -0
  31. package/dist-lib/lib/layoutApi.js +94 -0
  32. package/dist-lib/lib/layoutMaker/documentProfiles.d.ts +50 -0
  33. package/dist-lib/lib/layoutMaker/documentProfiles.d.ts.map +1 -0
  34. package/dist-lib/lib/layoutMaker/documentProfiles.js +458 -0
  35. package/dist-lib/lib/layoutMaker/documentTypes.d.ts +123 -0
  36. package/dist-lib/lib/layoutMaker/documentTypes.d.ts.map +1 -0
  37. package/dist-lib/lib/layoutMaker/documentTypes.js +74 -0
  38. package/dist-lib/lib/layoutMaker/logoLibrary.d.ts +13 -0
  39. package/dist-lib/lib/layoutMaker/logoLibrary.d.ts.map +1 -0
  40. package/dist-lib/lib/layoutMaker/logoLibrary.js +54 -0
  41. package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts +196 -0
  42. package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts.map +1 -0
  43. package/dist-lib/lib/layoutMaker/pakbonBuilder.js +813 -0
  44. package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts +48 -0
  45. package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts.map +1 -0
  46. package/dist-lib/lib/layoutMaker/pakbonHtml.js +703 -0
  47. package/dist-lib/lib/layoutRenderer.d.ts +7 -0
  48. package/dist-lib/lib/layoutRenderer.d.ts.map +1 -0
  49. package/dist-lib/lib/layoutRenderer.js +233 -0
  50. package/dist-lib/lib/layoutTypes.d.ts +84 -0
  51. package/dist-lib/lib/layoutTypes.d.ts.map +1 -0
  52. package/dist-lib/lib/layoutTypes.js +25 -0
  53. package/dist-lib/lib/logisticsApi.d.ts +54 -0
  54. package/dist-lib/lib/logisticsApi.d.ts.map +1 -0
  55. package/dist-lib/lib/logisticsApi.js +72 -0
  56. package/dist-lib/lib/logisticsTypes.d.ts +34 -0
  57. package/dist-lib/lib/logisticsTypes.d.ts.map +1 -0
  58. package/dist-lib/lib/logisticsTypes.js +36 -0
  59. package/dist-lib/lib/orderContext.d.ts +50 -0
  60. package/dist-lib/lib/orderContext.d.ts.map +1 -0
  61. package/dist-lib/lib/orderContext.js +162 -0
  62. package/dist-lib/lib/pakbonOrderInput.d.ts +8 -0
  63. package/dist-lib/lib/pakbonOrderInput.d.ts.map +1 -0
  64. package/dist-lib/lib/pakbonOrderInput.js +150 -0
  65. package/dist-lib/lib/pickApi.d.ts +24 -1
  66. package/dist-lib/lib/pickApi.d.ts.map +1 -1
  67. package/dist-lib/lib/pickApi.js +46 -5
  68. package/dist-lib/lib/pickI18n.d.ts +14 -0
  69. package/dist-lib/lib/pickI18n.d.ts.map +1 -0
  70. package/dist-lib/lib/pickI18n.js +500 -0
  71. package/dist-lib/lib/pickPrint.d.ts +18 -0
  72. package/dist-lib/lib/pickPrint.d.ts.map +1 -0
  73. package/dist-lib/lib/pickPrint.js +184 -0
  74. package/dist-lib/lib/pickTypes.d.ts +1 -0
  75. package/dist-lib/lib/pickTypes.d.ts.map +1 -1
  76. package/package.json +5 -20
  77. package/dist-lib/components/PickBeheerPage.d.ts +0 -2
  78. package/dist-lib/components/PickBeheerPage.d.ts.map +0 -1
  79. package/dist-lib/components/PickBeheerPage.js +0 -84
  80. package/dist-lib/components/PickDashboardPage.d.ts +0 -2
  81. package/dist-lib/components/PickDashboardPage.d.ts.map +0 -1
  82. package/dist-lib/components/PickDashboardPage.js +0 -54
  83. package/dist-lib/components/PickKioskPage.d.ts +0 -7
  84. package/dist-lib/components/PickKioskPage.d.ts.map +0 -1
  85. package/dist-lib/components/PickKioskPage.js +0 -18
  86. package/dist-lib/components/PickstationDetailPage.d.ts +0 -6
  87. package/dist-lib/components/PickstationDetailPage.d.ts.map +0 -1
  88. package/dist-lib/components/PickstationDetailPage.js +0 -25
  89. package/dist-lib/components/pick/ConfigCrud.d.ts +0 -27
  90. package/dist-lib/components/pick/ConfigCrud.d.ts.map +0 -1
  91. package/dist-lib/components/pick/ConfigCrud.js +0 -64
  92. package/dist-lib/components/pick/CountryTiles.d.ts +0 -9
  93. package/dist-lib/components/pick/CountryTiles.d.ts.map +0 -1
  94. package/dist-lib/components/pick/CountryTiles.js +0 -13
@@ -0,0 +1,23 @@
1
+ import { type LayoutLogoRow, type LayoutRef, type ResolvedLayout } from "./layoutTypes";
2
+ /** Vraagt de actieve layout voor een documentsoort op bij de Logistiek Engine. */
3
+ export declare function fetchLayoutRef(documentType: string): Promise<LayoutRef | null>;
4
+ /** Haalt de layoutrij plus elementen, variabelen en logo's op. */
5
+ export declare function fetchLayout(layoutId: string, documentType: string): Promise<ResolvedLayout>;
6
+ /**
7
+ * Bepaalt en laadt de layout voor een documentsoort. Gebruikt bij voorkeur de
8
+ * layoutId die de Engine in de wachtrijregel heeft meegegeven.
9
+ */
10
+ export declare function resolveLayout(args: {
11
+ documentType: string;
12
+ layoutId?: string | null;
13
+ }): Promise<ResolvedLayout>;
14
+ /**
15
+ * Zet de logo-records uit de layout om in de vorm die de layout-module
16
+ * verwacht: een publiek bereikbare `viewUrl` per logo.
17
+ */
18
+ export declare function logosMetViewUrl(logos: Record<string, LayoutLogoRow>): Promise<{
19
+ id: string;
20
+ naam: string;
21
+ viewUrl: string | null;
22
+ }[]>;
23
+ //# sourceMappingURL=layoutApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layoutApi.d.ts","sourceRoot":"","sources":["../../src/lib/layoutApi.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAEvB,kFAAkF;AAClF,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOpF;AAED,kEAAkE;AAClE,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAmBjG;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,OAAO,CAAC,cAAc,CAAC,CAS1B;AAID;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GACnC,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,CAAC,CAgCjE"}
@@ -0,0 +1,94 @@
1
+ // Leest documentlayouts uit de gedeelde database. De module bepaalt zelf nooit
2
+ // welke layout bij een documentsoort hoort: dat doet logistics_document_layout.
3
+ import { pickDb } from "./pickApi";
4
+ import { safeArray } from "./pickTypes";
5
+ import { MissingLayoutError, } from "./layoutTypes";
6
+ /** Vraagt de actieve layout voor een documentsoort op bij de Logistiek Engine. */
7
+ export async function fetchLayoutRef(documentType) {
8
+ const { data, error } = await pickDb.rpc("logistics_document_layout", {
9
+ _document_code: documentType,
10
+ });
11
+ if (error)
12
+ throw new Error(error.message);
13
+ const ref = data;
14
+ return ref && ref.layoutId ? ref : null;
15
+ }
16
+ /** Haalt de layoutrij plus elementen, variabelen en logo's op. */
17
+ export async function fetchLayout(layoutId, documentType) {
18
+ // Het pickscherm is openbaar. Lees daarom via de beperkte SECURITY DEFINER
19
+ // functie in plaats van rechtstreeks door de RLS van de Layout maker heen.
20
+ const { data, error } = await pickDb.rpc("pick_document_layout_data", {
21
+ _layout_id: layoutId,
22
+ });
23
+ if (error)
24
+ throw new Error(error.message);
25
+ const bundle = data && typeof data === "object" && !Array.isArray(data)
26
+ ? data
27
+ : {};
28
+ const layout = bundle["layout"];
29
+ if (!layout || layout.actief === false)
30
+ throw new MissingLayoutError(documentType);
31
+ const elements = safeArray(bundle["elements"]);
32
+ const variables = safeArray(bundle["variables"]);
33
+ const logos = {};
34
+ for (const logo of safeArray(bundle["logos"]))
35
+ logos[logo.id] = logo;
36
+ return { layout, elements, variables, logos };
37
+ }
38
+ /**
39
+ * Bepaalt en laadt de layout voor een documentsoort. Gebruikt bij voorkeur de
40
+ * layoutId die de Engine in de wachtrijregel heeft meegegeven.
41
+ */
42
+ export async function resolveLayout(args) {
43
+ const documentType = args.documentType || "pakbon";
44
+ let layoutId = args.layoutId ?? null;
45
+ if (!layoutId) {
46
+ const ref = await fetchLayoutRef(documentType);
47
+ if (!ref)
48
+ throw new MissingLayoutError(documentType);
49
+ layoutId = ref.layoutId;
50
+ }
51
+ return fetchLayout(layoutId, documentType);
52
+ }
53
+ const LOGO_BUCKET = "layout-logos";
54
+ /**
55
+ * Zet de logo-records uit de layout om in de vorm die de layout-module
56
+ * verwacht: een publiek bereikbare `viewUrl` per logo.
57
+ */
58
+ export async function logosMetViewUrl(logos) {
59
+ const rijen = Object.values(logos ?? {});
60
+ if (!rijen.length)
61
+ return [];
62
+ const storage = pickDb.storage;
63
+ const paden = rijen.map((l) => l.bestandspad ?? l.bestand_url).filter(Boolean);
64
+ const map = new Map();
65
+ if (storage && paden.length) {
66
+ try {
67
+ const { data } = await storage.from(LOGO_BUCKET).createSignedUrls(paden, 60 * 60);
68
+ for (const r of safeArray(data)) {
69
+ if (r.path && r.signedUrl)
70
+ map.set(r.path, r.signedUrl);
71
+ }
72
+ }
73
+ catch {
74
+ // geen leesrechten op ondertekende URL's: hieronder valt de publieke URL in
75
+ }
76
+ for (const pad of paden) {
77
+ if (map.has(pad))
78
+ continue;
79
+ try {
80
+ const { data } = storage.from(LOGO_BUCKET).getPublicUrl(pad);
81
+ if (data?.publicUrl)
82
+ map.set(pad, data.publicUrl);
83
+ }
84
+ catch {
85
+ // logo blijft leeg
86
+ }
87
+ }
88
+ }
89
+ return rijen.map((l) => {
90
+ const pad = l.bestandspad ?? l.bestand_url ?? "";
91
+ const url = map.get(pad) ?? (/^https?:\/\//.test(pad) ? pad : null);
92
+ return { id: l.id, naam: l.naam, viewUrl: url };
93
+ });
94
+ }
@@ -0,0 +1,50 @@
1
+ import type { PapierFormaatDef } from "./documentTypes";
2
+ export type InstellingType = "schakelaar" | "keuze" | "meerkeuze" | "tekst" | "getal" | "kleur";
3
+ export interface InstellingDef {
4
+ key: string;
5
+ label: string;
6
+ type: InstellingType;
7
+ hint?: string;
8
+ /** opties voor keuze / meerkeuze */
9
+ opties?: {
10
+ value: string;
11
+ label: string;
12
+ }[];
13
+ standaard?: unknown;
14
+ }
15
+ export interface InstellingGroep {
16
+ key: string;
17
+ label: string;
18
+ omschrijving?: string;
19
+ instellingen: InstellingDef[];
20
+ }
21
+ export interface DocumentProfiel {
22
+ /** komt overeen met document_layouts.documenttype */
23
+ id: string;
24
+ label: string;
25
+ omschrijving: string;
26
+ /** getoond in stap 1 van de wizard */
27
+ primair?: boolean;
28
+ /** formaten die bij dit documenttype horen */
29
+ formaten: PapierFormaatDef[];
30
+ standaardFormaat: string;
31
+ standaardOrientatie: "portrait" | "landscape";
32
+ /** entiteiten uit het veldregister die relevant zijn */
33
+ entiteiten: string[];
34
+ /** extra aanwijzing voor de AI-layoutimport */
35
+ aiHint: string;
36
+ /** kan per formaat een standaardprinter krijgen */
37
+ printerPerFormaat?: boolean;
38
+ groepen: InstellingGroep[];
39
+ }
40
+ export declare const STICKER_FORMATEN: PapierFormaatDef[];
41
+ export declare const VERZENDLABEL_FORMATEN: PapierFormaatDef[];
42
+ export declare const DOCUMENT_PROFIELEN: DocumentProfiel[];
43
+ export declare function documentProfiel(id: string): DocumentProfiel;
44
+ export declare function primaireProfielen(): DocumentProfiel[];
45
+ export type DocumentConfig = Record<string, Record<string, unknown>>;
46
+ /** Standaardwaarden van een profiel als opslagbaar configuratieobject. */
47
+ export declare function standaardConfig(profiel: DocumentProfiel): DocumentConfig;
48
+ /** Waarde uit de opgeslagen config, met terugval op de profielstandaard. */
49
+ export declare function configWaarde(config: DocumentConfig | null | undefined, groep: InstellingGroep, inst: InstellingDef): unknown;
50
+ //# sourceMappingURL=documentProfiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentProfiles.d.ts","sourceRoot":"","sources":["../../../src/lib/layoutMaker/documentProfiles.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,OAAO,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,UAAU,GAAG,WAAW,CAAC;IAC9C,wDAAwD;IACxD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAyBD,eAAO,MAAM,gBAAgB,EAAE,gBAAgB,EAO9C,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,EAOnD,CAAC;AA4YF,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAe/C,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,CAK3D;AAED,wBAAgB,iBAAiB,IAAI,eAAe,EAAE,CAErD;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAErE,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CAUxE;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACzC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,aAAa,GAClB,OAAO,CAIT"}
@@ -0,0 +1,458 @@
1
+ // ============================================================================
2
+ // src/lib/documentProfiles.ts — configuratieprofielen per documentsoort
3
+ //
4
+ // Een nieuw documenttype toevoegen = één profiel toevoegen aan DOCUMENT_PROFIELEN.
5
+ // De wizard, de designer en de printregels lezen dit register uit; de editor
6
+ // zelf hoeft niet te worden aangepast.
7
+ // ============================================================================
8
+ const vinkjes = (key, label, items, omschrijving) => ({
9
+ key,
10
+ label,
11
+ omschrijving,
12
+ instellingen: items.map(([k, l, aan]) => ({
13
+ key: k,
14
+ label: l,
15
+ type: "schakelaar",
16
+ standaard: !!aan,
17
+ })),
18
+ });
19
+ const A4 = { code: "A4", label: "A4 (210 × 297 mm)", breedte: 210, hoogte: 297 };
20
+ const A5 = { code: "A5", label: "A5 (148 × 210 mm)", breedte: 148, hoogte: 210 };
21
+ const A6 = { code: "A6", label: "A6 (105 × 148 mm)", breedte: 105, hoogte: 148 };
22
+ const BON80 = { code: "BON80", label: "Bon 80 mm", breedte: 80, hoogte: 200 };
23
+ const VRIJ = { code: "VRIJ", label: "Vrij formaat", breedte: 100, hoogte: 100 };
24
+ export const STICKER_FORMATEN = [
25
+ { code: "STICKER_50x30", label: "50 × 30 mm", breedte: 50, hoogte: 30 },
26
+ { code: "STICKER_70x40", label: "70 × 40 mm", breedte: 70, hoogte: 40 },
27
+ { code: "STICKER_100x50", label: "100 × 50 mm", breedte: 100, hoogte: 50 },
28
+ { code: "STICKER_100x100", label: "100 × 100 mm", breedte: 100, hoogte: 100 },
29
+ { code: "STICKER_100x150", label: "100 × 150 mm", breedte: 100, hoogte: 150 },
30
+ VRIJ,
31
+ ];
32
+ export const VERZENDLABEL_FORMATEN = [
33
+ { code: "LABEL_100x150", label: "Label 100 × 150 mm", breedte: 100, hoogte: 150 },
34
+ { code: "LABEL_100x62", label: "Label 100 × 62 mm", breedte: 100, hoogte: 62 },
35
+ A6,
36
+ A5,
37
+ A4,
38
+ VRIJ,
39
+ ];
40
+ // --- Pakbon -----------------------------------------------------------------
41
+ const pakbon = {
42
+ id: "pakbon",
43
+ label: "Pakbon",
44
+ omschrijving: "Orderregels, fusten en lagen voor de expeditie.",
45
+ primair: true,
46
+ formaten: [A4, A5, BON80, VRIJ],
47
+ standaardFormaat: "A4",
48
+ standaardOrientatie: "portrait",
49
+ entiteiten: ["order", "klant", "regel", "bedrijf", "systeem"],
50
+ aiHint: "Dit is een pakbon: herken orderkop, adresblok, regeltabel met aantallen en totalen.",
51
+ groepen: [
52
+ {
53
+ key: "structuur",
54
+ label: "Structuur van de pakbon",
55
+ omschrijving: "Hoe wordt de pakbon samengesteld?",
56
+ instellingen: [
57
+ {
58
+ key: "splitsing",
59
+ label: "Pakbon aanmaken",
60
+ type: "keuze",
61
+ standaard: "per_order",
62
+ opties: [
63
+ { value: "per_order", label: "Eén pakbon per order" },
64
+ { value: "per_kar", label: "Eén pakbon per kar" },
65
+ { value: "order_en_kar", label: "Zowel per order als per kar" },
66
+ { value: "per_klant", label: "Eén pakbon per klant" },
67
+ { value: "per_afleveradres", label: "Eén pakbon per afleveradres" },
68
+ { value: "per_route", label: "Eén pakbon per route" },
69
+ { value: "per_transporteur", label: "Eén pakbon per transporteur" },
70
+ ],
71
+ },
72
+ {
73
+ key: "groepering",
74
+ label: "Artikelen groeperen",
75
+ type: "keuze",
76
+ standaard: "per_order",
77
+ opties: [
78
+ { value: "per_order", label: "Per order" },
79
+ { value: "per_klant", label: "Per klant" },
80
+ { value: "per_kar", label: "Per kar" },
81
+ { value: "per_locatie", label: "Per locatie" },
82
+ { value: "per_afleveradres", label: "Per afleveradres" },
83
+ { value: "per_productgroep", label: "Per productgroep" },
84
+ { value: "geen", label: "Niet groeperen" },
85
+ ],
86
+ },
87
+ {
88
+ key: "fustweergave",
89
+ label: "Weergave fusten en lagen",
90
+ type: "keuze",
91
+ standaard: "totaal",
92
+ opties: [
93
+ { value: "verbergen", label: "Fusten volledig verbergen" },
94
+ { value: "totaal", label: "Alleen totaal aantal fusten" },
95
+ { value: "per_laag", label: "Fusten per laag tonen" },
96
+ { value: "gegroepeerd", label: "Fusten gegroepeerd tonen" },
97
+ { value: "laag_apart", label: "Iedere laag apart tonen" },
98
+ { value: "lege_fusten", label: "Ook lege fusten tonen" },
99
+ { value: "belading", label: "Alleen belading tonen" },
100
+ { value: "belading_potmaat", label: "Belading inclusief potmaat" },
101
+ ],
102
+ },
103
+ ],
104
+ },
105
+ vinkjes("product", "Productinformatie", [
106
+ ["artikelnummer", "Artikelnummer", true],
107
+ ["artikelnaam", "Artikelnaam", true],
108
+ ["aantal", "Aantal", true],
109
+ ["potmaat", "Potmaat"],
110
+ ["hoogte", "Hoogte"],
111
+ ["belading", "Belading"],
112
+ ["laagnummer", "Laagnummer"],
113
+ ["barcode", "Barcode"],
114
+ ["qrcode", "QR-code"],
115
+ ["kleur", "Kleur"],
116
+ ["productgroep", "Productgroep"],
117
+ ["productomschrijving", "Productomschrijving"],
118
+ ["interne_opmerking", "Interne opmerking"],
119
+ ["klantopmerking", "Klantopmerking"],
120
+ ["productfoto", "Productfoto"],
121
+ ["leverancierscode", "Productcode leverancier"],
122
+ ]),
123
+ vinkjes("order", "Orderinformatie", [
124
+ ["ordernummer", "Ordernummer", true],
125
+ ["orderdatum", "Orderdatum", true],
126
+ ["leverdatum", "Leverdatum", true],
127
+ ["aflevermoment", "Aflevermoment"],
128
+ ["klantnummer", "Klantnummer"],
129
+ ["klantnaam", "Klantnaam", true],
130
+ ["contactpersoon", "Contactpersoon"],
131
+ ["telefoon", "Telefoonnummer"],
132
+ ["email", "E-mailadres"],
133
+ ["referentie", "Referentie"],
134
+ ["transporteur", "Transporteur"],
135
+ ["chauffeur", "Chauffeur"],
136
+ ["route", "Route"],
137
+ ["pickstation", "Pickstation"],
138
+ ["magazijn", "Magazijn"],
139
+ ["orderstatus", "Orderstatus"],
140
+ ]),
141
+ vinkjes("totalen", "Totalen", [
142
+ ["totaal_producten", "Totaal aantal producten", true],
143
+ ["totaal_lagen", "Totaal aantal lagen"],
144
+ ["totaal_fusten", "Totaal aantal fusten"],
145
+ ["totaal_karren", "Totaal aantal karren"],
146
+ ["gewicht", "Gewicht"],
147
+ ["volume", "Volume"],
148
+ ]),
149
+ vinkjes("overig", "Overige instellingen", [
150
+ ["logo", "Logo tonen", true],
151
+ ["handtekening", "Handtekeningvak"],
152
+ ["order_qr", "QR-code voor order"],
153
+ ["order_barcode", "Barcode ordernummer"],
154
+ ["watermerk", "Watermerk"],
155
+ ["eigen_tekst", "Eigen tekst onderaan"],
156
+ ["voorwaarden", "Algemene voorwaarden"],
157
+ ["extra_opmerkingen", "Extra opmerkingen"],
158
+ ]),
159
+ ],
160
+ };
161
+ // --- Sticker ----------------------------------------------------------------
162
+ const sticker = {
163
+ id: "sticker",
164
+ label: "Sticker",
165
+ omschrijving: "Compacte sticker met de gekozen bestelafbeelding.",
166
+ primair: true,
167
+ formaten: STICKER_FORMATEN,
168
+ standaardFormaat: "STICKER_100x150",
169
+ standaardOrientatie: "portrait",
170
+ entiteiten: ["regel", "order", "klant", "bedrijf", "systeem"],
171
+ aiHint: "Dit is een sticker: herken vooral de afbeelding, artikelnaam en barcode.",
172
+ printerPerFormaat: true,
173
+ groepen: [
174
+ {
175
+ key: "klantlayout",
176
+ label: "Layout van de klant",
177
+ omschrijving: "Veel klanten leveren zelf een stickerontwerp aan. Zet dit aan om dat ontwerp altijd te gebruiken.",
178
+ instellingen: [
179
+ {
180
+ key: "gebruik_klantlayout",
181
+ label: "Kies altijd de layout van de klant",
182
+ type: "schakelaar",
183
+ standaard: false,
184
+ hint: "Is er geen klantlayout bekend? Dan wordt deze layout gebruikt.",
185
+ },
186
+ {
187
+ key: "terugval",
188
+ label: "Als de klant geen layout heeft",
189
+ type: "keuze",
190
+ standaard: "deze_layout",
191
+ opties: [
192
+ { value: "deze_layout", label: "Deze layout gebruiken" },
193
+ { value: "niet_printen", label: "Niet afdrukken en melden" },
194
+ ],
195
+ },
196
+ ],
197
+ },
198
+ {
199
+ key: "afbeelding",
200
+ label: "Afbeelding",
201
+ omschrijving: "Standaard wordt alleen de gekozen afbeelding van de bestelling afgedrukt.",
202
+ instellingen: [
203
+ { key: "toon_afbeelding", label: "Afbeelding tonen", type: "schakelaar", standaard: true },
204
+ {
205
+ key: "schaling",
206
+ label: "Schalen",
207
+ type: "keuze",
208
+ standaard: "passend",
209
+ opties: [
210
+ { value: "passend", label: "Passend binnen sticker" },
211
+ { value: "vullend", label: "Sticker volledig vullen (bijsnijden)" },
212
+ { value: "breedte", label: "Op breedte schalen" },
213
+ { value: "hoogte", label: "Op hoogte schalen" },
214
+ ],
215
+ },
216
+ ],
217
+ },
218
+ vinkjes("extra", "Optionele gegevens", [
219
+ ["artikelnaam", "Artikelnaam"],
220
+ ["artikelcode", "Artikelcode"],
221
+ ["barcode", "Barcode"],
222
+ ["qrcode", "QR-code"],
223
+ ["aantal", "Aantal"],
224
+ ["potmaat", "Potmaat"],
225
+ ["productgroep", "Productgroep"],
226
+ ["klantnaam", "Klantnaam"],
227
+ ["productomschrijving", "Productomschrijving"],
228
+ ], "Alles wat je aanzet komt onder de afbeelding te staan."),
229
+ ],
230
+ };
231
+ // --- Verzendlabel -----------------------------------------------------------
232
+ const verzendlabel = {
233
+ id: "verzendlabel",
234
+ label: "Verzendlabel",
235
+ omschrijving: "Afzender, ontvanger, transport en waarschuwingspictogrammen.",
236
+ primair: true,
237
+ formaten: VERZENDLABEL_FORMATEN,
238
+ standaardFormaat: "LABEL_100x150",
239
+ standaardOrientatie: "portrait",
240
+ entiteiten: ["order", "klant", "bedrijf", "systeem"],
241
+ aiHint: "Dit is een verzendlabel: herken afzender, ontvanger, barcode en track & trace.",
242
+ printerPerFormaat: true,
243
+ groepen: [
244
+ vinkjes("afzender", "Afzender", [
245
+ ["bedrijfsnaam", "Bedrijfsnaam", true],
246
+ ["logo", "Logo", true],
247
+ ["adres", "Adres", true],
248
+ ["telefoon", "Telefoon"],
249
+ ["email", "E-mail"],
250
+ ]),
251
+ vinkjes("ontvanger", "Ontvanger", [
252
+ ["naam", "Naam", true],
253
+ ["bedrijf", "Bedrijf", true],
254
+ ["straat", "Straat", true],
255
+ ["huisnummer", "Huisnummer", true],
256
+ ["postcode", "Postcode", true],
257
+ ["plaats", "Plaats", true],
258
+ ["land", "Land", true],
259
+ ]),
260
+ vinkjes("verzending", "Verzending", [
261
+ ["transporteur", "Transporteur", true],
262
+ ["verzendmethode", "Verzendmethode"],
263
+ ["route", "Route"],
264
+ ["track_trace", "Track & Trace", true],
265
+ ["ordernummer", "Ordernummer", true],
266
+ ["referentie", "Referentie"],
267
+ ["gewicht", "Gewicht"],
268
+ ["colli", "Aantal colli"],
269
+ ["barcode", "Barcode", true],
270
+ ["qrcode", "QR-code"],
271
+ ]),
272
+ vinkjes("extra", "Extra markeringen", [
273
+ ["fragile", "Fragile-logo"],
274
+ ["niet_stapelen", "Niet stapelen"],
275
+ ["koel", "Koel bewaren"],
276
+ ["adr", "ADR-markeringen"],
277
+ ["eigen_pictogrammen", "Eigen pictogrammen"],
278
+ ["vrije_tekst", "Vrije tekst"],
279
+ ]),
280
+ ],
281
+ };
282
+ // --- Productiebon -----------------------------------------------------------
283
+ const productiebon = {
284
+ id: "productiebon",
285
+ label: "Productiebon",
286
+ omschrijving: "Werkinstructie met materialen en productiestappen.",
287
+ primair: true,
288
+ formaten: [A4, A5, VRIJ],
289
+ standaardFormaat: "A4",
290
+ standaardOrientatie: "portrait",
291
+ entiteiten: ["regel", "order", "bedrijf", "systeem"],
292
+ aiHint: "Dit is een productiebon: herken productfoto, materialenlijst en stappenlijst.",
293
+ groepen: [
294
+ vinkjes("product", "Productinformatie", [
295
+ ["grote_foto", "Grote productfoto", true],
296
+ ["meerdere_fotos", "Meerdere productfoto's"],
297
+ ["artikelnummer", "Artikelnummer", true],
298
+ ["artikelnaam", "Artikelnaam", true],
299
+ ["productomschrijving", "Productomschrijving"],
300
+ ["variant", "Variant"],
301
+ ["potmaat", "Potmaat"],
302
+ ["afmetingen", "Afmetingen"],
303
+ ]),
304
+ {
305
+ key: "materialen",
306
+ label: "Productiematerialen",
307
+ omschrijving: "Welke materiaalsoorten en welke kolommen komen op de bon?",
308
+ instellingen: [
309
+ {
310
+ key: "soorten",
311
+ label: "Materiaalsoorten",
312
+ type: "meerkeuze",
313
+ standaard: ["plant", "pot", "tray", "kar", "sticker"],
314
+ opties: [
315
+ { value: "plant", label: "Plant" },
316
+ { value: "pot", label: "Pot" },
317
+ { value: "tray", label: "Tray" },
318
+ { value: "kar", label: "Kar" },
319
+ { value: "sticker", label: "Sticker" },
320
+ { value: "label", label: "Label" },
321
+ { value: "verpakking", label: "Verpakking" },
322
+ { value: "hoes", label: "Hoes" },
323
+ { value: "decoratie", label: "Decoratie" },
324
+ { value: "meststoffen", label: "Meststoffen" },
325
+ { value: "overig", label: "Overige materialen" },
326
+ ],
327
+ },
328
+ {
329
+ key: "kolommen",
330
+ label: "Kolommen per materiaal",
331
+ type: "meerkeuze",
332
+ standaard: ["artikelnummer", "naam", "aantal", "eenheid"],
333
+ opties: [
334
+ { value: "artikelnummer", label: "Artikelnummer" },
335
+ { value: "naam", label: "Naam" },
336
+ { value: "aantal", label: "Aantal" },
337
+ { value: "eenheid", label: "Eenheid" },
338
+ { value: "magazijnlocatie", label: "Magazijnlocatie" },
339
+ { value: "barcode", label: "Barcode" },
340
+ ],
341
+ },
342
+ ],
343
+ },
344
+ {
345
+ key: "stappen",
346
+ label: "Productiestappen",
347
+ omschrijving: "Volgorde en detail van de werkinstructie.",
348
+ instellingen: [
349
+ {
350
+ key: "stappen",
351
+ label: "Stappen",
352
+ type: "meerkeuze",
353
+ standaard: ["verzamelen", "pot", "sticker", "controleren", "verpakken", "kar"],
354
+ opties: [
355
+ { value: "verzamelen", label: "Product verzamelen" },
356
+ { value: "pot", label: "Pot toevoegen" },
357
+ { value: "sticker", label: "Sticker plaatsen" },
358
+ { value: "controleren", label: "Product controleren" },
359
+ { value: "verpakken", label: "Verpakken" },
360
+ { value: "kar", label: "Op kar plaatsen" },
361
+ ],
362
+ },
363
+ {
364
+ key: "stapdetails",
365
+ label: "Per stap tonen",
366
+ type: "meerkeuze",
367
+ standaard: ["omschrijving"],
368
+ opties: [
369
+ { value: "omschrijving", label: "Omschrijving" },
370
+ { value: "afbeelding", label: "Afbeelding" },
371
+ { value: "controlepunten", label: "Controlepunten" },
372
+ { value: "tijd", label: "Benodigde tijd" },
373
+ { value: "medewerker", label: "Benodigde medewerker" },
374
+ { value: "gereedschap", label: "Benodigd gereedschap" },
375
+ ],
376
+ },
377
+ ],
378
+ },
379
+ vinkjes("extra", "Extra informatie", [
380
+ ["werkinstructies", "Werkinstructies"],
381
+ ["veiligheid", "Veiligheidsinstructies"],
382
+ ["controlelijst", "Controlelijst"],
383
+ ["interne_opmerkingen", "Interne opmerkingen"],
384
+ ["klantinstructies", "Klantspecifieke instructies"],
385
+ ["productfotos", "Productfoto's"],
386
+ ["explosietekening", "Explosietekening"],
387
+ ["qr_handleiding", "QR-code naar handleiding"],
388
+ ["qr_video", "QR-code naar instructievideo"],
389
+ ]),
390
+ ],
391
+ };
392
+ // --- Generiek profiel voor overige documentsoorten --------------------------
393
+ function generiek(id, label, omschrijving) {
394
+ return {
395
+ id,
396
+ label,
397
+ omschrijving,
398
+ formaten: [A4, A5, A6, BON80, VRIJ],
399
+ standaardFormaat: "A4",
400
+ standaardOrientatie: "portrait",
401
+ entiteiten: ["order", "klant", "regel", "factuur", "bedrijf", "systeem"],
402
+ aiHint: `Dit is een ${label.toLowerCase()}.`,
403
+ groepen: [
404
+ vinkjes("overig", "Onderdelen", [
405
+ ["logo", "Logo tonen", true],
406
+ ["adresblok", "Adresblok", true],
407
+ ["regeltabel", "Regeltabel", true],
408
+ ["totalen", "Totalen", true],
409
+ ["voettekst", "Voettekst"],
410
+ ["barcode", "Barcode"],
411
+ ["qrcode", "QR-code"],
412
+ ["handtekening", "Handtekeningvak"],
413
+ ]),
414
+ ],
415
+ };
416
+ }
417
+ export const DOCUMENT_PROFIELEN = [
418
+ pakbon,
419
+ sticker,
420
+ verzendlabel,
421
+ productiebon,
422
+ generiek("factuur", "Factuur", "Facturatie met btw en totalen."),
423
+ generiek("offerte", "Offerte", "Aanbieding met regels en voorwaarden."),
424
+ generiek("orderbevestiging", "Orderbevestiging", "Bevestiging van een geplaatste order."),
425
+ generiek("etiket", "Etiket", "Klein etiket voor product of fust."),
426
+ generiek("productlabel", "Productlabel", "Label met productgegevens."),
427
+ generiek("barcode_label", "Barcode label", "Label met uitsluitend codes."),
428
+ generiek("magazijnlijst", "Magazijnlijst", "Verzamellijst voor het magazijn."),
429
+ generiek("controlelijst", "Controlelijst", "Afvinklijst voor controle."),
430
+ generiek("transportdocument", "Transportdocument", "Document voor de rit."),
431
+ generiek("vrij", "Vrij document", "Lege layout zonder vooraf ingestelde onderdelen."),
432
+ ];
433
+ export function documentProfiel(id) {
434
+ return (DOCUMENT_PROFIELEN.find((p) => p.id === id) ??
435
+ generiek(id, id, "Documentsoort zonder eigen profiel."));
436
+ }
437
+ export function primaireProfielen() {
438
+ return DOCUMENT_PROFIELEN.filter((p) => p.primair);
439
+ }
440
+ /** Standaardwaarden van een profiel als opslagbaar configuratieobject. */
441
+ export function standaardConfig(profiel) {
442
+ const config = {};
443
+ for (const groep of profiel.groepen) {
444
+ config[groep.key] = {};
445
+ for (const inst of groep.instellingen) {
446
+ config[groep.key][inst.key] =
447
+ inst.standaard ?? (inst.type === "meerkeuze" ? [] : inst.type === "schakelaar" ? false : "");
448
+ }
449
+ }
450
+ return config;
451
+ }
452
+ /** Waarde uit de opgeslagen config, met terugval op de profielstandaard. */
453
+ export function configWaarde(config, groep, inst) {
454
+ const g = config?.[groep.key];
455
+ if (g && Object.prototype.hasOwnProperty.call(g, inst.key))
456
+ return g[inst.key];
457
+ return inst.standaard ?? (inst.type === "meerkeuze" ? [] : inst.type === "schakelaar" ? false : "");
458
+ }