@flowselections/layout-maker 1.31.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.
Files changed (75) hide show
  1. package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
  2. package/dist-lib/components/ComputersLijst.js +5 -5
  3. package/dist-lib/components/DocumentenPage.d.ts.map +1 -1
  4. package/dist-lib/components/DocumentenPage.js +3 -2
  5. package/dist-lib/components/LayoutPrinterSelect.d.ts +8 -0
  6. package/dist-lib/components/LayoutPrinterSelect.d.ts.map +1 -0
  7. package/dist-lib/components/LayoutPrinterSelect.js +23 -0
  8. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  9. package/dist-lib/components/LayoutsPage.js +16 -3
  10. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  11. package/dist-lib/components/PakbonBuilderPage.js +3 -1
  12. package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
  13. package/dist-lib/components/PakbonSectiesPanel.js +6 -2
  14. package/dist-lib/components/PdfMapAutoSaver.d.ts +6 -0
  15. package/dist-lib/components/PdfMapAutoSaver.d.ts.map +1 -0
  16. package/dist-lib/components/PdfMapAutoSaver.js +12 -0
  17. package/dist-lib/components/PdfMapGlobaleBanner.d.ts +12 -0
  18. package/dist-lib/components/PdfMapGlobaleBanner.d.ts.map +1 -0
  19. package/dist-lib/components/PdfMapGlobaleBanner.js +30 -0
  20. package/dist-lib/components/PdfMapToestemmingBanner.d.ts +7 -0
  21. package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -0
  22. package/dist-lib/components/PdfMapToestemmingBanner.js +139 -0
  23. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  24. package/dist-lib/components/PrintQueuePage.js +42 -3
  25. package/dist-lib/components/PrintenPage.d.ts.map +1 -1
  26. package/dist-lib/components/PrintenPage.js +3 -2
  27. package/dist-lib/components/PrinterSetupWizard.d.ts.map +1 -1
  28. package/dist-lib/components/PrinterSetupWizard.js +25 -2
  29. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  30. package/dist-lib/components/PrintplekDetailPage.js +30 -4
  31. package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
  32. package/dist-lib/components/PrintplekWizard.js +81 -3
  33. package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
  34. package/dist-lib/components/ProductiebonBuilderPage.js +3 -1
  35. package/dist-lib/index.d.ts +6 -0
  36. package/dist-lib/index.d.ts.map +1 -1
  37. package/dist-lib/index.js +11 -1
  38. package/dist-lib/integrations/supabase/auth-middleware.d.ts +293 -8
  39. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  40. package/dist-lib/integrations/supabase/client.server.d.ts +293 -8
  41. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  42. package/dist-lib/integrations/supabase/types.d.ts +295 -8
  43. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  44. package/dist-lib/lib/aiLayout.functions.d.ts +293 -8
  45. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  46. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  47. package/dist-lib/lib/htmlPdf.server.js +43 -6
  48. package/dist-lib/lib/orderData.server.d.ts.map +1 -1
  49. package/dist-lib/lib/orderData.server.js +117 -10
  50. package/dist-lib/lib/pdfJobSaver.d.ts +20 -0
  51. package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -0
  52. package/dist-lib/lib/pdfJobSaver.js +173 -0
  53. package/dist-lib/lib/pdfMap.d.ts +48 -0
  54. package/dist-lib/lib/pdfMap.d.ts.map +1 -0
  55. package/dist-lib/lib/pdfMap.js +219 -0
  56. package/dist-lib/lib/pdfPrinter.d.ts +9 -0
  57. package/dist-lib/lib/pdfPrinter.d.ts.map +1 -0
  58. package/dist-lib/lib/pdfPrinter.js +34 -0
  59. package/dist-lib/lib/previewPdf.d.ts +10 -0
  60. package/dist-lib/lib/previewPdf.d.ts.map +1 -0
  61. package/dist-lib/lib/previewPdf.js +202 -0
  62. package/dist-lib/lib/printApi.d.ts.map +1 -1
  63. package/dist-lib/lib/printApi.js +9 -1
  64. package/dist-lib/lib/printQueue.server.d.ts +14 -1
  65. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  66. package/dist-lib/lib/printQueue.server.js +125 -27
  67. package/dist-lib/lib/printService.functions.d.ts +1172 -32
  68. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  69. package/dist-lib/lib/useDocumentData.d.ts +10 -0
  70. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  71. package/dist-lib/lib/useDocumentData.js +19 -0
  72. package/dist-lib/lib/voorbeeldPrint.d.ts +4 -0
  73. package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
  74. package/dist-lib/lib/voorbeeldPrint.js +13 -2
  75. package/package.json +14 -2
@@ -41,7 +41,7 @@ async function log(db, jobId, gebeurtenis, detail) {
41
41
  });
42
42
  }
43
43
  /** Fout waarbij opnieuw proberen zinloos is (er valt niets te printen). */
44
- class GeenDocumentFout extends Error {
44
+ export class GeenDocumentFout extends Error {
45
45
  constructor() {
46
46
  super(...arguments);
47
47
  this.name = "GeenDocumentFout";
@@ -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
- const documentLogo = config?.logo?.logoId;
422
- if (documentLogo)
423
- ids.add(String(documentLogo));
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
- if (!printer?.extern_printer_id) {
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
- const liggend = String(layout?.orientatie ?? "portrait") === "landscape";
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 breedteMm = Number(layout?.breedte_mm ?? standaardMaat(printer).breedte);
693
- const hoogteMm = Number(layout?.hoogte_mm ?? standaardMaat(printer).hoogte);
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
- const { data, error } = await db.rpc("claim_cloud_print_jobs", { _max: max });
848
- if (error)
849
- throw new Error(error.message);
850
- const jobs = arr(data);
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) {
@@ -864,3 +937,28 @@ export async function verwerkWachtrij(db, max = 5) {
864
937
  bijgewerkt: await synchroniseerStatussen(db),
865
938
  };
866
939
  }
940
+ /**
941
+ * Dezelfde documentkeuze als de printwachtrij maakt, maar zonder printer en
942
+ * zonder statuswijziging. Gebruikt door het voorbeeld (`preview-pdf`) zodat
943
+ * het voorbeeld exact toont wat er straks uit de printer komt.
944
+ */
945
+ export async function bepaalDocumentKeuze(db, job) {
946
+ let bron = await zoekBronregel(db, job);
947
+ if (await isFloridayLayoutKeuze(db, job)) {
948
+ bron = "extern_pdf";
949
+ job.layout_id = null;
950
+ }
951
+ if (bron === "eigen_layout") {
952
+ job.pdf_base64 = null;
953
+ job.pdf_url = null;
954
+ }
955
+ const klaar = await kantEnKlarePdf(db, job);
956
+ if (!klaar && bron === "extern_pdf") {
957
+ throw new GeenDocumentFout("Voor dit document is ingesteld dat het aangeleverde document wordt " +
958
+ "gebruikt, maar er is geen PDF meegestuurd.");
959
+ }
960
+ const keuze = klaar
961
+ ? { layout: null, ontwerpWint: false }
962
+ : await zoekLayout(db, job);
963
+ return { keuze, klaarPdf: klaar };
964
+ }