@flowselections/logistiek-engine 1.0.181 → 1.0.185

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":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;CAKvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAosMD,eAAO,MAAM,cAAc,EAAE,YAAY,EAUL,CAAC;AAErC,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAmBR;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAiB9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAIR"}
1
+ {"version":3,"file":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;CAKvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA65MD,eAAO,MAAM,cAAc,EAAE,YAAY,EAUL,CAAC;AAErC,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAmBR;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAiB9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAIR"}
@@ -1235,12 +1235,121 @@ CONTROLELIJST
1235
1235
  uit logistics_events.error.
1236
1236
  [ ] Meld terug met je pakketversie.`,
1237
1237
  },
1238
+ {
1239
+ number: 27,
1240
+ title: "Vervoerder tonen en handmatig kiezen",
1241
+ date: "2026-10-22",
1242
+ summary: "Ordervervoerder tonen met bron en reden; handmatig kiezen via logistics_set_order_carrier.",
1243
+ body: `GEDEELD CONTRACT VERVOERDER (eigenaar: Logistiek Engine, versie 1.0.184)
1244
+ - Kolommen op orders (Engine): carrier_id, carrier_source, carrier_reason,
1245
+ carrier_resolved_at, carrier_set_by, carrier_set_at.
1246
+ - carrier_source: handmatig, afleverlocatie, afleverlocatie_gln, klant,
1247
+ werkgebied, favoriet, geen, oud.
1248
+ - Functies (Engine): logistics_resolve_carrier(p_order_id uuid) → jsonb
1249
+ {carrier_id, carrier_name, carrier_kind, bron, reden, waarschuwing};
1250
+ logistics_resolve_carrier_many(p_order_ids uuid[]);
1251
+ logistics_resolve_carrier_for_location(p_location_id uuid, p_customer_id uuid)
1252
+ en _many (zelfde volgorde zonder stap 1);
1253
+ logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid) — de enige
1254
+ manier om handmatig te kiezen; NULL = terug naar automatisch.
1255
+ - Volgorde: 1 handmatig → 2 afleverlocatie (self_pickup = klant haalt op;
1256
+ carrier_id alleen als carrier_assignment_source = 'manual') → 3
1257
+ carriers.delivery_location_glns bevat de GLN → 4 customers.default_carrier_id
1258
+ → 5 werkgebied plaats > provincie > land met ophaalmoment op de leverdag →
1259
+ 6 afh_favorite_carrier(). Overgeslagen (met reden): extern zonder e-mail,
1260
+ carrier_kind leeg, archived_at gevuld. is_default telt niet meer mee.
1261
+ - Altijd op id, nooit op naam. Herkennen op carrier_kind, nooit op naam.
1262
+ - Niet herberekenen na aanmelding, plan_locked_at, start picken, gepickt of
1263
+ vastgezette kar; dan alleen waarschuwing "Vervoerder zou nu <X> zijn".
1264
+ - Opslaan of wijzigen van een vervoerder verstuurt nooit zelf een mail.
1265
+ - Geen migraties met omgevingswaarden; geen URL's, sleutels of namen in code.
1266
+
1267
+ Bouw in Verkoop (geen eigen vervoerderlogica, geen eigen opslag):
1268
+ 1. Orderdetail en orderlijst: toon orders.carrier_id als naam, plus bron en
1269
+ carrier_reason. carrier_source = 'geen': rode melding met carrier_reason
1270
+ ("Geen vervoerder: stel een favoriete vervoerder in (Afhandeling →
1271
+ Vervoerders)"). Toon waarschuwing uit logistics_resolve_carrier als die er is.
1272
+ 2. Handmatig kiezen: alleen via rpc logistics_set_order_carrier(p_order_id,
1273
+ p_carrier_id); knop "Automatisch" = p_carrier_id null. Schrijf nooit zelf
1274
+ carrier_* of custom_fields.carrier.
1275
+ 3. Nieuwe order (HO/MO/AO en FO-import): niets doen; de Engine vult de
1276
+ vervoerder bij het aanmaken. Bron 'oud' tonen als "Overgenomen (oud)".
1277
+ 4. Lijsten met veel orders: logistics_resolve_carrier_many alleen voor een
1278
+ voorstel; de opgeslagen kolommen zijn leidend.`,
1279
+ },
1238
1280
  ],
1239
1281
  },
1240
1282
  afhandeling: {
1241
1283
  order: 2,
1242
1284
  summary: "Voert belading, controle, printen en transport uit volgens de taak-payload.",
1243
1285
  revisions: [
1286
+ {
1287
+ number: 32,
1288
+ title: "Aanmelden: vervangen regel (vastlegging)",
1289
+ date: "2026-10-22",
1290
+ summary: "Vastlegging; niet doorsturen. Vervangt punt 6 van prompt 31.",
1291
+ body: `Vastlegging, geen bouwopdracht (al zo gebouwd in Afhandeling 1.0.77).
1292
+ Punt 6 van prompt 31 ("nooit bij floriday_fulfilled = true") is vervangen door:
1293
+ - Wél aanmelden bij custom_fields.floriday_fulfilled = true samen met
1294
+ floriday_fulfilled_by_erp = true (door ons afgehandeld).
1295
+ - Nooit aanmelden bij custom_fields.floriday_fulfilled_externally = true
1296
+ (extern afgehandeld), nooit bij geannuleerde orders, nooit bij eigen vervoer
1297
+ of afhalen (carrier_kind).
1298
+ - De Engine leest floriday_fulfilled niet voor de vervoerderregel; de
1299
+ bevriesregel gebruikt alleen carrier_signup_dispatches (sent_at, order_ids).`,
1300
+ },
1301
+ {
1302
+ number: 31,
1303
+ title: "Vervoerder: soort, favoriet, GLN-lijst",
1304
+ date: "2026-10-22",
1305
+ summary: "Gebouwd in Afhandeling 1.0.77. Punt 6 vervangen door prompt 32.",
1306
+ body: `GEDEELD CONTRACT VERVOERDER (eigenaar: Logistiek Engine, versie 1.0.184)
1307
+ - Kolommen op orders (Engine): carrier_id, carrier_source, carrier_reason,
1308
+ carrier_resolved_at, carrier_set_by, carrier_set_at.
1309
+ - carrier_source: handmatig, afleverlocatie, afleverlocatie_gln, klant,
1310
+ werkgebied, favoriet, geen, oud.
1311
+ - Functies (Engine): logistics_resolve_carrier(p_order_id uuid) → jsonb
1312
+ {carrier_id, carrier_name, carrier_kind, bron, reden, waarschuwing};
1313
+ logistics_resolve_carrier_many(p_order_ids uuid[]);
1314
+ logistics_resolve_carrier_for_location(p_location_id uuid, p_customer_id uuid)
1315
+ en _many (zelfde volgorde zonder stap 1);
1316
+ logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid) — de enige
1317
+ manier om handmatig te kiezen; NULL = terug naar automatisch.
1318
+ - Volgorde: 1 handmatig → 2 afleverlocatie (self_pickup = klant haalt op;
1319
+ carrier_id alleen als carrier_assignment_source = 'manual') → 3
1320
+ carriers.delivery_location_glns bevat de GLN → 4 customers.default_carrier_id
1321
+ → 5 werkgebied plaats > provincie > land met ophaalmoment op de leverdag →
1322
+ 6 afh_favorite_carrier(). Overgeslagen (met reden): extern zonder e-mail,
1323
+ carrier_kind leeg, archived_at gevuld. is_default telt niet meer mee.
1324
+ - Altijd op id, nooit op naam. Herkennen op carrier_kind, nooit op naam.
1325
+ - Niet herberekenen na aanmelding, plan_locked_at, start picken, gepickt of
1326
+ vastgezette kar; dan alleen waarschuwing "Vervoerder zou nu <X> zijn".
1327
+ - Opslaan of wijzigen van een vervoerder verstuurt nooit zelf een mail.
1328
+ - Geen migraties met omgevingswaarden; geen URL's, sleutels of namen in code.
1329
+
1330
+ Bouw in Afhandeling (de Engine leest dit alleen; wijzig geen Engine-functies):
1331
+ 1. carriers.carrier_kind text met waarden extern / eigen_vervoer /
1332
+ klant_haalt_op. Bestaande "eigen vervoer"-rij: NIET automatisch op naam
1333
+ omzetten; toon in Vervoerders een melding "Soort ontbreekt" per vervoerder
1334
+ tot de gebruiker hem kiest. Vervoerders zonder soort worden overgeslagen.
1335
+ 2. is_favorite (precies één, via "Maak favoriet"), archived_at (archiveren i.p.v.
1336
+ verwijderen), delivery_location_glns text[] (beheerbaar per vervoerder).
1337
+ 3. afh_favorite_carrier() blijft een rij met carrier_id; extern zonder e-mail
1338
+ mag geen favoriet zijn (bestaat al, behouden).
1339
+ 4. is_default niet meer gebruiken in schermen of logica.
1340
+ 5. Vervoerders-scherm: bovenaan een melding als er geen favoriet is: "Geen
1341
+ favoriete vervoerder: orders zonder andere vervoerder blijven staan."
1342
+ 6. Aanmeldingen: alleen orders met orders.carrier_id van soort extern; nooit
1343
+ bij eigen vervoer of afhalen; nooit bij custom_fields.floriday_fulfilled = true
1344
+ of floriday_fulfilled_externally = true of geannuleerd; hooguit één aanmelding
1345
+ per zending (carrier_signup_dispatches), zichtbaar bij de order; schakelaar per
1346
+ Shell "Aanmeldingen automatisch versturen" (standaard uit) met een lijst
1347
+ "klaar om te versturen" die je kunt bekijken. Lees de vervoerder uit
1348
+ orders.carrier_id, niet meer uit custom_fields.carrier.
1349
+ 7. control_get_todays_carts en de carrier-lijsten: vervoerdersnaam via
1350
+ orders.carrier_id; "Eigen vervoer"/"Afhalen" op carrier_kind.
1351
+ Toets: elke nieuwe functie met safeupdate (geen UPDATE/DELETE zonder WHERE).`,
1352
+ },
1244
1353
  {
1245
1354
  number: 30,
1246
1355
  title: "Karnummer koppelen aan het kar-id",
@@ -5175,6 +5284,48 @@ CONTROLELIJST
5175
5284
  - Dit veld meegeven als strategy_id bij logistics_emit_event, of beschikbaar
5176
5285
  maken zodat de Verkoop-module het kan meegeven.`,
