@flowselections/mailbox-orders 1.0.14 → 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 +927 -133
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +927 -133
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +936 -137
- 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 -154
- package/dist-lib/lib/product-name.d.ts +3 -0
- package/dist-lib/lib/product-name.d.ts.map +1 -0
- package/dist-lib/lib/product-name.js +10 -0
- 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":"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"}
|
|
@@ -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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"}
|
|
@@ -328,59 +328,37 @@ export const approveProposal = createServerFn({ method: "POST" })
|
|
|
328
328
|
throw new Error(blockText);
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
customer_name: data.customerName,
|
|
336
|
-
customer_id: data.customerId,
|
|
337
|
-
order_date: new Date().toISOString().slice(0, 10),
|
|
338
|
-
delivery_date: data.deliveryDate,
|
|
339
|
-
status: "nieuw",
|
|
340
|
-
total: "0",
|
|
341
|
-
notes: data.notes,
|
|
342
|
-
custom_fields: { ...customFields, source: "mailbox" },
|
|
343
|
-
}).select("id").single();
|
|
344
|
-
if (orderErr)
|
|
345
|
-
throw new Error(orderErr.message);
|
|
346
|
-
const items = data.lines.map((l) => ({
|
|
347
|
-
order_id: order.id,
|
|
348
|
-
product_id: l.product_id,
|
|
349
|
-
product_name: l.raw_product_text || "Onbekend product",
|
|
350
|
-
quantity: Math.max(1, Math.round(l.quantity ?? 1)),
|
|
351
|
-
unit: l.unit ?? "stuks",
|
|
352
|
-
}));
|
|
353
|
-
const { error: itemsErr } = await supabaseAdmin.from("order_items").insert(items);
|
|
354
|
-
if (itemsErr)
|
|
355
|
-
throw new Error(itemsErr.message);
|
|
356
|
-
if (data.fieldValues && data.fieldValues.length > 0) {
|
|
357
|
-
for (const fv of data.fieldValues) {
|
|
358
|
-
await supabaseAdmin.from("mailbox_proposal_field_values").upsert({
|
|
359
|
-
proposal_id: data.proposalId,
|
|
360
|
-
field_key: fv.field_key,
|
|
361
|
-
value: fv.value === undefined ? null : fv.value,
|
|
362
|
-
ai_filled: false,
|
|
363
|
-
needs_review: false,
|
|
364
|
-
}, { onConflict: "proposal_id,field_key" });
|
|
365
|
-
}
|
|
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.");
|
|
366
335
|
}
|
|
367
|
-
await supabaseAdmin.
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
.
|
|
375
|
-
|
|
376
|
-
|
|
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.");
|
|
377
355
|
}
|
|
378
356
|
// ─── Gebeurtenis melden aan de Logistics Engine ─────────────────────────
|
|
379
357
|
const deliveryLocationRef = typeof customFields["delivery_location"] === "string" ? customFields["delivery_location"] : null;
|
|
380
358
|
await context.supabase.rpc("logistics_emit_event", {
|
|
381
359
|
p_source_module: "mailbox",
|
|
382
360
|
p_event_type: "order.received",
|
|
383
|
-
p_order_ref: orderNumber,
|
|
361
|
+
p_order_ref: result.orderNumber,
|
|
384
362
|
p_payload: {
|
|
385
363
|
checkinAt: data.deliveryDate,
|
|
386
364
|
pickupAt: data.deliveryDate,
|
|
@@ -392,9 +370,15 @@ export const approveProposal = createServerFn({ method: "POST" })
|
|
|
392
370
|
ruleVersion: null,
|
|
393
371
|
},
|
|
394
372
|
p_shadow: true,
|
|
395
|
-
p_idempotency_key: `mailbox:${
|
|
373
|
+
p_idempotency_key: `mailbox:${data.proposalId}:order.received:v1`,
|
|
396
374
|
});
|
|
397
|
-
return {
|
|
375
|
+
return {
|
|
376
|
+
ok: true,
|
|
377
|
+
orderId: result.orderId,
|
|
378
|
+
orderNumber: result.orderNumber,
|
|
379
|
+
alreadyApproved: result.alreadyApproved === true,
|
|
380
|
+
shortages,
|
|
381
|
+
};
|
|
398
382
|
});
|
|
399
383
|
export const rejectProposal = createServerFn({ method: "POST" })
|
|
400
384
|
.middleware([requireSupabaseAuth])
|
|
@@ -522,106 +506,14 @@ export const createCustomerFromGroup = createServerFn({ method: "POST" })
|
|
|
522
506
|
throw new Error(error.message);
|
|
523
507
|
return { id: inserted.id, created: true };
|
|
524
508
|
});
|
|
525
|
-
// Producten voor de picker
|
|
526
|
-
//
|
|
527
|
-
//
|
|
528
|
-
// geen products-rij heeft, wordt hier automatisch aangemaakt (id = floriday_id)
|
|
529
|
-
// zodat bestelregels, belading en orders er gewoon naar kunnen verwijzen
|
|
530
|
-
// 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.
|
|
531
512
|
export const listProductsForPicker = createServerFn({ method: "GET" })
|
|
532
513
|
.middleware([requireSupabaseAuth])
|
|
533
514
|
.handler(async ({ context }) => {
|
|
534
515
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server");
|
|
535
|
-
// ── 1.
|
|
536
|
-
const { data: cacheRows } = await supabaseAdmin
|
|
537
|
-
.from("floriday_trade_items_cache")
|
|
538
|
-
.select("floriday_id, is_deleted, data")
|
|
539
|
-
.range(0, 4999);
|
|
540
|
-
const tradeItems = (Array.isArray(cacheRows) ? cacheRows : []).filter((r) => !r?.is_deleted && typeof r?.floriday_id === "string");
|
|
541
|
-
const { data: existingRows } = await supabaseAdmin
|
|
542
|
-
.from("products")
|
|
543
|
-
.select("id, custom_fields, floriday_trade_item_id")
|
|
544
|
-
.range(0, 9999);
|
|
545
|
-
const existing = Array.isArray(existingRows) ? existingRows : [];
|
|
546
|
-
const known = new Set();
|
|
547
|
-
for (const p of existing) {
|
|
548
|
-
known.add(String(p.id));
|
|
549
|
-
const fid = p?.custom_fields?.floriday_id ?? p?.floriday_trade_item_id;
|
|
550
|
-
if (typeof fid === "string" && fid)
|
|
551
|
-
known.add(fid);
|
|
552
|
-
}
|
|
553
|
-
const norm = (v) => Math.max(1, Math.round(Number(v ?? 1)) || 1);
|
|
554
|
-
const nameOf = (d) => {
|
|
555
|
-
const n = d?.tradeItemName;
|
|
556
|
-
if (typeof n === "string" && n.trim())
|
|
557
|
-
return n.trim();
|
|
558
|
-
if (n && typeof n === "object") {
|
|
559
|
-
const v = n.nl ?? n.en ?? Object.values(n).find((x) => typeof x === "string");
|
|
560
|
-
if (typeof v === "string" && v.trim())
|
|
561
|
-
return v.trim();
|
|
562
|
-
}
|
|
563
|
-
return typeof d?.tradeItemReference === "string" && d.tradeItemReference
|
|
564
|
-
? d.tradeItemReference
|
|
565
|
-
: "Onbekend artikel";
|
|
566
|
-
};
|
|
567
|
-
const missing = tradeItems.filter((r) => !known.has(r.floriday_id));
|
|
568
|
-
const buildRow = (r) => {
|
|
569
|
-
const d = r.data ?? {};
|
|
570
|
-
const pk = Array.isArray(d.packingConfigurations) ? d.packingConfigurations[0] ?? {} : {};
|
|
571
|
-
return {
|
|
572
|
-
id: r.floriday_id,
|
|
573
|
-
product: nameOf(d),
|
|
574
|
-
// batch + location zijn NOT NULL zonder default in de Voorraad Module
|
|
575
|
-
batch: "",
|
|
576
|
-
location: "",
|
|
577
|
-
unit: "stuks",
|
|
578
|
-
quantity: 0,
|
|
579
|
-
plants_per_crate: norm(pk?.piecesPerPackage ?? pk?.unitsPerPackage),
|
|
580
|
-
crates_per_layer: norm(pk?.packagesPerLayer),
|
|
581
|
-
layers_per_cart: norm(pk?.layersPerLoadCarrier),
|
|
582
|
-
floriday_trade_item_id: r.floriday_id,
|
|
583
|
-
article_number: typeof d?.supplierArticleCode === "string" ? d.supplierArticleCode : null,
|
|
584
|
-
custom_fields: { floriday_id: r.floriday_id, source: "floriday_trade_items_cache" },
|
|
585
|
-
};
|
|
586
|
-
};
|
|
587
|
-
// Concept-artikelen uit de Voorraad Module (nog niet in Floriday) ook tonen
|
|
588
|
-
const { data: draftRowsAll } = await supabaseAdmin
|
|
589
|
-
.from("trade_item_drafts")
|
|
590
|
-
.select("id, data, floriday_id")
|
|
591
|
-
.range(0, 4999);
|
|
592
|
-
const draftMissing = (Array.isArray(draftRowsAll) ? draftRowsAll : []).filter((d) => typeof d?.id === "string" && !known.has(d.id) &&
|
|
593
|
-
!(typeof d?.floriday_id === "string" && known.has(d.floriday_id)));
|
|
594
|
-
const buildDraftRow = (r) => {
|
|
595
|
-
const d = r.data ?? {};
|
|
596
|
-
const pk = Array.isArray(d.packingConfigurations) ? d.packingConfigurations[0] ?? {} : {};
|
|
597
|
-
return {
|
|
598
|
-
id: r.id,
|
|
599
|
-
product: nameOf(d),
|
|
600
|
-
batch: "",
|
|
601
|
-
location: "",
|
|
602
|
-
unit: "stuks",
|
|
603
|
-
quantity: 0,
|
|
604
|
-
plants_per_crate: norm(pk?.unitsPerPackage ?? pk?.piecesPerPackage),
|
|
605
|
-
crates_per_layer: norm(pk?.packagesPerLayer),
|
|
606
|
-
layers_per_cart: norm(pk?.layersPerLoadCarrier),
|
|
607
|
-
article_number: typeof d?.supplierArticleCode === "string" ? d.supplierArticleCode : null,
|
|
608
|
-
custom_fields: { draft_id: r.id, source: "trade_item_drafts" },
|
|
609
|
-
};
|
|
610
|
-
};
|
|
611
|
-
const toInsert = [...missing.map(buildRow), ...draftMissing.map(buildDraftRow)];
|
|
612
|
-
// Artikelen die (nog) niet in `products` staan, tonen we hoe dan ook —
|
|
613
|
-
// ook als materialiseren faalt.
|
|
614
|
-
let virtualRows = [];
|
|
615
|
-
if (toInsert.length > 0) {
|
|
616
|
-
const { error: upsertError } = await supabaseAdmin
|
|
617
|
-
.from("products")
|
|
618
|
-
.upsert(toInsert, { onConflict: "id" });
|
|
619
|
-
if (upsertError) {
|
|
620
|
-
console.error("[listProductsForPicker] materialiseren mislukt:", upsertError.message);
|
|
621
|
-
virtualRows = toInsert;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
// ── 2. Voorraad verzamelen ──────────────────────────────────────────────
|
|
516
|
+
// ── 1. Voorraad verzamelen ──────────────────────────────────────────────
|
|
625
517
|
const { data: stockRows } = await supabaseAdmin
|
|
626
518
|
.from("trade_item_stock")
|
|
627
519
|
.select("trade_item_key, physical_stock, reserved_stock");
|
|
@@ -657,8 +549,6 @@ export const listProductsForPicker = createServerFn({ method: "GET" })
|
|
|
657
549
|
.in("id", Array.from(availByDraftId.keys()));
|
|
658
550
|
for (const d of Array.isArray(drafts) ? drafts : []) {
|
|
659
551
|
const qty = availByDraftId.get(d.id) ?? 0;
|
|
660
|
-
// Concepten worden ook als product gematerialiseerd op hun eigen id
|
|
661
|
-
addAvail(availByProductId, d.id, qty);
|
|
662
552
|
const linked = d?.data?.linkedProductId;
|
|
663
553
|
if (typeof linked === "string" && linked)
|
|
664
554
|
addAvail(availByProductId, linked, qty);
|
|
@@ -684,19 +574,13 @@ export const listProductsForPicker = createServerFn({ method: "GET" })
|
|
|
684
574
|
catch {
|
|
685
575
|
// view optioneel
|
|
686
576
|
}
|
|
687
|
-
// ──
|
|
577
|
+
// ── 2. Alle bestaande producten teruggeven ─────────────────────────────
|
|
688
578
|
const { data } = await supabaseAdmin
|
|
689
579
|
.from("products")
|
|
690
580
|
.select("id, product, unit, plants_per_crate, crates_per_layer, layers_per_cart, custom_fields, floriday_trade_item_id")
|
|
691
581
|
.order("product")
|
|
692
582
|
.range(0, 9999);
|
|
693
|
-
const
|
|
694
|
-
const seen = new Set(dbRows.map((p) => String(p.id)));
|
|
695
|
-
const allRows = [
|
|
696
|
-
...dbRows,
|
|
697
|
-
...virtualRows.filter((v) => !seen.has(String(v.id))),
|
|
698
|
-
];
|
|
699
|
-
const items = allRows
|
|
583
|
+
const items = (Array.isArray(data) ? data : [])
|
|
700
584
|
.map((p) => {
|
|
701
585
|
const fid = p?.custom_fields?.floriday_id ?? p?.floriday_trade_item_id;
|
|
702
586
|
const byProd = availByProductId.get(p.id) ?? 0;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-name.d.ts","sourceRoot":"","sources":["../../src/lib/product-name.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAO5E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Haalt een aantal-prefix ("3x ", "3 x ", "10 stuks ") weg uit ruwe mailtekst. */
|
|
2
|
+
export function stripLeadingQuantity(text) {
|
|
3
|
+
const t = (text ?? "").trim();
|
|
4
|
+
if (!t)
|
|
5
|
+
return "";
|
|
6
|
+
const cleaned = t
|
|
7
|
+
.replace(/^\d+[.,]?\d*\s*(x|st|stk|stuks|stuk|planten|plant|fust|fusten|pcs)?\s*[-:·]?\s*/i, "")
|
|
8
|
+
.trim();
|
|
9
|
+
return cleaned || t;
|
|
10
|
+
}
|