@flowselections/floriday-verkoop-module 1.0.77 → 1.0.82
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/verkoop/CreateOrderPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.js +33 -8
- package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -1
- package/dist-lib/components/verkoop/EditLocalOrderDialog.js +1 -1
- package/dist-lib/components/verkoop/FloridayStageLine.d.ts +15 -0
- package/dist-lib/components/verkoop/FloridayStageLine.d.ts.map +1 -0
- package/dist-lib/components/verkoop/FloridayStageLine.js +25 -0
- package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts +1 -1
- package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -1
- package/dist-lib/components/verkoop/PlanCoverageBadge.js +5 -2
- package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailPage.js +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +38 -6
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.js +4 -8
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.js +7 -1
- package/dist-lib/integrations/supabase/types.d.ts +1486 -2
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/belading.server.d.ts +0 -11
- package/dist-lib/lib/belading.server.d.ts.map +1 -1
- package/dist-lib/lib/belading.server.js +4 -41
- package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
- package/dist-lib/lib/cart-replan.functions.js +3 -22
- package/dist-lib/lib/central-secrets.server.d.ts +5 -0
- package/dist-lib/lib/central-secrets.server.d.ts.map +1 -0
- package/dist-lib/lib/central-secrets.server.js +65 -0
- package/dist-lib/lib/create-order.functions.d.ts +15 -0
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.js +28 -13
- package/dist-lib/lib/customer-name.d.ts +8 -0
- package/dist-lib/lib/customer-name.d.ts.map +1 -0
- package/dist-lib/lib/customer-name.js +9 -0
- package/dist-lib/lib/engine-block-alerts.d.ts +22 -0
- package/dist-lib/lib/engine-block-alerts.d.ts.map +1 -0
- package/dist-lib/lib/engine-block-alerts.js +43 -0
- package/dist-lib/lib/engine-block-alerts.server.d.ts +7 -0
- package/dist-lib/lib/engine-block-alerts.server.d.ts.map +1 -0
- package/dist-lib/lib/engine-block-alerts.server.js +75 -0
- package/dist-lib/lib/floriday-change-diff.check.d.ts +2 -0
- package/dist-lib/lib/floriday-change-diff.check.d.ts.map +1 -0
- package/dist-lib/lib/floriday-change-diff.check.js +27 -0
- package/dist-lib/lib/floriday-change-diff.d.ts +7 -0
- package/dist-lib/lib/floriday-change-diff.d.ts.map +1 -0
- package/dist-lib/lib/floriday-change-diff.js +51 -0
- package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-mirror.functions.js +38 -39
- package/dist-lib/lib/floriday-status.d.ts +48 -0
- package/dist-lib/lib/floriday-status.d.ts.map +1 -0
- package/dist-lib/lib/floriday-status.js +99 -0
- package/dist-lib/lib/floriday-status.server.d.ts +7 -0
- package/dist-lib/lib/floriday-status.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-status.server.js +74 -0
- package/dist-lib/lib/load-carriers.server.d.ts +1 -1
- package/dist-lib/lib/load-carriers.server.d.ts.map +1 -1
- package/dist-lib/lib/load-carriers.server.js +3 -6
- package/dist-lib/lib/logistics-engine.server.d.ts.map +1 -1
- package/dist-lib/lib/logistics-engine.server.js +2 -22
- package/dist-lib/lib/order-block-mail.server.d.ts.map +1 -1
- package/dist-lib/lib/order-block-mail.server.js +31 -15
- package/dist-lib/lib/order-cancel.server.d.ts +9 -0
- package/dist-lib/lib/order-cancel.server.d.ts.map +1 -1
- package/dist-lib/lib/order-cancel.server.js +90 -0
- package/dist-lib/lib/plan-coverage.check.d.ts +2 -0
- package/dist-lib/lib/plan-coverage.check.d.ts.map +1 -0
- package/dist-lib/lib/plan-coverage.check.js +17 -0
- package/dist-lib/lib/plan-coverage.d.ts +12 -0
- package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
- package/dist-lib/lib/plan-coverage.js +27 -1
- package/dist-lib/lib/plan-coverage.server.d.ts.map +1 -1
- package/dist-lib/lib/plan-coverage.server.js +20 -13
- package/dist-lib/lib/review-dismissals.server.d.ts +3 -0
- package/dist-lib/lib/review-dismissals.server.d.ts.map +1 -0
- package/dist-lib/lib/review-dismissals.server.js +26 -0
- package/dist-lib/lib/salesorders-list.functions.d.ts +1 -1
- package/dist-lib/lib/salesorders-list.functions.js +1 -1
- package/dist-lib/lib/salesorders-list.server.d.ts +1 -1
- package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-list.server.js +104 -3
- package/dist-lib/lib/salesorders-mapping.d.ts +17 -0
- package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-mapping.js +1 -0
- package/dist-lib/lib/salesorders.functions.d.ts +1 -5
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.js +32 -2
- package/dist-lib/lib/useSalesOrdersQuery.d.ts +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateOrderPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderPage.tsx"],"names":[],"mappings":"AAqFA,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"CreateOrderPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderPage.tsx"],"names":[],"mappings":"AAqFA,wBAAgB,eAAe,gCAkzB9B"}
|
|
@@ -12,10 +12,9 @@ import { ArrowLeft, Plus, Trash2 } from "lucide-react";
|
|
|
12
12
|
import { useServerFn } from "@tanstack/react-start";
|
|
13
13
|
import { SearchableSelect } from "./SearchableSelect";
|
|
14
14
|
import { computeEarliestDelivery } from "../../lib/carrier-availability.js";
|
|
15
|
-
import { listCustomersForCreateOrder, ensureCustomerFromTwinfield, listProductsForCreateOrder, listDeliveryLocationsForCustomerCO, listPickupLocationsCO, listCarriersForCreateOrder, getOrderPickDaysCO, listBeladingOptionsForProducts, createManualOrder, } from "../../lib/create-order.functions.js";
|
|
15
|
+
import { listCustomersForCreateOrder, ensureCustomerFromTwinfield, listProductsForCreateOrder, listDeliveryLocationsForCustomerCO, listPickupLocationsCO, listCarriersForCreateOrder, getOrderPickDaysCO, listBeladingOptionsForProducts, createManualOrder, getEffectivePrices, } from "../../lib/create-order.functions.js";
|
|
16
16
|
import { checkOrderStockAllowed } from "../../lib/logistics-stock.functions.js";
|
|
17
17
|
import { useAllowedLoadCarriers } from "../../lib/useAllowedLoadCarriers.js";
|
|
18
|
-
import { DISABLED_LOAD_CARRIER_MESSAGE } from "../../lib/load-carriers.js";
|
|
19
18
|
const beladingKey = (b) => `${b.plants_per_crate}x${b.crates_per_layer}x${b.layers_per_cart}`;
|
|
20
19
|
const beladingLabel = (b) => `${b.plants_per_crate} planten/fust · ${b.crates_per_layer} fusten/laag · ${b.layers_per_cart} lagen`;
|
|
21
20
|
/** "Eurokrat · Deense container" — type fust en type kar bij deze belading. */
|
|
@@ -42,6 +41,7 @@ export function CreateOrderPage() {
|
|
|
42
41
|
const qc = useQueryClient();
|
|
43
42
|
const fetchCustomers = useServerFn(listCustomersForCreateOrder);
|
|
44
43
|
const fetchProducts = useServerFn(listProductsForCreateOrder);
|
|
44
|
+
const fetchEffectivePrices = useServerFn(getEffectivePrices);
|
|
45
45
|
const fetchDeliveryLocations = useServerFn(listDeliveryLocationsForCustomerCO);
|
|
46
46
|
const fetchPickupLocations = useServerFn(listPickupLocationsCO);
|
|
47
47
|
const fetchCarriers = useServerFn(listCarriersForCreateOrder);
|
|
@@ -266,9 +266,6 @@ export function CreateOrderPage() {
|
|
|
266
266
|
throw new Error("Selecteer een vervoerder");
|
|
267
267
|
if (!isReservation && !deliveryDate)
|
|
268
268
|
throw new Error("Selecteer een leverdatum");
|
|
269
|
-
if (loadCarrierType && !loadCarriersEngine.allowed.includes(loadCarrierType)) {
|
|
270
|
-
throw new Error(DISABLED_LOAD_CARRIER_MESSAGE);
|
|
271
|
-
}
|
|
272
269
|
const validLines = lines.filter((l) => l.product_id && (l.quantity ?? 0) > 0);
|
|
273
270
|
if (validLines.length === 0)
|
|
274
271
|
throw new Error("Voeg minimaal één product toe");
|
|
@@ -435,10 +432,38 @@ export function CreateOrderPage() {
|
|
|
435
432
|
unit: next[idx].unit ?? p?.unit ?? "stuks",
|
|
436
433
|
quantity: normalizedQ,
|
|
437
434
|
belading: b,
|
|
438
|
-
unit_price: next[idx].unit_price ?? (p?.sale_price != null ? Number(p.sale_price) : null),
|
|
435
|
+
unit_price: next[idx].unit_price ?? (p?.sale_price != null && Number(p.sale_price) > 0 ? Number(p.sale_price) : null),
|
|
439
436
|
};
|
|
440
437
|
}
|
|
441
438
|
setLines(next);
|
|
439
|
+
// Prijs uit prijsgroep/klantafspraak/artikel, als die bestaat.
|
|
440
|
+
if (v && customerId && !String(customerId).startsWith("twinfield:")) {
|
|
441
|
+
const lineIdx = idx;
|
|
442
|
+
const hadPrice = next[idx].unit_price;
|
|
443
|
+
fetchEffectivePrices({
|
|
444
|
+
data: {
|
|
445
|
+
customerId,
|
|
446
|
+
onDate: deliveryDate || undefined,
|
|
447
|
+
lines: [{ productId: v, quantity: Number(next[idx].quantity ?? 0) || undefined }],
|
|
448
|
+
},
|
|
449
|
+
})
|
|
450
|
+
.then((res) => {
|
|
451
|
+
const hit = res?.[v];
|
|
452
|
+
if (!hit)
|
|
453
|
+
return;
|
|
454
|
+
setLines((cur) => {
|
|
455
|
+
const copy = [...cur];
|
|
456
|
+
const ln = copy[lineIdx];
|
|
457
|
+
if (!ln || ln.product_id !== v)
|
|
458
|
+
return cur;
|
|
459
|
+
if (ln.unit_price != null && ln.unit_price !== hadPrice)
|
|
460
|
+
return cur;
|
|
461
|
+
copy[lineIdx] = { ...ln, unit_price: hit.price };
|
|
462
|
+
return copy;
|
|
463
|
+
});
|
|
464
|
+
})
|
|
465
|
+
.catch(() => undefined);
|
|
466
|
+
}
|
|
442
467
|
} }), outOfStock && (_jsx("div", { className: "mt-1 text-xs text-amber-600", children: "Let op: dit product staat momenteel niet op voorraad." })), line.product_id && shortageByProduct.has(line.product_id) && (_jsx("div", { className: `mt-1 text-xs ${stockBlocked ? "text-destructive" : "text-amber-600"}`, children: (() => {
|
|
443
468
|
const s = shortageByProduct.get(line.product_id);
|
|
444
469
|
return `${s.product}: besteld ${s.wanted}, beschikbaar ${s.available}, tekort ${s.missing}`;
|
|
@@ -483,8 +508,8 @@ export function CreateOrderPage() {
|
|
|
483
508
|
const v = e.target.value === "" ? null : Number(e.target.value);
|
|
484
509
|
next[idx] = { ...next[idx], unit_price: v };
|
|
485
510
|
setLines(next);
|
|
486
|
-
}, placeholder: "\u20AC prijs" }), _jsx(Button, { variant: "ghost", size: "icon", className: "col-span-1", onClick: () => setLines(lines.filter((_, i) => i !== idx)), "aria-label": "Regel verwijderen", children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, idx));
|
|
487
|
-
}), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setLines([...lines, { product_id: null, product_name: "", quantity: null, unit: "stuks", unit_price: null, belading: null }]), children: [_jsx(Plus, { className: "h-3 w-3 mr-1" }), " Regel toevoegen"] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Opmerkingen" }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: "Optionele notities bij deze bestelling", rows: 3 })] }), stockCheck && stockCheck.shortages.length > 0 && (_jsxs("div", { className: `rounded-md border p-3 text-sm ${stockBlocked
|
|
511
|
+
}, placeholder: "\u20AC prijs", "aria-invalid": !!line.product_id && !(Number(line.unit_price) > 0), title: !!line.product_id && !(Number(line.unit_price) > 0) ? "Geen prijs" : undefined }), _jsx(Button, { variant: "ghost", size: "icon", className: "col-span-1", onClick: () => setLines(lines.filter((_, i) => i !== idx)), "aria-label": "Regel verwijderen", children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, idx));
|
|
512
|
+
}), lines.some((l) => l.product_id && !(Number(l.unit_price) > 0)) && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: ["Geen prijs: ", lines.filter((l) => l.product_id && !(Number(l.unit_price) > 0)).length, " regel(s) zonder prijs. Er is geen prijs gevonden in prijsgroep of artikel; vul de prijs in."] })), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setLines([...lines, { product_id: null, product_name: "", quantity: null, unit: "stuks", unit_price: null, belading: null }]), children: [_jsx(Plus, { className: "h-3 w-3 mr-1" }), " Regel toevoegen"] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Opmerkingen" }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: "Optionele notities bij deze bestelling", rows: 3 })] }), stockCheck && stockCheck.shortages.length > 0 && (_jsxs("div", { className: `rounded-md border p-3 text-sm ${stockBlocked
|
|
488
513
|
? "border-destructive/40 bg-destructive/5 text-destructive"
|
|
489
514
|
: "border-amber-500/40 bg-amber-500/5 text-amber-700"}`, children: [_jsx("div", { className: "font-medium", children: stockBlocked
|
|
490
515
|
? "Bestelling geblokkeerd — onvoldoende voorraad"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditLocalOrderDialog.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/EditLocalOrderDialog.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,IAAI,EACJ,YAAY,GACb,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,
|
|
1
|
+
{"version":3,"file":"EditLocalOrderDialog.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/EditLocalOrderDialog.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,IAAI,EACJ,YAAY,GACb,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,sCAuiBA"}
|
|
@@ -246,7 +246,7 @@ export function EditLocalOrderDialog({ orderId, open, onOpenChange, }) {
|
|
|
246
246
|
})() }))] }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { type: "number", min: 0, step: ppc ?? 1, value: it.quantity, disabled: removed, onChange: (e) => setPlants(idx, Number(e.target.value)) }) }), _jsx("div", { className: "col-span-3", children: _jsx(Input, { type: "number", min: 0, step: 1, value: ppc === null ? "" : fusten, disabled: removed || ppc === null, onChange: (e) => setFusten(idx, Number(e.target.value)) }) }), _jsx("div", { className: "col-span-1 flex justify-end", children: canEditProducts && (_jsx(Button, { variant: "ghost", size: "sm", title: removed ? "Verwijderen ongedaan maken" : "Regel verwijderen", onClick: () => setRemovedIds((prev) => prev.includes(it.id)
|
|
247
247
|
? prev.filter((x) => x !== it.id)
|
|
248
248
|
: [...prev, it.id]), children: _jsx(Trash2, { className: "h-4 w-4" }) })) })] }, it.id));
|
|
249
|
-
}), newItems.map((n, idx) => {
|
|
249
|
+
}), newItems.some((n) => !(Number(n.unitPrice) > 0)) && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: ["Geen prijs: ", newItems.filter((n) => !(Number(n.unitPrice) > 0)).length, " nieuwe regel(s) zonder prijs in artikel of prijsgroep."] })), newItems.map((n, idx) => {
|
|
250
250
|
const ppc = Math.max(1, n.plantsPerCrate);
|
|
251
251
|
const fusten = Math.ceil(n.quantity / ppc);
|
|
252
252
|
const setNewQty = (plants) => setNewItems((prev) => prev.map((p, i) => i === idx
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type FloridayStatusSummary } from "../../lib/floriday-status.js";
|
|
2
|
+
import type { OrderStage } from "../../lib/order-status.js";
|
|
3
|
+
/** Extra regel "Floriday: …" met een melding als de stand afwijkt. Alleen weergave. */
|
|
4
|
+
export declare function FloridayStageLine({ status, stage, floridayFulfilled, isFloriday, notReportedCount, bufferSize, }: {
|
|
5
|
+
status: FloridayStatusSummary | null | undefined;
|
|
6
|
+
stage: OrderStage | undefined;
|
|
7
|
+
floridayFulfilled?: boolean;
|
|
8
|
+
isFloriday?: boolean;
|
|
9
|
+
notReportedCount?: number;
|
|
10
|
+
bufferSize?: number;
|
|
11
|
+
}): import("react").JSX.Element | null;
|
|
12
|
+
export declare function MissingPriceBadge({ show }: {
|
|
13
|
+
show: boolean | undefined;
|
|
14
|
+
}): import("react").JSX.Element | null;
|
|
15
|
+
//# sourceMappingURL=FloridayStageLine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloridayStageLine.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/FloridayStageLine.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA8D,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC/H,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,KAAK,EACL,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,UAAU,GACX,EAAE;IACD,MAAM,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IACjD,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,sCAwCA;AAED,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,sCAOxE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { AlertTriangle } from "lucide-react";
|
|
3
|
+
import { Badge } from "@flowselections/core";
|
|
4
|
+
import { deviatesFromFloriday, floridayStageLabel, notReportedState } from "../../lib/floriday-status.js";
|
|
5
|
+
/** Extra regel "Floriday: …" met een melding als de stand afwijkt. Alleen weergave. */
|
|
6
|
+
export function FloridayStageLine({ status, stage, floridayFulfilled, isFloriday, notReportedCount, bufferSize, }) {
|
|
7
|
+
const nr = isFloriday || status
|
|
8
|
+
? notReportedState(stage, status?.stage ?? null, !!floridayFulfilled)
|
|
9
|
+
: null;
|
|
10
|
+
const warn = nr === "waarschuwing" || nr === "waarschuwing_onbekend";
|
|
11
|
+
const bufferHint = bufferSize && bufferSize > 1 && notReportedCount
|
|
12
|
+
? ` (${notReportedCount} van ${bufferSize} nog niet afgemeld)`
|
|
13
|
+
: "";
|
|
14
|
+
const notReported = warn ? (_jsx("div", { className: "mt-1", children: _jsxs(Badge, { variant: "outline", className: "border-amber-400/60 bg-amber-50 text-amber-800", children: [_jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), "Verzonden in het ERP, nog niet afgemeld bij Floriday", nr === "waarschuwing_onbekend" ? " (Floriday-stand onbekend)" : "", bufferHint] }) })) : nr === "al_afgehandeld" ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: "Al afgehandeld in Floriday" })) : null;
|
|
15
|
+
if (!status)
|
|
16
|
+
return notReported;
|
|
17
|
+
const unknown = status.stage === "onbekend";
|
|
18
|
+
const deviates = !warn && deviatesFromFloriday(status.stage, stage);
|
|
19
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1 text-xs text-muted-foreground", children: [_jsxs("span", { title: unknown && status.error ? `Niet opgehaald: ${status.error}` : undefined, children: ["Floriday: ", unknown ? "stand onbekend" : floridayStageLabel(status.stage)] }), deviates && (_jsxs(Badge, { variant: "outline", className: "border-amber-400/40 text-amber-600", children: [_jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), "Wijkt af van Floriday"] }))] }), notReported] }));
|
|
20
|
+
}
|
|
21
|
+
export function MissingPriceBadge({ show }) {
|
|
22
|
+
if (!show)
|
|
23
|
+
return null;
|
|
24
|
+
return (_jsx(Badge, { variant: "outline", className: "border-destructive/40 text-destructive", children: "Geen prijs" }));
|
|
25
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type PlanCoverageSummary } from "../../lib/plan-coverage.js";
|
|
2
2
|
export declare function PlanCoverageBadge({ coverage, showReason, }: {
|
|
3
3
|
coverage: PlanCoverageSummary | null | undefined;
|
|
4
4
|
showReason?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlanCoverageBadge.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/PlanCoverageBadge.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"PlanCoverageBadge.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/PlanCoverageBadge.tsx"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGnF,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,UAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,sCAoCA"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { AlertTriangle } from "lucide-react";
|
|
3
|
+
import { coverageDetailText } from "../../lib/plan-coverage.js";
|
|
3
4
|
// Indelingsstatus zoals de Logistiek Engine die levert. Alleen weergave.
|
|
4
5
|
export function PlanCoverageBadge({ coverage, showReason = true, }) {
|
|
5
6
|
if (!coverage)
|
|
6
7
|
return null;
|
|
7
8
|
const { state, label, progressPct, reason, shared } = coverage;
|
|
9
|
+
const detail = coverageDetailText(coverage);
|
|
10
|
+
const tip = reason ? `${reason}\n${detail}` : detail;
|
|
8
11
|
const base = "inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] font-medium";
|
|
9
12
|
if (state === "geen_indeling") {
|
|
10
|
-
return (_jsxs("div", { className: "mt-1 min-w-0", children: [_jsxs("span", { className: `${base} border-destructive/40 bg-destructive/10 text-destructive`, title:
|
|
13
|
+
return (_jsxs("div", { className: "mt-1 min-w-0", children: [_jsxs("span", { className: `${base} border-destructive/40 bg-destructive/10 text-destructive`, title: tip, children: [_jsx(AlertTriangle, { className: "h-3 w-3 shrink-0" }), label] }), showReason && reason && _jsx("div", { className: "mt-0.5 text-xs text-destructive", children: reason })] }));
|
|
11
14
|
}
|
|
12
15
|
const tone = state === "deels"
|
|
13
16
|
? "border-primary/40 bg-primary/10 text-foreground"
|
|
@@ -19,5 +22,5 @@ export function PlanCoverageBadge({ coverage, showReason = true, }) {
|
|
|
19
22
|
: state === "ingedeeld" && shared
|
|
20
23
|
? `${label} · gedeeld met buffer`
|
|
21
24
|
: label;
|
|
22
|
-
return (_jsx("div", { className: "mt-1", children: _jsx("span", { className: `${base} ${tone}`, title:
|
|
25
|
+
return (_jsx("div", { className: "mt-1", children: _jsx("span", { className: `${base} ${tone}`, title: tip, children: text }) }));
|
|
23
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SalesOrderDetailPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailPage.tsx"],"names":[],"mappings":"AAgGA,wBAAgB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"SalesOrderDetailPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailPage.tsx"],"names":[],"mappings":"AAgGA,wBAAgB,oBAAoB,gCAsPnC"}
|
|
@@ -130,7 +130,7 @@ export function SalesOrderDetailPage() {
|
|
|
130
130
|
const rawLocalId = isLocal && salesOrderId.startsWith("local:")
|
|
131
131
|
? salesOrderId.slice("local:".length)
|
|
132
132
|
: null;
|
|
133
|
-
return (_jsxs("main", { className: "space-y-5 p-6", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsxs(Link, { to: "/floriday-verkoop/verkooporders", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Terug naar verkooporders"] }) }), rawLocalId && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setEditOpen(true), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Bestelling bewerken"] }))] }), isLoading && (_jsx("div", { className: "rounded-lg border border-border bg-card p-8 text-sm text-muted-foreground", children: "Laden\u2026" })), error && (_jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: error.message })), !isLoading && !error && !primary && (_jsx("div", { className: "rounded-lg border border-border bg-card p-8 text-sm text-muted-foreground", children: "Order niet gevonden." })), primary && isBuffer && (_jsxs("div", { className: "rounded-lg border border-primary/30 bg-primary/5 p-4", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(Layers, { className: "h-4 w-4 text-primary" }), _jsx("span", { className: "text-sm font-semibold text-foreground", children: "Orderbuffer" }), _jsxs(Badge, { variant: "outline", className: "border-primary/40 text-primary", children: [bufferOrders.length, " orders samengevoegd"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3 text-sm md:grid-cols-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Totale omzet" }), _jsx("div", { className: "font-semibold text-foreground", children: eur.format(totals.revenue) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Karren" }), _jsx("div", { className: "font-semibold text-foreground", children: formatLoadUnits(totals.karren, totals.cartType) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Fusten" }), _jsx("div", { className: "font-semibold text-foreground", children: formatLoadUnits(totals.fusten, totals.crateType) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Klant" }), _jsx("div", { className: "font-semibold text-foreground", children: primary.customer.name })] })] }), _jsx(BufferAddresses, { orderId: primary.id }), _jsxs("div", { className: "mt-4 border-t border-primary/20 pt-3 text-sm", children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 text-muted-foreground", children: [_jsx(Truck, { className: "h-3.5 w-3.5" }), _jsx("span", { children: "Vervoerder" })] }), _jsx(OrderCarrierPicker, { orderId: primary.id, applyToBuffer: true, locked: bufferOrders.every((o) => !!o.isReservation) }), _jsxs("div", { className: "mt-3 mb-1 flex items-center gap-1.5 text-muted-foreground", children: [_jsx(Clock, { className: "h-3.5 w-3.5" }), _jsx("span", { children: "Ophaalmoment" })] }), _jsx(OrderPickupMomentPicker, { orderId: primary.id, readOnly: true, compact: true })] }), _jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: bufferOrders.map((o) => {
|
|
133
|
+
return (_jsxs("main", { className: "space-y-5 p-6", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsxs(Link, { to: "/floriday-verkoop/verkooporders", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Terug naar verkooporders"] }) }), rawLocalId && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setEditOpen(true), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Bestelling bewerken"] }))] }), isLoading && (_jsx("div", { className: "rounded-lg border border-border bg-card p-8 text-sm text-muted-foreground", children: "Laden\u2026" })), error && (_jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: error.message })), !isLoading && !error && !primary && (_jsx("div", { className: "rounded-lg border border-border bg-card p-8 text-sm text-muted-foreground", children: "Order niet gevonden." })), primary && isBuffer && (_jsxs("div", { className: "rounded-lg border border-primary/30 bg-primary/5 p-4", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(Layers, { className: "h-4 w-4 text-primary" }), _jsx("span", { className: "text-sm font-semibold text-foreground", children: "Orderbuffer" }), _jsxs(Badge, { variant: "outline", className: "border-primary/40 text-primary", children: [bufferOrders.length, " orders samengevoegd"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3 text-sm md:grid-cols-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Totale omzet" }), _jsx("div", { className: "font-semibold text-foreground", children: eur.format(totals.revenue) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Karren" }), _jsx("div", { className: "font-semibold text-foreground", children: formatLoadUnits(totals.karren, totals.cartType) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Fusten" }), _jsx("div", { className: "font-semibold text-foreground", children: formatLoadUnits(totals.fusten, totals.crateType) })] }), _jsxs("div", { children: [_jsx("div", { className: "text-muted-foreground", children: "Klant" }), _jsx("div", { className: "font-semibold text-foreground", children: primary.customer.name }), primary.customer.legalName && (_jsx("div", { className: "text-xs text-muted-foreground", children: primary.customer.legalName }))] })] }), _jsx(BufferAddresses, { orderId: primary.id }), _jsxs("div", { className: "mt-4 border-t border-primary/20 pt-3 text-sm", children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 text-muted-foreground", children: [_jsx(Truck, { className: "h-3.5 w-3.5" }), _jsx("span", { children: "Vervoerder" })] }), _jsx(OrderCarrierPicker, { orderId: primary.id, applyToBuffer: true, locked: bufferOrders.every((o) => !!o.isReservation) }), _jsxs("div", { className: "mt-3 mb-1 flex items-center gap-1.5 text-muted-foreground", children: [_jsx(Clock, { className: "h-3.5 w-3.5" }), _jsx("span", { children: "Ophaalmoment" })] }), _jsx(OrderPickupMomentPicker, { orderId: primary.id, readOnly: true, compact: true })] }), _jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: bufferOrders.map((o) => {
|
|
134
134
|
// Een Floriday-order hoort altijd een centraal ordernummer te
|
|
135
135
|
// hebben. Ontbreekt het, dan tonen we bewust géén chip: liever
|
|
136
136
|
// zichtbaar missend dan een verzonnen uuid-fragment.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SalesOrderDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"SalesOrderDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AA4JnE,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,cAAc,EACd,eAAuB,GACxB,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,+BAydA"}
|
|
@@ -13,6 +13,7 @@ import { OrderControlStatusCard } from "./OrderControlStatusCard";
|
|
|
13
13
|
import { OrderCarrierPicker } from "./OrderCarrierPicker";
|
|
14
14
|
import { OrderPickupMomentPicker } from "./OrderPickupMomentPicker";
|
|
15
15
|
import { PlanCoverageBadge } from "./PlanCoverageBadge";
|
|
16
|
+
import { FloridayStageLine } from "./FloridayStageLine";
|
|
16
17
|
function AddressCard({ icon, lines, extra, }) {
|
|
17
18
|
return (_jsxs("div", { className: "inline-flex max-w-xs items-start gap-3 rounded-md border border-border bg-card p-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-primary/10 text-primary", children: icon }), _jsxs("div", { className: "text-sm", children: [lines.length > 0 ? lines.map((l, i) => _jsx("div", { children: l }, i)) : _jsx("div", { children: "\u2014" }), extra && _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: extra })] })] }));
|
|
18
19
|
}
|
|
@@ -145,8 +146,10 @@ export function SalesOrderDetailView({ order, sellerFallback, hideKarindeling =
|
|
|
145
146
|
if (lcShort)
|
|
146
147
|
beladingParts.push(lcShort);
|
|
147
148
|
const belading = beladingParts.length > 0 ? beladingParts.join(" - ") : "—";
|
|
148
|
-
const
|
|
149
|
+
const fsEntry = order.floridayStatus?.entries?.[0] ?? null;
|
|
150
|
+
const klantReferentie = pickStr(o.customerOrderId) ?? pickStr(fsEntry?.customerOrderId) ?? "—";
|
|
149
151
|
const floridayRef = pickStr(o.salesChannelOrderId) ??
|
|
152
|
+
pickStr(fsEntry?.salesChannelOrderId) ??
|
|
150
153
|
pickStr(o.batchReference) ??
|
|
151
154
|
pickStr(o.salesOrderId)?.slice(0, 16) ??
|
|
152
155
|
"—";
|
|
@@ -199,11 +202,34 @@ export function SalesOrderDetailView({ order, sellerFallback, hideKarindeling =
|
|
|
199
202
|
const map = { NL: "Nederland", BE: "België", DE: "Duitsland", FR: "Frankrijk", ES: "Spanje", IT: "Italië", GB: "Verenigd Koninkrijk", PL: "Polen", DK: "Denemarken" };
|
|
200
203
|
return map[addr.country.toUpperCase()] ?? addr.country;
|
|
201
204
|
})();
|
|
202
|
-
|
|
205
|
+
// Ordervelden uit het Floriday-statusoverzicht (alleen weergave).
|
|
206
|
+
const fs = order.floridayStatus ?? null;
|
|
207
|
+
const fe = fs?.entries?.[0] ?? null;
|
|
208
|
+
const incoterm = pickStr(fe?.incoterm) ??
|
|
209
|
+
pickStr(o.delivery?.incoterm) ??
|
|
210
|
+
pickStr(o.incoterm) ??
|
|
211
|
+
(fe ? "niet opgegeven" : "—");
|
|
203
212
|
const productUnit = Number(o.calculatedFields?.totalPricePerPiece?.value ?? o.pricePerPiece?.value ?? order.quantity.unitPrice) || 0;
|
|
204
213
|
const purchaseUnit = Number(o.pricePerPiece?.value ?? productUnit) || 0;
|
|
205
214
|
const transportPerPiece = Number(o.deliveryPricePerPiece ?? Math.max(0, productUnit - purchaseUnit)) || 0;
|
|
206
|
-
const
|
|
215
|
+
const priceLines = (order.priceLines ?? []).filter((l) => l.pieces > 0);
|
|
216
|
+
const linesTotal = priceLines.reduce((sum, l) => sum + l.pieces * l.unitPrice, 0);
|
|
217
|
+
const totalAmount = priceLines.length > 0 && linesTotal > 0
|
|
218
|
+
? linesTotal
|
|
219
|
+
: Number(o.calculatedFields?.orderAmount?.value ?? order.revenue) || 0;
|
|
220
|
+
// Totaalregel opgebouwd uit de orderregels (nooit uit afgeronde fusten).
|
|
221
|
+
const totalBreakdown = (() => {
|
|
222
|
+
if (priceLines.length === 0) {
|
|
223
|
+
return numberOfPieces > 0 ? `${numberOfPieces.toLocaleString("nl-NL")} stuks × ${eurFlex.format(productUnit)}` : "";
|
|
224
|
+
}
|
|
225
|
+
const byPrice = new Map();
|
|
226
|
+
for (const l of priceLines)
|
|
227
|
+
byPrice.set(l.unitPrice, (byPrice.get(l.unitPrice) ?? 0) + l.pieces);
|
|
228
|
+
return Array.from(byPrice.entries())
|
|
229
|
+
.map(([price, pcs]) => `${pcs.toLocaleString("nl-NL")} stuks × ${eurFlex.format(price)}`)
|
|
230
|
+
.join(" + ");
|
|
231
|
+
})();
|
|
232
|
+
const linesWithoutPrice = priceLines.filter((l) => !(l.unitPrice > 0)).length;
|
|
207
233
|
let oldProductPrice = null;
|
|
208
234
|
const mutations = Array.isArray(o.mutations) ? o.mutations : [];
|
|
209
235
|
const lastCorrection = [...mutations]
|
|
@@ -215,7 +241,11 @@ export function SalesOrderDetailView({ order, sellerFallback, hideKarindeling =
|
|
|
215
241
|
oldProductPrice = oldP;
|
|
216
242
|
}
|
|
217
243
|
const hasCorrection = !!lastCorrection;
|
|
218
|
-
|
|
244
|
+
// Handelsnaam van de gekoppelde klant (op id), anders bedrijfsnaam.
|
|
245
|
+
const customerName = pickStr(c.commercial_name) ?? pickStr(c.company_name) ?? pickStr(cRaw.commercialName) ?? order.customer.name;
|
|
246
|
+
const customerLegalName = pickStr(c.commercial_name) && pickStr(c.company_name) && pickStr(c.company_name) !== pickStr(c.commercial_name)
|
|
247
|
+
? pickStr(c.company_name)
|
|
248
|
+
: (order.customer.legalName ?? null);
|
|
219
249
|
const customerGln = pickStr(c.gln) ?? pickStr(cRaw.companyGln) ?? "—";
|
|
220
250
|
const customerAdmin = pickStr(c.custom_fields?.rfh_relation_id) ??
|
|
221
251
|
pickStr(cRaw.rfhRelationId) ??
|
|
@@ -226,7 +256,9 @@ export function SalesOrderDetailView({ order, sellerFallback, hideKarindeling =
|
|
|
226
256
|
const bestellingLabel = orderStageLabel(order.stage ?? (order.status.isCancelled ? "cancelled" : "incoming"));
|
|
227
257
|
return (_jsxs("div", { className: "space-y-6", children: [order.needsManualReview ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-foreground", children: [_jsx("div", { className: "font-semibold", children: "Handmatige beoordeling nodig" }), _jsxs("div", { className: "text-muted-foreground", children: [order.needsManualReview.reason, order.needsManualReview.at
|
|
228
258
|
? ` (geconstateerd op ${new Date(order.needsManualReview.at).toLocaleString("nl-NL")})`
|
|
229
|
-
: ""] })] })) : null, order.mixedDeliveryDates ? (_jsxs("div", { className: "rounded-md border border-border bg-muted/40 p-3 text-sm text-foreground", children: [_jsx("div", { className: "font-semibold", children: "Bestellingen met verschillende leverdatums" }), _jsx("div", { className: "text-muted-foreground", children: "Deze order bestaat uit Floriday-bestellingen met verschillende leverdatums. De vroegste leverdatum is aangehouden." })] })) : null, (order.unlinkedProducts?.length ?? 0) > 0 ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-foreground", children: [_jsx("div", { className: "font-semibold", children: "Floriday-artikel niet gekoppeld aan product" }), _jsx("ul", { className: "mt-1 space-y-0.5 text-muted-foreground", children: order.unlinkedProducts.map((u, i) => (_jsxs("li", { children: [u.name, " \u2014 trade-item-id ", u.tradeItemId ?? "onbekend"] }, i))) }), _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: "Koppel dit trade-item aan een product; de volgende synchronisatie neemt het dan over." })] })) : null, _jsxs("div", { className: "flex items-center gap-3 rounded-md border border-border bg-muted/30 p-3", children: [_jsx("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted", children: order.imageUrl ? (_jsx("img", { src: order.imageUrl, alt: "", className: "h-full w-full object-cover" })) : (_jsx(ImageIcon, { className: "h-6 w-6 text-muted-foreground" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "truncate text-base font-semibold text-foreground", children: [order.productName, o.tradeItemVersion ? (_jsxs("span", { className: "ml-2 text-xs font-normal text-muted-foreground", children: ["\u00B7 v", o.tradeItemVersion] })) : null] }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: order.orderNumber || order.sku || "—" })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-[1fr_360px]", children: [_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(SectionTitle, { children: "Verkooporder" }), _jsx(Row, { label: "Ordernummer", children: order.orderNumber || "—" }), _jsx(Row, { label: "Handelsvorm", children: tradingType }), _jsx(Row, { label: "Bestelmoment", children: fmtDateTime(order.orderedAt) }), _jsx(Row, { label: "Aantal", children: _jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsxs("div", { children: [formatLoadUnits(order.fustCount, order.crateTypeName), " fusten"] }), _jsxs("div", { children: [formatLoadUnits(order.karCount, order.cartTypeName), " karren", order.karShared ? " (gedeeld met buffer)" : "", _jsx(PlanCoverageBadge, { coverage: order.planCoverage })] })] }) }), _jsx(Row, { label: "Belading", children: belading }), _jsx(Row, { label: "Klant referentie", children: klantReferentie }), _jsx(Row, { label: "Floriday-referentie", children: floridayRef }), _jsx(Row, { label: "Verkoopkanaal", children: verkoopkanaal }), _jsx(Row, { label: "Financi\u00EBle afhandeling", children: financial }), _jsx(Row, { label: "Verkoper", children: sellerName ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "inline-flex h-6 w-6 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground", children: initials(sellerName) }), sellerName] })) : ("—") })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "
|
|
259
|
+
: ""] })] })) : null, order.mixedDeliveryDates ? (_jsxs("div", { className: "rounded-md border border-border bg-muted/40 p-3 text-sm text-foreground", children: [_jsx("div", { className: "font-semibold", children: "Bestellingen met verschillende leverdatums" }), _jsx("div", { className: "text-muted-foreground", children: "Deze order bestaat uit Floriday-bestellingen met verschillende leverdatums. De vroegste leverdatum is aangehouden." })] })) : null, (order.unlinkedProducts?.length ?? 0) > 0 ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-foreground", children: [_jsx("div", { className: "font-semibold", children: "Floriday-artikel niet gekoppeld aan product" }), _jsx("ul", { className: "mt-1 space-y-0.5 text-muted-foreground", children: order.unlinkedProducts.map((u, i) => (_jsxs("li", { children: [u.name, " \u2014 trade-item-id ", u.tradeItemId ?? "onbekend"] }, i))) }), _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: "Koppel dit trade-item aan een product; de volgende synchronisatie neemt het dan over." })] })) : null, _jsxs("div", { className: "flex items-center gap-3 rounded-md border border-border bg-muted/30 p-3", children: [_jsx("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted", children: order.imageUrl ? (_jsx("img", { src: order.imageUrl, alt: "", className: "h-full w-full object-cover" })) : (_jsx(ImageIcon, { className: "h-6 w-6 text-muted-foreground" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "truncate text-base font-semibold text-foreground", children: [order.productName, o.tradeItemVersion ? (_jsxs("span", { className: "ml-2 text-xs font-normal text-muted-foreground", children: ["\u00B7 v", o.tradeItemVersion] })) : null] }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: order.orderNumber || order.sku || "—" })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-6 lg:grid-cols-[1fr_360px]", children: [_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(SectionTitle, { children: "Verkooporder" }), _jsx(Row, { label: "Ordernummer", children: order.orderNumber || "—" }), _jsx(Row, { label: "Handelsvorm", children: tradingType }), _jsx(Row, { label: "Bestelmoment", children: fmtDateTime(order.orderedAt) }), _jsx(Row, { label: "Aantal", children: _jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsxs("div", { children: [formatLoadUnits(order.fustCount, order.crateTypeName), " fusten"] }), _jsxs("div", { children: [formatLoadUnits(order.karCount, order.cartTypeName), " karren", order.karShared ? " (gedeeld met buffer)" : "", _jsx(PlanCoverageBadge, { coverage: order.planCoverage })] })] }) }), _jsx(Row, { label: "Belading", children: belading }), _jsx(Row, { label: "Klant referentie", children: klantReferentie }), _jsx(Row, { label: "Floriday-referentie", children: floridayRef }), _jsx(Row, { label: "Verkoopkanaal", children: verkoopkanaal }), _jsx(Row, { label: "Financi\u00EBle afhandeling", children: financial }), _jsx(Row, { label: "Verkoper", children: sellerName ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx("span", { className: "inline-flex h-6 w-6 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground", children: initials(sellerName) }), sellerName] })) : ("—") })] }), fs && (_jsxs("div", { children: [_jsx(SectionTitle, { children: "Floriday" }), _jsx(Row, { label: "Stand", children: _jsx(FloridayStageLine, { status: fs, stage: order.stage, floridayFulfilled: order.floridayFulfilled, isFloriday: true }) }), _jsxs(Row, { label: "Herkomst status", children: [order.statusOrigin === "floriday" ? "Floriday" : "ERP", order.statusChangedAt ? ` · ${fmtDateTime(order.statusChangedAt)}` : ""] }), fs.entries.map((e) => (_jsx(Row, { label: `Bestelling ${e.salesOrderId.slice(0, 8)}`, children: _jsxs("div", { className: "space-y-0.5 text-sm", children: [_jsxs("div", { children: ["Floriday-status: ", e.salesOrderStatus ?? "—"] }), _jsxs("div", { children: ["Afleververzoeken: ", e.fulfillmentRequests.length, " \u00B7 Afhandelingen:", " ", e.fulfillmentOrders.length
|
|
260
|
+
? e.fulfillmentOrders.map((f) => f.status ?? "?").join(", ")
|
|
261
|
+
: "geen"] }), _jsxs("div", { children: ["Verkoopkanaal: ", e.salesChannel ?? "—", " \u00B7 Handelsvorm: ", e.tradeInstrument ?? "—", " \u00B7 Incoterm: ", e.incoterm ?? "niet opgegeven"] }), _jsxs("div", { children: ["Klantreferentie: ", e.customerOrderId ?? "—", " \u00B7 Floriday-referentie: ", e.salesChannelOrderId ?? "—"] }), _jsxs("div", { children: ["Koper: ", e.customerOrganizationId ?? "—", " \u00B7 GLN: ", e.customerGln ?? "—"] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Laatst gewijzigd: ", e.lastModifiedDateTime ? fmtDateTime(e.lastModifiedDateTime) : "—", " \u00B7 Ververst: ", e.cachedAt ? fmtDateTime(e.cachedAt) : "—"] })] }) }, e.salesOrderId)))] })), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Levering" }), _jsx(Row, { label: "Afleverdatum", children: fmtDateTime(order.deliveryAt) }), _jsx(Row, { label: "Incoterm", children: incoterm }), _jsx(Row, { label: "Afleveradres", children: _jsx(AddressCard, { icon: _jsx(MapPin, { className: "h-5 w-5" }), lines: resolvedAddresses?.delivery
|
|
230
262
|
? [
|
|
231
263
|
resolvedAddresses.delivery.name,
|
|
232
264
|
resolvedAddresses.delivery.line,
|
|
@@ -248,5 +280,5 @@ export function SalesOrderDetailView({ order, sellerFallback, hideKarindeling =
|
|
|
248
280
|
.join(" "),
|
|
249
281
|
resolvedAddresses.pickup.country,
|
|
250
282
|
].filter((v) => !!v && v.trim().length > 0)
|
|
251
|
-
: [], extra: resolvedAddresses?.pickup?.gln ?? null }) }), _jsx(Row, { label: "Vervoerder", children: _jsx(OrderCarrierPicker, { orderId: String(order.id), locked: !!order.isReservation }) }), _jsx(Row, { label: "Ophaalmoment", children: _jsx(OrderPickupMomentPicker, { orderId: String(order.id) }) })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Klant" }),
|
|
283
|
+
: [], extra: resolvedAddresses?.pickup?.gln ?? null }) }), _jsx(Row, { label: "Vervoerder", children: _jsx(OrderCarrierPicker, { orderId: String(order.id), locked: !!order.isReservation }) }), _jsx(Row, { label: "Ophaalmoment", children: _jsx(OrderPickupMomentPicker, { orderId: String(order.id) }) })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Klant" }), _jsxs(Row, { label: "Naam", children: [_jsx("span", { className: "font-medium", children: customerName }), customerLegalName && (_jsx("div", { className: "text-xs text-muted-foreground", children: customerLegalName }))] }), !fs && (order.floridayIds?.length ?? 0) > 0 && (_jsx(FloridayStageLine, { status: null, stage: order.stage, floridayFulfilled: order.floridayFulfilled, isFloriday: true })), _jsx(Row, { label: "GLN", children: customerGln }), _jsx(Row, { label: "Administratienummer", children: customerAdmin }), _jsx(Row, { label: "Telefoonnummer", children: customerPhone })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Prijs per stuk" }), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Product" }), _jsxs("span", { children: [oldProductPrice !== null && (_jsx("span", { className: "mr-2 text-destructive line-through", children: eurFlex.format(oldProductPrice) })), eurFlex.format(productUnit)] })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Transportkosten" }), _jsx("span", { children: eurFlex.format(transportPerPiece) })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Inkoopprijs" }), _jsx("span", { children: eurFlex.format(purchaseUnit) })] }), _jsxs("div", { className: "mt-2 flex justify-between border-t border-border pt-2 font-semibold", children: [_jsx("span", { children: "Totaal" }), _jsxs("span", { children: [_jsx("span", { className: "mr-2 text-xs font-normal text-muted-foreground", children: totalBreakdown ? `(${totalBreakdown})` : null }), eurFlex.format(totalAmount)] })] }), (order.missingPrice || (linesWithoutPrice > 0 && !fs)) && (_jsxs("div", { className: "mt-2 rounded-md border border-destructive/40 bg-destructive/10 px-2 py-1 text-xs text-destructive", children: ["Geen prijs: ", linesWithoutPrice || "een of meer", " regel(s) zonder prijs. Vul de prijs in voordat de order wordt bevestigd."] }))] })] }), _jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Status" }), _jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Bestelling" }), _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${orderStageBadgeClass(order.stage ?? "incoming")}`, children: bestellingLabel })] }), order.floridayFulfilled && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Floriday" }), _jsx("span", { className: "rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground", title: "Administratief doorgegeven aan Floriday. Dit bepaalt de orderstatus niet.", children: "Doorgegeven aan Floriday" })] })), hasCorrection && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Correctie" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), "Correctie is verwerkt"] })] }))] })] })] })] }), _jsx(OrderLinePackingCard, { orderId: String(order.id) }), _jsx(OrderShipmentsCard, { order: order }), !hideKarindeling && _jsx(OrderKarindelingCard, { order: order }), o?.salesOrderId ? (_jsxs(_Fragment, { children: [_jsx(OrderControlStatusCard, { floridayId: String(o.salesOrderId), isControlled: order.status.isControlled, controlledAt: order.status.controlledAt }), _jsx(OrderAfleverbrievenCard, { salesOrderId: String(o.salesOrderId), orderNumber: order.orderNumber ?? undefined })] })) : null] }));
|
|
252
284
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SalesOrdersTable.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrdersTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SalesOrdersTable.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrdersTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAsBjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAyGnE,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAG1D;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,OAAO,EACP,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,EAAE;IACD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC7C,qBA6SA"}
|
|
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
3
|
import { Badge, Checkbox, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
|
|
4
4
|
import { formatLoadUnits } from "../../lib/load-carrier-labels.js";
|
|
5
|
-
import { useAllowedLoadCarriers } from "../../lib/useAllowedLoadCarriers.js";
|
|
6
5
|
import { orderStageBadgeClass, orderStageLabel } from "../../lib/order-status.js";
|
|
7
6
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@flowselections/core";
|
|
8
7
|
import { MoreVertical, AlertTriangle, ArrowDown } from "lucide-react";
|
|
9
8
|
import { PlanCoverageBadge } from "./PlanCoverageBadge";
|
|
9
|
+
import { FloridayStageLine, MissingPriceBadge } from "./FloridayStageLine";
|
|
10
10
|
function formatDateShort(iso) {
|
|
11
11
|
if (!iso)
|
|
12
12
|
return { date: "—", time: "" };
|
|
@@ -72,7 +72,6 @@ export function salesOrderRowId(row) {
|
|
|
72
72
|
export function SalesOrdersTable({ orders, loading, onSelectOrder, onDeleteOrder, onEditOrder, onFulfillOrder, fulfillingId, selectedIds, onSelectionChange, }) {
|
|
73
73
|
const [internalSelected, setInternalSelected] = useState([]);
|
|
74
74
|
const selected = useMemo(() => new Set(selectedIds ?? internalSelected), [selectedIds, internalSelected]);
|
|
75
|
-
const allowedCarrierCodes = useAllowedLoadCarriers().allowed;
|
|
76
75
|
const rowIds = useMemo(() => orders.map(salesOrderRowId), [orders]);
|
|
77
76
|
const allChecked = rowIds.length > 0 && rowIds.every((id) => selected.has(id));
|
|
78
77
|
const someChecked = !allChecked && rowIds.some((id) => selected.has(id));
|
|
@@ -100,17 +99,14 @@ export function SalesOrdersTable({ orders, loading, onSelectOrder, onDeleteOrder
|
|
|
100
99
|
const ordered = formatDateShort(row.orderedAt);
|
|
101
100
|
const delivery = formatDelivery(row.deliveryAt);
|
|
102
101
|
const reserved = row.reservationCount ?? (row.isReservation ? 1 : 0);
|
|
103
|
-
const carrierDisabled = allowedCarrierCodes.length > 0 &&
|
|
104
|
-
!!row.loadCarrierType &&
|
|
105
|
-
!allowedCarrierCodes.includes(row.loadCarrierType);
|
|
106
102
|
const incomplete = row.incomplete ?? [];
|
|
107
|
-
return (_jsxs(TableRow, { className: `align-top cursor-pointer ${isBuffer ? "bg-muted/20 border-l-2 border-primary/40" : ""}`, onClick: () => onSelectOrder?.(row), children: [_jsx(TableCell, { onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: selected.has(rowId), onCheckedChange: () => toggle(rowId) }) }), _jsxs(TableCell, { children: [_jsx("div", { className: "font-medium text-foreground", children: delivery.date }), delivery.time && (_jsx("div", { className: "text-xs text-muted-foreground", children: delivery.time }))] }), _jsxs(TableCell, { children: [_jsx("div", { className: "font-medium text-foreground", children: formatPickDate(row.pickDate) }), row.pickupLabel && (_jsxs("div", { className: "text-xs text-muted-foreground", title: "Ophaalmoment van de vervoerder", children: ["Ophalen: ", row.pickupLabel] })), _jsx("div", { className: "mt-1 flex flex-wrap gap-1", children: row.printedAt && (_jsx(Badge, { variant: "outline", className: "border-transparent bg-muted text-[11px] font-normal text-muted-foreground", title: "Deze order is al uitgeprint.", children: "uitgeprint" })) })] }), _jsxs(TableCell, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium text-foreground", children: row.customer.name }), isBuffer && (_jsxs(Badge, { variant: "outline", className: "border-primary/30 text-primary", children: ["Buffer \u00B7 ", bufferSize] })), reserved > 0 && (_jsx(Badge, { variant: "outline", className: "border-amber-400/40 text-amber-600", children: reserved === bufferSize
|
|
103
|
+
return (_jsxs(TableRow, { className: `align-top cursor-pointer ${isBuffer ? "bg-muted/20 border-l-2 border-primary/40" : ""}`, onClick: () => onSelectOrder?.(row), children: [_jsx(TableCell, { onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: selected.has(rowId), onCheckedChange: () => toggle(rowId) }) }), _jsxs(TableCell, { children: [_jsx("div", { className: "font-medium text-foreground", children: delivery.date }), delivery.time && (_jsx("div", { className: "text-xs text-muted-foreground", children: delivery.time }))] }), _jsxs(TableCell, { children: [_jsx("div", { className: "font-medium text-foreground", children: formatPickDate(row.pickDate) }), row.pickupLabel && (_jsxs("div", { className: "text-xs text-muted-foreground", title: "Ophaalmoment van de vervoerder", children: ["Ophalen: ", row.pickupLabel] })), _jsx("div", { className: "mt-1 flex flex-wrap gap-1", children: row.printedAt && (_jsx(Badge, { variant: "outline", className: "border-transparent bg-muted text-[11px] font-normal text-muted-foreground", title: "Deze order is al uitgeprint.", children: "uitgeprint" })) })] }), _jsxs(TableCell, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium text-foreground", children: row.customer.name }), isBuffer && (_jsxs(Badge, { variant: "outline", className: "border-primary/30 text-primary", children: ["Buffer \u00B7 ", bufferSize] })), _jsx(MissingPriceBadge, { show: row.missingPrice }), reserved > 0 && (_jsx(Badge, { variant: "outline", className: "border-amber-400/40 text-amber-600", children: reserved === bufferSize
|
|
108
104
|
? "Reservering"
|
|
109
|
-
: `Reservering · ${reserved} van ${bufferSize}` })),
|
|
105
|
+
: `Reservering · ${reserved} van ${bufferSize}` }))] }), row.customer.legalName && (_jsx("div", { className: "text-xs text-muted-foreground", children: row.customer.legalName })), _jsx("div", { className: "text-xs text-muted-foreground", children: [row.customer.postalCode, row.customer.city].filter(Boolean).join(" ") }), incomplete.length > 0 && (_jsxs("div", { className: "mt-1 inline-flex items-center gap-1 text-xs text-amber-600", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), incomplete.join(" · ")] })), (row.unlinkedProducts?.length ?? 0) > 0 && (_jsxs("div", { className: "mt-1 flex items-start gap-1 text-xs text-destructive", title: row.unlinkedProducts
|
|
110
106
|
.map((u) => `${u.name} (trade-item ${u.tradeItemId ?? "onbekend"})`)
|
|
111
107
|
.join("\n"), children: [_jsx(AlertTriangle, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsxs("span", { children: ["Floriday-artikel niet gekoppeld aan product:", " ", row.unlinkedProducts
|
|
112
108
|
.map((u) => `${u.name} (trade-item ${u.tradeItemId ?? "onbekend"})`)
|
|
113
|
-
.join(", ")] })] }))] }), _jsxs(TableCell, { children: [_jsx("div", { className: "font-medium text-foreground", children: row.engineCounts && row.karCount > 0 ? (_jsxs(_Fragment, { children: [formatLoadUnits(row.karCount, row.cartTypeName), row.karShared && (_jsx("span", { className: "ml-1 text-xs font-normal text-muted-foreground", children: "(gedeeld met buffer)" }))] })) : (_jsx("span", { className: "text-muted-foreground", children: "\u2014" })) }), _jsx(PlanCoverageBadge, { coverage: row.planCoverage })] }), _jsx(TableCell, { children: _jsx("div", { className: "font-medium text-foreground", children: formatLoadUnits(row.fustCount, row.crateTypeName) }) }), _jsx(TableCell, { className: "text-sm text-foreground", children: row.carrierName || _jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }), _jsx(TableCell, { children: _jsx(StatusTag, { order: row }) }), showRevenue && (_jsxs(TableCell, { className: "font-medium text-foreground", children: ["\u20AC ", Math.round(row.revenue ?? 0).toLocaleString("nl-NL")] })), _jsxs(TableCell, { children: [_jsx("div", { className: "text-sm text-foreground", children: ordered.date }), _jsx("div", { className: "text-xs text-muted-foreground", children: isBuffer
|
|
109
|
+
.join(", ")] })] }))] }), _jsxs(TableCell, { children: [_jsx("div", { className: "font-medium text-foreground", children: row.engineCounts && row.karCount > 0 ? (_jsxs(_Fragment, { children: [formatLoadUnits(row.karCount, row.cartTypeName), row.karShared && (_jsx("span", { className: "ml-1 text-xs font-normal text-muted-foreground", children: "(gedeeld met buffer)" }))] })) : (_jsx("span", { className: "text-muted-foreground", children: "\u2014" })) }), _jsx(PlanCoverageBadge, { coverage: row.planCoverage }), _jsx(FloridayStageLine, { status: row.floridayStatus, stage: row.stage, floridayFulfilled: isBuffer ? !row.notReportedToFloriday : row.floridayFulfilled, isFloriday: !!row.notReportedToFloriday || (row.floridayIds?.length ?? 0) > 0, notReportedCount: row.notReportedCount, bufferSize: bufferSize })] }), _jsx(TableCell, { children: _jsx("div", { className: "font-medium text-foreground", children: formatLoadUnits(row.fustCount, row.crateTypeName) }) }), _jsx(TableCell, { className: "text-sm text-foreground", children: row.carrierName || _jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }), _jsx(TableCell, { children: _jsx(StatusTag, { order: row }) }), showRevenue && (_jsxs(TableCell, { className: "font-medium text-foreground", children: ["\u20AC ", Math.round(row.revenue ?? 0).toLocaleString("nl-NL")] })), _jsxs(TableCell, { children: [_jsx("div", { className: "text-sm text-foreground", children: ordered.date }), _jsx("div", { className: "text-xs text-muted-foreground", children: isBuffer
|
|
114
110
|
? `${bufferSize} orders`
|
|
115
111
|
: row.orderNumber || ordered.time })] }), _jsx(TableCell, { onClick: (e) => e.stopPropagation(), children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(MoreVertical, { className: "h-4 w-4" }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuItem, { disabled: isBuffer || !row.isLocal, onClick: () => !isBuffer && row.isLocal && onEditOrder?.(row), title: isBuffer
|
|
116
112
|
? "Buffer-orders kunnen niet gebundeld bewerkt worden."
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerkoopOrdersPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/VerkoopOrdersPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VerkoopOrdersPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/VerkoopOrdersPage.tsx"],"names":[],"mappings":"AAkFA,wBAAgB,iBAAiB,gCA2sBhC"}
|
|
@@ -33,6 +33,11 @@ const STATUS_TABS = [
|
|
|
33
33
|
BACKLOG_TAB,
|
|
34
34
|
]
|
|
35
35
|
: [{ id: s.id, label: s.label, hint: s.hint }]),
|
|
36
|
+
{
|
|
37
|
+
id: "not_reported",
|
|
38
|
+
label: "Nog niet afgemeld bij Floriday",
|
|
39
|
+
hint: "Verzonden in het ERP, maar nog niet afgemeld bij Floriday. Er wordt niets gewijzigd.",
|
|
40
|
+
},
|
|
36
41
|
];
|
|
37
42
|
// Statusfiltering, buffer-groepering en totalen gebeuren serverside
|
|
38
43
|
// (zie src/lib/salesorders-list.server.ts).
|
|
@@ -212,6 +217,7 @@ export function VerkoopOrdersPage() {
|
|
|
212
217
|
picked: 0,
|
|
213
218
|
shipped: 0,
|
|
214
219
|
cancelled: 0,
|
|
220
|
+
not_reported: 0,
|
|
215
221
|
};
|
|
216
222
|
const warnings = data?.warnings ?? [];
|
|
217
223
|
const truncated = data?.truncated ?? false;
|
|
@@ -315,7 +321,7 @@ export function VerkoopOrdersPage() {
|
|
|
315
321
|
(active
|
|
316
322
|
? "bg-primary text-primary-foreground"
|
|
317
323
|
: "bg-muted text-muted-foreground"), children: count })] }, t.id));
|
|
318
|
-
}) }) }), _jsxs("div", { className: "shrink-0 flex flex-wrap items-center justify-between gap-3", children: [_jsx(SalesOrdersFilters, { value: filters, onChange: setFilters }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setFilterPanelOpen(true), "aria-label": "Filters", children: [_jsx(Filter, { className: "mr-2 h-4 w-4" }), "Filters", activeFilterCount > 0 && (_jsx("span", { className: "ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground", children: activeFilterCount }))] }), _jsx(Button, { variant: "outline", size: "icon", onClick: handleSync, disabled: syncing, "aria-label": "Synchroniseren", title: "Synchroniseren", children: _jsx(RefreshCw, { className: "h-4 w-4 " + (syncing ? "animate-spin" : "") }) }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleExport, children: [_jsx(Download, { className: "mr-2 h-4 w-4" }), " Exporteren"] }), _jsxs(Button, { size: "sm", onClick: () => navigate({ to: "/floriday-verkoop/verkooporders/nieuw" }), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Bestelling aanmaken"] })] })] }), _jsx("div", { className: "shrink-0", children: _jsx(AnalyticsCards, { totals: totals, loading: isLoading }) }), _jsx("div", { className: "shrink-0", children: _jsx(StockConsumptionAlertsBanner, {}) }), error && (_jsxs("div", { className: "shrink-0 flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0 text-destructive" }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "font-medium text-destructive", children: "Bestellingen konden niet geladen worden" }), _jsx("div", { className: "mt-1 text-muted-foreground", children: error.message })] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => refetch(), disabled: isFetching, children: "Opnieuw proberen" })] })), (warnings.length > 0 || truncated) && (_jsxs("div", { className: "shrink-0 flex items-start gap-3 rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { className: "space-y-1 text-muted-foreground", children: [warnings.map((w) => (_jsx("div", { children: w }, w))), truncated && (_jsx("div", { children: "Niet alle orders konden worden meegenomen. Kies een kortere periode voor een volledig overzicht." }))] })] })), selectedRows.length > 0 && (_jsxs("div", { className: "shrink-0 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-primary/30 bg-primary/5 p-3", children: [_jsxs("div", { className: "text-sm text-foreground", children: [_jsx("span", { className: "font-medium", children: selectedRows.length }), " geselecteerd", selectedPlan.total !== selectedRows.length && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.total, " onderliggende bestelling(en)"] })), selectedPlan.skipped > 0 && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.skipped, " Floriday-order(s) worden overgeslagen"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setSelectedRowIds([]), children: "Selectie wissen" }), _jsx(Button, { size: "sm", className: "bg-destructive text-destructive-foreground hover:bg-destructive/90", disabled: selectedPlan.deletable.length === 0, onClick: () => {
|
|
324
|
+
}) }) }), _jsxs("div", { className: "shrink-0 flex flex-wrap items-center justify-between gap-3", children: [_jsx(SalesOrdersFilters, { value: filters, onChange: setFilters }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setFilterPanelOpen(true), "aria-label": "Filters", children: [_jsx(Filter, { className: "mr-2 h-4 w-4" }), "Filters", activeFilterCount > 0 && (_jsx("span", { className: "ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground", children: activeFilterCount }))] }), _jsx(Button, { variant: "outline", size: "icon", onClick: handleSync, disabled: syncing, "aria-label": "Synchroniseren", title: "Synchroniseren", children: _jsx(RefreshCw, { className: "h-4 w-4 " + (syncing ? "animate-spin" : "") }) }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleExport, children: [_jsx(Download, { className: "mr-2 h-4 w-4" }), " Exporteren"] }), _jsxs(Button, { size: "sm", onClick: () => navigate({ to: "/floriday-verkoop/verkooporders/nieuw" }), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Bestelling aanmaken"] })] })] }), _jsx("div", { className: "shrink-0", children: _jsx(AnalyticsCards, { totals: totals, loading: isLoading }) }), _jsx("div", { className: "shrink-0", children: _jsx(StockConsumptionAlertsBanner, {}) }), error && (_jsxs("div", { className: "shrink-0 flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0 text-destructive" }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "font-medium text-destructive", children: "Bestellingen konden niet geladen worden" }), _jsx("div", { className: "mt-1 text-muted-foreground", children: error.message })] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => refetch(), disabled: isFetching, children: "Opnieuw proberen" })] })), (warnings.length > 0 || truncated) && (_jsxs("div", { className: "shrink-0 flex items-start gap-3 rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { className: "space-y-1 text-muted-foreground", children: [warnings.map((w) => (_jsx("div", { children: w }, w))), truncated && (_jsx("div", { children: "Niet alle orders konden worden meegenomen. Kies een kortere periode voor een volledig overzicht." }))] })] })), selectedRows.length > 0 && (_jsxs("div", { className: "shrink-0 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-primary/30 bg-primary/5 p-3", children: [_jsxs("div", { className: "text-sm text-foreground", children: [_jsx("span", { className: "font-medium", children: selectedRows.length }), " geselecteerd", selectedPlan.total !== selectedRows.length && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.total, " onderliggende bestelling(en)"] })), selectedPlan.skipped > 0 && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.skipped, " Floriday-order(s) worden overgeslagen"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setSelectedRowIds([]), children: "Selectie wissen" }), _jsx(Button, { size: "sm", className: "bg-destructive text-destructive-foreground hover:bg-destructive/90", disabled: selectedPlan.deletable.length === 0, onClick: () => {
|
|
319
325
|
setCancelReason("");
|
|
320
326
|
setPendingAction({
|
|
321
327
|
rows: selectedRows,
|