@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.
Files changed (90) hide show
  1. package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
  2. package/dist-lib/components/verkoop/CreateOrderPage.js +33 -8
  3. package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -1
  4. package/dist-lib/components/verkoop/EditLocalOrderDialog.js +1 -1
  5. package/dist-lib/components/verkoop/FloridayStageLine.d.ts +15 -0
  6. package/dist-lib/components/verkoop/FloridayStageLine.d.ts.map +1 -0
  7. package/dist-lib/components/verkoop/FloridayStageLine.js +25 -0
  8. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts +1 -1
  9. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -1
  10. package/dist-lib/components/verkoop/PlanCoverageBadge.js +5 -2
  11. package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -1
  12. package/dist-lib/components/verkoop/SalesOrderDetailPage.js +1 -1
  13. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
  14. package/dist-lib/components/verkoop/SalesOrderDetailView.js +38 -6
  15. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  16. package/dist-lib/components/verkoop/SalesOrdersTable.js +4 -8
  17. package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
  18. package/dist-lib/components/verkoop/VerkoopOrdersPage.js +7 -1
  19. package/dist-lib/integrations/supabase/types.d.ts +1486 -2
  20. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  21. package/dist-lib/integrations/supabase/types.js +1 -0
  22. package/dist-lib/lib/belading.server.d.ts +0 -11
  23. package/dist-lib/lib/belading.server.d.ts.map +1 -1
  24. package/dist-lib/lib/belading.server.js +4 -41
  25. package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
  26. package/dist-lib/lib/cart-replan.functions.js +3 -22
  27. package/dist-lib/lib/central-secrets.server.d.ts +5 -0
  28. package/dist-lib/lib/central-secrets.server.d.ts.map +1 -0
  29. package/dist-lib/lib/central-secrets.server.js +65 -0
  30. package/dist-lib/lib/create-order.functions.d.ts +15 -0
  31. package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
  32. package/dist-lib/lib/create-order.functions.js +28 -13
  33. package/dist-lib/lib/customer-name.d.ts +8 -0
  34. package/dist-lib/lib/customer-name.d.ts.map +1 -0
  35. package/dist-lib/lib/customer-name.js +9 -0
  36. package/dist-lib/lib/engine-block-alerts.d.ts +22 -0
  37. package/dist-lib/lib/engine-block-alerts.d.ts.map +1 -0
  38. package/dist-lib/lib/engine-block-alerts.js +43 -0
  39. package/dist-lib/lib/engine-block-alerts.server.d.ts +7 -0
  40. package/dist-lib/lib/engine-block-alerts.server.d.ts.map +1 -0
  41. package/dist-lib/lib/engine-block-alerts.server.js +75 -0
  42. package/dist-lib/lib/floriday-change-diff.check.d.ts +2 -0
  43. package/dist-lib/lib/floriday-change-diff.check.d.ts.map +1 -0
  44. package/dist-lib/lib/floriday-change-diff.check.js +27 -0
  45. package/dist-lib/lib/floriday-change-diff.d.ts +7 -0
  46. package/dist-lib/lib/floriday-change-diff.d.ts.map +1 -0
  47. package/dist-lib/lib/floriday-change-diff.js +51 -0
  48. package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
  49. package/dist-lib/lib/floriday-mirror.functions.js +38 -39
  50. package/dist-lib/lib/floriday-status.d.ts +48 -0
  51. package/dist-lib/lib/floriday-status.d.ts.map +1 -0
  52. package/dist-lib/lib/floriday-status.js +99 -0
  53. package/dist-lib/lib/floriday-status.server.d.ts +7 -0
  54. package/dist-lib/lib/floriday-status.server.d.ts.map +1 -0
  55. package/dist-lib/lib/floriday-status.server.js +74 -0
  56. package/dist-lib/lib/load-carriers.server.d.ts +1 -1
  57. package/dist-lib/lib/load-carriers.server.d.ts.map +1 -1
  58. package/dist-lib/lib/load-carriers.server.js +3 -6
  59. package/dist-lib/lib/logistics-engine.server.d.ts.map +1 -1
  60. package/dist-lib/lib/logistics-engine.server.js +2 -22
  61. package/dist-lib/lib/order-block-mail.server.d.ts.map +1 -1
  62. package/dist-lib/lib/order-block-mail.server.js +31 -15
  63. package/dist-lib/lib/order-cancel.server.d.ts +9 -0
  64. package/dist-lib/lib/order-cancel.server.d.ts.map +1 -1
  65. package/dist-lib/lib/order-cancel.server.js +90 -0
  66. package/dist-lib/lib/plan-coverage.check.d.ts +2 -0
  67. package/dist-lib/lib/plan-coverage.check.d.ts.map +1 -0
  68. package/dist-lib/lib/plan-coverage.check.js +17 -0
  69. package/dist-lib/lib/plan-coverage.d.ts +12 -0
  70. package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
  71. package/dist-lib/lib/plan-coverage.js +27 -1
  72. package/dist-lib/lib/plan-coverage.server.d.ts.map +1 -1
  73. package/dist-lib/lib/plan-coverage.server.js +20 -13
  74. package/dist-lib/lib/review-dismissals.server.d.ts +3 -0
  75. package/dist-lib/lib/review-dismissals.server.d.ts.map +1 -0
  76. package/dist-lib/lib/review-dismissals.server.js +26 -0
  77. package/dist-lib/lib/salesorders-list.functions.d.ts +1 -1
  78. package/dist-lib/lib/salesorders-list.functions.js +1 -1
  79. package/dist-lib/lib/salesorders-list.server.d.ts +1 -1
  80. package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
  81. package/dist-lib/lib/salesorders-list.server.js +104 -3
  82. package/dist-lib/lib/salesorders-mapping.d.ts +17 -0
  83. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
  84. package/dist-lib/lib/salesorders-mapping.js +1 -0
  85. package/dist-lib/lib/salesorders.functions.d.ts +1 -5
  86. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  87. package/dist-lib/lib/salesorders.functions.js +32 -2
  88. package/dist-lib/lib/useSalesOrdersQuery.d.ts +1 -1
  89. package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
  90. 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,gCAmxB9B"}
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,sCAkiBA"}
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 { PlanCoverageSummary } from "../../lib/plan-coverage.js";
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,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,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,sCAkCA"}
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: reason ?? undefined, 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 })] }));
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: reason ?? undefined, children: text }) }));
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,gCAmPnC"}
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;AA2JnE,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,+BA8YA"}
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 klantReferentie = pickStr(o.customerOrderId) ?? "—";
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
- const incoterm = pickStr(o.delivery?.incoterm) ?? pickStr(o.incoterm) ?? "—";
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 totalAmount = Number(o.calculatedFields?.orderAmount?.value ?? order.revenue) || 0;
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
- const customerName = pickStr(cRaw.commercialName) ?? pickStr(c.commercial_name) ?? pickStr(c.company_name) ?? order.customer.name;
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: "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
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" }), _jsx(Row, { label: "Naam", children: _jsx("span", { className: "font-medium", children: customerName }) }), _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: [_jsxs("span", { className: "mr-2 text-xs font-normal text-muted-foreground", children: ["(", packages, " \u00D7 ", piecesPerPackage, " \u00D7 ", eurFlex.format(productUnit), ")"] }), eurFlex.format(totalAmount)] })] })] })] }), _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] }));
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;AAuBjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAwGnE,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,qBA+SA"}
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}` })), carrierDisabled && (_jsx(Badge, { variant: "outline", className: "border-destructive/40 text-destructive", title: "Deze ladingdrager is uitgeschakeld in de Logistiek Engine.", children: "Ladingdrager uitgeschakeld" }))] }), _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
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":"AA6EA,wBAAgB,iBAAiB,gCA0sBhC"}
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,