@flowselections/floriday-afhandeling-module 1.0.8 → 1.0.10

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 (94) hide show
  1. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts +9 -0
  2. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -0
  3. package/dist-lib/components/afhandeling/DagDetailDialog.js +145 -0
  4. package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
  5. package/dist-lib/components/afhandeling/LeveringenPage.js +17 -69
  6. package/dist-lib/components/afhandeling/PickAgendaView.d.ts +6 -0
  7. package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -0
  8. package/dist-lib/components/afhandeling/PickAgendaView.js +40 -0
  9. package/dist-lib/components/afhandeling/PickingPage.d.ts +2 -0
  10. package/dist-lib/components/afhandeling/PickingPage.d.ts.map +1 -0
  11. package/dist-lib/components/afhandeling/PickingPage.js +5 -0
  12. package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts +9 -0
  13. package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts.map +1 -0
  14. package/dist-lib/components/afhandeling/PlanningAgendaPage.js +7 -0
  15. package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts +12 -0
  16. package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts.map +1 -0
  17. package/dist-lib/components/afhandeling/ServiceAreaSelect.js +79 -0
  18. package/dist-lib/components/afhandeling/VervoerderForm.d.ts.map +1 -1
  19. package/dist-lib/components/afhandeling/VervoerderForm.js +73 -12
  20. package/dist-lib/components/afhandeling/VervoerdersPage.d.ts.map +1 -1
  21. package/dist-lib/components/afhandeling/VervoerdersPage.js +23 -5
  22. package/dist-lib/components/afhandeling/WeekAgendaView.d.ts +13 -0
  23. package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -0
  24. package/dist-lib/components/afhandeling/WeekAgendaView.js +142 -0
  25. package/dist-lib/components/pickstation/LanguagePicker.d.ts +5 -0
  26. package/dist-lib/components/pickstation/LanguagePicker.d.ts.map +1 -0
  27. package/dist-lib/components/pickstation/LanguagePicker.js +5 -0
  28. package/dist-lib/components/pickstation/PakbonTemplate.d.ts +20 -0
  29. package/dist-lib/components/pickstation/PakbonTemplate.d.ts.map +1 -0
  30. package/dist-lib/components/pickstation/PakbonTemplate.js +76 -0
  31. package/dist-lib/components/pickstation/printDocuments.d.ts +3 -0
  32. package/dist-lib/components/pickstation/printDocuments.d.ts.map +1 -0
  33. package/dist-lib/components/pickstation/printDocuments.js +53 -0
  34. package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts +2 -0
  35. package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -0
  36. package/dist-lib/components/settings/AfhandelingSettingsCard.js +72 -0
  37. package/dist-lib/components/settings/VervoerdersSettingsCard.d.ts +2 -0
  38. package/dist-lib/components/settings/VervoerdersSettingsCard.d.ts.map +1 -0
  39. package/dist-lib/components/settings/VervoerdersSettingsCard.js +30 -0
  40. package/dist-lib/hooks/useOrderPlanning.d.ts +17 -0
  41. package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -0
  42. package/dist-lib/hooks/useOrderPlanning.js +131 -0
  43. package/dist-lib/index.d.ts +5 -0
  44. package/dist-lib/index.d.ts.map +1 -1
  45. package/dist-lib/index.js +16 -6
  46. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2793 -137
  47. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  48. package/dist-lib/integrations/supabase/client.d.ts +2793 -137
  49. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  50. package/dist-lib/integrations/supabase/client.server.d.ts +2793 -137
  51. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  52. package/dist-lib/integrations/supabase/types.d.ts +2870 -131
  53. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  54. package/dist-lib/integrations/supabase/types.js +2 -0
  55. package/dist-lib/lib/afhandelingSettings.functions.d.ts +18597 -0
  56. package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -0
  57. package/dist-lib/lib/afhandelingSettings.functions.js +98 -0
  58. package/dist-lib/lib/carrierSignupMail.server.d.ts +56 -0
  59. package/dist-lib/lib/carrierSignupMail.server.d.ts.map +1 -0
  60. package/dist-lib/lib/carrierSignupMail.server.js +229 -0
  61. package/dist-lib/lib/carriers.functions.d.ts +34091 -14161
  62. package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
  63. package/dist-lib/lib/carriers.functions.js +69 -6
  64. package/dist-lib/lib/cartAssignments.functions.d.ts +46479 -0
  65. package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -0
  66. package/dist-lib/lib/cartAssignments.functions.js +130 -0
  67. package/dist-lib/lib/cartMoveImpact.d.ts +8 -0
  68. package/dist-lib/lib/cartMoveImpact.d.ts.map +1 -0
  69. package/dist-lib/lib/cartMoveImpact.js +26 -0
  70. package/dist-lib/lib/floriday.functions.d.ts +2798 -137
  71. package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
  72. package/dist-lib/lib/floriday.functions.js +178 -93
  73. package/dist-lib/lib/geo/euServiceAreas.d.ts +30 -0
  74. package/dist-lib/lib/geo/euServiceAreas.d.ts.map +1 -0
  75. package/dist-lib/lib/geo/euServiceAreas.js +277 -0
  76. package/dist-lib/lib/invalidatePlanning.d.ts +11 -0
  77. package/dist-lib/lib/invalidatePlanning.d.ts.map +1 -0
  78. package/dist-lib/lib/invalidatePlanning.js +25 -0
  79. package/dist-lib/lib/pickDate.d.ts +21 -0
  80. package/dist-lib/lib/pickDate.d.ts.map +1 -0
  81. package/dist-lib/lib/pickDate.js +71 -0
  82. package/dist-lib/lib/pickstationI18n.d.ts +35 -0
  83. package/dist-lib/lib/pickstationI18n.d.ts.map +1 -0
  84. package/dist-lib/lib/pickstationI18n.js +171 -0
  85. package/dist-lib/lib/pickstationOrders.server.d.ts +9 -0
  86. package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -0
  87. package/dist-lib/lib/pickstationOrders.server.js +372 -0
  88. package/dist-lib/lib/pickstationTypes.d.ts +26 -0
  89. package/dist-lib/lib/pickstationTypes.d.ts.map +1 -0
  90. package/dist-lib/lib/pickstationTypes.js +1 -0
  91. package/dist-lib/lib/planning.d.ts +82 -0
  92. package/dist-lib/lib/planning.d.ts.map +1 -0
  93. package/dist-lib/lib/planning.js +243 -0
  94. package/package.json +12 -6
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Centrale planningsmodule — werkdagen-rekenkern, ophaalmomenten,
3
+ * order-planning en pickverdeling. Eén bron van waarheid voor alle agenda-views.
4
+ *
5
+ * Model — bezorgdag = dag 0. Elk ophaalmoment definieert per stap (aanmelden,
6
+ * ophalen, bezorgen) hoeveel werkdagen vóór de bezorgdag de stap plaatsvindt
7
+ * en op welk tijdstip.
8
+ */
9
+ export const DEFAULT_PICKUP_MOMENT = {
10
+ signup_days: 2,
11
+ signup_time: "16:00",
12
+ pickup_days: 1,
13
+ pickup_time: "17:30",
14
+ delivery_days: 0,
15
+ delivery_time: "08:00",
16
+ };
17
+ function sameDay(a, b) {
18
+ return (a.getFullYear() === b.getFullYear() &&
19
+ a.getMonth() === b.getMonth() &&
20
+ a.getDate() === b.getDate());
21
+ }
22
+ export function isWorkday(d, holidays) {
23
+ const day = d.getDay();
24
+ if (day === 0 || day === 6)
25
+ return false;
26
+ if (holidays && holidays.some((h) => sameDay(h, d)))
27
+ return false;
28
+ return true;
29
+ }
30
+ function normalize(d) {
31
+ const out = new Date(d);
32
+ out.setHours(0, 0, 0, 0);
33
+ return out;
34
+ }
35
+ export function subtractWorkdays(date, n, holidays) {
36
+ const out = normalize(date);
37
+ let remaining = Math.max(0, Math.floor(n));
38
+ while (remaining > 0) {
39
+ out.setDate(out.getDate() - 1);
40
+ if (isWorkday(out, holidays))
41
+ remaining--;
42
+ }
43
+ return out;
44
+ }
45
+ export function addWorkdays(date, n, holidays) {
46
+ const out = normalize(date);
47
+ let remaining = Math.max(0, Math.floor(n));
48
+ while (remaining > 0) {
49
+ out.setDate(out.getDate() + 1);
50
+ if (isWorkday(out, holidays))
51
+ remaining--;
52
+ }
53
+ return out;
54
+ }
55
+ function parseHHMM(time) {
56
+ const [h = "0", m = "0"] = (time ?? "").split(":");
57
+ return { h: Number(h) || 0, m: Number(m) || 0 };
58
+ }
59
+ function atTime(date, time) {
60
+ const { h, m } = parseHHMM(time);
61
+ const out = new Date(date);
62
+ out.setHours(h, m, 0, 0);
63
+ return out;
64
+ }
65
+ /**
66
+ * Bepaal de aanmelddeadline van een moment voor een gegeven bezorgdag.
67
+ */
68
+ export function getSignupDeadline(deliveryDate, moment, holidays) {
69
+ const day = subtractWorkdays(deliveryDate, moment.signup_days, holidays);
70
+ return atTime(day, moment.signup_time);
71
+ }
72
+ /**
73
+ * Kies het juiste ophaalmoment op basis van het ordertijdstip.
74
+ * - Voorkeursvolgorde: vroegst gesorteerd op aanmelddeadline.
75
+ * - Eerste moment waarvan deadline nog niet is verstreken wint.
76
+ * - Als alle deadlines verstreken zijn → laatste moment (best effort).
77
+ */
78
+ export function selectPickupMoment(deliveryDate, orderCreatedAt, moments, holidays) {
79
+ if (moments.length === 0)
80
+ return DEFAULT_PICKUP_MOMENT;
81
+ if (moments.length === 1)
82
+ return moments[0];
83
+ const now = orderCreatedAt ?? new Date();
84
+ const sorted = [...moments].sort((a, b) => {
85
+ const da = getSignupDeadline(deliveryDate, a, holidays).getTime();
86
+ const db = getSignupDeadline(deliveryDate, b, holidays).getTime();
87
+ return da - db;
88
+ });
89
+ for (const m of sorted) {
90
+ const deadline = getSignupDeadline(deliveryDate, m, holidays);
91
+ if (now.getTime() <= deadline.getTime())
92
+ return m;
93
+ }
94
+ return sorted[sorted.length - 1];
95
+ }
96
+ export function calculateOrderPlanning(deliveryDate, rules) {
97
+ if (!deliveryDate)
98
+ return null;
99
+ const d = typeof deliveryDate === "string" ? new Date(deliveryDate) : deliveryDate;
100
+ if (Number.isNaN(d.getTime()))
101
+ return null;
102
+ const delivery = normalize(d);
103
+ const moments = rules.pickupMoments.length > 0 ? rules.pickupMoments : [DEFAULT_PICKUP_MOMENT];
104
+ const orderCreated = rules.orderCreatedAt == null
105
+ ? null
106
+ : rules.orderCreatedAt instanceof Date
107
+ ? rules.orderCreatedAt
108
+ : new Date(rules.orderCreatedAt);
109
+ const moment = selectPickupMoment(delivery, orderCreated, moments, rules.holidays);
110
+ const pickup = subtractWorkdays(delivery, moment.pickup_days, rules.holidays);
111
+ const transportRegister = subtractWorkdays(delivery, moment.signup_days, rules.holidays);
112
+ const pickStart = subtractWorkdays(pickup, rules.pickDurationWorkdays, rules.holidays);
113
+ return {
114
+ deliveryDate: delivery,
115
+ pickupDate: pickup,
116
+ transportRegisterDate: transportRegister,
117
+ pickStartDate: pickStart,
118
+ scheduledPickDate: pickStart,
119
+ pickAssignments: [{ date: pickStart, cartCount: 0 }],
120
+ movedEarlier: false,
121
+ selectedMoment: moment,
122
+ };
123
+ }
124
+ export function distributePickDates(items, options) {
125
+ const getCarts = (it) => {
126
+ const n = options.getCartCount?.(it);
127
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1;
128
+ };
129
+ const getOverride = (it, idx) => {
130
+ const raw = options.getCartOverride?.(it, idx);
131
+ if (!raw)
132
+ return null;
133
+ const date = raw instanceof Date ? raw : raw.date;
134
+ const out = new Date(date);
135
+ out.setHours(0, 0, 0, 0);
136
+ const movedFrom = raw instanceof Date ? null : raw.movedFromDate;
137
+ const movedFromDate = movedFrom ? new Date(movedFrom) : null;
138
+ if (movedFromDate)
139
+ movedFromDate.setHours(0, 0, 0, 0);
140
+ return { date: out, movedFromDate };
141
+ };
142
+ const key = (d) => `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
143
+ const load = new Map();
144
+ const result = new Map();
145
+ const distribute = options.enabled && options.maxWorkdaysEarlier > 0;
146
+ const sorted = [...items].sort((a, b) => {
147
+ const ad = a.planning?.pickStartDate.getTime() ?? Infinity;
148
+ const bd = b.planning?.pickStartDate.getTime() ?? Infinity;
149
+ return ad - bd;
150
+ });
151
+ const baseTargets = new Map();
152
+ // Stap 1: bepaal eerst de volledige automatische verdeling, zonder
153
+ // handmatige overrides. Daardoor blijft de automatische balans stabiel en
154
+ // kan een latere handmatige verplaatsing niet door volgende orders worden
155
+ // "teruggevuld".
156
+ for (const item of sorted) {
157
+ if (!item.planning) {
158
+ result.set(item, item);
159
+ continue;
160
+ }
161
+ const deadline = item.planning.pickStartDate;
162
+ const carts = getCarts(item);
163
+ // Kandidaten in chronologische volgorde
164
+ const candidates = [];
165
+ if (distribute) {
166
+ let cursor = deadline;
167
+ for (let i = 0; i < options.maxWorkdaysEarlier; i++) {
168
+ cursor = subtractWorkdays(cursor, 1, options.holidays);
169
+ candidates.unshift(cursor);
170
+ }
171
+ }
172
+ candidates.push(deadline);
173
+ const targets = [];
174
+ for (let c = 0; c < carts; c++) {
175
+ let target;
176
+ if (!distribute) {
177
+ target = deadline;
178
+ load.set(key(target), (load.get(key(target)) ?? 0) + 1);
179
+ }
180
+ else {
181
+ let best = candidates[candidates.length - 1];
182
+ let bestLoad = load.get(key(best)) ?? 0;
183
+ for (let i = candidates.length - 2; i >= 0; i--) {
184
+ const cand = candidates[i];
185
+ const l = load.get(key(cand)) ?? 0;
186
+ if (l < bestLoad) {
187
+ best = cand;
188
+ bestLoad = l;
189
+ }
190
+ }
191
+ target = best;
192
+ load.set(key(target), bestLoad + 1);
193
+ }
194
+ targets[c] = target;
195
+ }
196
+ baseTargets.set(item, targets);
197
+ }
198
+ // Stap 2: pas overrides pas toe nadat alle automatische doelen vaststaan.
199
+ // Dit maakt een verplaatsing absoluut: 10/10 wordt na één kar verplaatsen
200
+ // echt 9/11, niet opnieuw 10/10 door load-balancing.
201
+ for (const item of sorted) {
202
+ if (!item.planning)
203
+ continue;
204
+ const deadline = item.planning.pickStartDate;
205
+ const carts = getCarts(item);
206
+ const targets = [...(baseTargets.get(item) ?? [])];
207
+ const perDay = new Map();
208
+ for (let c = 0; c < carts; c++) {
209
+ const override = getOverride(item, c);
210
+ if (override) {
211
+ // Handmatige verplaatsingen gelden altijd voor de concrete kar-index
212
+ // die de gebruiker aanklikt. Niet ruilen met een andere kar op dezelfde
213
+ // brondag, want dan blijft de aangeklikte kar visueel staan.
214
+ targets[c] = override.date;
215
+ }
216
+ }
217
+ for (let c = 0; c < carts; c++) {
218
+ const target = targets[c];
219
+ const k = key(target);
220
+ const existing = perDay.get(k);
221
+ if (existing) {
222
+ existing.cartCount += 1;
223
+ existing.cartIndexes.push(c);
224
+ }
225
+ else {
226
+ perDay.set(k, { date: target, cartCount: 1, cartIndexes: [c] });
227
+ }
228
+ }
229
+ const assignments = Array.from(perDay.values()).sort((a, b) => a.date.getTime() - b.date.getTime());
230
+ const earliest = assignments[0]?.date ?? deadline;
231
+ const moved = assignments.some((a) => a.date.getTime() !== deadline.getTime());
232
+ result.set(item, {
233
+ ...item,
234
+ planning: {
235
+ ...item.planning,
236
+ scheduledPickDate: earliest,
237
+ pickAssignments: assignments,
238
+ movedEarlier: moved,
239
+ },
240
+ });
241
+ }
242
+ return items.map((it) => result.get(it) ?? it);
243
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/floriday-afhandeling-module",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
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.5.3",
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",
@@ -71,12 +71,18 @@
71
71
  {
72
72
  "export": "LeveringenPage",
73
73
  "route": "afhandeling/leveringen",
74
- "title": "Leveringen"
74
+ "title": "Planning en Leveringen"
75
75
  },
76
76
  {
77
- "export": "VervoerdersPage",
78
- "route": "afhandeling/vervoerders",
79
- "title": "Vervoerders"
77
+ "export": "NieuweLeveringPage",
78
+ "route": "afhandeling/leveringen/nieuw",
79
+ "title": "Levering aanmaken",
80
+ "nav": false
81
+ },
82
+ {
83
+ "export": "PickingPage",
84
+ "route": "afhandeling/picking",
85
+ "title": "Pick Agenda"
80
86
  }
81
87
  ]
82
88
  }