@flowselections/floriday-voorraad 1.0.94 → 1.0.96
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/components/voorraad/ArtikelWizard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ArtikelWizard.js +21 -41
- package/dist-lib/components/voorraad/FloridayTakeoverPanel.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FloridayTakeoverPanel.js +18 -1
- package/dist-lib/components/voorraad/StockBulkButtons.d.ts.map +1 -1
- package/dist-lib/components/voorraad/StockBulkButtons.js +59 -0
- package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadTable.js +16 -1
- package/dist-lib/integrations/supabase/types.d.ts +282 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/__tests__/product-packings.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/product-packings.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/product-packings.test.js +42 -0
- package/dist-lib/lib/ensure-article-codes.d.ts.map +1 -1
- package/dist-lib/lib/ensure-article-codes.js +2 -12
- package/dist-lib/lib/floriday-payload.d.ts +15 -0
- package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
- package/dist-lib/lib/floriday-payload.js +36 -10
- package/dist-lib/lib/fusten.d.ts.map +1 -1
- package/dist-lib/lib/fusten.js +6 -1
- package/dist-lib/lib/product-packing.d.ts +8 -5
- package/dist-lib/lib/product-packing.d.ts.map +1 -1
- package/dist-lib/lib/product-packing.js +44 -36
- package/dist-lib/lib/product-packings.d.ts +33 -0
- package/dist-lib/lib/product-packings.d.ts.map +1 -0
- package/dist-lib/lib/product-packings.js +89 -0
- package/dist-lib/server-hooks/floriday-follow.d.ts.map +1 -1
- package/dist-lib/server-hooks/floriday-follow.js +11 -1
- package/package.json +1 -1
- package/sql/AGENTS.md +5 -0
- package/sql/floriday-voorraad-schema.sql +182 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArtikelWizard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelWizard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ArtikelWizard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelWizard.tsx"],"names":[],"mappings":"AA8MA,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,cAAc,EACvB,WAAW,EACX,SAAS,EACT,WAAW,GACZ,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,+BA0tEL"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { saveOwnPackings, packingRowsFromWizard } from "../../lib/product-packings.js";
|
|
2
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
4
|
import { Link, useNavigate } from "@tanstack/react-router";
|
|
4
5
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Button, Card, CardContent, Checkbox, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, toast, } from "@flowselections/core";
|
|
@@ -405,11 +406,12 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
|
|
|
405
406
|
? crypto.randomUUID()
|
|
406
407
|
: `pk-${Date.now()}`,
|
|
407
408
|
source: "VBN",
|
|
408
|
-
loadCarrier: "
|
|
409
|
+
loadCarrier: "",
|
|
409
410
|
packagingType: "",
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
411
|
+
// Leeg laten wat niet bekend is; nooit aanvullen.
|
|
412
|
+
unitsPerPackage: ppc,
|
|
413
|
+
packagesPerLayer: cpl,
|
|
414
|
+
layersPerLoadCarrier: lpc,
|
|
413
415
|
isPrimary: true,
|
|
414
416
|
isCustomerSpecific: false,
|
|
415
417
|
customerOrganizationIds: [],
|
|
@@ -1424,36 +1426,23 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
|
|
|
1424
1426
|
if (!item) {
|
|
1425
1427
|
throw new Error("Het product kon niet worden teruggelezen");
|
|
1426
1428
|
}
|
|
1427
|
-
//
|
|
1428
|
-
try {
|
|
1429
|
-
await supabase
|
|
1430
|
-
.from("floriday_trade_items_cache")
|
|
1431
|
-
.update({
|
|
1432
|
-
data: item,
|
|
1433
|
-
fetched_at: new Date().toISOString(),
|
|
1434
|
-
})
|
|
1435
|
-
.eq("connection_id", activeId)
|
|
1436
|
-
.eq("floriday_id", resolvedTradeItemId);
|
|
1437
|
-
}
|
|
1438
|
-
catch {
|
|
1439
|
-
/* wordt automatisch bijgewerkt bij de volgende synchronisatie */
|
|
1440
|
-
}
|
|
1429
|
+
// De Floriday-kopie is van Floriday-authenticatie; Voorraad schrijft er nooit in.
|
|
1441
1430
|
// Floriday heeft de belading nu bevestigd: direct wegschrijven op
|
|
1442
1431
|
// het product, zodat andere modules niet hoeven te wachten op de
|
|
1443
1432
|
// 5-minuten-cron. De trigger/cron blijft het vangnet.
|
|
1444
1433
|
const targetProductId = productId ?? draftId ?? null;
|
|
1445
1434
|
const confirmedPacking = pickPrimaryPacking(item?.packingConfigurations);
|
|
1446
|
-
if (targetProductId
|
|
1435
|
+
if (targetProductId) {
|
|
1447
1436
|
try {
|
|
1448
1437
|
await writeConfirmedPacking({
|
|
1449
1438
|
productId: targetProductId,
|
|
1450
|
-
|
|
1451
|
-
|
|
1439
|
+
connectionId: activeId,
|
|
1440
|
+
item,
|
|
1452
1441
|
});
|
|
1453
1442
|
setPackingStatus({
|
|
1454
|
-
known:
|
|
1455
|
-
confirmedAt: new Date().toISOString(),
|
|
1456
|
-
source: "
|
|
1443
|
+
known: Boolean(confirmedPacking),
|
|
1444
|
+
confirmedAt: confirmedPacking ? new Date().toISOString() : null,
|
|
1445
|
+
source: "product_packings:floriday",
|
|
1457
1446
|
packing: confirmedPacking,
|
|
1458
1447
|
});
|
|
1459
1448
|
}
|
|
@@ -1553,6 +1542,10 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
|
|
|
1553
1542
|
if (draftFloridayId && data.warehouseId) {
|
|
1554
1543
|
await saveWarehousePreference(draftFloridayId, data.warehouseId);
|
|
1555
1544
|
}
|
|
1545
|
+
// Eigen artikel (zonder Floriday): verpakkingen uit de wizard opslaan.
|
|
1546
|
+
if (newId && !draftFloridayId && !publishedTradeItemId) {
|
|
1547
|
+
await saveOwnPackings(newId, packingRowsFromWizard(data.packingConfigurations));
|
|
1548
|
+
}
|
|
1556
1549
|
setDraftId(newId);
|
|
1557
1550
|
toast.success(draftId ? "Artikel bijgewerkt" : "Artikel opgeslagen");
|
|
1558
1551
|
navigate({ to: "/voorraad" });
|
|
@@ -1586,6 +1579,9 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
|
|
|
1586
1579
|
});
|
|
1587
1580
|
if (localId && localId !== draftId)
|
|
1588
1581
|
setDraftId(localId);
|
|
1582
|
+
if (localId && !pushTargetId) {
|
|
1583
|
+
await saveOwnPackings(localId, packingRowsFromWizard(snapshot.packingConfigurations));
|
|
1584
|
+
}
|
|
1589
1585
|
}
|
|
1590
1586
|
catch (e) {
|
|
1591
1587
|
const msg = e.message || "Onbekende fout";
|
|
@@ -1624,23 +1620,7 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
|
|
|
1624
1620
|
if (!res?.attemptId) {
|
|
1625
1621
|
throw new Error("Gateway gaf geen attemptId terug");
|
|
1626
1622
|
}
|
|
1627
|
-
|
|
1628
|
-
const cachePayload = {
|
|
1629
|
-
...buildAddTradeItemPayload(snapshot),
|
|
1630
|
-
tradeItemId: pushTargetId,
|
|
1631
|
-
};
|
|
1632
|
-
await supabase
|
|
1633
|
-
.from("floriday_trade_items_cache")
|
|
1634
|
-
.update({
|
|
1635
|
-
data: cachePayload,
|
|
1636
|
-
fetched_at: new Date().toISOString(),
|
|
1637
|
-
})
|
|
1638
|
-
.eq("connection_id", activeId)
|
|
1639
|
-
.eq("floriday_id", pushTargetId);
|
|
1640
|
-
}
|
|
1641
|
-
catch {
|
|
1642
|
-
/* niet kritiek; sync corrigeert */
|
|
1643
|
-
}
|
|
1623
|
+
// Geen eigen kopie in floriday_trade_items_cache: Floriday-auth vult die.
|
|
1644
1624
|
if (localId) {
|
|
1645
1625
|
await markLocalSyncStatus(localId, {
|
|
1646
1626
|
dirty: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloridayTakeoverPanel.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridayTakeoverPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FloridayTakeoverPanel.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridayTakeoverPanel.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,sBAAsB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAoCvF;AAED,wBAAgB,qBAAqB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAkTtF"}
|
|
@@ -7,6 +7,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
7
7
|
* Toont ook "Floriday leidend voor X, ERP voor Y" en de alleen-lezen-stand
|
|
8
8
|
* (uit Floriday-authenticatie: floriday_write_mode()).
|
|
9
9
|
*/
|
|
10
|
+
import { copyPackingsFromFloriday, PACKING_INCOMPLETE_TEXT } from "../../lib/product-packings.js";
|
|
10
11
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
11
12
|
import { useServerFn } from "@tanstack/react-start";
|
|
12
13
|
import { toast } from "sonner";
|
|
@@ -143,11 +144,27 @@ export function FloridayTakeoverPanel({ connectionId }) {
|
|
|
143
144
|
stock_source: r.stockSource, price_source: r.priceSource, offer_forms: r.forms,
|
|
144
145
|
}));
|
|
145
146
|
const { data, error } = await sb.rpc("floriday_takeover_apply", { p_connection_id: connectionId, p_items: items });
|
|
146
|
-
setBusy(false);
|
|
147
147
|
if (error) {
|
|
148
|
+
setBusy(false);
|
|
148
149
|
toast.error("Overnemen is niet gelukt; er is niets veranderd.", { description: error.message });
|
|
149
150
|
return;
|
|
150
151
|
}
|
|
152
|
+
// Nieuw aangemaakte artikelen: verpakkingen exact uit de Floriday-kopie overnemen.
|
|
153
|
+
// Bestaande artikelen volgen pas na akkoord op de herstellijst.
|
|
154
|
+
const createdIds = chosen.filter((r) => r.action === "aanmaken").map((r) => r.tradeItemId);
|
|
155
|
+
if (createdIds.length) {
|
|
156
|
+
try {
|
|
157
|
+
const { data: prods } = await sb.from("products").select("id").in("floriday_trade_item_id", createdIds);
|
|
158
|
+
const res = await copyPackingsFromFloriday(sb, connectionId, (prods ?? []).map((p) => p.id));
|
|
159
|
+
if (res.no_packings_in_floriday) {
|
|
160
|
+
toast.warning(`${res.no_packings_in_floriday} artikelen hebben in Floriday geen verpakking. ${PACKING_INCOMPLETE_TEXT}.`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
toast.error("Verpakkingen konden niet worden overgenomen.", { description: e.message });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
setBusy(false);
|
|
151
168
|
toast.success(`${data?.items ?? 0} artikelen overgenomen${data?.created_products ? `, ${data.created_products} nieuw` : ""}.`);
|
|
152
169
|
setRows(null);
|
|
153
170
|
loadRuns();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StockBulkButtons.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockBulkButtons.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StockBulkButtons.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockBulkButtons.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAgH3D,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,kBAAkB,EAClB,UAAU,GACX,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,+BA4qBA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { positiveIntOrNull, saveOwnPackings } from "../../lib/product-packings.js";
|
|
2
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
4
|
import * as XLSX from "xlsx";
|
|
4
5
|
import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, toast, } from "@flowselections/core";
|
|
@@ -26,7 +27,14 @@ const COLUMNS = [
|
|
|
26
27
|
"Minimum voorraad",
|
|
27
28
|
"Gereserveerde voorraad",
|
|
28
29
|
"Inkomende voorraad",
|
|
30
|
+
"Fust (VBN-code)",
|
|
31
|
+
"Ladingdrager",
|
|
32
|
+
"Stuks per fust",
|
|
33
|
+
"Fusten per laag",
|
|
34
|
+
"Lagen per ladingdrager",
|
|
29
35
|
];
|
|
36
|
+
/** Verpakkingskolommen (alleen eigen artikelen zonder Floriday); leeg blijft leeg. */
|
|
37
|
+
const PACKING_COLUMNS = ["Fust (VBN-code)", "Ladingdrager", "Stuks per fust", "Fusten per laag", "Lagen per ladingdrager"];
|
|
30
38
|
const ACTIVE = ["ontvangen", "bezig", "gestopt"];
|
|
31
39
|
const rpc = (fn, args) => supabase.rpc(fn, args);
|
|
32
40
|
function parseNumber(val) {
|
|
@@ -65,6 +73,7 @@ const STATUS_LABEL = {
|
|
|
65
73
|
};
|
|
66
74
|
export function StockBulkButtons({ items, activeConnectionId, onImported, }) {
|
|
67
75
|
const fileRef = useRef(null);
|
|
76
|
+
const packingByCode = useRef(new Map());
|
|
68
77
|
const [open, setOpen] = useState(false);
|
|
69
78
|
const [busy, setBusy] = useState(null);
|
|
70
79
|
const [progress, setProgress] = useState(null);
|
|
@@ -205,6 +214,7 @@ export function StockBulkButtons({ items, activeConnectionId, onImported, }) {
|
|
|
205
214
|
const wb = XLSX.read(buf, { type: "array" });
|
|
206
215
|
const sheet = wb.Sheets[wb.SheetNames[0]];
|
|
207
216
|
const rows = XLSX.utils.sheet_to_json(sheet, { defval: "" });
|
|
217
|
+
packingByCode.current = new Map();
|
|
208
218
|
const out = [];
|
|
209
219
|
let existing = 0;
|
|
210
220
|
let fresh = 0;
|
|
@@ -245,6 +255,29 @@ export function StockBulkButtons({ items, activeConnectionId, onImported, }) {
|
|
|
245
255
|
}
|
|
246
256
|
base[key] = p.value;
|
|
247
257
|
}
|
|
258
|
+
if (PACKING_COLUMNS.some((c) => String(row[c] ?? "").trim() !== "")) {
|
|
259
|
+
const read = (c) => {
|
|
260
|
+
const raw = String(row[c] ?? "").trim();
|
|
261
|
+
const v = positiveIntOrNull(raw);
|
|
262
|
+
if (raw !== "" && v === null)
|
|
263
|
+
throw new Error(`${c}: geen geldig heel getal groter dan 0`);
|
|
264
|
+
return v;
|
|
265
|
+
};
|
|
266
|
+
try {
|
|
267
|
+
packingByCode.current.set(code, [{
|
|
268
|
+
vbn_package_code: read("Fust (VBN-code)"),
|
|
269
|
+
load_carrier: String(row["Ladingdrager"] ?? "").trim() || null,
|
|
270
|
+
pieces_per_package: read("Stuks per fust"),
|
|
271
|
+
packages_per_layer: read("Fusten per laag"),
|
|
272
|
+
layers_per_load_carrier: read("Lagen per ladingdrager"),
|
|
273
|
+
is_primary: true,
|
|
274
|
+
}]);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
out.push({ ...base, error: err.message });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
248
281
|
const custom = readCustomValues(row);
|
|
249
282
|
base.custom_values = Object.keys(custom).length ? custom : null;
|
|
250
283
|
const ex = byCode.get(code);
|
|
@@ -344,6 +377,32 @@ export function StockBulkButtons({ items, activeConnectionId, onImported, }) {
|
|
|
344
377
|
done = data.done_chunks ?? done + 1;
|
|
345
378
|
setProgress({ done, total, rows: Math.min(done * chunkSize, totalRows), totalRows });
|
|
346
379
|
}
|
|
380
|
+
// Verpakkingen uit het bestand vastleggen, alleen voor eigen artikelen (zonder Floriday).
|
|
381
|
+
const packingErrors = [];
|
|
382
|
+
const codes = [...packingByCode.current.keys()];
|
|
383
|
+
for (let i = 0; i < codes.length; i += 200) {
|
|
384
|
+
const part = codes.slice(i, i + 200);
|
|
385
|
+
const { data: prods } = await supabase
|
|
386
|
+
.from("products")
|
|
387
|
+
.select("id,article_number,floriday_trade_item_id")
|
|
388
|
+
.in("article_number", part);
|
|
389
|
+
for (const pr of (prods ?? [])) {
|
|
390
|
+
if (pr.floriday_trade_item_id)
|
|
391
|
+
continue; // Floriday-artikel: verpakking komt uit Floriday
|
|
392
|
+
const rows = packingByCode.current.get(String(pr.article_number));
|
|
393
|
+
if (!rows)
|
|
394
|
+
continue;
|
|
395
|
+
try {
|
|
396
|
+
await saveOwnPackings(pr.id, rows);
|
|
397
|
+
}
|
|
398
|
+
catch (err) {
|
|
399
|
+
packingErrors.push(`${pr.article_number}: ${err.message}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
packingByCode.current = new Map();
|
|
404
|
+
if (packingErrors.length)
|
|
405
|
+
toast.error(`Verpakking niet opgeslagen bij ${packingErrors.length} artikelen`, { description: packingErrors.slice(0, 5).join("; ") });
|
|
347
406
|
const { data: fin } = await supabase
|
|
348
407
|
.from("stock_import_runs")
|
|
349
408
|
.select("updated_rows,created_rows,skipped_rows")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AA8EzE,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,cAAc,EACd,WAAW,EACX,cAAc,GACf,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,+BAwTA"}
|
|
@@ -7,6 +7,7 @@ import { supabase } from "../../integrations/supabase/client.js";
|
|
|
7
7
|
import { useVoorraadCustomFields } from "../../hooks/useVoorraadCustomFields.js";
|
|
8
8
|
import { formatCustomValue } from "../../lib/voorraad-custom-fields.js";
|
|
9
9
|
import { InventoryStatusBadge } from "./InventoryStatusBadge.js";
|
|
10
|
+
import { loadIncompletePackingIds, PACKING_INCOMPLETE_TEXT } from "../../lib/product-packings.js";
|
|
10
11
|
import { PRODUCT_TYPE_CLASSES, PRODUCT_TYPE_HELP, PRODUCT_TYPE_LABELS, toStructureType } from "../../lib/product-types.js";
|
|
11
12
|
const columns = [
|
|
12
13
|
{ key: "quantity", label: "Liggend" },
|
|
@@ -89,6 +90,20 @@ export function settingKeyOf(item) {
|
|
|
89
90
|
}
|
|
90
91
|
export function VoorraadTable({ items, loading, settingsByKey, selected, onToggleSelect, onToggleAll, onOpenSettings, }) {
|
|
91
92
|
const navigate = useNavigate();
|
|
93
|
+
// Artikelen zonder volledige primaire verpakking (karindeling kan ze niet plannen).
|
|
94
|
+
const [incompletePacking, setIncompletePacking] = useState(new Set());
|
|
95
|
+
const productIdsKey = items.map((i) => i.productId ?? "").join(",");
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
let cancelled = false;
|
|
98
|
+
const ids = items.map((i) => i.productId).filter((x) => Boolean(x));
|
|
99
|
+
loadIncompletePackingIds(ids)
|
|
100
|
+
.then((set) => { if (!cancelled)
|
|
101
|
+
setIncompletePacking(set); })
|
|
102
|
+
.catch(() => { if (!cancelled)
|
|
103
|
+
setIncompletePacking(new Set()); });
|
|
104
|
+
return () => { cancelled = true; };
|
|
105
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
106
|
+
}, [productIdsKey]);
|
|
92
107
|
const { fields } = useVoorraadCustomFields();
|
|
93
108
|
const { visible, toggle } = useVisibleColumns();
|
|
94
109
|
const allExtraColumns = fields.filter((f) => f.show_in_columns);
|
|
@@ -135,7 +150,7 @@ export function VoorraadTable({ items, loading, settingsByKey, selected, onToggl
|
|
|
135
150
|
open();
|
|
136
151
|
}
|
|
137
152
|
}
|
|
138
|
-
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [onToggleSelect && (_jsx("td", { className: "p-3", onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: settingProductId ? selected?.has(settingProductId) : false, disabled: !settingProductId, onCheckedChange: () => settingProductId && onToggleSelect(settingProductId), "aria-label": `Selecteer ${item.name}` }) })), _jsx("td", { className: "p-2", children: thumbUrl ? (_jsx("img", { src: thumbUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsxs("div", { className: "flex flex-col items-start gap-1", children: [_jsx("span", { className: "font-medium text-foreground", children: item.name }), _jsxs("div", { role: "status", "aria-label": floriday
|
|
153
|
+
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [onToggleSelect && (_jsx("td", { className: "p-3", onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: settingProductId ? selected?.has(settingProductId) : false, disabled: !settingProductId, onCheckedChange: () => settingProductId && onToggleSelect(settingProductId), "aria-label": `Selecteer ${item.name}` }) })), _jsx("td", { className: "p-2", children: thumbUrl ? (_jsx("img", { src: thumbUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsxs("div", { className: "flex flex-col items-start gap-1", children: [_jsx("span", { className: "font-medium text-foreground", children: item.name }), item.productId && incompletePacking.has(item.productId) && (_jsx("span", { className: "text-[11px] font-medium text-destructive", children: PACKING_INCOMPLETE_TEXT })), _jsxs("div", { role: "status", "aria-label": floriday
|
|
139
154
|
? "Online in Floriday"
|
|
140
155
|
: "Niet online in Floriday", title: floriday
|
|
141
156
|
? "Online in Floriday"
|