@flowselections/logistiek-engine 1.0.124 → 1.0.128

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.
@@ -40,6 +40,18 @@ export type CartCarriersResult = {
40
40
  code: string;
41
41
  error: string;
42
42
  };
43
+ /**
44
+ * Groepeert karregels (met geneste `order_carts`) per kar en houdt alleen de
45
+ * regels van de eigen orderregels over. Werkt ook voor een gedeelde bufferkar
46
+ * (order_carts.order_id leeg). Een set is één karregel; die telt als geheel mee.
47
+ */
48
+ export declare function groupOwnCartLines(lines: Array<Record<string, unknown>>, ownItemIds: string[]): Array<{
49
+ id: string;
50
+ cart_number: number | null;
51
+ carrier_type: string | null;
52
+ total_layers_used: number | null;
53
+ order_cart_items: Array<Record<string, unknown>>;
54
+ }>;
43
55
  export declare function buildCartCarriers(carts: CartInput[], requests: DeliveryRequestInput[]): CartCarriersResult;
44
56
  export type FulfillmentDecision = {
45
57
  kind: "klaar";
@@ -1 +1 @@
1
- {"version":3,"file":"floridayCartCarriers.d.ts","sourceRoot":"","sources":["../../src/lib/floridayCartCarriers.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;QAAE,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0BAA0B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,wBAAwB,EAAE,MAAM,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,YAAY,EAAE,WAAW,EAAE,CAAA;CAAE,GACzC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,EAAE,oBAAoB,EAAE,GAC/B,kBAAkB,CAuEpB;AAMD,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAElF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,mBAAmB,CA0B5E"}
1
+ {"version":3,"file":"floridayCartCarriers.d.ts","sourceRoot":"","sources":["../../src/lib/floridayCartCarriers.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,38 @@
7
7
  // niet met de delivery-order, dan wordt er niets opgebouwd en komt er een
8
8
  // duidelijke reden terug. Er wordt nooit stil teruggevallen op 0 lagen.
9
9
  // ============================================================================
10
+ /**
11
+ * Groepeert karregels (met geneste `order_carts`) per kar en houdt alleen de
12
+ * regels van de eigen orderregels over. Werkt ook voor een gedeelde bufferkar
13
+ * (order_carts.order_id leeg). Een set is één karregel; die telt als geheel mee.
14
+ */
15
+ export function groupOwnCartLines(lines, ownItemIds) {
16
+ const own = new Set(ownItemIds.map(String));
17
+ const carts = new Map();
18
+ for (const line of Array.isArray(lines) ? lines : []) {
19
+ if (!own.has(String(line["order_item_id"] ?? "")))
20
+ continue;
21
+ const rawCart = line["order_carts"];
22
+ const cart = (Array.isArray(rawCart) ? rawCart[0] : rawCart);
23
+ const id = String(cart?.["id"] ?? line["cart_id"] ?? "");
24
+ if (!id)
25
+ continue;
26
+ let entry = carts.get(id);
27
+ if (!entry) {
28
+ entry = {
29
+ id,
30
+ cart_number: cart?.["cart_number"] ?? null,
31
+ carrier_type: cart?.["carrier_type"] ?? null,
32
+ total_layers_used: cart?.["total_layers_used"] ?? null,
33
+ order_cart_items: [],
34
+ };
35
+ carts.set(id, entry);
36
+ }
37
+ const { order_carts: _skip, ...rest } = line;
38
+ entry.order_cart_items.push(rest);
39
+ }
40
+ return [...carts.values()].sort((a, b) => (a.cart_number ?? 0) - (b.cart_number ?? 0) || a.id.localeCompare(b.id));
41
+ }
10
42
  export function buildCartCarriers(carts, requests) {
11
43
  if (carts.length === 0) {
12
44
  return { ok: false, code: "geen_karindeling", error: "Er is nog geen karindeling voor deze order." };
@@ -1 +1 @@
1
- {"version":3,"file":"floridayPush.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayPush.server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAc/C,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD;AAaD,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,OAAO,2BAA2B,EAAE,WAAW,EAAE,CAAC;CACjE;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAUnE;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,cAAc,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CACN;IACE,EAAE,EAAE,IAAI,CAAC;IACT,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,cAAc,EAAE,OAAO,2BAA2B,EAAE,oBAAoB,EAAE,CAAC;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7C,CAoEA;AAED,8CAA8C;AAC9C,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAyHtB;AAQD,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AA6BD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAElF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,eAAe,CAAC,CAwL1B;AAQD,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F"}
1
+ {"version":3,"file":"floridayPush.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayPush.server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAc/C,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD;AAaD,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,OAAO,2BAA2B,EAAE,WAAW,EAAE,CAAC;CACjE;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAUnE;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,cAAc,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CACN;IACE,EAAE,EAAE,IAAI,CAAC;IACT,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,cAAc,EAAE,OAAO,2BAA2B,EAAE,oBAAoB,EAAE,CAAC;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7C,CAoEA;AAED,8CAA8C;AAC9C,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAiItB;AAQD,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AA6BD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAElF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,eAAe,CAAC,CAwL1B;AAQD,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F"}
@@ -133,20 +133,49 @@ export async function buildFloridayPayload(sb, orderRef) {
133
133
  // Wachttoestand, geen mislukking: de delivery-order kan later binnenkomen.
134
134
  return { ok: false, code: found.code, error: found.error, permanent: false };
135
135
  }
136
- const { data: carts, error: cartsError } = await sb
137
- .from("order_carts")
138
- .select("id, cart_number, carrier_type, total_layers_used, max_layers, occupancy_pct, weight_kg, order_cart_items(product_id, product_name, crates, boxes, plants_per_crate, order_item_id)")
136
+ // Orderregel → Floriday fulfillmentRequest (order_items.source_line_key).
137
+ const { data: orderItems, error: itemsError } = await sb
138
+ .from("order_items")
139
+ .select("id, source_line_key")
139
140
  .eq("order_id", row["id"])
140
- .order("cart_number", { ascending: true });
141
- if (cartsError) {
141
+ // Regels in quarantaine (Verkoop-herstel) gaan niet mee naar Floriday.
142
+ .is("quarantined_at", null);
143
+ if (itemsError) {
142
144
  return {
143
145
  ok: false,
144
- code: "db_error_carts",
145
- error: `Karindeling niet leesbaar: ${cartsError.message}`,
146
+ code: "db_error_order_items",
147
+ error: `Orderregels niet leesbaar: ${itemsError.message}`,
146
148
  permanent: false,
147
149
  };
148
150
  }
149
- const cartRows = (Array.isArray(carts) ? carts : []);
151
+ const requestByItem = new Map();
152
+ const ownItemIds = [];
153
+ for (const it of (Array.isArray(orderItems) ? orderItems : [])) {
154
+ ownItemIds.push(String(it["id"]));
155
+ const key = String(it["source_line_key"] ?? "").trim();
156
+ if (key)
157
+ requestByItem.set(String(it["id"]), key);
158
+ }
159
+ // Karren via de eigen orderregels, niet via order_carts.order_id: een gedeelde
160
+ // bufferkar staat op naam van de buffer. Alleen de eigen regels gaan mee.
161
+ let lineRows = [];
162
+ if (ownItemIds.length > 0) {
163
+ const { data: lines, error: cartsError } = await sb
164
+ .from("order_cart_items")
165
+ .select("cart_id, order_item_id, product_id, product_name, crates, boxes, plants_per_crate, order_carts!inner(id, cart_number, carrier_type, total_layers_used)")
166
+ .in("order_item_id", ownItemIds);
167
+ if (cartsError) {
168
+ return {
169
+ ok: false,
170
+ code: "db_error_carts",
171
+ error: `Karindeling niet leesbaar: ${cartsError.message}`,
172
+ permanent: false,
173
+ };
174
+ }
175
+ lineRows = (Array.isArray(lines) ? lines : []);
176
+ }
177
+ const { groupOwnCartLines } = await import("./floridayCartCarriers.js");
178
+ const cartRows = groupOwnCartLines(lineRows, ownItemIds);
150
179
  const indeling = cartRows.map((cart) => {
151
180
  const items = Array.isArray(cart["order_cart_items"])
152
181
  ? cart["order_cart_items"]
@@ -164,27 +193,6 @@ export async function buildFloridayPayload(sb, orderRef) {
164
193
  .sort((a, b) => String(a.productId).localeCompare(String(b.productId))),
165
194
  };
166
195
  });
167
- // Orderregel → Floriday fulfillmentRequest (order_items.source_line_key).
168
- const { data: orderItems, error: itemsError } = await sb
169
- .from("order_items")
170
- .select("id, source_line_key")
171
- .eq("order_id", row["id"])
172
- // Regels in quarantaine (Verkoop-herstel) gaan niet mee naar Floriday.
173
- .is("quarantined_at", null);
174
- if (itemsError) {
175
- return {
176
- ok: false,
177
- code: "db_error_order_items",
178
- error: `Orderregels niet leesbaar: ${itemsError.message}`,
179
- permanent: false,
180
- };
181
- }
182
- const requestByItem = new Map();
183
- for (const it of (Array.isArray(orderItems) ? orderItems : [])) {
184
- const key = String(it["source_line_key"] ?? "").trim();
185
- if (key)
186
- requestByItem.set(String(it["id"]), key);
187
- }
188
196
  const { buildCartCarriers } = await import("./floridayCartCarriers.js");
189
197
  const carriers = buildCartCarriers(cartRows.map((cart) => ({
190
198
  cartNumber: cart["cart_number"] ?? null,
@@ -0,0 +1,3 @@
1
+ /** Floriday-koppeling weigert omdat een vast kenmerk (eigendom Afhandeling) ontbreekt. */
2
+ export declare function isKenmerkOntbreekt(error: string | null | undefined): boolean;
3
+ //# sourceMappingURL=kenmerk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kenmerk.d.ts","sourceRoot":"","sources":["../../src/lib/kenmerk.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAM5E"}
@@ -0,0 +1,6 @@
1
+ /** Floriday-koppeling weigert omdat een vast kenmerk (eigendom Afhandeling) ontbreekt. */
2
+ export function isKenmerkOntbreekt(error) {
3
+ const t = String(error ?? "").toLowerCase();
4
+ return (/(fulfillmentorderid|loadcarrierreference|loadcarrieritemid)[^.]*ontbreekt/.test(t) ||
5
+ /missing[^.]*(fulfillmentorderid|loadcarrierreference|loadcarrieritemid)/.test(t));
6
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAIvB,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;AA2vJD,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;;;;;;;;;;;CAIvB,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;AAqzJD,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"}
@@ -1917,6 +1917,34 @@ CONTROLELIJST
1917
1917
  [ ] Een order op een gedeelde bufferkar toont "Ingedeeld", niet "geen kar".
1918
1918
  `,
1919
1919
  },
1920
+ {
1921
+ number: 21,
1922
+ title: "Scanbron meesturen bij Controle uitvoeren in bulk",
1923
+ date: "2026-10-13",
1924
+ summary: "Bij \"Controle uitvoeren\" in bulk per kar afmeld_bron = 'bulk' meesturen.",
1925
+ body: `AANVULLING op de eerdere prompts (die blijven geldig).
1926
+
1927
+ WAT ER VERANDERT
1928
+ Afmelden in bulk legt nu ook per kar één goedgekeurde controlescan vast, net als
1929
+ de scanner. Eén definitie van "gecontroleerd": een kar met een goedgekeurde
1930
+ controlescan; elke order met regels op die kar telt als gecontroleerd.
1931
+
1932
+ WAT JE DOET
1933
+ - In de aanroep van control_mark_carts_delivered_detail (of
1934
+ control_mark_carts_delivered) vanuit "Controle uitvoeren" zet je in ELK item
1935
+ van de jsonb-lijst het veld afmeld_bron = 'bulk'.
1936
+ - Toon het resultaat zoals nu; er komt geen nieuw scherm.
1937
+
1938
+ NIET DOEN
1939
+ - Geen eigen telling van "gecontroleerd"; de Engine bepaalt dat.
1940
+ - Geen terugwerkende goedkeuring van oude afmeldingen (zou belading van oude
1941
+ karren naar Floriday in gang zetten).
1942
+ - Geen URL's, sleutels, project-refs, klantnamen of vaste id's in code.
1943
+
1944
+ CONTROLELIJST
1945
+ [ ] Na bulkcontrole staat in logistics_control_scan bron = 'bulk' voor elke kar.
1946
+ [ ] Een kar die al met de scanner is afgemeld, krijgt geen tweede scan.`,
1947
+ },
1920
1948
  ],
1921
1949
  },
1922
1950
  pickschermen: {
@@ -3911,6 +3939,34 @@ CONTROLELIJST
3911
3939
  [ ] Bij scan_only wordt er nergens een printjob aangemaakt.
3912
3940
  [ ] Foutteksten komen letterlijk van de Engine.`,
3913
3941
  },
3942
+ {
3943
+ number: 6,
3944
+ title: "Scanbron meesturen bij afmelden op de controlepost",
3945
+ date: "2026-10-13",
3946
+ summary: "Bij \"Kar afgehandeld bij de Logistiek Engine\" per kar afmeld_bron = 'scanner' meesturen.",
3947
+ body: `AANVULLING op de eerdere prompts (die blijven geldig).
3948
+
3949
+ WAT ER VERANDERT
3950
+ Bij het afmelden legt de Engine per kar één goedgekeurde controlescan vast
3951
+ (logistics_control_scan, approved_at gevuld) met een bron. Zonder bron staat er
3952
+ 'onbekend'. De eindcontrole-scanner moet de bron meesturen.
3953
+
3954
+ WAT JE DOET
3955
+ - In de aanroep van control_mark_carts_delivered_detail (of
3956
+ control_mark_carts_delivered) zet je in ELK item van de jsonb-lijst het veld
3957
+ afmeld_bron = 'scanner'.
3958
+ - Verder verandert er niets aan de aanroep of aan de afhandeling van het antwoord.
3959
+
3960
+ NIET DOEN
3961
+ - Geen eigen telling van "gecontroleerd"; de Engine bepaalt dat (een kar met een
3962
+ goedgekeurde controlescan).
3963
+ - Geen terugwerkende goedkeuring van oude afmeldingen.
3964
+ - Geen URL's, sleutels, project-refs, klantnamen of vaste id's in code.
3965
+
3966
+ CONTROLELIJST
3967
+ [ ] Na een scan staat in logistics_control_scan bron = 'scanner' voor die kar.
3968
+ [ ] Twee keer scannen geeft nog steeds één controlescan.`,
3969
+ },
3914
3970
  ],
3915
3971
  },
3916
3972
  voorraad: {
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.124";
1
+ export declare const MODULE_VERSION = "1.0.128";
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.124";
2
+ export const MODULE_VERSION = "1.0.128";
@@ -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,CA2b1B;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":"AAeA,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,CA4c1B;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"}
@@ -11,6 +11,7 @@
11
11
  // Er wordt niets bevestigd of afgehandeld, en er komen geen omgevings- of
12
12
  // klantwaarden in deze code.
13
13
  // ============================================================================
14
+ import { isKenmerkOntbreekt } from "./kenmerk.js";
14
15
  import { trace, newTraceId, classifyError } from "./trace.server.js";
15
16
  import { FLOW_NODE } from "./flowNodes.js";
16
17
  import { printViaLayout } from "./layoutPrint.server.js";
@@ -268,6 +269,24 @@ export async function runShippingNoteQueue(sb, options = {}) {
268
269
  await houdVast(aangemaakt.error ?? "De poort staat het aanmaken van de verzendbrief niet toe.");
269
270
  continue;
270
271
  }
272
+ else if (!aangemaakt.ok && isKenmerkOntbreekt(aangemaakt.error)) {
273
+ // Vaste kenmerken zijn van Afhandeling; de Engine maakt ze nooit zelf.
274
+ await sb.rpc("logistics_slip_note_hold_kenmerk", {
275
+ _id: row.id,
276
+ _reason: `Wacht op vast kenmerk van Afhandeling: ${aangemaakt.error}`,
277
+ });
278
+ run.waiting++;
279
+ await trace(sb, {
280
+ ...basis,
281
+ step: "Wacht op vast kenmerk van Afhandeling",
282
+ status: "wachtend",
283
+ decision: "wacht_op_kenmerk",
284
+ reason: aangemaakt.error ?? "Vast kenmerk ontbreekt.",
285
+ rule: "Afhandeling is eigenaar van fulfillmentOrderId/loadCarrierReference/loadCarrierItemId",
286
+ nextStep: "Gaat pas verder als Afhandeling het kenmerk vastlegt of belading_verstuurder op 'afhandeling' staat",
287
+ });
288
+ continue;
289
+ }
271
290
  else if (!aangemaakt.ok) {
272
291
  await wacht(`Wachten op Floriday-verzendbrief: ${aangemaakt.error ?? "Floriday heeft het document nog niet aangemaakt."}`, aangemaakt.skipped ? "nog_niet_beschikbaar" : classifyFloridayReason(aangemaakt.error ?? ""));
273
292
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.124",
3
+ "version": "1.0.128",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [