@flowselections/floriday-verkoop-module 1.0.93 → 1.0.98
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 +82 -43
- package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderKarindelingCard.js +1 -1
- package/dist-lib/components/verkoop/OrderPickupMomentPicker.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderPickupMomentPicker.js +2 -1
- package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -1
- package/dist-lib/components/verkoop/PlanCoverageBadge.js +7 -5
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +2 -1
- package/dist-lib/integrations/supabase/types.d.ts +327 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/carrier-availability.d.ts +0 -28
- package/dist-lib/lib/carrier-availability.d.ts.map +1 -1
- package/dist-lib/lib/carrier-availability.js +3 -141
- package/dist-lib/lib/cart-replan.functions.d.ts +5 -0
- package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
- package/dist-lib/lib/cart-replan.functions.js +25 -1
- package/dist-lib/lib/create-order.functions.d.ts +5 -0
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.js +81 -54
- package/dist-lib/lib/departure-preview.check.d.ts +2 -0
- package/dist-lib/lib/departure-preview.check.d.ts.map +1 -0
- package/dist-lib/lib/departure-preview.check.js +37 -0
- package/dist-lib/lib/departure-preview.d.ts +47 -0
- package/dist-lib/lib/departure-preview.d.ts.map +1 -0
- package/dist-lib/lib/departure-preview.functions.d.ts +13 -0
- package/dist-lib/lib/departure-preview.functions.d.ts.map +1 -0
- package/dist-lib/lib/departure-preview.functions.js +17 -0
- package/dist-lib/lib/departure-preview.js +70 -0
- package/dist-lib/lib/departure-preview.server.d.ts +10 -0
- package/dist-lib/lib/departure-preview.server.d.ts.map +1 -0
- package/dist-lib/lib/departure-preview.server.js +29 -0
- package/dist-lib/lib/floriday-external-fulfillment.check.d.ts +2 -0
- package/dist-lib/lib/floriday-external-fulfillment.check.d.ts.map +1 -0
- package/dist-lib/lib/floriday-external-fulfillment.check.js +21 -0
- package/dist-lib/lib/floriday-external-fulfillment.d.ts +19 -0
- package/dist-lib/lib/floriday-external-fulfillment.d.ts.map +1 -0
- package/dist-lib/lib/floriday-external-fulfillment.js +24 -0
- package/dist-lib/lib/floriday-external-fulfillment.server.d.ts +5 -0
- package/dist-lib/lib/floriday-external-fulfillment.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-external-fulfillment.server.js +110 -0
- package/dist-lib/lib/floriday-fulfillment-status.server.d.ts +2 -0
- package/dist-lib/lib/floriday-fulfillment-status.server.d.ts.map +1 -1
- package/dist-lib/lib/floriday-fulfillment-status.server.js +3 -0
- package/dist-lib/lib/floriday-line-key.check.d.ts +2 -0
- package/dist-lib/lib/floriday-line-key.check.d.ts.map +1 -0
- package/dist-lib/lib/floriday-line-key.check.js +31 -0
- package/dist-lib/lib/floriday-line-key.d.ts +12 -0
- package/dist-lib/lib/floriday-line-key.d.ts.map +1 -0
- package/dist-lib/lib/floriday-line-key.js +20 -0
- package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-mirror.functions.js +38 -2
- package/dist-lib/lib/logistics-engine.functions.d.ts +1 -1
- package/dist-lib/lib/order-departure.server.d.ts +1 -0
- package/dist-lib/lib/order-departure.server.d.ts.map +1 -1
- package/dist-lib/lib/order-departure.server.js +16 -4
- package/dist-lib/lib/order-pickup.functions.d.ts +4 -0
- package/dist-lib/lib/order-pickup.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-pickup.functions.js +7 -0
- package/dist-lib/lib/plan-coverage.d.ts +13 -1
- package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
- package/dist-lib/lib/plan-coverage.js +20 -1
- package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-list.server.js +6 -6
- package/dist-lib/lib/salesorders-mapping.d.ts +5 -0
- package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.js +6 -0
- package/package.json +2 -2
|
@@ -15,35 +15,7 @@ export type CarrierAvailability = {
|
|
|
15
15
|
delivery_weekdays?: number[] | null;
|
|
16
16
|
pickup_moments?: PickupMoment[] | null;
|
|
17
17
|
};
|
|
18
|
-
export type EarliestDelivery = {
|
|
19
|
-
/** Leverdatum als YYYY-MM-DD. */
|
|
20
|
-
deliveryISO: string;
|
|
21
|
-
/** Ophaal-/aanmelddag als YYYY-MM-DD. */
|
|
22
|
-
pickupISO: string;
|
|
23
|
-
/** Uiterste aanmeldmoment dat hierbij hoort (ISO-datum + tijd), indien bekend. */
|
|
24
|
-
signupDeadlineISO: string | null;
|
|
25
|
-
signupTime: string | null;
|
|
26
|
-
/** Aanlevertijd van het gekozen moment, bv. "20:00". */
|
|
27
|
-
deliveryTime: string | null;
|
|
28
|
-
};
|
|
29
18
|
export declare function toISODate(d: Date): string;
|
|
30
19
|
/** "20:00:00" / "20:00" -> "20:00"; leeg -> null. */
|
|
31
20
|
export declare function normalizeTime(t: string | null | undefined): string | null;
|
|
32
|
-
/**
|
|
33
|
-
* Eerst mogelijke leverdatum.
|
|
34
|
-
*
|
|
35
|
-
* - Een ophaaldag telt alleen mee als het bijbehorende aanmeldmoment nog niet
|
|
36
|
-
* verstreken is (aanmelddeadline = ophaaldag − signup_days op signup_time).
|
|
37
|
-
* - Ophaaldag moet in pickup_weekdays vallen, leverdag in delivery_weekdays.
|
|
38
|
-
* - `pickDays` (interne orderpicktijd) is de minimale voorlooptijd tot de ophaaldag.
|
|
39
|
-
*/
|
|
40
|
-
export declare function computeEarliestDelivery(carrier: CarrierAvailability | null | undefined, pickDays: number, now?: Date, horizonDays?: number): EarliestDelivery;
|
|
41
|
-
/** "Nu" in Europe/Amsterdam als lokale Date — voor servercode die in UTC draait. */
|
|
42
|
-
export declare function nowInAmsterdam(base?: Date): Date;
|
|
43
|
-
/**
|
|
44
|
-
* Aanlevertijd die hoort bij een (al vastgelegde) leverdatum van een order.
|
|
45
|
-
* Kiest het aanmeldmoment dat op die datum uitkomt; bij meerdere momenten het
|
|
46
|
-
* moment dat het laatst nog haalbaar was op het referentiemoment (besteltijd).
|
|
47
|
-
*/
|
|
48
|
-
export declare function resolveDeliveryTimeForDate(carrier: CarrierAvailability | null | undefined, deliveryISO: string, reference?: Date): string | null;
|
|
49
21
|
//# sourceMappingURL=carrier-availability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"carrier-availability.d.ts","sourceRoot":"","sources":["../../src/lib/carrier-availability.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"carrier-availability.d.ts","sourceRoot":"","sources":["../../src/lib/carrier-availability.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;CACxC,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAEzC;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAIzE"}
|
|
@@ -1,26 +1,9 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// exact hetzelfde antwoord geven.
|
|
1
|
+
// Gegevens van de vervoerder (pickup_moments). Hier wordt niets berekend:
|
|
2
|
+
// ophaalmomenten, werkdagen, tijdzone en de eerst haalbare leverdatum komen
|
|
3
|
+
// van de Logistiek Engine (logistics_departure_preview / logistics_order_departure).
|
|
5
4
|
export function toISODate(d) {
|
|
6
5
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
7
6
|
}
|
|
8
|
-
function addDays(d, n) {
|
|
9
|
-
const c = new Date(d.getTime());
|
|
10
|
-
c.setDate(c.getDate() + n);
|
|
11
|
-
return c;
|
|
12
|
-
}
|
|
13
|
-
/** ISO-weekdag: maandag = 1 … zondag = 7. */
|
|
14
|
-
function isoWeekday(d) {
|
|
15
|
-
return d.getDay() === 0 ? 7 : d.getDay();
|
|
16
|
-
}
|
|
17
|
-
function parseTime(t, fallback) {
|
|
18
|
-
const s = (t ?? fallback) || fallback;
|
|
19
|
-
const m = /^(\d{1,2}):(\d{2})/.exec(String(s));
|
|
20
|
-
if (!m)
|
|
21
|
-
return [23, 59];
|
|
22
|
-
return [Number(m[1]), Number(m[2])];
|
|
23
|
-
}
|
|
24
7
|
/** "20:00:00" / "20:00" -> "20:00"; leeg -> null. */
|
|
25
8
|
export function normalizeTime(t) {
|
|
26
9
|
const m = /^(\d{1,2}):(\d{2})/.exec(String(t ?? "").trim());
|
|
@@ -28,124 +11,3 @@ export function normalizeTime(t) {
|
|
|
28
11
|
return null;
|
|
29
12
|
return `${String(Number(m[1])).padStart(2, "0")}:${m[2]}`;
|
|
30
13
|
}
|
|
31
|
-
function allowsWeekday(list, d) {
|
|
32
|
-
if (!Array.isArray(list) || list.length === 0)
|
|
33
|
-
return true;
|
|
34
|
-
return list.map(Number).includes(isoWeekday(d));
|
|
35
|
-
}
|
|
36
|
-
function momentsOf(carrier) {
|
|
37
|
-
const raw = Array.isArray(carrier.pickup_moments) ? carrier.pickup_moments : [];
|
|
38
|
-
if (raw.length > 0)
|
|
39
|
-
return raw;
|
|
40
|
-
// Terugval op de losse signup_time-velden.
|
|
41
|
-
const times = [carrier.signup_time_1, carrier.signup_time_2].filter(Boolean);
|
|
42
|
-
if (times.length > 0) {
|
|
43
|
-
return times.map((t) => ({
|
|
44
|
-
signup_time: t,
|
|
45
|
-
signup_days: carrier.signup_days_before_delivery ?? 0,
|
|
46
|
-
delivery_days: carrier.delivery_days ?? 0,
|
|
47
|
-
}));
|
|
48
|
-
}
|
|
49
|
-
// Geen aanmeldmomenten bekend: één moment zonder deadline.
|
|
50
|
-
return [{ signup_time: null, signup_days: carrier.signup_days_before_delivery ?? 0, delivery_days: carrier.delivery_days ?? 0 }];
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Eerst mogelijke leverdatum.
|
|
54
|
-
*
|
|
55
|
-
* - Een ophaaldag telt alleen mee als het bijbehorende aanmeldmoment nog niet
|
|
56
|
-
* verstreken is (aanmelddeadline = ophaaldag − signup_days op signup_time).
|
|
57
|
-
* - Ophaaldag moet in pickup_weekdays vallen, leverdag in delivery_weekdays.
|
|
58
|
-
* - `pickDays` (interne orderpicktijd) is de minimale voorlooptijd tot de ophaaldag.
|
|
59
|
-
*/
|
|
60
|
-
export function computeEarliestDelivery(carrier, pickDays, now = new Date(), horizonDays = 90) {
|
|
61
|
-
const lead = Math.max(0, Number(pickDays) || 0);
|
|
62
|
-
const today = new Date(now.getTime());
|
|
63
|
-
today.setHours(0, 0, 0, 0);
|
|
64
|
-
const carrierDeliveryDays = Math.max(0, Number(carrier?.delivery_days ?? 0) || 0);
|
|
65
|
-
if (!carrier) {
|
|
66
|
-
const d = addDays(today, lead);
|
|
67
|
-
return { deliveryISO: toISODate(d), pickupISO: toISODate(d), signupDeadlineISO: null, signupTime: null, deliveryTime: null };
|
|
68
|
-
}
|
|
69
|
-
const moments = momentsOf(carrier);
|
|
70
|
-
let best = null;
|
|
71
|
-
for (let i = lead; i <= horizonDays; i++) {
|
|
72
|
-
const pickupDate = addDays(today, i);
|
|
73
|
-
if (!allowsWeekday(carrier.pickup_weekdays, pickupDate))
|
|
74
|
-
continue;
|
|
75
|
-
for (const m of moments) {
|
|
76
|
-
const signupDays = Math.max(0, Number(m.signup_days ?? carrier.signup_days_before_delivery ?? 0) || 0);
|
|
77
|
-
const signupDate = addDays(pickupDate, -signupDays);
|
|
78
|
-
let deadlineISO = null;
|
|
79
|
-
if (m.signup_time) {
|
|
80
|
-
const [hh, mm] = parseTime(m.signup_time, "23:59");
|
|
81
|
-
const deadline = new Date(signupDate.getTime());
|
|
82
|
-
deadline.setHours(hh, mm, 0, 0);
|
|
83
|
-
if (deadline.getTime() <= now.getTime())
|
|
84
|
-
continue; // aanmeldmoment verstreken
|
|
85
|
-
deadlineISO = `${toISODate(signupDate)}T${String(hh).padStart(2, "0")}:${String(mm).padStart(2, "0")}`;
|
|
86
|
-
}
|
|
87
|
-
else if (signupDate.getTime() < today.getTime()) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
const deliveryDays = Math.max(0, Number(m.delivery_days ?? carrierDeliveryDays) || 0);
|
|
91
|
-
const deliveryDate = addDays(pickupDate, deliveryDays);
|
|
92
|
-
if (!allowsWeekday(carrier.delivery_weekdays, deliveryDate))
|
|
93
|
-
continue;
|
|
94
|
-
const candidate = {
|
|
95
|
-
deliveryISO: toISODate(deliveryDate),
|
|
96
|
-
pickupISO: toISODate(pickupDate),
|
|
97
|
-
signupDeadlineISO: deadlineISO,
|
|
98
|
-
signupTime: m.signup_time ?? null,
|
|
99
|
-
deliveryTime: normalizeTime(m.delivery_time),
|
|
100
|
-
};
|
|
101
|
-
if (!best ||
|
|
102
|
-
candidate.deliveryISO < best.deliveryISO ||
|
|
103
|
-
(candidate.deliveryISO === best.deliveryISO &&
|
|
104
|
-
(candidate.deliveryTime ?? "99:99") < (best.deliveryTime ?? "99:99"))) {
|
|
105
|
-
best = candidate;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (best)
|
|
109
|
-
break; // eerste geldige ophaaldag bepaalt de vroegste levering
|
|
110
|
-
}
|
|
111
|
-
if (best)
|
|
112
|
-
return best;
|
|
113
|
-
const fallback = addDays(today, lead + carrierDeliveryDays);
|
|
114
|
-
return { deliveryISO: toISODate(fallback), pickupISO: toISODate(fallback), signupDeadlineISO: null, signupTime: null, deliveryTime: null };
|
|
115
|
-
}
|
|
116
|
-
/** "Nu" in Europe/Amsterdam als lokale Date — voor servercode die in UTC draait. */
|
|
117
|
-
export function nowInAmsterdam(base = new Date()) {
|
|
118
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
119
|
-
timeZone: "Europe/Amsterdam",
|
|
120
|
-
year: "numeric", month: "2-digit", day: "2-digit",
|
|
121
|
-
hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false,
|
|
122
|
-
}).formatToParts(base);
|
|
123
|
-
const get = (t) => Number(parts.find((p) => p.type === t)?.value ?? 0);
|
|
124
|
-
return new Date(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"), 0);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Aanlevertijd die hoort bij een (al vastgelegde) leverdatum van een order.
|
|
128
|
-
* Kiest het aanmeldmoment dat op die datum uitkomt; bij meerdere momenten het
|
|
129
|
-
* moment dat het laatst nog haalbaar was op het referentiemoment (besteltijd).
|
|
130
|
-
*/
|
|
131
|
-
export function resolveDeliveryTimeForDate(carrier, deliveryISO, reference = new Date()) {
|
|
132
|
-
if (!carrier || !deliveryISO)
|
|
133
|
-
return null;
|
|
134
|
-
const moments = momentsOf(carrier);
|
|
135
|
-
const candidates = [];
|
|
136
|
-
for (const m of moments) {
|
|
137
|
-
const time = normalizeTime(m.delivery_time);
|
|
138
|
-
if (!time)
|
|
139
|
-
continue;
|
|
140
|
-
candidates.push({ time, signup: normalizeTime(m.signup_time) });
|
|
141
|
-
}
|
|
142
|
-
if (candidates.length === 0)
|
|
143
|
-
return null;
|
|
144
|
-
if (candidates.length === 1)
|
|
145
|
-
return candidates[0].time;
|
|
146
|
-
const refTime = `${String(reference.getHours()).padStart(2, "0")}:${String(reference.getMinutes()).padStart(2, "0")}`;
|
|
147
|
-
const sorted = [...candidates].sort((a, b) => a.time.localeCompare(b.time));
|
|
148
|
-
// Eerste moment waarvan het aanmeldmoment op de besteltijd nog niet verstreken is.
|
|
149
|
-
const still = sorted.find((c) => !c.signup || c.signup > refTime);
|
|
150
|
-
return (still ?? sorted[sorted.length - 1]).time;
|
|
151
|
-
}
|
|
@@ -79,6 +79,11 @@ export declare const getOrderPlanCoverage: import("@tanstack/start-client-core")
|
|
|
79
79
|
}, Promise<{
|
|
80
80
|
orderId: string;
|
|
81
81
|
coverage: import("./plan-coverage.js").PlanCoverage;
|
|
82
|
+
externalEvent: {
|
|
83
|
+
status: string | null;
|
|
84
|
+
error: string | null;
|
|
85
|
+
sendError: string | null;
|
|
86
|
+
} | null;
|
|
82
87
|
}>>;
|
|
83
88
|
export declare const replanBufferForOrder: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
84
89
|
supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-replan.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cart-replan.functions.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM;QAYrD,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAlBnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC,CA+YD;AA4BD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM;QAzBxD,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAoBnB;AAED,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;QA/B3B,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GA6BhB,CAAC;AAML,wBAAsB,oBAAoB,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC;IAC/D,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC,CAED;AAMD,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO
|
|
1
|
+
{"version":3,"file":"cart-replan.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cart-replan.functions.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM;QAYrD,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAlBnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC,CA+YD;AA4BD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM;QAzBxD,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAoBnB;AAED,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;QA/B3B,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GA6BhB,CAAC;AAML,wBAAsB,oBAAoB,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC;IAC/D,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC,CAED;AAMD,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;;;;gBAUA,MAAM,GAAG,IAAI;eAAS,MAAM,GAAG,IAAI;mBAAa,MAAM,GAAG,IAAI;;GAsB1F,CAAC;AAEL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;QAxf3B,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAsfhB,CAAC"}
|
|
@@ -393,7 +393,31 @@ export const getOrderPlanCoverage = createServerFn({ method: "GET" })
|
|
|
393
393
|
const { unknownCoverage } = await import("./plan-coverage.js");
|
|
394
394
|
const cov = (await loadPlanCoverage(context.supabase, [dbOrderId])).get(dbOrderId) ??
|
|
395
395
|
unknownCoverage("Geen antwoord van de Engine");
|
|
396
|
-
|
|
396
|
+
// Uitkomst van de melding "Afgehandeld in Floriday" (alleen lezen).
|
|
397
|
+
let externalEvent = null;
|
|
398
|
+
try {
|
|
399
|
+
const { data: o } = await context.supabase.from("orders")
|
|
400
|
+
.select("custom_fields")
|
|
401
|
+
.eq("id", dbOrderId)
|
|
402
|
+
.maybeSingle();
|
|
403
|
+
const cf = (o?.custom_fields ?? {});
|
|
404
|
+
const evId = typeof cf.floriday_external_engine_event_id === "string" ? cf.floriday_external_engine_event_id : null;
|
|
405
|
+
const sendError = typeof cf.floriday_external_engine_error === "string" ? cf.floriday_external_engine_error : null;
|
|
406
|
+
if (evId) {
|
|
407
|
+
const { data: ev } = await context.supabase.from("logistics_events")
|
|
408
|
+
.select("status, error")
|
|
409
|
+
.eq("id", evId)
|
|
410
|
+
.maybeSingle();
|
|
411
|
+
externalEvent = { status: ev?.status ?? null, error: ev?.error ?? null, sendError };
|
|
412
|
+
}
|
|
413
|
+
else if (sendError) {
|
|
414
|
+
externalEvent = { status: null, error: null, sendError };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
externalEvent = null;
|
|
419
|
+
}
|
|
420
|
+
return { orderId: dbOrderId, coverage: cov, externalEvent };
|
|
397
421
|
});
|
|
398
422
|
export const replanBufferForOrder = createServerFn({ method: "POST" })
|
|
399
423
|
.middleware([requireSupabaseAuth])
|
|
@@ -146,6 +146,10 @@ export declare const createManualOrder: import("@tanstack/start-client-core").Op
|
|
|
146
146
|
isReservation?: boolean | undefined;
|
|
147
147
|
loadCarrierType?: string | null | undefined;
|
|
148
148
|
notes?: string | null | undefined;
|
|
149
|
+
momentKey?: string | null | undefined;
|
|
150
|
+
acceptLateSignup?: boolean | undefined;
|
|
151
|
+
acceptedByName?: string | null | undefined;
|
|
152
|
+
source?: "manual" | "mailbox" | undefined;
|
|
149
153
|
}, Promise<{
|
|
150
154
|
ok: true;
|
|
151
155
|
orderId: string;
|
|
@@ -219,6 +223,7 @@ export declare const updateLocalOrder: import("@tanstack/start-client-core").Opt
|
|
|
219
223
|
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
220
224
|
orderId: string;
|
|
221
225
|
deliveryDate?: string | undefined;
|
|
226
|
+
acceptLateSignup?: boolean | undefined;
|
|
222
227
|
items?: {
|
|
223
228
|
itemId: string;
|
|
224
229
|
quantity: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-order.functions.d.ts","sourceRoot":"","sources":["../../src/lib/create-order.functions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,2BAA2B;;;;;;GA+CpC,CAAC;AAIL,eAAO,MAAM,2BAA2B;;;;0CAElB,OAAO;;;;GAoDzB,CAAC;AAWL,eAAO,MAAM,0BAA0B;;;;;;YA+D7B,MAAM;iBACD,MAAM;sBACD,MAAM,GAAG,IAAI;cACrB,MAAM;oBACA,MAAM,GAAG,IAAI;0BACP,MAAM;0BACN,MAAM;yBACP,MAAM;wBACP,MAAM;wBACN,MAAM;yBACL,MAAM;kBACb,OAAO;gBACT,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS;;GA6RpD,CAAC;AAGL,eAAO,MAAM,kCAAkC;;;;0CAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;GAkDzB,CAAC;AAKL,eAAO,MAAM,qBAAqB;;;;;;YAoBI,MAAM;;;GAIxC,CAAC;AAGL,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;GAWnC,CAAC;AASL,eAAO,MAAM,8BAA8B;;;;8CAEjB,OAAO;;;;GAU7B,CAAC;AASL,eAAO,MAAM,mBAAmB;;;;;;;;0BAgBuB,MAAM;0BAAoB,MAAM;yBAAmB,MAAM;;;GA8C5G,CAAC;AAGL,eAAO,MAAM,kBAAkB;;;;;;GAU3B,CAAC;
|
|
1
|
+
{"version":3,"file":"create-order.functions.d.ts","sourceRoot":"","sources":["../../src/lib/create-order.functions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,2BAA2B;;;;;;GA+CpC,CAAC;AAIL,eAAO,MAAM,2BAA2B;;;;0CAElB,OAAO;;;;GAoDzB,CAAC;AAWL,eAAO,MAAM,0BAA0B;;;;;;YA+D7B,MAAM;iBACD,MAAM;sBACD,MAAM,GAAG,IAAI;cACrB,MAAM;oBACA,MAAM,GAAG,IAAI;0BACP,MAAM;0BACN,MAAM;yBACP,MAAM;wBACP,MAAM;wBACN,MAAM;yBACL,MAAM;kBACb,OAAO;gBACT,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS;;GA6RpD,CAAC;AAGL,eAAO,MAAM,kCAAkC;;;;0CAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;GAkDzB,CAAC;AAKL,eAAO,MAAM,qBAAqB;;;;;;YAoBI,MAAM;;;GAIxC,CAAC;AAGL,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;GAWnC,CAAC;AASL,eAAO,MAAM,8BAA8B;;;;8CAEjB,OAAO;;;;GAU7B,CAAC;AASL,eAAO,MAAM,mBAAmB;;;;;;;;0BAgBuB,MAAM;0BAAoB,MAAM;yBAAmB,MAAM;;;GA8C5G,CAAC;AAGL,eAAO,MAAM,kBAAkB;;;;;;GAU3B,CAAC;AA0CL,eAAO,MAAM,iBAAiB;;;;8CAEJ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;aA0OY,MAAM;GAE/C,CAAC;AAKL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;GAY7B,CAAC;AAQL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;GAoG7B,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;8CAER,OAAO;;;;GAyB7B,CAAC;AA0CL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;aA0JG,MAAM;iBACQ,MAAM,GAAG,IAAI;kBACX,MAAM;;YAEnB,MAAM,GAAG,IAAI;;;;YAkB7B,MAAM;mBACS,MAAM,GAAG,IAAI;qBACT,MAAM;;cAErB,MAAM,GAAG,IAAI;;;;;;GAQpC,CAAC;AAIL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;;;;;;;;;;;;;;;GAmO7B,CAAC;AAKL,eAAO,MAAM,kBAAkB;;;;8CAEL,OAAO;;;;;;;;WAUM,MAAM;YAAU,MAAM,GAAG,IAAI;WAahE,CAAC"}
|
|
@@ -658,15 +658,14 @@ const CreateManualOrderInput = z.object({
|
|
|
658
658
|
loadCarrierType: z.string().max(50).nullable().optional(),
|
|
659
659
|
notes: z.string().max(2000).nullable().optional(),
|
|
660
660
|
lines: z.array(LineInput).min(1),
|
|
661
|
+
// Gekozen ophaalmoment (momentKey uit de Engine-voorbeeldversie).
|
|
662
|
+
momentKey: z.string().max(64).nullable().optional(),
|
|
663
|
+
// Bewust aanmaken na de aanmeldtijd (spoedorder). Zonder dit wordt een
|
|
664
|
+
// niet-haalbare leverdatum geweigerd.
|
|
665
|
+
acceptLateSignup: z.boolean().optional(),
|
|
666
|
+
acceptedByName: z.string().max(255).nullable().optional(),
|
|
667
|
+
source: z.enum(["manual", "mailbox"]).optional(),
|
|
661
668
|
});
|
|
662
|
-
function addCalendarDays(base, n) {
|
|
663
|
-
const x = new Date(base);
|
|
664
|
-
x.setDate(x.getDate() + n);
|
|
665
|
-
return x;
|
|
666
|
-
}
|
|
667
|
-
function toISODate(d) {
|
|
668
|
-
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
669
|
-
}
|
|
670
669
|
export const createManualOrder = createServerFn({ method: "POST" })
|
|
671
670
|
.middleware([requireSupabaseAuth])
|
|
672
671
|
.inputValidator((input) => CreateManualOrderInput.parse(input))
|
|
@@ -677,45 +676,52 @@ export const createManualOrder = createServerFn({ method: "POST" })
|
|
|
677
676
|
const { assertOrderAllowed } = await import("./logistics-stock.server.js");
|
|
678
677
|
await assertOrderAllowed(context.supabase, data.lines.map((l) => ({ productId: l.product_id, quantity: Number(l.quantity) })));
|
|
679
678
|
}
|
|
680
|
-
// Validatie eerst mogelijke leverdatum — o.b.v. de aanmeldmomenten van de
|
|
681
|
-
// vervoerder (pickup_moments), niet enkel kalenderdagen. Een reservering
|
|
682
|
-
// heeft nog geen vervoerder en dus geen leverdatumvalidatie.
|
|
683
|
-
if (!data.isReservation && !data.carrierId) {
|
|
684
|
-
throw new Error("Selecteer een vervoerder");
|
|
685
|
-
}
|
|
686
679
|
// Ladingdrager: zonder keuze de standaard van de Engine; geen eigen controle.
|
|
687
680
|
const { resolveLoadCarrierType } = await import("./load-carriers.server.js");
|
|
688
681
|
const loadCarrierType = await resolveLoadCarrierType(context.supabase, data.loadCarrierType);
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
: null;
|
|
696
|
-
const carrierDeliveryDays = Math.max(0, Number(c?.delivery_days ?? 0));
|
|
697
|
-
const { data: settings } = await context.supabase
|
|
698
|
-
.from("afhandeling_settings")
|
|
699
|
-
.select("pick_days_before_transport")
|
|
700
|
-
.order("updated_at", { ascending: false })
|
|
701
|
-
.limit(1).maybeSingle();
|
|
702
|
-
const pickDays = Math.max(0, Number(settings?.pick_days_before_transport ?? 0));
|
|
703
|
-
const { computeEarliestDelivery, nowInAmsterdam, resolveDeliveryTimeForDate } = await import("./carrier-availability.js");
|
|
704
|
-
const nowLocal = nowInAmsterdam();
|
|
705
|
-
const earliest = computeEarliestDelivery(c, pickDays, nowLocal);
|
|
706
|
-
// Aanlevertijd van het aanmeldmoment dat bij deze leverdatum hoort (bv. 20:00).
|
|
707
|
-
const deliveryTime = data.isReservation
|
|
708
|
-
? null
|
|
709
|
-
: (data.deliveryDate === earliest.deliveryISO
|
|
710
|
-
? earliest.deliveryTime
|
|
711
|
-
: resolveDeliveryTimeForDate(c, data.deliveryDate ?? "", nowLocal));
|
|
712
|
-
const earliestISO = earliest.deliveryISO;
|
|
682
|
+
// Ophaalmoment en haalbaarheid komen alleen van de Logistiek Engine
|
|
683
|
+
// (logistics_departure_preview). Geen eigen berekening of terugval.
|
|
684
|
+
let carrierId = data.isReservation ? null : (data.carrierId ?? null);
|
|
685
|
+
let momentKey = null;
|
|
686
|
+
let deliveryTime = null;
|
|
687
|
+
let lateSignup = null;
|
|
713
688
|
if (!data.isReservation) {
|
|
714
689
|
if (!data.deliveryDate)
|
|
715
690
|
throw new Error("Leverdatum ontbreekt.");
|
|
716
|
-
|
|
717
|
-
|
|
691
|
+
const { loadDeparturePreview, deliveryTimeForMoment } = await import("./departure-preview.server.js");
|
|
692
|
+
const { decidePreview } = await import("./departure-preview.js");
|
|
693
|
+
const preview = await loadDeparturePreview(context.supabase, {
|
|
694
|
+
carrierId,
|
|
695
|
+
deliveryLocation: data.deliveryLocationId,
|
|
696
|
+
deliveryDate: data.deliveryDate.slice(0, 10),
|
|
697
|
+
momentKey: data.momentKey ?? null,
|
|
698
|
+
});
|
|
699
|
+
const d = decidePreview(preview);
|
|
700
|
+
if (d.kind === "blocked")
|
|
701
|
+
throw new Error(d.reason);
|
|
702
|
+
if (d.kind === "late") {
|
|
703
|
+
if (!data.acceptLateSignup) {
|
|
704
|
+
throw new Error(d.firstDate
|
|
705
|
+
? `${d.reason} De eerste haalbare leverdatum is ${d.firstDate}.`
|
|
706
|
+
: d.reason);
|
|
707
|
+
}
|
|
708
|
+
const by = context.claims?.email ?? null;
|
|
709
|
+
lateSignup = {
|
|
710
|
+
by_user_id: context.userId ?? null,
|
|
711
|
+
by_email: by,
|
|
712
|
+
by_name: data.acceptedByName ?? by,
|
|
713
|
+
at: new Date().toISOString(),
|
|
714
|
+
delivery_date: data.deliveryDate.slice(0, 10),
|
|
715
|
+
signup_deadline: preview?.chosen?.signupDeadline ?? null,
|
|
716
|
+
reason: d.reason,
|
|
717
|
+
source: data.source ?? "manual",
|
|
718
|
+
};
|
|
718
719
|
}
|
|
720
|
+
carrierId = preview?.carrierId ?? carrierId;
|
|
721
|
+
if (!carrierId)
|
|
722
|
+
throw new Error("Er is geen vervoerder bekend voor deze afleverlocatie. Kies een vervoerder.");
|
|
723
|
+
momentKey = d.momentKey;
|
|
724
|
+
deliveryTime = await deliveryTimeForMoment(context.supabase, carrierId, momentKey);
|
|
719
725
|
}
|
|
720
726
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
721
727
|
// Zorg dat elk product_id (= identiteit uit de voorraadmodule) een rij
|
|
@@ -829,8 +835,10 @@ export const createManualOrder = createServerFn({ method: "POST" })
|
|
|
829
835
|
source: "manual",
|
|
830
836
|
delivery_location: data.deliveryLocationId,
|
|
831
837
|
pickup_location: data.pickupLocationId,
|
|
832
|
-
carrier:
|
|
838
|
+
carrier: carrierId,
|
|
833
839
|
delivery_time: deliveryTime,
|
|
840
|
+
pickup_moment: momentKey,
|
|
841
|
+
...(lateSignup ? { late_signup_override: lateSignup } : {}),
|
|
834
842
|
is_reservation: !!data.isReservation,
|
|
835
843
|
load_carrier_type: loadCarrierType,
|
|
836
844
|
},
|
|
@@ -1036,6 +1044,7 @@ export const deleteMailboxProposal = createServerFn({ method: "POST" })
|
|
|
1036
1044
|
const UpdateLocalOrderInput = z.object({
|
|
1037
1045
|
orderId: z.string().uuid(),
|
|
1038
1046
|
deliveryDate: z.string().min(1).max(50).optional(),
|
|
1047
|
+
acceptLateSignup: z.boolean().optional(),
|
|
1039
1048
|
items: z
|
|
1040
1049
|
.array(z.object({
|
|
1041
1050
|
itemId: z.string().uuid(),
|
|
@@ -1255,7 +1264,7 @@ export const updateLocalOrder = createServerFn({ method: "POST" })
|
|
|
1255
1264
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
1256
1265
|
const { data: order, error: oErr } = await supabaseAdmin
|
|
1257
1266
|
.from("orders")
|
|
1258
|
-
.select("id, custom_fields, order_source, is_reservation, plan_locked_at")
|
|
1267
|
+
.select("id, custom_fields, order_source, is_reservation, plan_locked_at, delivery_date")
|
|
1259
1268
|
.eq("id", data.orderId)
|
|
1260
1269
|
.maybeSingle();
|
|
1261
1270
|
if (oErr)
|
|
@@ -1378,23 +1387,41 @@ export const updateLocalOrder = createServerFn({ method: "POST" })
|
|
|
1378
1387
|
}
|
|
1379
1388
|
// Leverdatum bijwerken (alleen als niet-reservering).
|
|
1380
1389
|
if (data.deliveryDate && !order.is_reservation) {
|
|
1381
|
-
//
|
|
1390
|
+
// Haalbaarheid en moment alleen via de Engine; geen eigen berekening.
|
|
1382
1391
|
let newDeliveryTime = cf?.delivery_time ?? null;
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
const
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1392
|
+
let newMoment = cf?.pickup_moment ?? null;
|
|
1393
|
+
let lateOverride = cf?.late_signup_override ?? null;
|
|
1394
|
+
const newDate = String(data.deliveryDate).slice(0, 10);
|
|
1395
|
+
if (newDate !== String(order.delivery_date ?? "").slice(0, 10) && cf?.delivery_location) {
|
|
1396
|
+
const { loadDeparturePreview, deliveryTimeForMoment } = await import("./departure-preview.server.js");
|
|
1397
|
+
const { decidePreview } = await import("./departure-preview.js");
|
|
1398
|
+
const preview = await loadDeparturePreview(context.supabase, {
|
|
1399
|
+
carrierId: cf?.carrier ?? null,
|
|
1400
|
+
deliveryLocation: String(cf.delivery_location),
|
|
1401
|
+
deliveryDate: newDate,
|
|
1402
|
+
momentKey: null,
|
|
1403
|
+
});
|
|
1404
|
+
const d = decidePreview(preview);
|
|
1405
|
+
if (d.kind === "blocked")
|
|
1406
|
+
throw new Error(d.reason);
|
|
1407
|
+
if (d.kind === "late") {
|
|
1408
|
+
if (!data.acceptLateSignup) {
|
|
1409
|
+
throw new Error(d.firstDate ? `${d.reason} De eerste haalbare leverdatum is ${d.firstDate}.` : d.reason);
|
|
1410
|
+
}
|
|
1411
|
+
const by = context.claims?.email ?? null;
|
|
1412
|
+
lateOverride = {
|
|
1413
|
+
by_user_id: context.userId ?? null, by_email: by, by_name: by,
|
|
1414
|
+
at: new Date().toISOString(), delivery_date: newDate,
|
|
1415
|
+
signup_deadline: preview?.chosen?.signupDeadline ?? null, reason: d.reason, source: "manual",
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
newMoment = d.momentKey;
|
|
1419
|
+
newDeliveryTime = await deliveryTimeForMoment(context.supabase, cf?.carrier ?? null, newMoment);
|
|
1393
1420
|
}
|
|
1394
1421
|
const { error: uErr } = await supabaseAdmin.from("orders")
|
|
1395
1422
|
.update({
|
|
1396
1423
|
delivery_date: data.deliveryDate,
|
|
1397
|
-
custom_fields: { ...(cf ?? {}), delivery_time: newDeliveryTime },
|
|
1424
|
+
custom_fields: { ...(cf ?? {}), delivery_time: newDeliveryTime, pickup_moment: newMoment, ...(lateOverride ? { late_signup_override: lateOverride } : {}) },
|
|
1398
1425
|
updated_at: new Date().toISOString(),
|
|
1399
1426
|
})
|
|
1400
1427
|
.eq("id", data.orderId);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"departure-preview.check.d.ts","sourceRoot":"","sources":["../../src/lib/departure-preview.check.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Controle voorbeeld-ophaalmoment. Draai: bun src/lib/departure-preview.check.ts
|
|
2
|
+
import { decidePreview, normalizePreview } from "./departure-preview.js";
|
|
3
|
+
import { LIST_CHUNK } from "./order-departure.server.js";
|
|
4
|
+
let failed = 0;
|
|
5
|
+
function check(name, got, want) {
|
|
6
|
+
const ok = got === want;
|
|
7
|
+
if (!ok)
|
|
8
|
+
failed++;
|
|
9
|
+
console.log(`${ok ? "OK " : "FOUT"} ${name}: ${got}${ok ? "" : ` (verwacht ${want})`}`);
|
|
10
|
+
}
|
|
11
|
+
const good = decidePreview(normalizePreview({
|
|
12
|
+
ok: true, carrierId: "c", deliveryDateFeasible: true,
|
|
13
|
+
moments: [{ momentKey: "1@15:00|1@13:00", departureAt: "2026-10-20T13:00:00Z", signupDeadline: "2026-10-20T11:00:00Z", feasible: true },
|
|
14
|
+
{ momentKey: "1@09:00|1@07:00", departureAt: "2026-10-20T07:00:00Z", signupDeadline: "2026-10-20T05:00:00Z", feasible: false }],
|
|
15
|
+
chosen: { momentKey: "1@15:00|1@13:00", departureAt: "2026-10-20T13:00:00Z", signupDeadline: "2026-10-20T11:00:00Z" },
|
|
16
|
+
}));
|
|
17
|
+
check("haalbaar: soort", good.kind, "ok");
|
|
18
|
+
check("haalbaar: tekst", good.kind === "ok" ? good.text : null, "ophalen di 20 okt 15:00 · aanmelden di 20 okt 13:00");
|
|
19
|
+
check("niet-haalbaar moment blijft zichtbaar", normalizePreview({ ok: true, moments: [{ momentKey: "x", feasible: false }] })?.moments[0].feasible, false);
|
|
20
|
+
const late = decidePreview(normalizePreview({
|
|
21
|
+
ok: true, deliveryDateFeasible: false, reason: "Aanmelden kan tot di 20-10 13:00.",
|
|
22
|
+
firstFeasibleDeliveryDate: "2026-10-22", firstFeasibleReason: "Eerstvolgende aanmelding do 13:00",
|
|
23
|
+
chosen: { momentKey: "k", departureAt: "2026-10-20T13:00:00Z" },
|
|
24
|
+
}));
|
|
25
|
+
check("te laat: soort (toch aanmaken mogelijk)", late.kind, "late");
|
|
26
|
+
check("te laat: reden", late.kind === "late" ? late.reason : null, "Aanmelden kan tot di 20-10 13:00.");
|
|
27
|
+
check("te laat: eerste datum", late.kind === "late" ? late.firstDate : null, "2026-10-22");
|
|
28
|
+
const bad = decidePreview(normalizePreview({ ok: false, reason: "Geen vervoerder bekend", chosen: { departureAt: "2026-10-20T13:00:00Z" } }));
|
|
29
|
+
check("ok=false: geblokkeerd", bad.kind, "blocked");
|
|
30
|
+
check("ok=false: alleen reden", bad.kind === "blocked" ? bad.reason : null, "Geen vervoerder bekend");
|
|
31
|
+
check("geen antwoord: geblokkeerd", decidePreview(null).kind, "blocked");
|
|
32
|
+
check("lijst in delen van 1000", LIST_CHUNK, 1000);
|
|
33
|
+
if (failed) {
|
|
34
|
+
console.error(`${failed} controle(s) mislukt`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
console.log("Alle controles geslaagd");
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface PreviewMoment {
|
|
2
|
+
momentKey: string;
|
|
3
|
+
departureAt: string | null;
|
|
4
|
+
signupDeadline: string | null;
|
|
5
|
+
feasible: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface DeparturePreview {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
reason: string | null;
|
|
10
|
+
carrierId: string | null;
|
|
11
|
+
moments: PreviewMoment[];
|
|
12
|
+
chosen: {
|
|
13
|
+
momentKey: string | null;
|
|
14
|
+
departureAt: string | null;
|
|
15
|
+
signupDeadline: string | null;
|
|
16
|
+
} | null;
|
|
17
|
+
deliveryDateFeasible: boolean;
|
|
18
|
+
deliveryDateReason: string | null;
|
|
19
|
+
firstFeasibleDeliveryDate: string | null;
|
|
20
|
+
firstFeasibleReason: string | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function normalizePreview(raw: unknown): DeparturePreview | null;
|
|
23
|
+
export declare const PREVIEW_UNKNOWN = "Het ophaalmoment is nu niet bekend. Probeer het over een minuut opnieuw.";
|
|
24
|
+
export type PreviewDecision = {
|
|
25
|
+
kind: "ok";
|
|
26
|
+
momentKey: string | null;
|
|
27
|
+
text: string | null;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "late";
|
|
30
|
+
reason: string;
|
|
31
|
+
firstDate: string | null;
|
|
32
|
+
firstReason: string | null;
|
|
33
|
+
momentKey: string | null;
|
|
34
|
+
text: string | null;
|
|
35
|
+
} | {
|
|
36
|
+
kind: "blocked";
|
|
37
|
+
reason: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Wat je ziet / of je mag aanmaken.
|
|
41
|
+
* - ok = false of geen antwoord: geblokkeerd, alleen de reden.
|
|
42
|
+
* - leverdatum niet haalbaar: "te laat" — alleen aanmaken na bewuste keuze.
|
|
43
|
+
*/
|
|
44
|
+
export declare function decidePreview(p: DeparturePreview | null): PreviewDecision;
|
|
45
|
+
export declare function momentLabel(m: PreviewMoment): string;
|
|
46
|
+
export declare const LATE_CONFIRM = "Deze order komt na de aanmeldtijd. De vervoerder krijgt hem als te laat aangemeld. Doorgaan?";
|
|
47
|
+
//# sourceMappingURL=departure-preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"departure-preview.d.ts","sourceRoot":"","sources":["../../src/lib/departure-preview.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACvG,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAID,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CA2BtE;AAED,eAAO,MAAM,eAAe,6EAA6E,CAAC;AAE1G,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrI;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AASxC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,eAAe,CAgBzE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAEpD;AAED,eAAO,MAAM,YAAY,iGACuE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const getDeparturePreview: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
2
|
+
supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
|
|
3
|
+
userId: string;
|
|
4
|
+
claims: import("@supabase/auth-js").User;
|
|
5
|
+
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
6
|
+
carrierId: string | null;
|
|
7
|
+
deliveryLocation: string;
|
|
8
|
+
deliveryDate: string;
|
|
9
|
+
momentKey?: string | null | undefined;
|
|
10
|
+
}, Promise<{
|
|
11
|
+
preview: import("./departure-preview.js").DeparturePreview | null;
|
|
12
|
+
}>>;
|
|
13
|
+
//# sourceMappingURL=departure-preview.functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"departure-preview.functions.d.ts","sourceRoot":"","sources":["../../src/lib/departure-preview.functions.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB;;;;8CAEN,OAAO;;;;;;;GAa7B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware.js";
|
|
4
|
+
export const getDeparturePreview = createServerFn({ method: "GET" })
|
|
5
|
+
.middleware([requireSupabaseAuth])
|
|
6
|
+
.inputValidator((input) => z
|
|
7
|
+
.object({
|
|
8
|
+
carrierId: z.string().uuid().nullable(),
|
|
9
|
+
deliveryLocation: z.string().min(1).max(100),
|
|
10
|
+
deliveryDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
11
|
+
momentKey: z.string().max(64).nullable().optional(),
|
|
12
|
+
})
|
|
13
|
+
.parse(input))
|
|
14
|
+
.handler(async ({ data, context }) => {
|
|
15
|
+
const { loadDeparturePreview } = await import("./departure-preview.server.js");
|
|
16
|
+
return { preview: await loadDeparturePreview(context.supabase, data) };
|
|
17
|
+
});
|