@flowselections/mailbox-orders 1.0.15 → 1.0.16
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.
- package/dist-lib/integrations/supabase/client.d.ts +844 -150
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +844 -150
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +852 -153
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/mailbox-ai.server.d.ts.map +1 -1
- package/dist-lib/lib/mailbox-ai.server.js +6 -3
- package/dist-lib/lib/mailbox.functions.d.ts +1 -0
- package/dist-lib/lib/mailbox.functions.d.ts.map +1 -1
- package/dist-lib/lib/mailbox.functions.js +38 -172
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailbox-ai.server.d.ts","sourceRoot":"","sources":["../../src/lib/mailbox-ai.server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAAE,6BAA6B,EAAE,CAAC;AAEzC,KAAK,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;AAE5C,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,GAAG,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzC,KAAK,EAAE,KAAK,CAAC;QACX,gBAAgB,EAAE,MAAM,CAAC;QACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC,CAAC;IACH,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;IACF,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,2FAA2F;AAC3F,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGrF;AAgJD,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,GAAG,OAAa;;;;;;;EA4BhD;
|
|
1
|
+
{"version":3,"file":"mailbox-ai.server.d.ts","sourceRoot":"","sources":["../../src/lib/mailbox-ai.server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAAE,6BAA6B,EAAE,CAAC;AAEzC,KAAK,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;AAE5C,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,GAAG,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzC,KAAK,EAAE,KAAK,CAAC;QACX,gBAAgB,EAAE,MAAM,CAAC;QACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC,CAAC;IACH,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;IACF,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,2FAA2F;AAC3F,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGrF;AAgJD,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,GAAG,OAAa;;;;;;;EA4BhD;AAqGD,mDAAmD;AACnD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI3D;AAID,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM;CAMlE;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,iBAAiB,EAAE,CAAC;IACpC,cAAc,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GACA,OAAO,CAAC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CA4ErD"}
|
|
@@ -195,7 +195,8 @@ function strList(v) {
|
|
|
195
195
|
? v.map((x) => (typeof x === "string" ? x.slice(0, 120) : "")).filter(Boolean).slice(0, 50)
|
|
196
196
|
: [];
|
|
197
197
|
}
|
|
198
|
-
function normalize(raw) {
|
|
198
|
+
function normalize(raw, productCatalog) {
|
|
199
|
+
const allowedProductIds = new Set(productCatalog.map((product) => product.id));
|
|
199
200
|
const fields = {};
|
|
200
201
|
const rawFields = raw?.fields && typeof raw.fields === "object" ? raw.fields : {};
|
|
201
202
|
for (const [k, v] of Object.entries(rawFields)) {
|
|
@@ -213,7 +214,9 @@ function normalize(raw) {
|
|
|
213
214
|
const lines = rawLines
|
|
214
215
|
.map((l) => ({
|
|
215
216
|
raw_product_text: typeof l?.raw_product_text === "string" ? l.raw_product_text.slice(0, 500) : "",
|
|
216
|
-
product_id: typeof l?.product_id === "string" &&
|
|
217
|
+
product_id: typeof l?.product_id === "string" && allowedProductIds.has(l.product_id)
|
|
218
|
+
? l.product_id
|
|
219
|
+
: null,
|
|
217
220
|
plant_type: typeof l?.plant_type === "string" && l.plant_type.trim() ? l.plant_type.trim().slice(0, 200) : null,
|
|
218
221
|
quantity: num(l?.quantity),
|
|
219
222
|
unit: typeof l?.unit === "string" ? l.unit.slice(0, 40) : null,
|
|
@@ -283,7 +286,7 @@ export async function parseOrderEmail(admin, args) {
|
|
|
283
286
|
const started = Date.now();
|
|
284
287
|
try {
|
|
285
288
|
const completion = await callProvider(cfg, system, user);
|
|
286
|
-
const parsed = normalize(extractJson(completion.text));
|
|
289
|
+
const parsed = normalize(extractJson(completion.text), args.productCatalog);
|
|
287
290
|
const durationMs = Date.now() - started;
|
|
288
291
|
await logAiCall(admin, {
|
|
289
292
|
moduleKey: cfg.moduleKey,
|
|
@@ -160,6 +160,7 @@ export declare const approveProposal: import("@tanstack/start-client-core").Opti
|
|
|
160
160
|
ok: true;
|
|
161
161
|
orderId: string;
|
|
162
162
|
orderNumber: string;
|
|
163
|
+
alreadyApproved: boolean;
|
|
163
164
|
shortages: any[];
|
|
164
165
|
}>>;
|
|
165
166
|
export declare const rejectProposal: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailbox.functions.d.ts","sourceRoot":"","sources":["../../src/lib/mailbox.functions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"mailbox.functions.d.ts","sourceRoot":"","sources":["../../src/lib/mailbox.functions.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@ import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
|
|
|
4
4
|
import { createClient } from "@supabase/supabase-js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { computeEarliestDelivery } from "../lib/delivery-date";
|
|
7
|
-
import { stripLeadingQuantity } from "../lib/product-name";
|
|
8
7
|
import { emailBodyText, inlineCidImages, normalizeAddressList, normalizeAttachments, sanitizeEmailHtml, stripInvisible, } from "./mailbox-body";
|
|
9
8
|
import { EMPTY_LOAD_CARRIERS, isLoadCarrierAllowed, loadCarrierLabel, normalizeAllowedLoadCarriers, } from "./load-carriers";
|
|
10
9
|
// ─── Actieve mailbox (uit gedeelde e-mail-auth module) ──────────────────────
|
|
@@ -329,76 +328,37 @@ export const approveProposal = createServerFn({ method: "POST" })
|
|
|
329
328
|
throw new Error(blockText);
|
|
330
329
|
}
|
|
331
330
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
customer_name: data.customerName,
|
|
337
|
-
customer_id: data.customerId,
|
|
338
|
-
order_date: new Date().toISOString().slice(0, 10),
|
|
339
|
-
delivery_date: data.deliveryDate,
|
|
340
|
-
status: "nieuw",
|
|
341
|
-
total: "0",
|
|
342
|
-
notes: data.notes,
|
|
343
|
-
custom_fields: { ...customFields, source: "mailbox" },
|
|
344
|
-
}).select("id").single();
|
|
345
|
-
if (orderErr)
|
|
346
|
-
throw new Error(orderErr.message);
|
|
347
|
-
// Productnaam altijd uit de catalogus; alleen zonder koppeling terugvallen
|
|
348
|
-
// op de (opgeschoonde) tekst uit de mail.
|
|
349
|
-
const linkedIds = Array.from(new Set(data.lines.map((l) => l.product_id).filter((v) => !!v)));
|
|
350
|
-
const nameById = new Map();
|
|
351
|
-
if (linkedIds.length > 0) {
|
|
352
|
-
const { data: prodRows } = await supabaseAdmin
|
|
353
|
-
.from("products")
|
|
354
|
-
.select("id, product")
|
|
355
|
-
.in("id", linkedIds);
|
|
356
|
-
for (const p of Array.isArray(prodRows) ? prodRows : []) {
|
|
357
|
-
const n = typeof p?.product === "string" ? p.product.trim() : "";
|
|
358
|
-
if (n)
|
|
359
|
-
nameById.set(String(p.id), n);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
const items = data.lines.map((l) => ({
|
|
363
|
-
order_id: order.id,
|
|
364
|
-
product_id: l.product_id,
|
|
365
|
-
product_name: (l.product_id ? nameById.get(l.product_id) : null) ||
|
|
366
|
-
stripLeadingQuantity(l.raw_product_text) ||
|
|
367
|
-
"Onbekend product",
|
|
368
|
-
quantity: Math.max(1, Math.round(l.quantity ?? 1)),
|
|
369
|
-
unit: l.unit ?? "stuks",
|
|
370
|
-
}));
|
|
371
|
-
const { error: itemsErr } = await supabaseAdmin.from("order_items").insert(items);
|
|
372
|
-
if (itemsErr)
|
|
373
|
-
throw new Error(itemsErr.message);
|
|
374
|
-
if (data.fieldValues && data.fieldValues.length > 0) {
|
|
375
|
-
for (const fv of data.fieldValues) {
|
|
376
|
-
await supabaseAdmin.from("mailbox_proposal_field_values").upsert({
|
|
377
|
-
proposal_id: data.proposalId,
|
|
378
|
-
field_key: fv.field_key,
|
|
379
|
-
value: fv.value === undefined ? null : fv.value,
|
|
380
|
-
ai_filled: false,
|
|
381
|
-
needs_review: false,
|
|
382
|
-
}, { onConflict: "proposal_id,field_key" });
|
|
383
|
-
}
|
|
331
|
+
if (!data.customerId)
|
|
332
|
+
throw new Error("Selecteer een bestaande klant.");
|
|
333
|
+
if (data.lines.some((line) => !line.product_id || !line.quantity || line.quantity <= 0)) {
|
|
334
|
+
throw new Error("Iedere bestelregel moet aan een bestaand product gekoppeld zijn.");
|
|
384
335
|
}
|
|
385
|
-
await supabaseAdmin.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
.
|
|
393
|
-
|
|
394
|
-
|
|
336
|
+
const { data: approval, error: approvalError } = await supabaseAdmin.rpc("approve_mailbox_order_proposal", {
|
|
337
|
+
p_proposal_id: data.proposalId,
|
|
338
|
+
p_reviewed_by: context.userId,
|
|
339
|
+
p_customer_id: data.customerId,
|
|
340
|
+
p_delivery_date: data.deliveryDate,
|
|
341
|
+
p_notes: data.notes ?? "",
|
|
342
|
+
p_custom_fields: customFields,
|
|
343
|
+
p_lines: data.lines.map((line) => ({
|
|
344
|
+
product_id: line.product_id,
|
|
345
|
+
quantity: line.quantity,
|
|
346
|
+
unit: line.unit,
|
|
347
|
+
})),
|
|
348
|
+
p_field_values: data.fieldValues ?? [],
|
|
349
|
+
});
|
|
350
|
+
if (approvalError)
|
|
351
|
+
throw new Error(approvalError.message);
|
|
352
|
+
const result = approval;
|
|
353
|
+
if (!result?.orderId || !result.orderNumber) {
|
|
354
|
+
throw new Error("Bestelling kon niet veilig worden aangemaakt.");
|
|
395
355
|
}
|
|
396
356
|
// ─── Gebeurtenis melden aan de Logistics Engine ─────────────────────────
|
|
397
357
|
const deliveryLocationRef = typeof customFields["delivery_location"] === "string" ? customFields["delivery_location"] : null;
|
|
398
358
|
await context.supabase.rpc("logistics_emit_event", {
|
|
399
359
|
p_source_module: "mailbox",
|
|
400
360
|
p_event_type: "order.received",
|
|
401
|
-
p_order_ref: orderNumber,
|
|
361
|
+
p_order_ref: result.orderNumber,
|
|
402
362
|
p_payload: {
|
|
403
363
|
checkinAt: data.deliveryDate,
|
|
404
364
|
pickupAt: data.deliveryDate,
|
|
@@ -410,9 +370,15 @@ export const approveProposal = createServerFn({ method: "POST" })
|
|
|
410
370
|
ruleVersion: null,
|
|
411
371
|
},
|
|
412
372
|
p_shadow: true,
|
|
413
|
-
p_idempotency_key: `mailbox:${
|
|
373
|
+
p_idempotency_key: `mailbox:${data.proposalId}:order.received:v1`,
|
|
414
374
|
});
|
|
415
|
-
return {
|
|
375
|
+
return {
|
|
376
|
+
ok: true,
|
|
377
|
+
orderId: result.orderId,
|
|
378
|
+
orderNumber: result.orderNumber,
|
|
379
|
+
alreadyApproved: result.alreadyApproved === true,
|
|
380
|
+
shortages,
|
|
381
|
+
};
|
|
416
382
|
});
|
|
417
383
|
export const rejectProposal = createServerFn({ method: "POST" })
|
|
418
384
|
.middleware([requireSupabaseAuth])
|
|
@@ -540,106 +506,14 @@ export const createCustomerFromGroup = createServerFn({ method: "POST" })
|
|
|
540
506
|
throw new Error(error.message);
|
|
541
507
|
return { id: inserted.id, created: true };
|
|
542
508
|
});
|
|
543
|
-
// Producten voor de picker
|
|
544
|
-
//
|
|
545
|
-
//
|
|
546
|
-
// geen products-rij heeft, wordt hier automatisch aangemaakt (id = floriday_id)
|
|
547
|
-
// zodat bestelregels, belading en orders er gewoon naar kunnen verwijzen
|
|
548
|
-
// Voorraad komt uit `trade_item_stock` en `trade_item_stock_view`.
|
|
509
|
+
// Producten voor de picker: uitsluitend bestaande rijen uit `products`.
|
|
510
|
+
// Deze module maakt nooit zelf artikelen aan. Voorraad wordt alleen als
|
|
511
|
+
// aanvullende informatie opgehaald uit de Voorraad Module.
|
|
549
512
|
export const listProductsForPicker = createServerFn({ method: "GET" })
|
|
550
513
|
.middleware([requireSupabaseAuth])
|
|
551
514
|
.handler(async ({ context }) => {
|
|
552
515
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server");
|
|
553
|
-
// ── 1.
|
|
554
|
-
const { data: cacheRows } = await supabaseAdmin
|
|
555
|
-
.from("floriday_trade_items_cache")
|
|
556
|
-
.select("floriday_id, is_deleted, data")
|
|
557
|
-
.range(0, 4999);
|
|
558
|
-
const tradeItems = (Array.isArray(cacheRows) ? cacheRows : []).filter((r) => !r?.is_deleted && typeof r?.floriday_id === "string");
|
|
559
|
-
const { data: existingRows } = await supabaseAdmin
|
|
560
|
-
.from("products")
|
|
561
|
-
.select("id, custom_fields, floriday_trade_item_id")
|
|
562
|
-
.range(0, 9999);
|
|
563
|
-
const existing = Array.isArray(existingRows) ? existingRows : [];
|
|
564
|
-
const known = new Set();
|
|
565
|
-
for (const p of existing) {
|
|
566
|
-
known.add(String(p.id));
|
|
567
|
-
const fid = p?.custom_fields?.floriday_id ?? p?.floriday_trade_item_id;
|
|
568
|
-
if (typeof fid === "string" && fid)
|
|
569
|
-
known.add(fid);
|
|
570
|
-
}
|
|
571
|
-
const norm = (v) => Math.max(1, Math.round(Number(v ?? 1)) || 1);
|
|
572
|
-
const nameOf = (d) => {
|
|
573
|
-
const n = d?.tradeItemName;
|
|
574
|
-
if (typeof n === "string" && n.trim())
|
|
575
|
-
return n.trim();
|
|
576
|
-
if (n && typeof n === "object") {
|
|
577
|
-
const v = n.nl ?? n.en ?? Object.values(n).find((x) => typeof x === "string");
|
|
578
|
-
if (typeof v === "string" && v.trim())
|
|
579
|
-
return v.trim();
|
|
580
|
-
}
|
|
581
|
-
return typeof d?.tradeItemReference === "string" && d.tradeItemReference
|
|
582
|
-
? d.tradeItemReference
|
|
583
|
-
: "Onbekend artikel";
|
|
584
|
-
};
|
|
585
|
-
const missing = tradeItems.filter((r) => !known.has(r.floriday_id));
|
|
586
|
-
const buildRow = (r) => {
|
|
587
|
-
const d = r.data ?? {};
|
|
588
|
-
const pk = Array.isArray(d.packingConfigurations) ? d.packingConfigurations[0] ?? {} : {};
|
|
589
|
-
return {
|
|
590
|
-
id: r.floriday_id,
|
|
591
|
-
product: nameOf(d),
|
|
592
|
-
// batch + location zijn NOT NULL zonder default in de Voorraad Module
|
|
593
|
-
batch: "",
|
|
594
|
-
location: "",
|
|
595
|
-
unit: "stuks",
|
|
596
|
-
quantity: 0,
|
|
597
|
-
plants_per_crate: norm(pk?.piecesPerPackage ?? pk?.unitsPerPackage),
|
|
598
|
-
crates_per_layer: norm(pk?.packagesPerLayer),
|
|
599
|
-
layers_per_cart: norm(pk?.layersPerLoadCarrier),
|
|
600
|
-
floriday_trade_item_id: r.floriday_id,
|
|
601
|
-
article_number: typeof d?.supplierArticleCode === "string" ? d.supplierArticleCode : null,
|
|
602
|
-
custom_fields: { floriday_id: r.floriday_id, source: "floriday_trade_items_cache" },
|
|
603
|
-
};
|
|
604
|
-
};
|
|
605
|
-
// Concept-artikelen uit de Voorraad Module (nog niet in Floriday) ook tonen
|
|
606
|
-
const { data: draftRowsAll } = await supabaseAdmin
|
|
607
|
-
.from("trade_item_drafts")
|
|
608
|
-
.select("id, data, floriday_id")
|
|
609
|
-
.range(0, 4999);
|
|
610
|
-
const draftMissing = (Array.isArray(draftRowsAll) ? draftRowsAll : []).filter((d) => typeof d?.id === "string" && !known.has(d.id) &&
|
|
611
|
-
!(typeof d?.floriday_id === "string" && known.has(d.floriday_id)));
|
|
612
|
-
const buildDraftRow = (r) => {
|
|
613
|
-
const d = r.data ?? {};
|
|
614
|
-
const pk = Array.isArray(d.packingConfigurations) ? d.packingConfigurations[0] ?? {} : {};
|
|
615
|
-
return {
|
|
616
|
-
id: r.id,
|
|
617
|
-
product: nameOf(d),
|
|
618
|
-
batch: "",
|
|
619
|
-
location: "",
|
|
620
|
-
unit: "stuks",
|
|
621
|
-
quantity: 0,
|
|
622
|
-
plants_per_crate: norm(pk?.unitsPerPackage ?? pk?.piecesPerPackage),
|
|
623
|
-
crates_per_layer: norm(pk?.packagesPerLayer),
|
|
624
|
-
layers_per_cart: norm(pk?.layersPerLoadCarrier),
|
|
625
|
-
article_number: typeof d?.supplierArticleCode === "string" ? d.supplierArticleCode : null,
|
|
626
|
-
custom_fields: { draft_id: r.id, source: "trade_item_drafts" },
|
|
627
|
-
};
|
|
628
|
-
};
|
|
629
|
-
const toInsert = [...missing.map(buildRow), ...draftMissing.map(buildDraftRow)];
|
|
630
|
-
// Artikelen die (nog) niet in `products` staan, tonen we hoe dan ook —
|
|
631
|
-
// ook als materialiseren faalt.
|
|
632
|
-
let virtualRows = [];
|
|
633
|
-
if (toInsert.length > 0) {
|
|
634
|
-
const { error: upsertError } = await supabaseAdmin
|
|
635
|
-
.from("products")
|
|
636
|
-
.upsert(toInsert, { onConflict: "id" });
|
|
637
|
-
if (upsertError) {
|
|
638
|
-
console.error("[listProductsForPicker] materialiseren mislukt:", upsertError.message);
|
|
639
|
-
virtualRows = toInsert;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
// ── 2. Voorraad verzamelen ──────────────────────────────────────────────
|
|
516
|
+
// ── 1. Voorraad verzamelen ──────────────────────────────────────────────
|
|
643
517
|
const { data: stockRows } = await supabaseAdmin
|
|
644
518
|
.from("trade_item_stock")
|
|
645
519
|
.select("trade_item_key, physical_stock, reserved_stock");
|
|
@@ -675,8 +549,6 @@ export const listProductsForPicker = createServerFn({ method: "GET" })
|
|
|
675
549
|
.in("id", Array.from(availByDraftId.keys()));
|
|
676
550
|
for (const d of Array.isArray(drafts) ? drafts : []) {
|
|
677
551
|
const qty = availByDraftId.get(d.id) ?? 0;
|
|
678
|
-
// Concepten worden ook als product gematerialiseerd op hun eigen id
|
|
679
|
-
addAvail(availByProductId, d.id, qty);
|
|
680
552
|
const linked = d?.data?.linkedProductId;
|
|
681
553
|
if (typeof linked === "string" && linked)
|
|
682
554
|
addAvail(availByProductId, linked, qty);
|
|
@@ -702,19 +574,13 @@ export const listProductsForPicker = createServerFn({ method: "GET" })
|
|
|
702
574
|
catch {
|
|
703
575
|
// view optioneel
|
|
704
576
|
}
|
|
705
|
-
// ──
|
|
577
|
+
// ── 2. Alle bestaande producten teruggeven ─────────────────────────────
|
|
706
578
|
const { data } = await supabaseAdmin
|
|
707
579
|
.from("products")
|
|
708
580
|
.select("id, product, unit, plants_per_crate, crates_per_layer, layers_per_cart, custom_fields, floriday_trade_item_id")
|
|
709
581
|
.order("product")
|
|
710
582
|
.range(0, 9999);
|
|
711
|
-
const
|
|
712
|
-
const seen = new Set(dbRows.map((p) => String(p.id)));
|
|
713
|
-
const allRows = [
|
|
714
|
-
...dbRows,
|
|
715
|
-
...virtualRows.filter((v) => !seen.has(String(v.id))),
|
|
716
|
-
];
|
|
717
|
-
const items = allRows
|
|
583
|
+
const items = (Array.isArray(data) ? data : [])
|
|
718
584
|
.map((p) => {
|
|
719
585
|
const fid = p?.custom_fields?.floriday_id ?? p?.floriday_trade_item_id;
|
|
720
586
|
const byProd = availByProductId.get(p.id) ?? 0;
|