5177
5286
  },
5287
+ {
5288
+ number: 2,
5289
+ title: "Vervoerder: standaard per klant en per locatie",
5290
+ date: "2026-10-22",
5291
+ summary: "Gebouwd in Klanten 1.0.66.",
5292
+ body: `GEDEELD CONTRACT VERVOERDER (eigenaar: Logistiek Engine, versie 1.0.184)
5293
+ - Kolommen op orders (Engine): carrier_id, carrier_source, carrier_reason,
5294
+ carrier_resolved_at, carrier_set_by, carrier_set_at.
5295
+ - carrier_source: handmatig, afleverlocatie, afleverlocatie_gln, klant,
5296
+ werkgebied, favoriet, geen, oud.
5297
+ - Functies (Engine): logistics_resolve_carrier(p_order_id uuid) → jsonb
5298
+ {carrier_id, carrier_name, carrier_kind, bron, reden, waarschuwing};
5299
+ logistics_resolve_carrier_many(p_order_ids uuid[]);
5300
+ logistics_resolve_carrier_for_location(p_location_id uuid, p_customer_id uuid)
5301
+ en _many (zelfde volgorde zonder stap 1);
5302
+ logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid) — de enige
5303
+ manier om handmatig te kiezen; NULL = terug naar automatisch.
5304
+ - Volgorde: 1 handmatig → 2 afleverlocatie (self_pickup = klant haalt op;
5305
+ carrier_id alleen als carrier_assignment_source = 'manual') → 3
5306
+ carriers.delivery_location_glns bevat de GLN → 4 customers.default_carrier_id
5307
+ → 5 werkgebied plaats > provincie > land met ophaalmoment op de leverdag →
5308
+ 6 afh_favorite_carrier(). Overgeslagen (met reden): extern zonder e-mail,
5309
+ carrier_kind leeg, archived_at gevuld. is_default telt niet meer mee.
5310
+ - Altijd op id, nooit op naam. Herkennen op carrier_kind, nooit op naam.
5311
+ - Niet herberekenen na aanmelding, plan_locked_at, start picken, gepickt of
5312
+ vastgezette kar; dan alleen waarschuwing "Vervoerder zou nu <X> zijn".
5313
+ - Opslaan of wijzigen van een vervoerder verstuurt nooit zelf een mail.
5314
+ - Geen migraties met omgevingswaarden; geen URL's, sleutels of namen in code.
5315
+
5316
+ Bouw in Klanten:
5317
+ 1. customers.default_carrier_id uuid (verwijzing naar carriers.id, leeg mag).
5318
+ Keuzelijst toont alleen niet-gearchiveerde vervoerders met een soort.
5319
+ 2. Afleverlocatie: keuze "Automatisch" (carrier_id leeg; er wordt GEEN voorstel
5320
+ opgeslagen), een vervoerder (carrier_id + carrier_assignment_source =
5321
+ 'manual'), of "Klant haalt zelf op" (self_pickup = true).
5322
+ 3. Toon naast "Automatisch" het voorstel uit
5323
+ logistics_resolve_carrier_for_location_many(p_location_ids, p_customer_id):
5324
+ naam + reden in gewone taal. Alleen tonen, niet opslaan.
5325
+ 4. Verwijder pickCarrierForLocation; geen eigen tweede variant meer.
5326
+ 5. Geen e-maileis in Klanten; de Engine slaat extern zonder e-mail over en zegt
5327
+ dat in de reden.`,
5328
+ },
5178
5329
  ],
5179
5330
  },
5180
5331
  mailbox: {
@@ -5351,6 +5502,72 @@ Zelf rekenen doe je niet.
5351
5502
  order: 9,
5352
5503
  summary: "Levert de documentlayouts. Kiest zelf geen layout en geen printer: de Engine bepaalt welke layout en welke printplek bij een document horen.",
5353
5504
  revisions: [
5505
+ {
5506
+ number: 15,
5507
+ title: "carrier_label op documenten",
5508
+ date: "2026-10-22",
5509
+ summary: "carrier_label uit de Engine tonen; nooit 'onbekend' bij eigen vervoer of afhalen.",
5510
+ body: `GEDEELD CONTRACT VERVOERDER (eigenaar: Logistiek Engine, versie 1.0.184)
5511
+ - Kolommen op orders (Engine): carrier_id, carrier_source, carrier_reason,
5512
+ carrier_resolved_at, carrier_set_by, carrier_set_at.
5513
+ - carrier_source: handmatig, afleverlocatie, afleverlocatie_gln, klant,
5514
+ werkgebied, favoriet, geen, oud.
5515
+ - Functies (Engine): logistics_resolve_carrier(p_order_id uuid) → jsonb
5516
+ {carrier_id, carrier_name, carrier_kind, bron, reden, waarschuwing};
5517
+ logistics_resolve_carrier_many(p_order_ids uuid[]);
5518
+ logistics_resolve_carrier_for_location(p_location_id uuid, p_customer_id uuid)
5519
+ en _many (zelfde volgorde zonder stap 1);
5520
+ logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid) — de enige
5521
+ manier om handmatig te kiezen; NULL = terug naar automatisch.
5522
+ - Volgorde: 1 handmatig → 2 afleverlocatie (self_pickup = klant haalt op;
5523
+ carrier_id alleen als carrier_assignment_source = 'manual') → 3
5524
+ carriers.delivery_location_glns bevat de GLN → 4 customers.default_carrier_id
5525
+ → 5 werkgebied plaats > provincie > land met ophaalmoment op de leverdag →
5526
+ 6 afh_favorite_carrier(). Overgeslagen (met reden): extern zonder e-mail,
5527
+ carrier_kind leeg, archived_at gevuld. is_default telt niet meer mee.
5528
+ - Altijd op id, nooit op naam. Herkennen op carrier_kind, nooit op naam.
5529
+ - Niet herberekenen na aanmelding, plan_locked_at, start picken, gepickt of
5530
+ vastgezette kar; dan alleen waarschuwing "Vervoerder zou nu <X> zijn".
5531
+ - Opslaan of wijzigen van een vervoerder verstuurt nooit zelf een mail.
5532
+ - Geen migraties met omgevingswaarden; geen URL's, sleutels of namen in code.
5533
+
5534
+ Bouw in Layouts:
5535
+ 1. Veld carrier_label in pakbon, afleverbrief, verzendlabel en transportdocument:
5536
+ neem het over uit de Engine-payload (logistics_brief_transport →
5537
+ carrier_label). Waarden: vervoerdersnaam, "Eigen vervoer", "Afhalen".
5538
+ 2. Toon nooit "onbekend". Ontbreekt carrier_label, dan blokkeert het document
5539
+ met "Geen vervoerder" (de Engine blokkeert de planning al).
5540
+ 3. Geen eigen opzoeking van vervoerders op naam.`,
5541
+ },
5542
+ {
5543
+ number: 14,
5544
+ title: "Geladen etiket instellen: pad en formaat",
5545
+ date: "2026-10-21",
5546
+ summary: "De Engine toont 'Stel bij je labelprinter in welk etiket erin zit' met een knop naar jullie printerinstelling.",
5547
+ body: `KOPPELPROMPT LAYOUTS EN PRINTERS – geladen etiket (Engine 1.0.182)
5548
+
5549
+ Situatie: bij alle printers is printers.geladen_etiket leeg, ook bij de
5550
+ labelprinter. De Engine print dan geen Floriday-klantstickers (nooit schalen,
5551
+ nooit gokken) en toont nu in Beheer:
5552
+ "Stel bij je labelprinter in welk etiket erin zit" met een knop.
5553
+
5554
+ Gevraagd:
5555
+ 1. Zet in app_settings de sleutel 'layouts_printer_settings_path' met het
5556
+ relatieve pad (binnen de Shell, met leading slash, zonder domein) naar de
5557
+ pagina waar je het geladen etiket van een printer instelt. Bijvoorbeeld het
5558
+ pad van jullie printeroverzicht. Geen volledige URL, geen domein. Zonder
5559
+ deze sleutel toont de Engine de melding zonder knop.
5560
+ 2. Maak op die pagina het veld "Geladen etiket" (breedte × hoogte in mm)
5561
+ duidelijk zichtbaar bij elke labelprinter, met dezelfde tekst als kop.
5562
+ 3. Bevestig dat geladen_etiketten(_werkplek_id, _print_plek_id) per printer
5563
+ breedte_mm en hoogte_mm teruggeeft zodra het etiket is ingesteld, en een
5564
+ lege lijst (geen fout) als geen enkele printer een etiket heeft.
5565
+ 4. Als een pickstation-scherm van jullie de printers toont: dezelfde melding
5566
+ tonen zolang een labelprinter geen geladen etiket heeft.
5567
+
5568
+ Zodra het etiket is ingesteld, pakt de Engine de wachtende stickers bij de
5569
+ volgende ronde vanzelf weer op.`,
5570
+ },
5354
5571
  {
5355
5572
  number: 13,
5356
5573
  title: "Correctie 1.69.2: eigen traysticker per fust",
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.181";
1
+ export declare const MODULE_VERSION = "1.0.185";
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.181";
2
+ export const MODULE_VERSION = "1.0.185";
@@ -1 +1 @@
1
- {"version":3,"file":"stickerQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/stickerQueue.server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkB5D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,UAAU,GAAG;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,mBAAmB,CAAC;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAKD,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAExD,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,CAEzD;AAaD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAuW5G;AAoGD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGzD"}
1
+ {"version":3,"file":"stickerQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/stickerQueue.server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAuB5D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,UAAU,GAAG;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,mBAAmB,CAAC;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAKD,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAExD,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,CAEzD;AAaD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAwa5G;AAoGD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGzD"}
@@ -18,7 +18,7 @@ import { trace, newTraceId } from "./trace.server.js";
18
18
  import { printViaLayoutGecontroleerd, floridayLayout, bucketUitLink } from "./layoutPrint.server.js";
19
19
  import { getFlorydayDocument, getFlorydayFulfillmentStatus } from "./floridayDocuments.server.js";
20
20
  import { controleerTrayPayload } from "./eigenTraysticker.js";
21
- import { controleerEtiket, parseGeladenEtiketten, pdfFormaat, stickerBackoffMinuten, stickerKopieen, waarschuwingTekst, } from "./stickerRules.js";
21
+ import { controleerEtiket, ETIKET_ONTBREEKT, MAAT_ONBEKEND, maatSleutel, pastOpEenPrinter, pastNergensTekst, parseGeladenEtiketten, pdfFormaat, stickerBackoffMinuten, stickerKopieen, waarschuwingTekst, } from "./stickerRules.js";
22
22
  const COLS = "id, soort, bron_id, order_id, order_number, cart_id, kopieen, breedte_mm, hoogte_mm, print_plek_id, fulfillment_order_id, status, attempts, sticker_type, print_job_id, herprint_reden, herprint_requested_at, eigen_sticker_id";
23
23
  /** Opslag van eigen stickers (Klanten-module, customer_product_stickers). */
24
24
  export const EIGEN_STICKER_BUCKET = "customer-stickers";
@@ -146,6 +146,58 @@ export async function runStickerQueue(sb, opts = {}) {
146
146
  await meld(r, f, c.etiket, c.ok);
147
147
  }
148
148
  }
149
+ // 3b. 1.0.182: vroeg waarschuwen bij binnenkomst: past de stickermaat op geen enkele printer?
150
+ // Eén melding per maat per order (bron_id = maat:BxH). Niet leesbaar → geen melding.
151
+ {
152
+ const { data: alle, error: alleFout } = await sb.rpc("geladen_etiketten", { _werkplek_id: null, _print_plek_id: null });
153
+ const lijstAlle = alleFout ? null : parseGeladenEtiketten(alle);
154
+ const { data } = await sb
155
+ .from("logistics_sticker_prints")
156
+ .select("order_id, breedte_mm, hoogte_mm")
157
+ .eq("soort", "sticker")
158
+ .in("status", ["wacht_op_moment", "klaar", "geblokkeerd"])
159
+ .not("breedte_mm", "is", null)
160
+ .not("order_id", "is", null)
161
+ .limit(500);
162
+ const gezien = new Set();
163
+ for (const r of (Array.isArray(data) ? data : [])) {
164
+ const f = { breedteMm: Number(r["breedte_mm"]), hoogteMm: Number(r["hoogte_mm"]) };
165
+ if (!(f.breedteMm > 0 && f.hoogteMm > 0))
166
+ continue;
167
+ const orderId = String(r["order_id"]);
168
+ const sleutel = maatSleutel(f);
169
+ if (gezien.has(orderId + sleutel))
170
+ continue;
171
+ gezien.add(orderId + sleutel);
172
+ const past = pastOpEenPrinter(f, lijstAlle);
173
+ if (past === null)
174
+ continue;
175
+ if (past) {
176
+ await sb
177
+ .from("logistics_order_sticker_warnings")
178
+ .update({ opgelost_op: nu() })
179
+ .eq("order_id", orderId)
180
+ .eq("soort", "sticker-maat")
181
+ .eq("bron_id", sleutel)
182
+ .is("opgelost_op", null);
183
+ continue;
184
+ }
185
+ const grootste = lijstAlle[0] ?? null;
186
+ await sb.from("logistics_order_sticker_warnings").upsert({
187
+ order_id: orderId,
188
+ soort: "sticker-maat",
189
+ bron_id: sleutel,
190
+ benodigd_breedte_mm: f.breedteMm,
191
+ benodigd_hoogte_mm: f.hoogteMm,
192
+ geladen_breedte_mm: grootste?.breedteMm ?? null,
193
+ geladen_hoogte_mm: grootste?.hoogteMm ?? null,
194
+ plek: "alle printers",
195
+ melding: pastNergensTekst(f, lijstAlle),
196
+ opgelost_op: null,
197
+ }, { onConflict: "order_id,soort,bron_id", ignoreDuplicates: false });
198
+ run.warnings++;
199
+ }
200
+ }
149
201
  // 4. Printen.
150
202
  const { data: klaar } = await sb
151
203
  .from("logistics_sticker_prints")
@@ -283,10 +335,18 @@ export async function runStickerQueue(sb, opts = {}) {
283
335
  f = null;
284
336
  }
285
337
  }
338
+ // 1.0.182: maat onbekend of geen geladen etiket = wachten met uitleg, niet stil weigeren.
339
+ if (!f) {
340
+ await later(MAAT_ONBEKEND);
341
+ continue;
342
+ }
286
343
  const lijst = await etiketten(r.print_plek_id);
344
+ if (lijst === null || lijst.length === 0) {
345
+ await later(ETIKET_ONTBREEKT);
346
+ continue;
347
+ }
287
348
  const controle = controleerEtiket(f, lijst, r.soort === "traysticker" ? "tray-sticker" : "sticker");
288
- if (f && lijst !== null)
289
- await meld(r, f, controle.etiket, controle.ok);
349
+ await meld(r, f, controle.etiket, controle.ok);
290
350
  if (!controle.ok) {
291
351
  await blokkeer(controle.reden);
292
352
  continue;
@@ -18,6 +18,38 @@ export declare function past(sticker: Formaat, etiket: Formaat, spelingMm?: numb
18
18
  * Rijen zonder bruikbaar formaat vallen weg. null = antwoord niet leesbaar.
19
19
  */
20
20
  export declare function parseGeladenEtiketten(data: unknown): GeladenEtiket[] | null;
21
+ /** 1.0.182: vaste meldingen; de sticker wacht (geen stille weigering). */
22
+ export declare const ETIKET_ONTBREEKT = "Stel bij je labelprinter in welk etiket erin zit. De sticker wacht tot het geladen etiket bekend is.";
23
+ export declare const MAAT_ONBEKEND = "Maat onbekend: Floriday gaf geen stickermaat en de pdf bevat er geen. De sticker wacht.";
24
+ export type StickerSoort = "PACKAGE" | "PRODUCT" | "POT" | "SLEEVE" | "LAYER" | "LOAD_CARRIER" | "DOCUMENT";
25
+ export interface OrderTellingen {
26
+ fusten: number | null;
27
+ planten: number | null;
28
+ lagen: number | null;
29
+ karren: number | null;
30
+ }
31
+ export type KopieenBron = "numberOfCopies" | "numberOfUnits" | `afgeleid:${StickerSoort}`;
32
+ /**
33
+ * 1.0.182 (gelijk aan logistics_sticker_copies): aantal klantstickers.
34
+ * numberOfCopies → additionalServices.numberOfUnits (unit LABEL, zelfde stickerId)
35
+ * → afgeleid uit stickersoort en order. null = onbekend → blokkeren.
36
+ */
37
+ export declare function kiesStickerKopieen(input: {
38
+ stickerId: string;
39
+ numberOfCopies?: unknown;
40
+ additionalServices?: unknown;
41
+ stickerType?: string | null;
42
+ order?: OrderTellingen | null;
43
+ }): {
44
+ aantal: number;
45
+ bron: KopieenBron;
46
+ } | null;
47
+ /** 1.0.182: past een maat op minstens één geladen etiket? null = niet te beoordelen. */
48
+ export declare function pastOpEenPrinter(sticker: Formaat, etiketten: GeladenEtiket[] | null): boolean | null;
49
+ /** Vroege melding als de maat op geen enkele printer past. */
50
+ export declare function pastNergensTekst(sticker: Formaat, etiketten: GeladenEtiket[]): string;
51
+ /** Sleutel voor één vroege waarschuwing per maat per order. */
52
+ export declare function maatSleutel(f: Formaat): string;
21
53
  export type EtiketControle = {
22
54
  ok: true;
23
55
  etiket: GeladenEtiket;
@@ -1 +1 @@
1
- {"version":3,"file":"stickerRules.d.ts","sourceRoot":"","sources":["../../src/lib/stickerRules.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAY5D;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAG/C;AAED,yEAAyE;AACzE,wBAAgB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,SAAI,GAAG,OAAO,CAG9E;AAOD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,EAAE,GAAG,IAAI,CAsB3E;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACnC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI,EACjC,IAAI,SAAY,GACf,cAAc,CAwBhB;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,MAAM,GAAG,IAAI,CAOf;AAED,uHAAuH;AACvH,eAAO,MAAM,2BAA2B,+BAAgC,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,GAC9G,cAAc,GAAG,cAAc,GAAG,IAAI,CAQxC"}
1
+ {"version":3,"file":"stickerRules.d.ts","sourceRoot":"","sources":["../../src/lib/stickerRules.ts"],"names":[],"mappings":"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"}
@@ -66,6 +66,64 @@ export function parseGeladenEtiketten(data) {
66
66
  }
67
67
  return uit;
68
68
  }
69
+ /** 1.0.182: vaste meldingen; de sticker wacht (geen stille weigering). */
70
+ export const ETIKET_ONTBREEKT = "Stel bij je labelprinter in welk etiket erin zit. De sticker wacht tot het geladen etiket bekend is.";
71
+ export const MAAT_ONBEKEND = "Maat onbekend: Floriday gaf geen stickermaat en de pdf bevat er geen. De sticker wacht.";
72
+ function positief(v) {
73
+ const n = typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v;
74
+ return typeof n === "number" && Number.isInteger(n) && n > 0 ? n : null;
75
+ }
76
+ /**
77
+ * 1.0.182 (gelijk aan logistics_sticker_copies): aantal klantstickers.
78
+ * numberOfCopies → additionalServices.numberOfUnits (unit LABEL, zelfde stickerId)
79
+ * → afgeleid uit stickersoort en order. null = onbekend → blokkeren.
80
+ */
81
+ export function kiesStickerKopieen(input) {
82
+ const a = positief(input.numberOfCopies);
83
+ if (a)
84
+ return { aantal: a, bron: "numberOfCopies" };
85
+ if (Array.isArray(input.additionalServices)) {
86
+ let som = 0;
87
+ for (const s of input.additionalServices) {
88
+ if (!s || typeof s !== "object")
89
+ continue;
90
+ const r = s;
91
+ if (String(r["unit"] ?? "").toUpperCase() !== "LABEL" || r["stickerId"] !== input.stickerId)
92
+ continue;
93
+ som += positief(r["numberOfUnits"]) ?? 0;
94
+ }
95
+ if (som > 0)
96
+ return { aantal: som, bron: "numberOfUnits" };
97
+ }
98
+ const t = String(input.stickerType ?? "").toUpperCase();
99
+ if (t === "DOCUMENT")
100
+ return { aantal: 1, bron: "afgeleid:DOCUMENT" };
101
+ const o = input.order;
102
+ if (!o)
103
+ return null;
104
+ const v = t === "PACKAGE" ? o.fusten
105
+ : t === "PRODUCT" || t === "POT" || t === "SLEEVE" ? o.planten
106
+ : t === "LAYER" ? o.lagen
107
+ : t === "LOAD_CARRIER" ? o.karren
108
+ : null;
109
+ const n = positief(v);
110
+ return n ? { aantal: n, bron: `afgeleid:${t}` } : null;
111
+ }
112
+ /** 1.0.182: past een maat op minstens één geladen etiket? null = niet te beoordelen. */
113
+ export function pastOpEenPrinter(sticker, etiketten) {
114
+ if (!etiketten || etiketten.length === 0)
115
+ return null;
116
+ return etiketten.some((e) => past(sticker, e));
117
+ }
118
+ /** Vroege melding als de maat op geen enkele printer past. */
119
+ export function pastNergensTekst(sticker, etiketten) {
120
+ const geladen = [...new Set(etiketten.map((e) => formaatTekst(e)))].join(", ");
121
+ return `Voor deze order is een sticker ${formaatTekst(sticker)} nodig; die past op geen enkele printer (geladen: ${geladen}).`;
122
+ }
123
+ /** Sleutel voor één vroege waarschuwing per maat per order. */
124
+ export function maatSleutel(f) {
125
+ return `maat:${f.breedteMm}x${f.hoogteMm}`;
126
+ }
69
127
  /**
70
128
  * Fail closed: geen leesbaar antwoord, geen labelprinter of één labelprinter
71
129
  * waarop de sticker niet past = niet printen.
@@ -74,15 +132,8 @@ export function controleerEtiket(sticker, etiketten, bron = "sticker") {
74
132
  if (!sticker) {
75
133
  return { ok: false, reden: `Formaat van de ${bron} is onbekend; niet geprint.`, etiket: null };
76
134
  }
77
- if (etiketten === null) {
78
- return {
79
- ok: false,
80
- reden: "Sticker niet geprint: het etiketformaat van de printer is onbekend. Stel het geladen etiket in bij Printen.",
81
- etiket: null,
82
- };
83
- }
84
- if (etiketten.length === 0) {
85
- return { ok: false, reden: "Op deze plek staat geen labelprinter met een geladen etiket; niet geprint.", etiket: null };
135
+ if (etiketten === null || etiketten.length === 0) {
136
+ return { ok: false, reden: ETIKET_ONTBREEKT, etiket: null };
86
137
  }
87
138
  for (const e of etiketten) {
88
139
  if (!past(sticker, e)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.181",
3
+ "version": "1.0.185",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [
@@ -143,7 +143,7 @@
143
143
  "devDependencies": {
144
144
  "@cloudflare/vite-plugin": "^1.25.5",
145
145
  "@eslint/js": "^9.32.0",
146
- "@flowselections/core": "1.0.29",
146
+ "@flowselections/core": "1.0.30",
147
147
  "@lovable.dev/vite-tanstack-config": "2.26.5",
148
148
  "@rsbuild/core": "^1.0.0",
149
149
  "@tailwindcss/vite": "^4.2.1",