@flowselections/logistiek-engine 1.0.133 → 1.0.135

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.
@@ -1 +1 @@
1
- {"version":3,"file":"controlScan.server.d.ts","sourceRoot":"","sources":["../../src/lib/controlScan.server.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAiBD,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,mDAAmD;AACnD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAgBzC,mDAAmD;AACnD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC1F,GAAG,GAAE,MAAmB,GACvB,UAAU,GAAG,MAAM,GAAG,IAAI,CAK5B;AA6BD,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,cAAc,CAAC,CAsOzB"}
1
+ {"version":3,"file":"controlScan.server.d.ts","sourceRoot":"","sources":["../../src/lib/controlScan.server.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAiBD,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,mDAAmD;AACnD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAgBzC,mDAAmD;AACnD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC1F,GAAG,GAAE,MAAmB,GACvB,UAAU,GAAG,MAAM,GAAG,IAAI,CAK5B;AA6BD,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,cAAc,CAAC,CAqQzB"}
@@ -14,7 +14,7 @@
14
14
  // en dubbele scans worden al in de database geblokkeerd. Geen omgevings- of
15
15
  // klantwaarden in deze code; de printer komt uit de werkwijze in de database.
16
16
  // ============================================================================
17
- import { printViaLayout } from "./layoutPrint.server.js";
17
+ import { printViaLayout, floridayLayout } from "./layoutPrint.server.js";
18
18
  import { isFloridayCancelled, FLORIDAY_CANCELLED_REASON } from "./floridayCancellation.server.js";
19
19
  import { trace } from "./trace.server.js";
20
20
  /** Maximaal aantal wachtrondes op Floriday voordat de controle als mislukt stopt. */
@@ -224,9 +224,24 @@ export async function runControlScanQueue(sb, options = {}) {
224
224
  run.failed++;
225
225
  continue;
226
226
  }
227
+ // Layout op id: de actieve Floriday-afleverbrief (bij meerdere de standaard).
228
+ const layout = await floridayLayout(sb, "afleverbrief");
229
+ if (!layout.layoutId) {
230
+ await sb.rpc("logistics_control_scan_finish", {
231
+ _id: row.id,
232
+ _ok: false,
233
+ _status: "mislukt",
234
+ _fulfillment_order_id: fulfillmentOrderId,
235
+ _error_code: "geen_floriday_layout",
236
+ _error: `${layout.reden} Druk daarna op "Opnieuw proberen".`,
237
+ });
238
+ run.failed++;
239
+ continue;
240
+ }
227
241
  // Via de Layout maker; idempotent per controle.
228
242
  const printed = await printViaLayout(sb, {
229
243
  documenttype: "afleverbrief",
244
+ layoutId: layout.layoutId,
230
245
  documentnaam: `Afleverbrief ${row.order_number}`,
231
246
  pdfBase64: base64,
232
247
  pdfUrl: url,
@@ -235,6 +250,8 @@ export async function runControlScanQueue(sb, options = {}) {
235
250
  idempotentieSleutel: `controle-scan:${row.id}`,
236
251
  payload: {
237
252
  source: "controle_scan",
253
+ documenttype: "afleverbrief",
254
+ layout_id: layout.layoutId,
238
255
  is_floriday: true,
239
256
  order_id: row.order_id,
240
257
  ordernummer: row.order_number,
@@ -244,6 +261,19 @@ export async function runControlScanQueue(sb, options = {}) {
244
261
  control_scan_id: row.id,
245
262
  },
246
263
  });
264
+ if (!printed.ok && printed.errorCode === "DUBBEL_ORIGINEEL") {
265
+ // Er staat al een origineel klaar: bestaande opdracht vastleggen, niet opnieuw.
266
+ await sb.rpc("logistics_control_scan_finish", {
267
+ _id: row.id,
268
+ _ok: true,
269
+ _status: "geprint",
270
+ _print_job_id: printed.bestaandJobId ?? null,
271
+ _document_url: url,
272
+ _fulfillment_order_id: fulfillmentOrderId,
273
+ });
274
+ run.printed++;
275
+ continue;
276
+ }
247
277
  if (!printed.ok) {
248
278
  await sb.rpc("logistics_control_scan_finish", {
249
279
  _id: row.id,
@@ -21,7 +21,18 @@ export type LayoutPrintResult = {
21
21
  ok: false;
22
22
  errorCode: string;
23
23
  error: string;
24
+ bestaandJobId?: string | null;
24
25
  };
26
+ /** Haalt het bestaande opdracht-id uit een DUBBEL_ORIGINEEL-antwoord (details, hint of tekst). */
27
+ export declare function bestaandOpdrachtId(...bronnen: unknown[]): string | null;
28
+ /**
29
+ * Zoekt de actieve Floriday-layout voor een documentsoort op id (bij meerdere:
30
+ * de standaard). Geeft null + leesbare reden als er geen eenduidige layout is.
31
+ */
32
+ export declare function floridayLayout(sb: SupabaseClient, documenttype: string): Promise<{
33
+ layoutId: string | null;
34
+ reden: string | null;
35
+ }>;
25
36
  export declare function foutcode(message: string): string;
26
37
  export declare function printViaLayout(sb: SupabaseClient, input: LayoutPrintInput): Promise<LayoutPrintResult>;
27
38
  //# sourceMappingURL=layoutPrint.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layoutPrint.server.d.ts","sourceRoot":"","sources":["../../src/lib/layoutPrint.server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oHAAoH;IACpH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACxE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAKpD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAkC5B"}
1
+ {"version":3,"file":"layoutPrint.server.d.ts","sourceRoot":"","sources":["../../src/lib/layoutPrint.server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oHAAoH;IACpH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACxE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAInF,kGAAkG;AAClG,wBAAgB,kBAAkB,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,IAAI,CAuBvE;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,cAAc,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAQ5D;AAKD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAqD5B"}
@@ -6,6 +6,51 @@
6
6
  // standaardregels). Fouten (GEEN_PRINTER, GEEN_LAYOUT, GEEN_EXTERN_DOCUMENT)
7
7
  // komen als leesbare fout terug; er is geen stille terugval.
8
8
  // ============================================================================
9
+ const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
10
+ /** Haalt het bestaande opdracht-id uit een DUBBEL_ORIGINEEL-antwoord (details, hint of tekst). */
11
+ export function bestaandOpdrachtId(...bronnen) {
12
+ for (const b of bronnen) {
13
+ if (!b)
14
+ continue;
15
+ if (typeof b === "object") {
16
+ const o = b;
17
+ for (const k of ["bestaande_job_id", "bestaand_job_id", "job_id", "opdracht_id", "existing_job_id"]) {
18
+ const v = o[k];
19
+ if (typeof v === "string" && UUID_RE.test(v))
20
+ return v.match(UUID_RE)[0];
21
+ }
22
+ continue;
23
+ }
24
+ const t = String(b);
25
+ try {
26
+ const j = JSON.parse(t);
27
+ const id = bestaandOpdrachtId(j);
28
+ if (id)
29
+ return id;
30
+ }
31
+ catch {
32
+ /* geen JSON */
33
+ }
34
+ const m = t.match(UUID_RE);
35
+ if (m)
36
+ return m[0];
37
+ }
38
+ return null;
39
+ }
40
+ /**
41
+ * Zoekt de actieve Floriday-layout voor een documentsoort op id (bij meerdere:
42
+ * de standaard). Geeft null + leesbare reden als er geen eenduidige layout is.
43
+ */
44
+ export async function floridayLayout(sb, documenttype) {
45
+ const { data, error } = await sb.rpc("logistics_floriday_layout_id", {
46
+ p_documenttype: documenttype,
47
+ });
48
+ if (error)
49
+ return { layoutId: null, reden: `De Floriday-layout kon niet worden opgezocht: ${error.message}` };
50
+ const r = (data ?? {});
51
+ const id = typeof r["layout_id"] === "string" ? r["layout_id"] : null;
52
+ return { layoutId: id, reden: id ? null : String(r["reden"] ?? "Geen actieve Floriday-layout gevonden.") };
53
+ }
9
54
  const HINT = ' Los dit op bij Layouts en printers en druk daarna op "Opnieuw proberen"; opnieuw scannen is niet nodig.';
10
55
  export function foutcode(message) {
11
56
  const m = /^([A-Z_]+):/.exec(message.trim());
@@ -27,10 +72,29 @@ export async function printViaLayout(sb, input) {
27
72
  _idempotentie_sleutel: input.idempotentieSleutel,
28
73
  });
29
74
  if (error) {
30
- return { ok: false, errorCode: foutcode(error.message), error: `${error.message}${HINT}` };
75
+ const code = foutcode(error.message);
76
+ if (code === "DUBBEL_ORIGINEEL") {
77
+ const e = error;
78
+ return {
79
+ ok: false,
80
+ errorCode: code,
81
+ error: error.message,
82
+ bestaandJobId: bestaandOpdrachtId(e["details"], e["hint"], error.message),
83
+ };
84
+ }
85
+ return { ok: false, errorCode: code, error: `${error.message}${HINT}` };
31
86
  }
32
87
  const rows = Array.isArray(data) ? data : data ? [data] : [];
33
88
  const row = (rows[0] ?? null);
89
+ const rowCode = String(row?.["foutcode"] ?? row?.["code"] ?? row?.["status"] ?? "");
90
+ if (rowCode === "DUBBEL_ORIGINEEL") {
91
+ return {
92
+ ok: false,
93
+ errorCode: "DUBBEL_ORIGINEEL",
94
+ error: "Er staat al een origineel klaar voor deze kar en documentsoort.",
95
+ bestaandJobId: bestaandOpdrachtId(row),
96
+ };
97
+ }
34
98
  const jobId = row ? String(row["job_id"] ?? "") : "";
35
99
  if (!jobId) {
36
100
  return {
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.133";
1
+ export declare const MODULE_VERSION = "1.0.135";
2
2
  //# sourceMappingURL=moduleVersion.d.ts.map
@@ -1,2 +1,2 @@
1
1
  // Automatisch gegenereerd door prebuild:lib; niet handmatig aanpassen.
2
- export const MODULE_VERSION = "1.0.133";
2
+ export const MODULE_VERSION = "1.0.135";
@@ -1 +1 @@
1
- {"version":3,"file":"shippingNoteQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/shippingNoteQueue.server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAO5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAoCD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CA4a1B;AAMD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;AAElE,qGAAqG;AACrG,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAQ9F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAG5E;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,mBAAmB,GAAG,MAAM,CAI3E"}
1
+ {"version":3,"file":"shippingNoteQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/shippingNoteQueue.server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAO5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAoCD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CAud1B;AAMD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;AAElE,qGAAqG;AACrG,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAQ9F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAG5E;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,mBAAmB,GAAG,MAAM,CAI3E"}
@@ -13,7 +13,7 @@
13
13
  // ============================================================================
14
14
  import { trace, newTraceId, classifyError } from "./trace.server.js";
15
15
  import { FLOW_NODE } from "./flowNodes.js";
16
- import { printViaLayout } from "./layoutPrint.server.js";
16
+ import { printViaLayout, floridayLayout } from "./layoutPrint.server.js";
17
17
  import { SHIPPING_NOTE_DEFINITIEVE_FOUTEN, definitieveFout, parseMaxAttempts } from "./shippingNoteStates.js";
18
18
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19
19
  function pickPdf(result) {
@@ -48,6 +48,8 @@ export async function runShippingNoteQueue(sb, options = {}) {
48
48
  run.errors.push("De instelling logistics_shipping_note_max_attempts ontbreekt of is ongeldig (1-200); er worden geen verzendbrieven opgehaald.");
49
49
  return run;
50
50
  }
51
+ // Verzendbrieven die op een Floriday-layout wachtten, komen vrij zodra die er is.
52
+ await sb.rpc("logistics_slip_note_release_layout").then(() => undefined, () => undefined);
51
53
  const { data, error } = await sb.rpc("logistics_slip_note_claim", {
52
54
  _limit: options.limit ?? 10,
53
55
  _lease_seconds: 120,
@@ -343,17 +345,33 @@ export async function runShippingNoteQueue(sb, options = {}) {
343
345
  const slipPayload = slipRow["payload"] ?? {};
344
346
  const printPlekId = String(slipPayload["print_plek_id"] ?? "").trim() || null;
345
347
  const cartId = slipPayload["cart_id"] ?? row.cart_id;
348
+ // Layout op id: de actieve Floriday-afleverbrief (bij meerdere de standaard).
349
+ const layout = await floridayLayout(sb, "afleverbrief");
350
+ if (!layout.layoutId) {
351
+ await sb.rpc("logistics_slip_note_hold_layout", { _id: row.id, _reason: layout.reden });
352
+ run.waiting++;
353
+ await trace(sb, {
354
+ ...basis,
355
+ step: "Wacht op Floriday-layout",
356
+ status: "wachtend",
357
+ reason: layout.reden ?? "Geen Floriday-layout",
358
+ });
359
+ continue;
360
+ }
346
361
  const printed = await printViaLayout(sb, {
347
362
  documenttype: "afleverbrief",
363
+ layoutId: layout.layoutId,
348
364
  documentnaam: `Verzendbrief ${row.order_number}`,
349
365
  pdfBase64: base64,
350
366
  pdfUrl: url,
351
367
  printPlekId,
352
368
  herkomst: "floriday",
353
369
  isHerprint: Boolean(slipRow["is_herprint"] ?? false),
354
- idempotentieSleutel: `verzendbrief-bij-pakbon:${row.slip_job_id}`,
370
+ idempotentieSleutel: `verzendbrief-bij-pakbon:${row.slip_job_id}:${layout.layoutId}`,
355
371
  payload: {
356
372
  source: "pickstation",
373
+ documenttype: "afleverbrief",
374
+ layout_id: layout.layoutId,
357
375
  document_type_code: "verzendbrief",
358
376
  trigger: "with_packing_slip",
359
377
  is_floriday: true,
@@ -370,6 +388,26 @@ export async function runShippingNoteQueue(sb, options = {}) {
370
388
  fulfillment_order_id: fulfillmentOrderId,
371
389
  },
372
390
  });
391
+ if (!printed.ok && printed.errorCode === "DUBBEL_ORIGINEEL") {
392
+ // Staat al klaar: geen mislukte poging, niet opnieuw proberen.
393
+ await sb.rpc("logistics_slip_note_finish", {
394
+ _id: row.id,
395
+ _ok: true,
396
+ _status: "in_printwachtrij",
397
+ _print_job_id: printed.bestaandJobId ?? null,
398
+ _fulfillment_order_id: fulfillmentOrderId,
399
+ _error_code: "dubbel_origineel",
400
+ _error: `Staat al in de printwachtrij${printed.bestaandJobId ? ` (opdracht ${printed.bestaandJobId})` : ""}.`,
401
+ });
402
+ run.printed++;
403
+ await trace(sb, {
404
+ ...basis,
405
+ step: "Verzendbrief staat al in de printwachtrij",
406
+ status: "geslaagd",
407
+ decision: printed.bestaandJobId ? `bestaande opdracht ${printed.bestaandJobId}` : "bestaande opdracht",
408
+ });
409
+ continue;
410
+ }
373
411
  if (!printed.ok) {
374
412
  if (["GEEN_PRINTER", "GEEN_LAYOUT", "GEEN_EXTERN_DOCUMENT"].includes(printed.errorCode)) {
375
413
  await faal(printed.errorCode.toLowerCase(), printed.error, fulfillmentOrderId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.133",
3
+ "version": "1.0.135",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [