@flowselections/floriday-afhandeling-module 1.0.9 → 1.0.11
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/afhandeling/ControleLijstPrint.d.ts +7 -0
- package/dist-lib/components/afhandeling/ControleLijstPrint.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ControleLijstPrint.js +67 -0
- package/dist-lib/components/afhandeling/ControlePage.d.ts +2 -0
- package/dist-lib/components/afhandeling/ControlePage.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ControlePage.js +456 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts +9 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.js +149 -0
- package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/LeveringenPage.js +11 -5
- package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickAgendaView.js +13 -4
- package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PlanningAgendaPage.js +2 -2
- package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts +12 -0
- package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ServiceAreaSelect.js +79 -0
- package/dist-lib/components/afhandeling/VervoerderForm.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/VervoerderForm.js +62 -6
- package/dist-lib/components/afhandeling/VervoerdersPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/VervoerdersPage.js +25 -6
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts +2 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +63 -18
- package/dist-lib/components/afhandeling/WeekdayPicker.d.ts +12 -0
- package/dist-lib/components/afhandeling/WeekdayPicker.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/WeekdayPicker.js +30 -0
- package/dist-lib/components/pickstation/PakbonTemplate.d.ts +6 -2
- package/dist-lib/components/pickstation/PakbonTemplate.d.ts.map +1 -1
- package/dist-lib/components/pickstation/PakbonTemplate.js +37 -12
- package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
- package/dist-lib/components/settings/AfhandelingSettingsCard.js +25 -6
- package/dist-lib/components/ui/responsive-dialog.d.ts +20 -0
- package/dist-lib/components/ui/responsive-dialog.d.ts.map +1 -0
- package/dist-lib/components/ui/responsive-dialog.js +44 -0
- package/dist-lib/hooks/useOrderPlanning.d.ts +3 -0
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +64 -12
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +4 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2898 -147
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +2898 -147
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +2898 -147
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2986 -155
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +10666 -5151
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.js +42 -2
- package/dist-lib/lib/carrierMatch.server.d.ts +27 -0
- package/dist-lib/lib/carrierMatch.server.d.ts.map +1 -0
- package/dist-lib/lib/carrierMatch.server.js +75 -0
- package/dist-lib/lib/carrierSignupMail.server.d.ts +56 -0
- package/dist-lib/lib/carrierSignupMail.server.d.ts.map +1 -0
- package/dist-lib/lib/carrierSignupMail.server.js +229 -0
- package/dist-lib/lib/carriers.functions.d.ts +36404 -15470
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/carriers.functions.js +43 -2
- package/dist-lib/lib/cartAssignments.functions.d.ts +49609 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartAssignments.functions.js +130 -0
- package/dist-lib/lib/cartControl.functions.d.ts +99259 -0
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartControl.functions.js +489 -0
- package/dist-lib/lib/cartMoveImpact.d.ts +8 -0
- package/dist-lib/lib/cartMoveImpact.d.ts.map +1 -0
- package/dist-lib/lib/cartMoveImpact.js +26 -0
- package/dist-lib/lib/cartRescheduling.d.ts +30 -0
- package/dist-lib/lib/cartRescheduling.d.ts.map +1 -0
- package/dist-lib/lib/cartRescheduling.js +71 -0
- package/dist-lib/lib/floriday.functions.d.ts +2902 -147
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +178 -98
- package/dist-lib/lib/geo/euServiceAreas.d.ts +30 -0
- package/dist-lib/lib/geo/euServiceAreas.d.ts.map +1 -0
- package/dist-lib/lib/geo/euServiceAreas.js +277 -0
- package/dist-lib/lib/invalidatePlanning.d.ts +11 -0
- package/dist-lib/lib/invalidatePlanning.d.ts.map +1 -0
- package/dist-lib/lib/invalidatePlanning.js +25 -0
- package/dist-lib/lib/pickstationI18n.d.ts +12 -0
- package/dist-lib/lib/pickstationI18n.d.ts.map +1 -1
- package/dist-lib/lib/pickstationI18n.js +72 -0
- package/dist-lib/lib/pickstationOrders.server.d.ts +2 -1
- package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -1
- package/dist-lib/lib/pickstationOrders.server.js +393 -178
- package/dist-lib/lib/pickstationTypes.d.ts +23 -2
- package/dist-lib/lib/pickstationTypes.d.ts.map +1 -1
- package/dist-lib/lib/planning.d.ts +41 -2
- package/dist-lib/lib/planning.d.ts.map +1 -1
- package/dist-lib/lib/planning.js +159 -36
- package/package.json +2 -2
|
@@ -29,17 +29,46 @@ export interface PlanningRules {
|
|
|
29
29
|
/** Tijdstip waarop de order is binnengekomen (voor moment-selectie). */
|
|
30
30
|
orderCreatedAt?: string | Date | null;
|
|
31
31
|
holidays?: Date[];
|
|
32
|
+
/** ISO-dagnummers (1=ma … 7=zo) waarop gepickt mag worden. */
|
|
33
|
+
pickWeekdays?: number[];
|
|
34
|
+
/** ISO-dagnummers waarop de vervoerder karren bij ons ophaalt. */
|
|
35
|
+
carrierPickupWeekdays?: number[];
|
|
36
|
+
/** ISO-dagnummers waarop de vervoerder bij de klant bezorgt. */
|
|
37
|
+
carrierDeliveryWeekdays?: number[];
|
|
38
|
+
}
|
|
39
|
+
export interface PickAssignment {
|
|
40
|
+
date: Date;
|
|
41
|
+
cartCount: number;
|
|
42
|
+
/** Concrete kar-indexen op deze datum; nodig voor handmatig verplaatsen. */
|
|
43
|
+
cartIndexes?: number[];
|
|
32
44
|
}
|
|
33
45
|
export interface OrderPlanning {
|
|
34
46
|
deliveryDate: Date;
|
|
47
|
+
/** Oorspronkelijk gevraagde bezorgdatum (vóór eventuele weekdag-snap). */
|
|
48
|
+
requestedDeliveryDate: Date;
|
|
35
49
|
pickupDate: Date;
|
|
36
50
|
transportRegisterDate: Date;
|
|
37
51
|
pickStartDate: Date;
|
|
38
52
|
scheduledPickDate: Date;
|
|
53
|
+
/** Verdeling van karren over één of meerdere pickdagen. */
|
|
54
|
+
pickAssignments: PickAssignment[];
|
|
39
55
|
movedEarlier: boolean;
|
|
40
56
|
/** Welk moment is gekozen (handig voor debug / UI). */
|
|
41
57
|
selectedMoment: PickupMoment;
|
|
58
|
+
/** Korte uitleg waarom deze planning zo is gekozen. */
|
|
59
|
+
reason?: string;
|
|
60
|
+
/** Naam van de gekozen vervoerder (indien bekend). */
|
|
61
|
+
carrierName?: string;
|
|
42
62
|
}
|
|
63
|
+
/** ISO-dagnummer 1=ma … 7=zo van een Date. */
|
|
64
|
+
export declare function isoWeekday(d: Date): number;
|
|
65
|
+
export declare function normalizeWeekdays(days: number[] | undefined | null): number[];
|
|
66
|
+
/**
|
|
67
|
+
* Schuif een datum naar de dichtstbijzijnde toegestane weekdag
|
|
68
|
+
* (feestdagen uitgesloten). `direction` bepaalt of we naar het verleden
|
|
69
|
+
* of naar de toekomst opschuiven.
|
|
70
|
+
*/
|
|
71
|
+
export declare function snapToAllowedDay(date: Date, allowedWeekdays: number[] | undefined, direction: "backward" | "forward", holidays?: Date[]): Date;
|
|
43
72
|
export declare function isWorkday(d: Date, holidays?: Date[]): boolean;
|
|
44
73
|
export declare function subtractWorkdays(date: Date, n: number, holidays?: Date[]): Date;
|
|
45
74
|
export declare function addWorkdays(date: Date, n: number, holidays?: Date[]): Date;
|
|
@@ -55,12 +84,22 @@ export declare function getSignupDeadline(deliveryDate: Date, moment: PickupMome
|
|
|
55
84
|
*/
|
|
56
85
|
export declare function selectPickupMoment(deliveryDate: Date, orderCreatedAt: Date | null | undefined, moments: PickupMoment[], holidays?: Date[]): PickupMoment;
|
|
57
86
|
export declare function calculateOrderPlanning(deliveryDate: string | Date | null | undefined, rules: PlanningRules): OrderPlanning | null;
|
|
58
|
-
export interface PickDistributionOptions {
|
|
87
|
+
export interface PickDistributionOptions<T = unknown> {
|
|
59
88
|
enabled: boolean;
|
|
60
89
|
maxWorkdaysEarlier: number;
|
|
61
90
|
holidays?: Date[];
|
|
91
|
+
/** ISO-dagnummers waarop gepickt mag worden (1=ma … 7=zo). */
|
|
92
|
+
pickWeekdays?: number[];
|
|
93
|
+
/** Aantal karren per item — bepaalt het gewicht in de verdeling. */
|
|
94
|
+
getCartCount?: (item: T) => number;
|
|
95
|
+
/** Manual per-cart overrides — geïndexeerd op (itemKey, cartIndex) → Date. */
|
|
96
|
+
getCartOverride?: (item: T, cartIndex: number) => Date | PickCartOverride | null;
|
|
97
|
+
}
|
|
98
|
+
export interface PickCartOverride {
|
|
99
|
+
date: Date;
|
|
100
|
+
movedFromDate?: Date | null;
|
|
62
101
|
}
|
|
63
102
|
export declare function distributePickDates<T extends {
|
|
64
103
|
planning: OrderPlanning | null;
|
|
65
|
-
}>(items: T[], options: PickDistributionOptions): T[];
|
|
104
|
+
}>(items: T[], options: PickDistributionOptions<T>): T[];
|
|
66
105
|
//# sourceMappingURL=planning.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../src/lib/planning.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,EAAE,YAOnC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,wDAAwD;IACxD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../src/lib/planning.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,EAAE,YAOnC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,wDAAwD;IACxD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,kEAAkE;IAClE,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,gEAAgE;IAChE,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,IAAI,CAAC;IACnB,0EAA0E;IAC1E,qBAAqB,EAAE,IAAI,CAAC;IAC5B,UAAU,EAAE,IAAI,CAAC;IACjB,qBAAqB,EAAE,IAAI,CAAC;IAC5B,aAAa,EAAE,IAAI,CAAC;IACpB,iBAAiB,EAAE,IAAI,CAAC;IACxB,2DAA2D;IAC3D,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,cAAc,EAAE,YAAY,CAAC;IAC7B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAG1C;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAI7E;AAMD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,eAAe,EAAE,MAAM,EAAE,GAAG,SAAS,EACrC,SAAS,EAAE,UAAU,GAAG,SAAS,EACjC,QAAQ,CAAC,EAAE,IAAI,EAAE,GAChB,IAAI,CAUN;AAWD,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,OAAO,CAK7D;AAQD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,CAQ/E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,CAQ1E;AAcD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,IAAI,EAClB,MAAM,EAAE,YAAY,EACpB,QAAQ,CAAC,EAAE,IAAI,EAAE,GAChB,IAAI,CAGN;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,IAAI,EAClB,cAAc,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EACvC,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,CAAC,EAAE,IAAI,EAAE,GAChB,YAAY,CAgBd;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,EAC9C,KAAK,EAAE,aAAa,GACnB,aAAa,GAAG,IAAI,CA+EtB;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,GAAG,OAAO;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,8EAA8E;IAC9E,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,gBAAgB,GAAG,IAAI,CAAC;CAClF;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CAC7B;AAGD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,EAC9E,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAClC,CAAC,EAAE,CA4IL"}
|
package/dist-lib/lib/planning.js
CHANGED
|
@@ -14,6 +14,38 @@ export const DEFAULT_PICKUP_MOMENT = {
|
|
|
14
14
|
delivery_days: 0,
|
|
15
15
|
delivery_time: "08:00",
|
|
16
16
|
};
|
|
17
|
+
/** ISO-dagnummer 1=ma … 7=zo van een Date. */
|
|
18
|
+
export function isoWeekday(d) {
|
|
19
|
+
const g = d.getDay();
|
|
20
|
+
return g === 0 ? 7 : g;
|
|
21
|
+
}
|
|
22
|
+
const DEFAULT_WEEKDAYS = [1, 2, 3, 4, 5];
|
|
23
|
+
export function normalizeWeekdays(days) {
|
|
24
|
+
if (!Array.isArray(days) || days.length === 0)
|
|
25
|
+
return DEFAULT_WEEKDAYS;
|
|
26
|
+
const clean = days.map((n) => Number(n)).filter((n) => n >= 1 && n <= 7);
|
|
27
|
+
return clean.length > 0 ? Array.from(new Set(clean)) : DEFAULT_WEEKDAYS;
|
|
28
|
+
}
|
|
29
|
+
function isHoliday(d, holidays) {
|
|
30
|
+
return !!holidays && holidays.some((h) => sameDay(h, d));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Schuif een datum naar de dichtstbijzijnde toegestane weekdag
|
|
34
|
+
* (feestdagen uitgesloten). `direction` bepaalt of we naar het verleden
|
|
35
|
+
* of naar de toekomst opschuiven.
|
|
36
|
+
*/
|
|
37
|
+
export function snapToAllowedDay(date, allowedWeekdays, direction, holidays) {
|
|
38
|
+
const allowed = new Set(normalizeWeekdays(allowedWeekdays));
|
|
39
|
+
const out = normalize(date);
|
|
40
|
+
const step = direction === "forward" ? 1 : -1;
|
|
41
|
+
// Vangnet: max 62 iteraties om oneindige loops te voorkomen.
|
|
42
|
+
for (let i = 0; i < 62; i++) {
|
|
43
|
+
if (allowed.has(isoWeekday(out)) && !isHoliday(out, holidays))
|
|
44
|
+
return out;
|
|
45
|
+
out.setDate(out.getDate() + step);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
17
49
|
function sameDay(a, b) {
|
|
18
50
|
return (a.getFullYear() === b.getFullYear() &&
|
|
19
51
|
a.getMonth() === b.getMonth() &&
|
|
@@ -99,79 +131,170 @@ export function calculateOrderPlanning(deliveryDate, rules) {
|
|
|
99
131
|
const d = typeof deliveryDate === "string" ? new Date(deliveryDate) : deliveryDate;
|
|
100
132
|
if (Number.isNaN(d.getTime()))
|
|
101
133
|
return null;
|
|
102
|
-
const
|
|
134
|
+
const requested = normalize(d);
|
|
103
135
|
const moments = rules.pickupMoments.length > 0 ? rules.pickupMoments : [DEFAULT_PICKUP_MOMENT];
|
|
104
136
|
const orderCreated = rules.orderCreatedAt == null
|
|
105
137
|
? null
|
|
106
138
|
: rules.orderCreatedAt instanceof Date
|
|
107
139
|
? rules.orderCreatedAt
|
|
108
140
|
: new Date(rules.orderCreatedAt);
|
|
141
|
+
const reasons = [];
|
|
142
|
+
// 1) Snap bezorgdatum vooruit naar een dag waarop de vervoerder bezorgt.
|
|
143
|
+
const delivery = snapToAllowedDay(requested, rules.carrierDeliveryWeekdays, "forward", rules.holidays);
|
|
144
|
+
if (!sameDay(delivery, requested)) {
|
|
145
|
+
reasons.push(`Bezorgdatum verschoven naar ${delivery.toLocaleDateString("nl-NL")} omdat de vervoerder niet bezorgt op de gevraagde dag.`);
|
|
146
|
+
}
|
|
109
147
|
const moment = selectPickupMoment(delivery, orderCreated, moments, rules.holidays);
|
|
110
|
-
|
|
148
|
+
// 2) Ophaaldatum: terugtellen op werkdagen, daarna snappen op ophaaldagen vervoerder.
|
|
149
|
+
const pickupRaw = subtractWorkdays(delivery, moment.pickup_days, rules.holidays);
|
|
150
|
+
const pickup = snapToAllowedDay(pickupRaw, rules.carrierPickupWeekdays, "backward", rules.holidays);
|
|
151
|
+
if (!sameDay(pickup, pickupRaw)) {
|
|
152
|
+
reasons.push(`Ophaaldatum verschoven naar ${pickup.toLocaleDateString("nl-NL")} omdat de vervoerder alleen op bepaalde dagen ophaalt.`);
|
|
153
|
+
}
|
|
111
154
|
const transportRegister = subtractWorkdays(delivery, moment.signup_days, rules.holidays);
|
|
112
|
-
|
|
155
|
+
// 3) Pickstart: terugtellen vanaf ophaal, daarna snappen op pickdagen.
|
|
156
|
+
const pickStartRaw = subtractWorkdays(pickup, rules.pickDurationWorkdays, rules.holidays);
|
|
157
|
+
const pickStart = snapToAllowedDay(pickStartRaw, rules.pickWeekdays, "backward", rules.holidays);
|
|
158
|
+
if (!sameDay(pickStart, pickStartRaw)) {
|
|
159
|
+
reasons.push(`Pickdatum verschoven naar ${pickStart.toLocaleDateString("nl-NL")} vanwege de ingestelde pickdagen.`);
|
|
160
|
+
}
|
|
161
|
+
if (reasons.length === 0) {
|
|
162
|
+
reasons.push(`Planning gebaseerd op ophaalmoment ${moment.pickup_time ?? "standaard"}.`);
|
|
163
|
+
}
|
|
113
164
|
return {
|
|
114
165
|
deliveryDate: delivery,
|
|
166
|
+
requestedDeliveryDate: requested,
|
|
115
167
|
pickupDate: pickup,
|
|
116
168
|
transportRegisterDate: transportRegister,
|
|
117
169
|
pickStartDate: pickStart,
|
|
118
170
|
scheduledPickDate: pickStart,
|
|
171
|
+
pickAssignments: [{ date: pickStart, cartCount: 0 }],
|
|
119
172
|
movedEarlier: false,
|
|
120
173
|
selectedMoment: moment,
|
|
174
|
+
reason: reasons.join(" "),
|
|
121
175
|
};
|
|
122
176
|
}
|
|
123
177
|
export function distributePickDates(items, options) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
178
|
+
const getCarts = (it) => {
|
|
179
|
+
const n = options.getCartCount?.(it);
|
|
180
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1;
|
|
181
|
+
};
|
|
182
|
+
const getOverride = (it, idx) => {
|
|
183
|
+
const raw = options.getCartOverride?.(it, idx);
|
|
184
|
+
if (!raw)
|
|
185
|
+
return null;
|
|
186
|
+
const date = raw instanceof Date ? raw : raw.date;
|
|
187
|
+
const out = new Date(date);
|
|
188
|
+
out.setHours(0, 0, 0, 0);
|
|
189
|
+
const movedFrom = raw instanceof Date ? null : raw.movedFromDate;
|
|
190
|
+
const movedFromDate = movedFrom ? new Date(movedFrom) : null;
|
|
191
|
+
if (movedFromDate)
|
|
192
|
+
movedFromDate.setHours(0, 0, 0, 0);
|
|
193
|
+
return { date: out, movedFromDate };
|
|
194
|
+
};
|
|
195
|
+
const key = (d) => `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
|
|
196
|
+
const load = new Map();
|
|
197
|
+
const result = new Map();
|
|
198
|
+
const distribute = options.enabled && options.maxWorkdaysEarlier > 0;
|
|
138
199
|
const sorted = [...items].sort((a, b) => {
|
|
139
200
|
const ad = a.planning?.pickStartDate.getTime() ?? Infinity;
|
|
140
201
|
const bd = b.planning?.pickStartDate.getTime() ?? Infinity;
|
|
141
202
|
return ad - bd;
|
|
142
203
|
});
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
204
|
+
const baseTargets = new Map();
|
|
205
|
+
// Stap 1: bepaal eerst de volledige automatische verdeling, zonder
|
|
206
|
+
// handmatige overrides. Daardoor blijft de automatische balans stabiel en
|
|
207
|
+
// kan een latere handmatige verplaatsing niet door volgende orders worden
|
|
208
|
+
// "teruggevuld".
|
|
146
209
|
for (const item of sorted) {
|
|
147
210
|
if (!item.planning) {
|
|
148
211
|
result.set(item, item);
|
|
149
212
|
continue;
|
|
150
213
|
}
|
|
151
214
|
const deadline = item.planning.pickStartDate;
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
215
|
+
const carts = getCarts(item);
|
|
216
|
+
// Kandidaten in chronologische volgorde — alleen toegestane pickdagen.
|
|
217
|
+
const allowedSet = new Set(normalizeWeekdays(options.pickWeekdays));
|
|
218
|
+
const isAllowed = (d) => allowedSet.has(isoWeekday(d)) && !(options.holidays?.some((h) => sameDay(h, d)));
|
|
219
|
+
const candidates = [];
|
|
220
|
+
if (distribute) {
|
|
221
|
+
let cursor = deadline;
|
|
222
|
+
let added = 0;
|
|
223
|
+
// Loop met veiligheidsmarge; sla dagen over die niet zijn toegestaan.
|
|
224
|
+
for (let i = 0; i < options.maxWorkdaysEarlier * 3 && added < options.maxWorkdaysEarlier; i++) {
|
|
225
|
+
cursor = subtractWorkdays(cursor, 1, options.holidays);
|
|
226
|
+
if (isAllowed(cursor)) {
|
|
227
|
+
candidates.unshift(cursor);
|
|
228
|
+
added++;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
157
231
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
for (let
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
232
|
+
candidates.push(deadline);
|
|
233
|
+
const targets = [];
|
|
234
|
+
for (let c = 0; c < carts; c++) {
|
|
235
|
+
let target;
|
|
236
|
+
if (!distribute) {
|
|
237
|
+
target = deadline;
|
|
238
|
+
load.set(key(target), (load.get(key(target)) ?? 0) + 1);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
let best = candidates[candidates.length - 1];
|
|
242
|
+
let bestLoad = load.get(key(best)) ?? 0;
|
|
243
|
+
for (let i = candidates.length - 2; i >= 0; i--) {
|
|
244
|
+
const cand = candidates[i];
|
|
245
|
+
const l = load.get(key(cand)) ?? 0;
|
|
246
|
+
if (l < bestLoad) {
|
|
247
|
+
best = cand;
|
|
248
|
+
bestLoad = l;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
target = best;
|
|
252
|
+
load.set(key(target), bestLoad + 1);
|
|
253
|
+
}
|
|
254
|
+
targets[c] = target;
|
|
255
|
+
}
|
|
256
|
+
baseTargets.set(item, targets);
|
|
257
|
+
}
|
|
258
|
+
// Stap 2: pas overrides pas toe nadat alle automatische doelen vaststaan.
|
|
259
|
+
// Dit maakt een verplaatsing absoluut: 10/10 wordt na één kar verplaatsen
|
|
260
|
+
// echt 9/11, niet opnieuw 10/10 door load-balancing.
|
|
261
|
+
for (const item of sorted) {
|
|
262
|
+
if (!item.planning)
|
|
263
|
+
continue;
|
|
264
|
+
const deadline = item.planning.pickStartDate;
|
|
265
|
+
const carts = getCarts(item);
|
|
266
|
+
const targets = [...(baseTargets.get(item) ?? [])];
|
|
267
|
+
const perDay = new Map();
|
|
268
|
+
for (let c = 0; c < carts; c++) {
|
|
269
|
+
const override = getOverride(item, c);
|
|
270
|
+
if (override) {
|
|
271
|
+
// Handmatige verplaatsingen gelden altijd voor de concrete kar-index
|
|
272
|
+
// die de gebruiker aanklikt. Niet ruilen met een andere kar op dezelfde
|
|
273
|
+
// brondag, want dan blijft de aangeklikte kar visueel staan.
|
|
274
|
+
targets[c] = override.date;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
for (let c = 0; c < carts; c++) {
|
|
278
|
+
const target = targets[c];
|
|
279
|
+
const k = key(target);
|
|
280
|
+
const existing = perDay.get(k);
|
|
281
|
+
if (existing) {
|
|
282
|
+
existing.cartCount += 1;
|
|
283
|
+
existing.cartIndexes.push(c);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
perDay.set(k, { date: target, cartCount: 1, cartIndexes: [c] });
|
|
166
287
|
}
|
|
167
288
|
}
|
|
168
|
-
|
|
169
|
-
const
|
|
289
|
+
const assignments = Array.from(perDay.values()).sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
290
|
+
const earliest = assignments[0]?.date ?? deadline;
|
|
291
|
+
const moved = assignments.some((a) => a.date.getTime() !== deadline.getTime());
|
|
170
292
|
result.set(item, {
|
|
171
293
|
...item,
|
|
172
294
|
planning: {
|
|
173
295
|
...item.planning,
|
|
174
|
-
scheduledPickDate:
|
|
296
|
+
scheduledPickDate: earliest,
|
|
297
|
+
pickAssignments: assignments,
|
|
175
298
|
movedEarlier: moved,
|
|
176
299
|
},
|
|
177
300
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/floriday-afhandeling-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@cloudflare/vite-plugin": "^1.25.5",
|
|
42
42
|
"@eslint/js": "^9.32.0",
|
|
43
43
|
"@flowselections/core": "^1.0.11",
|
|
44
|
-
"@lovable.dev/vite-tanstack-config": "2.6.
|
|
44
|
+
"@lovable.dev/vite-tanstack-config": "2.6.4",
|
|
45
45
|
"@rsbuild/core": "^1.0.0",
|
|
46
46
|
"@tailwindcss/vite": "^4.2.1",
|
|
47
47
|
"@tanstack/react-query": "^5.83.0",
|