@flowselections/logistiek-engine 1.0.17 → 1.0.19
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/README.md +24 -24
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +158 -1515
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +30 -5
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +1147 -1091
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +12 -0
- package/package.json +1 -1
|
@@ -9,155 +9,155 @@
|
|
|
9
9
|
import { LOGISTICS_MODULES } from "./logisticsTasks";
|
|
10
10
|
function sharedBlock(moduleKey) {
|
|
11
11
|
const key = moduleKey === "<modulesleutel>" ? "<modulesleutel>" : moduleKey;
|
|
12
|
-
return `Alle communicatie met de Logistics Engine loopt uitsluitend via de gedeelde
|
|
13
|
-
Supabase-database. Je leest en schrijft gewoon tabellen met de bestaande
|
|
14
|
-
Supabase-client van deze module (ingelogde gebruiker, RLS). Geen API-key,
|
|
15
|
-
geen header, geen secret, geen edge function.
|
|
16
|
-
|
|
17
|
-
Verbinding — verplicht en fail-closed:
|
|
18
|
-
- Gebruik de Supabase-client van je EIGEN module, lazy geïnstantieerd en
|
|
19
|
-
uitsluitend gevoed door import.meta.env.VITE_SUPABASE_URL en
|
|
20
|
-
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY. Ontbreekt er een waarde, gooi
|
|
21
|
-
dan een harde fout; raad nooit een verbinding.
|
|
22
|
-
- Hardcodeer NOOIT een Supabase project-ref, URL of anon-key — ook niet als
|
|
23
|
-
fallback, voorbeeld of default. De shell bepaalt via env welke database geldt.
|
|
24
|
-
- Importeer NOOIT uit "@/integrations/supabase/client": dat bestand wordt door
|
|
25
|
-
de Supabase-integratie automatisch gegenereerd en overschreven met een
|
|
26
|
-
vastgezette project-ref, wat in een andere shell naar de verkeerde database
|
|
27
|
-
schrijft. Zet je eigen client in bijvoorbeeld
|
|
28
|
-
"@/integrations/supabase/moduleClient" en sluit het gegenereerde bestand uit
|
|
29
|
-
van je library-build.
|
|
30
|
-
|
|
31
|
-
De Engine beslist alles over buffering, belading, picken, controle, printen en
|
|
32
|
-
transport. Deze module voert alleen nog taken uit en beslist zelf niets meer.
|
|
33
|
-
|
|
34
|
-
--- Gebeurtenis melden: RPC logistics_emit_event (idempotent) ---
|
|
35
|
-
const { data } = await supabase.rpc("logistics_emit_event", {
|
|
36
|
-
p_source_module: "${key}",
|
|
37
|
-
p_event_type: "order.received", // of order.changed, stock.changed
|
|
38
|
-
p_order_ref: "SO-12345",
|
|
39
|
-
p_payload: {
|
|
40
|
-
checkinAt: "2026-08-01T10:00:00Z",
|
|
41
|
-
pickupAt: "2026-08-01T14:00:00Z",
|
|
42
|
-
customerRef: "CUST-1",
|
|
43
|
-
deliveryLocationRef: "LOC-1",
|
|
44
|
-
bufferRef: null,
|
|
45
|
-
loadCarriers: [{ type: "trolley", count: 3 }],
|
|
46
|
-
ruleVersion: null, // optioneel: plan op een vastgelegde regelversie
|
|
47
|
-
},
|
|
48
|
-
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
49
|
-
p_shadow: true,
|
|
50
|
-
p_idempotency_key: "${key}:SO-12345:order.received:v1",
|
|
51
|
-
});
|
|
52
|
-
// data = { eventId, planRunId, status, duplicate }
|
|
53
|
-
Geef ALTIJD een p_idempotency_key mee die uniek is per gebeurtenis. Stuur je
|
|
54
|
-
dezelfde melding twee keer (retry, dubbele webhook), dan plant de Engine maar
|
|
55
|
-
één keer en krijg je duplicate: true terug.
|
|
56
|
-
De Engine pakt de rij direct op (status pending -> processed), plant de keten en
|
|
57
|
-
zet plan_run_id en error terug op dezelfde rij.
|
|
58
|
-
|
|
59
|
-
--- Taken ophalen: SELECT op public.logistics_tasks ---
|
|
60
|
-
const { data } = await supabase
|
|
61
|
-
.from("logistics_tasks")
|
|
62
|
-
.select("*")
|
|
63
|
-
.eq("owner_module", "${key}")
|
|
64
|
-
.eq("status", "planned")
|
|
65
|
-
.order("planned_start", { ascending: true });
|
|
66
|
-
Kolommen: order_ref, buffer_ref, task_type, sequence, depends_on,
|
|
67
|
-
planned_start, planned_end, due_at, status, shadow, payload, result,
|
|
68
|
-
rule_version, claimed_by, claimed_at, error.
|
|
69
|
-
|
|
70
|
-
Realtime kan gewoon met supabase.channel() op logistics_tasks (in useEffect,
|
|
71
|
-
met removeChannel in de cleanup).
|
|
72
|
-
|
|
73
|
-
--- Taak claimen: ALTIJD via RPC, nooit met een eigen UPDATE ---
|
|
74
|
-
const { data: taak } = await supabase.rpc("logistics_claim_task", {
|
|
75
|
-
p_task_id: taskId, p_worker: "station-3",
|
|
76
|
-
});
|
|
77
|
-
if (!taak) { /* al door iemand anders geclaimd */ }
|
|
78
|
-
|
|
79
|
-
// of automatisch de eerstvolgende taak van deze module:
|
|
80
|
-
const { data: volgende } = await supabase.rpc("logistics_claim_next_task", {
|
|
81
|
-
p_owner_module: "${key}", p_worker: "station-3",
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
--- Taak afmelden: ook via RPC ---
|
|
85
|
-
await supabase.rpc("logistics_complete_task", { p_task_id: taskId, p_result: { ... } });
|
|
86
|
-
await supabase.rpc("logistics_fail_task", { p_task_id: taskId, p_error: "reden" });
|
|
87
|
-
|
|
88
|
-
--- Order annuleren ---
|
|
89
|
-
await supabase.rpc("logistics_emit_event", {
|
|
90
|
-
p_source_module: "${key}",
|
|
91
|
-
p_event_type: "order.cancelled",
|
|
92
|
-
p_order_ref: "SO-12345",
|
|
93
|
-
p_payload: { reason: "klant belde af" },
|
|
94
|
-
p_idempotency_key: "${key}:SO-12345:cancel:v1",
|
|
95
|
-
});
|
|
96
|
-
Al afgeronde taken blijven staan. Annuleer nooit zelf met een eigen UPDATE.
|
|
97
|
-
|
|
98
|
-
--- Order splitsen ---
|
|
99
|
-
await supabase.rpc("logistics_emit_event", {
|
|
100
|
-
p_source_module: "${key}",
|
|
101
|
-
p_event_type: "order.split",
|
|
102
|
-
p_order_ref: "SO-12345",
|
|
103
|
-
p_payload: {
|
|
104
|
-
checkinAt: "...", pickupAt: "...",
|
|
105
|
-
children: [
|
|
106
|
-
{ orderRef: "SO-12345-A", loadCarriers: [{ type: "trolley", count: 1 }] },
|
|
107
|
-
{ orderRef: "SO-12345-B", loadCarriers: [{ type: "trolley", count: 2 }] },
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
p_idempotency_key: "${key}:SO-12345:split:v1",
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
--- Spoed / prioriteit ---
|
|
114
|
-
await supabase.rpc("logistics_set_order_priority", {
|
|
115
|
-
p_order_ref: "SO-12345", p_priority: 100,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
--- Instellingen inzien (nooit zelf beslissen) ---
|
|
119
|
-
public.logistics_strategies de logistieke strategieën
|
|
120
|
-
public.logistics_rule_configs settings (jsonb) per strategie + current_version
|
|
121
|
-
public.logistics_plan_runs momentopname van de instellingen per planronde
|
|
122
|
-
Alleen lezen, en alleen om te tonen.
|
|
123
|
-
|
|
124
|
-
Ladingdragers: trolley, danish_container, euro_rolcontainer, pallet, euro_pallet, loose
|
|
125
|
-
Taakstatussen: planned, claimed, in_progress, done, skipped, cancelled,
|
|
126
|
-
superseded, failed
|
|
127
|
-
|
|
128
|
-
Eigenaarschap: meldingen, planruns en taken hebben een kolom user_id die de
|
|
129
|
-
database automatisch vult met het ingelogde account.
|
|
130
|
-
|
|
131
|
-
Start in schaduwmodus (shadow: true): eigen logica blijft draaien, Engine-taken
|
|
132
|
-
worden alleen getoond en vergeleken. Elke taak draagt rule_version — een lopende
|
|
12
|
+
return `Alle communicatie met de Logistics Engine loopt uitsluitend via de gedeelde
|
|
13
|
+
Supabase-database. Je leest en schrijft gewoon tabellen met de bestaande
|
|
14
|
+
Supabase-client van deze module (ingelogde gebruiker, RLS). Geen API-key,
|
|
15
|
+
geen header, geen secret, geen edge function.
|
|
16
|
+
|
|
17
|
+
Verbinding — verplicht en fail-closed:
|
|
18
|
+
- Gebruik de Supabase-client van je EIGEN module, lazy geïnstantieerd en
|
|
19
|
+
uitsluitend gevoed door import.meta.env.VITE_SUPABASE_URL en
|
|
20
|
+
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY. Ontbreekt er een waarde, gooi
|
|
21
|
+
dan een harde fout; raad nooit een verbinding.
|
|
22
|
+
- Hardcodeer NOOIT een Supabase project-ref, URL of anon-key — ook niet als
|
|
23
|
+
fallback, voorbeeld of default. De shell bepaalt via env welke database geldt.
|
|
24
|
+
- Importeer NOOIT uit "@/integrations/supabase/client": dat bestand wordt door
|
|
25
|
+
de Supabase-integratie automatisch gegenereerd en overschreven met een
|
|
26
|
+
vastgezette project-ref, wat in een andere shell naar de verkeerde database
|
|
27
|
+
schrijft. Zet je eigen client in bijvoorbeeld
|
|
28
|
+
"@/integrations/supabase/moduleClient" en sluit het gegenereerde bestand uit
|
|
29
|
+
van je library-build.
|
|
30
|
+
|
|
31
|
+
De Engine beslist alles over buffering, belading, picken, controle, printen en
|
|
32
|
+
transport. Deze module voert alleen nog taken uit en beslist zelf niets meer.
|
|
33
|
+
|
|
34
|
+
--- Gebeurtenis melden: RPC logistics_emit_event (idempotent) ---
|
|
35
|
+
const { data } = await supabase.rpc("logistics_emit_event", {
|
|
36
|
+
p_source_module: "${key}",
|
|
37
|
+
p_event_type: "order.received", // of order.changed, stock.changed
|
|
38
|
+
p_order_ref: "SO-12345",
|
|
39
|
+
p_payload: {
|
|
40
|
+
checkinAt: "2026-08-01T10:00:00Z",
|
|
41
|
+
pickupAt: "2026-08-01T14:00:00Z",
|
|
42
|
+
customerRef: "CUST-1",
|
|
43
|
+
deliveryLocationRef: "LOC-1",
|
|
44
|
+
bufferRef: null,
|
|
45
|
+
loadCarriers: [{ type: "trolley", count: 3 }],
|
|
46
|
+
ruleVersion: null, // optioneel: plan op een vastgelegde regelversie
|
|
47
|
+
},
|
|
48
|
+
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
49
|
+
p_shadow: true,
|
|
50
|
+
p_idempotency_key: "${key}:SO-12345:order.received:v1",
|
|
51
|
+
});
|
|
52
|
+
// data = { eventId, planRunId, status, duplicate }
|
|
53
|
+
Geef ALTIJD een p_idempotency_key mee die uniek is per gebeurtenis. Stuur je
|
|
54
|
+
dezelfde melding twee keer (retry, dubbele webhook), dan plant de Engine maar
|
|
55
|
+
één keer en krijg je duplicate: true terug.
|
|
56
|
+
De Engine pakt de rij direct op (status pending -> processed), plant de keten en
|
|
57
|
+
zet plan_run_id en error terug op dezelfde rij.
|
|
58
|
+
|
|
59
|
+
--- Taken ophalen: SELECT op public.logistics_tasks ---
|
|
60
|
+
const { data } = await supabase
|
|
61
|
+
.from("logistics_tasks")
|
|
62
|
+
.select("*")
|
|
63
|
+
.eq("owner_module", "${key}")
|
|
64
|
+
.eq("status", "planned")
|
|
65
|
+
.order("planned_start", { ascending: true });
|
|
66
|
+
Kolommen: order_ref, buffer_ref, task_type, sequence, depends_on,
|
|
67
|
+
planned_start, planned_end, due_at, status, shadow, payload, result,
|
|
68
|
+
rule_version, claimed_by, claimed_at, error.
|
|
69
|
+
|
|
70
|
+
Realtime kan gewoon met supabase.channel() op logistics_tasks (in useEffect,
|
|
71
|
+
met removeChannel in de cleanup).
|
|
72
|
+
|
|
73
|
+
--- Taak claimen: ALTIJD via RPC, nooit met een eigen UPDATE ---
|
|
74
|
+
const { data: taak } = await supabase.rpc("logistics_claim_task", {
|
|
75
|
+
p_task_id: taskId, p_worker: "station-3",
|
|
76
|
+
});
|
|
77
|
+
if (!taak) { /* al door iemand anders geclaimd */ }
|
|
78
|
+
|
|
79
|
+
// of automatisch de eerstvolgende taak van deze module:
|
|
80
|
+
const { data: volgende } = await supabase.rpc("logistics_claim_next_task", {
|
|
81
|
+
p_owner_module: "${key}", p_worker: "station-3",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
--- Taak afmelden: ook via RPC ---
|
|
85
|
+
await supabase.rpc("logistics_complete_task", { p_task_id: taskId, p_result: { ... } });
|
|
86
|
+
await supabase.rpc("logistics_fail_task", { p_task_id: taskId, p_error: "reden" });
|
|
87
|
+
|
|
88
|
+
--- Order annuleren ---
|
|
89
|
+
await supabase.rpc("logistics_emit_event", {
|
|
90
|
+
p_source_module: "${key}",
|
|
91
|
+
p_event_type: "order.cancelled",
|
|
92
|
+
p_order_ref: "SO-12345",
|
|
93
|
+
p_payload: { reason: "klant belde af" },
|
|
94
|
+
p_idempotency_key: "${key}:SO-12345:cancel:v1",
|
|
95
|
+
});
|
|
96
|
+
Al afgeronde taken blijven staan. Annuleer nooit zelf met een eigen UPDATE.
|
|
97
|
+
|
|
98
|
+
--- Order splitsen ---
|
|
99
|
+
await supabase.rpc("logistics_emit_event", {
|
|
100
|
+
p_source_module: "${key}",
|
|
101
|
+
p_event_type: "order.split",
|
|
102
|
+
p_order_ref: "SO-12345",
|
|
103
|
+
p_payload: {
|
|
104
|
+
checkinAt: "...", pickupAt: "...",
|
|
105
|
+
children: [
|
|
106
|
+
{ orderRef: "SO-12345-A", loadCarriers: [{ type: "trolley", count: 1 }] },
|
|
107
|
+
{ orderRef: "SO-12345-B", loadCarriers: [{ type: "trolley", count: 2 }] },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
p_idempotency_key: "${key}:SO-12345:split:v1",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
--- Spoed / prioriteit ---
|
|
114
|
+
await supabase.rpc("logistics_set_order_priority", {
|
|
115
|
+
p_order_ref: "SO-12345", p_priority: 100,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
--- Instellingen inzien (nooit zelf beslissen) ---
|
|
119
|
+
public.logistics_strategies de logistieke strategieën
|
|
120
|
+
public.logistics_rule_configs settings (jsonb) per strategie + current_version
|
|
121
|
+
public.logistics_plan_runs momentopname van de instellingen per planronde
|
|
122
|
+
Alleen lezen, en alleen om te tonen.
|
|
123
|
+
|
|
124
|
+
Ladingdragers: trolley, danish_container, euro_rolcontainer, pallet, euro_pallet, loose
|
|
125
|
+
Taakstatussen: planned, claimed, in_progress, done, skipped, cancelled,
|
|
126
|
+
superseded, failed
|
|
127
|
+
|
|
128
|
+
Eigenaarschap: meldingen, planruns en taken hebben een kolom user_id die de
|
|
129
|
+
database automatisch vult met het ingelogde account.
|
|
130
|
+
|
|
131
|
+
Start in schaduwmodus (shadow: true): eigen logica blijft draaien, Engine-taken
|
|
132
|
+
worden alleen getoond en vergeleken. Elke taak draagt rule_version — een lopende
|
|
133
133
|
order verandert nooit stilletjes mee als de Rule Engine wijzigt.`;
|
|
134
134
|
}
|
|
135
|
-
const STOCK_CONTRACT = `De Engine bepaalt of een bestelling met producten die niet op voorraad zijn
|
|
136
|
-
überhaupt aangemaakt mag worden. Die keuze staat in de Rule Engine
|
|
137
|
-
(Order verwerking -> "Bestellingen uitleveren wanneer een product niet op
|
|
138
|
-
voorraad is"). Beslis dit NOOIT zelf.
|
|
139
|
-
|
|
140
|
-
Roep vóór het opslaan van een nieuwe order (of het wijzigen van de aantallen)
|
|
141
|
-
altijd deze RPC aan:
|
|
142
|
-
|
|
143
|
-
const { data: check } = await supabase.rpc("logistics_check_order_allowed", {
|
|
144
|
-
p_lines: [
|
|
145
|
-
{ productId: "<uuid of artikelnummer of barcode of floriday trade item id>", quantity: 12 },
|
|
146
|
-
],
|
|
147
|
-
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
148
|
-
});
|
|
149
|
-
// check = { allowed, allowBackorder, shortages: [{ productId, product, wanted, available, missing }], reason }
|
|
150
|
-
|
|
151
|
-
Regels:
|
|
152
|
-
- allowed === false -> blokkeer het aanmaken/opslaan van de order volledig en
|
|
153
|
-
toon per regel uit check.shortages:
|
|
154
|
-
"<product>: besteld <wanted>, beschikbaar <available>, tekort <missing>".
|
|
155
|
-
Geen omweg, geen "toch doorgaan"-knop. reason = "insufficient_stock".
|
|
156
|
-
- allowed === true en shortages niet leeg -> order mag wél aangemaakt worden
|
|
157
|
-
(uitleveren zonder voorraad staat aan); de Engine maakt zelf de melding en/of
|
|
158
|
-
e-mail aan. Toon de tekorten alleen ter informatie.
|
|
159
|
-
- Alleen de instelling opvragen (bv. live waarschuwing tijdens typen):
|
|
160
|
-
const { data: mag } = await supabase.rpc("logistics_backorder_allowed", { p_strategy_id: null });
|
|
135
|
+
const STOCK_CONTRACT = `De Engine bepaalt of een bestelling met producten die niet op voorraad zijn
|
|
136
|
+
überhaupt aangemaakt mag worden. Die keuze staat in de Rule Engine
|
|
137
|
+
(Order verwerking -> "Bestellingen uitleveren wanneer een product niet op
|
|
138
|
+
voorraad is"). Beslis dit NOOIT zelf.
|
|
139
|
+
|
|
140
|
+
Roep vóór het opslaan van een nieuwe order (of het wijzigen van de aantallen)
|
|
141
|
+
altijd deze RPC aan:
|
|
142
|
+
|
|
143
|
+
const { data: check } = await supabase.rpc("logistics_check_order_allowed", {
|
|
144
|
+
p_lines: [
|
|
145
|
+
{ productId: "<uuid of artikelnummer of barcode of floriday trade item id>", quantity: 12 },
|
|
146
|
+
],
|
|
147
|
+
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
148
|
+
});
|
|
149
|
+
// check = { allowed, allowBackorder, shortages: [{ productId, product, wanted, available, missing }], reason }
|
|
150
|
+
|
|
151
|
+
Regels:
|
|
152
|
+
- allowed === false -> blokkeer het aanmaken/opslaan van de order volledig en
|
|
153
|
+
toon per regel uit check.shortages:
|
|
154
|
+
"<product>: besteld <wanted>, beschikbaar <available>, tekort <missing>".
|
|
155
|
+
Geen omweg, geen "toch doorgaan"-knop. reason = "insufficient_stock".
|
|
156
|
+
- allowed === true en shortages niet leeg -> order mag wél aangemaakt worden
|
|
157
|
+
(uitleveren zonder voorraad staat aan); de Engine maakt zelf de melding en/of
|
|
158
|
+
e-mail aan. Toon de tekorten alleen ter informatie.
|
|
159
|
+
- Alleen de instelling opvragen (bv. live waarschuwing tijdens typen):
|
|
160
|
+
const { data: mag } = await supabase.rpc("logistics_backorder_allowed", { p_strategy_id: null });
|
|
161
161
|
- Cache het antwoord niet: de instelling kan op elk moment wijzigen.`;
|
|
162
162
|
const MODULES = {
|
|
163
163
|
verkoop: {
|
|
@@ -170,16 +170,16 @@ const MODULES = {
|
|
|
170
170
|
date: "2026-07-24",
|
|
171
171
|
summary: "Orderbufferlogica eruit, events en taken via Supabase.",
|
|
172
172
|
withSharedContract: true,
|
|
173
|
-
body: `Haal weg: alle eigen orderbufferlogica, eigen samenvoegregels en alle
|
|
174
|
-
fetch-calls naar een Engine-URL plus eventuele secrets.
|
|
175
|
-
|
|
176
|
-
Bouw:
|
|
177
|
-
- Bij nieuwe/gewijzigde order een gebeurtenis melden via logistics_emit_event
|
|
178
|
-
(event_type order.received of order.changed).
|
|
179
|
-
- Taken van type buffer.close lezen uit logistics_tasks (owner_module "verkoop"),
|
|
180
|
-
uitvoeren en afmelden via logistics_claim_task + logistics_complete_task.
|
|
181
|
-
- Buffer-samenstelling tonen zoals die in payload staat (matchCriteria, release).
|
|
182
|
-
- release "manual" -> knop Vrijgeven. release "none" -> alleen tonen, niets doen.
|
|
173
|
+
body: `Haal weg: alle eigen orderbufferlogica, eigen samenvoegregels en alle
|
|
174
|
+
fetch-calls naar een Engine-URL plus eventuele secrets.
|
|
175
|
+
|
|
176
|
+
Bouw:
|
|
177
|
+
- Bij nieuwe/gewijzigde order een gebeurtenis melden via logistics_emit_event
|
|
178
|
+
(event_type order.received of order.changed).
|
|
179
|
+
- Taken van type buffer.close lezen uit logistics_tasks (owner_module "verkoop"),
|
|
180
|
+
uitvoeren en afmelden via logistics_claim_task + logistics_complete_task.
|
|
181
|
+
- Buffer-samenstelling tonen zoals die in payload staat (matchCriteria, release).
|
|
182
|
+
- release "manual" -> knop Vrijgeven. release "none" -> alleen tonen, niets doen.
|
|
183
183
|
- In schaduwmodus: Engine-buffersluittijd naast de eigen berekening tonen.`,
|
|
184
184
|
},
|
|
185
185
|
{
|
|
@@ -187,16 +187,16 @@ Bouw:
|
|
|
187
187
|
title: "Voorraadcontrole vóór het aanmaken van een order",
|
|
188
188
|
date: "2026-07-31",
|
|
189
189
|
summary: "Nieuwe eis bovenop prompt 1: order blokkeren als een product niet op voorraad is.",
|
|
190
|
-
body: `AANVULLING op koppelprompt 1 (die blijft gewoon geldig, niets terugdraaien).
|
|
191
|
-
|
|
192
|
-
Nieuwe verplichting: vóór het aanmaken of wijzigen van een order eerst de
|
|
193
|
-
voorraadcontrole van de Engine aanroepen.
|
|
194
|
-
|
|
195
|
-
${STOCK_CONTRACT}
|
|
196
|
-
|
|
197
|
-
In de Verkoop-module concreet:
|
|
198
|
-
- Blokkeer de opslaan-knop van de order zolang allowed false is.
|
|
199
|
-
- Toon de tekorten in het orderscherm, per regel bij het product.
|
|
190
|
+
body: `AANVULLING op koppelprompt 1 (die blijft gewoon geldig, niets terugdraaien).
|
|
191
|
+
|
|
192
|
+
Nieuwe verplichting: vóór het aanmaken of wijzigen van een order eerst de
|
|
193
|
+
voorraadcontrole van de Engine aanroepen.
|
|
194
|
+
|
|
195
|
+
${STOCK_CONTRACT}
|
|
196
|
+
|
|
197
|
+
In de Verkoop-module concreet:
|
|
198
|
+
- Blokkeer de opslaan-knop van de order zolang allowed false is.
|
|
199
|
+
- Toon de tekorten in het orderscherm, per regel bij het product.
|
|
200
200
|
- Doe de controle ook opnieuw bij het wijzigen van aantallen of regels.`,
|
|
201
201
|
},
|
|
202
202
|
{
|
|
@@ -204,51 +204,51 @@ In de Verkoop-module concreet:
|
|
|
204
204
|
title: "Bufferen mag alleen als de Engine dat zegt",
|
|
205
205
|
date: "2026-07-31",
|
|
206
206
|
summary: "Nieuwe eis bovenop prompt 1 en 2: geen eigen bufferbesluit meer, altijd eerst logistics_buffer_decision aanroepen.",
|
|
207
|
-
body: `AANVULLING op koppelprompt 1 en 2 (die blijven gewoon geldig).
|
|
208
|
-
|
|
209
|
-
Probleem: er stonden orders in een orderbuffer terwijl bufferen in de Rule Engine
|
|
210
|
-
UIT stond. De Verkoop-module beslist dat dus nog zelf. Dat moet eruit.
|
|
211
|
-
|
|
212
|
-
Haal weg: elke eigen regel, instelling of code die bepaalt of een order in een
|
|
213
|
-
orderbuffer / gecombineerde order terechtkomt, inclusief automatisch aanmaken of
|
|
214
|
-
toewijzen van een buffer bij het opslaan van een order.
|
|
215
|
-
|
|
216
|
-
Nieuwe verplichting: vraag het per order aan de Engine.
|
|
217
|
-
|
|
218
|
-
const { data: besluit } = await supabase.rpc("logistics_buffer_decision", {
|
|
219
|
-
p_order: {
|
|
220
|
-
orderRef: "SO-12345",
|
|
221
|
-
checkinAt: "2026-08-01T10:00:00Z",
|
|
222
|
-
customerRef: "CUST-1",
|
|
223
|
-
floridayCustomerRef: "FLOR-1",
|
|
224
|
-
bvoCustomerRef: "BVO-1",
|
|
225
|
-
deliveryLocationRef: "LOC-1",
|
|
226
|
-
deliveryDate: "2026-08-01",
|
|
227
|
-
carrierRef: "TRANS-1",
|
|
228
|
-
loadCarrierType: "trolley",
|
|
229
|
-
orderType: "standaard",
|
|
230
|
-
},
|
|
231
|
-
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
232
|
-
});
|
|
233
|
-
// besluit = { buffer, reason, bufferRef, bufferKey, matchCriteria,
|
|
234
|
-
// closeBeforeMinutes, bufferCloseAt, release }
|
|
235
|
-
|
|
236
|
-
Regels:
|
|
237
|
-
- besluit.buffer === false (reason "buffering_disabled") -> de order gaat LOS door.
|
|
238
|
-
Geen buffer aanmaken, geen bestaande buffer toewijzen, geen buffer tonen.
|
|
239
|
-
- besluit.buffer === true -> gebruik exact besluit.bufferRef als buffersleutel.
|
|
240
|
-
Orders met dezelfde bufferRef horen in dezelfde gecombineerde order. Bepaal die
|
|
241
|
-
groepering nooit zelf op eigen criteria.
|
|
242
|
-
- Toon buffersluittijd uit besluit.bufferCloseAt, en de vrijgave uit
|
|
243
|
-
besluit.release ("auto" | "manual" | "none"). Bij "manual" een knop Vrijgeven,
|
|
244
|
-
bij "none" alleen tonen.
|
|
245
|
-
- Cache het antwoord niet: de instelling kan op elk moment wijzigen. Vraag het
|
|
246
|
-
opnieuw bij elke wijziging van de order (aanmeldtijd, klant, locatie, aantallen).
|
|
247
|
-
- Stuur bufferRef mee in de payload van logistics_emit_event (veld bufferRef),
|
|
248
|
-
zodat de Engine en de Verkoop-module dezelfde buffer bedoelen.
|
|
249
|
-
|
|
250
|
-
Eenmalige opschoning: haal bij bestaande, nog niet afgehandelde orders de
|
|
251
|
-
bufferkoppeling weg zodra logistics_buffer_decision voor die order buffer=false
|
|
207
|
+
body: `AANVULLING op koppelprompt 1 en 2 (die blijven gewoon geldig).
|
|
208
|
+
|
|
209
|
+
Probleem: er stonden orders in een orderbuffer terwijl bufferen in de Rule Engine
|
|
210
|
+
UIT stond. De Verkoop-module beslist dat dus nog zelf. Dat moet eruit.
|
|
211
|
+
|
|
212
|
+
Haal weg: elke eigen regel, instelling of code die bepaalt of een order in een
|
|
213
|
+
orderbuffer / gecombineerde order terechtkomt, inclusief automatisch aanmaken of
|
|
214
|
+
toewijzen van een buffer bij het opslaan van een order.
|
|
215
|
+
|
|
216
|
+
Nieuwe verplichting: vraag het per order aan de Engine.
|
|
217
|
+
|
|
218
|
+
const { data: besluit } = await supabase.rpc("logistics_buffer_decision", {
|
|
219
|
+
p_order: {
|
|
220
|
+
orderRef: "SO-12345",
|
|
221
|
+
checkinAt: "2026-08-01T10:00:00Z",
|
|
222
|
+
customerRef: "CUST-1",
|
|
223
|
+
floridayCustomerRef: "FLOR-1",
|
|
224
|
+
bvoCustomerRef: "BVO-1",
|
|
225
|
+
deliveryLocationRef: "LOC-1",
|
|
226
|
+
deliveryDate: "2026-08-01",
|
|
227
|
+
carrierRef: "TRANS-1",
|
|
228
|
+
loadCarrierType: "trolley",
|
|
229
|
+
orderType: "standaard",
|
|
230
|
+
},
|
|
231
|
+
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
232
|
+
});
|
|
233
|
+
// besluit = { buffer, reason, bufferRef, bufferKey, matchCriteria,
|
|
234
|
+
// closeBeforeMinutes, bufferCloseAt, release }
|
|
235
|
+
|
|
236
|
+
Regels:
|
|
237
|
+
- besluit.buffer === false (reason "buffering_disabled") -> de order gaat LOS door.
|
|
238
|
+
Geen buffer aanmaken, geen bestaande buffer toewijzen, geen buffer tonen.
|
|
239
|
+
- besluit.buffer === true -> gebruik exact besluit.bufferRef als buffersleutel.
|
|
240
|
+
Orders met dezelfde bufferRef horen in dezelfde gecombineerde order. Bepaal die
|
|
241
|
+
groepering nooit zelf op eigen criteria.
|
|
242
|
+
- Toon buffersluittijd uit besluit.bufferCloseAt, en de vrijgave uit
|
|
243
|
+
besluit.release ("auto" | "manual" | "none"). Bij "manual" een knop Vrijgeven,
|
|
244
|
+
bij "none" alleen tonen.
|
|
245
|
+
- Cache het antwoord niet: de instelling kan op elk moment wijzigen. Vraag het
|
|
246
|
+
opnieuw bij elke wijziging van de order (aanmeldtijd, klant, locatie, aantallen).
|
|
247
|
+
- Stuur bufferRef mee in de payload van logistics_emit_event (veld bufferRef),
|
|
248
|
+
zodat de Engine en de Verkoop-module dezelfde buffer bedoelen.
|
|
249
|
+
|
|
250
|
+
Eenmalige opschoning: haal bij bestaande, nog niet afgehandelde orders de
|
|
251
|
+
bufferkoppeling weg zodra logistics_buffer_decision voor die order buffer=false
|
|
252
252
|
teruggeeft. Al verwerkte/verzonden orders laat je met rust.`,
|
|
253
253
|
},
|
|
254
254
|
{
|
|
@@ -256,33 +256,33 @@ teruggeeft. Al verwerkte/verzonden orders laat je met rust.`,
|
|
|
256
256
|
title: "Correctie bufferbesluit: nieuwe velden en uitleg",
|
|
257
257
|
date: "2026-08-02",
|
|
258
258
|
summary: "Nieuwe eis bovenop prompt 3: logistics_buffer_decision is gecorrigeerd, stuur alle matchvelden mee en gebruik de uitleg (trace).",
|
|
259
|
-
body: `AANVULLING op koppelprompt 1, 2 en 3 (die blijven gewoon geldig).
|
|
260
|
-
|
|
261
|
-
Wat er is gewijzigd aan de Engine-kant:
|
|
262
|
-
- logistics_buffer_decision las de Rule Engine-instellingen fout uit en negeerde de
|
|
263
|
-
aangevinkte criteria. Dat is opgelost: de gekozen criteria worden nu echt vergeleken.
|
|
264
|
-
- De buffersleutel bevat niet langer het exacte sluitmoment. Orders met dezelfde
|
|
265
|
-
gegevens maar een iets andere aanmeldtijd komen nu wél in dezelfde buffer.
|
|
266
|
-
- De functie heeft een derde parameter p_user_id (laat die weg of op null staan).
|
|
267
|
-
- Het antwoord bevat nu ook een veld trace: per criterium waarom het klopt of niet.
|
|
268
|
-
|
|
269
|
-
Wat de Verkoop-module moet doen:
|
|
270
|
-
1. Stuur bij elke aanroep ALLE velden mee die als criterium gekozen kunnen zijn.
|
|
271
|
-
Ontbreekt een waarde van een aangevinkt criterium, dan combineert de Engine de
|
|
272
|
-
order bewust NIET (reason "buffering_enabled_missing_data").
|
|
273
|
-
Verplichte velden in p_order:
|
|
274
|
-
orderRef, checkinAt, deliveryDate, customerRef, floridayCustomerRef,
|
|
275
|
-
bvoCustomerRef, deliveryLocationRef, carrierRef, loadCarrierType, orderType
|
|
276
|
-
deliveryLocationRef moet een stabiele sleutel zijn van het afleveradres
|
|
277
|
-
(locatie-id of genormaliseerd adres), niet een vrije tekst die per order verschilt.
|
|
278
|
-
2. Toon in het orderscherm de reden uit besluit.reason en, bij twijfel, de regels uit
|
|
279
|
-
besluit.trace ("waarom zit deze order niet bij die andere order?").
|
|
280
|
-
3. Vraag het besluit opnieuw op zodra een van bovenstaande velden wijzigt, en
|
|
281
|
-
verplaats de order dan naar de nieuwe bufferRef.
|
|
282
|
-
4. Bepaal nooit zelf of twee orders bij elkaar horen; vergelijk alleen bufferRef.
|
|
283
|
-
|
|
284
|
-
Eenmalige opschoning: haal voor alle nog niet verwerkte orders opnieuw het besluit op
|
|
285
|
-
en werk de bufferkoppeling bij. Orders die volgens de Engine samen horen, moeten daarna
|
|
259
|
+
body: `AANVULLING op koppelprompt 1, 2 en 3 (die blijven gewoon geldig).
|
|
260
|
+
|
|
261
|
+
Wat er is gewijzigd aan de Engine-kant:
|
|
262
|
+
- logistics_buffer_decision las de Rule Engine-instellingen fout uit en negeerde de
|
|
263
|
+
aangevinkte criteria. Dat is opgelost: de gekozen criteria worden nu echt vergeleken.
|
|
264
|
+
- De buffersleutel bevat niet langer het exacte sluitmoment. Orders met dezelfde
|
|
265
|
+
gegevens maar een iets andere aanmeldtijd komen nu wél in dezelfde buffer.
|
|
266
|
+
- De functie heeft een derde parameter p_user_id (laat die weg of op null staan).
|
|
267
|
+
- Het antwoord bevat nu ook een veld trace: per criterium waarom het klopt of niet.
|
|
268
|
+
|
|
269
|
+
Wat de Verkoop-module moet doen:
|
|
270
|
+
1. Stuur bij elke aanroep ALLE velden mee die als criterium gekozen kunnen zijn.
|
|
271
|
+
Ontbreekt een waarde van een aangevinkt criterium, dan combineert de Engine de
|
|
272
|
+
order bewust NIET (reason "buffering_enabled_missing_data").
|
|
273
|
+
Verplichte velden in p_order:
|
|
274
|
+
orderRef, checkinAt, deliveryDate, customerRef, floridayCustomerRef,
|
|
275
|
+
bvoCustomerRef, deliveryLocationRef, carrierRef, loadCarrierType, orderType
|
|
276
|
+
deliveryLocationRef moet een stabiele sleutel zijn van het afleveradres
|
|
277
|
+
(locatie-id of genormaliseerd adres), niet een vrije tekst die per order verschilt.
|
|
278
|
+
2. Toon in het orderscherm de reden uit besluit.reason en, bij twijfel, de regels uit
|
|
279
|
+
besluit.trace ("waarom zit deze order niet bij die andere order?").
|
|
280
|
+
3. Vraag het besluit opnieuw op zodra een van bovenstaande velden wijzigt, en
|
|
281
|
+
verplaats de order dan naar de nieuwe bufferRef.
|
|
282
|
+
4. Bepaal nooit zelf of twee orders bij elkaar horen; vergelijk alleen bufferRef.
|
|
283
|
+
|
|
284
|
+
Eenmalige opschoning: haal voor alle nog niet verwerkte orders opnieuw het besluit op
|
|
285
|
+
en werk de bufferkoppeling bij. Orders die volgens de Engine samen horen, moeten daarna
|
|
286
286
|
dezelfde bufferRef hebben.`,
|
|
287
287
|
},
|
|
288
288
|
{
|
|
@@ -290,46 +290,102 @@ dezelfde bufferRef hebben.`,
|
|
|
290
290
|
title: "Alleen ladingdragers tonen die de Engine toestaat",
|
|
291
291
|
date: "2026-08-03",
|
|
292
292
|
summary: "Nieuwe eis bovenop prompt 1 t/m 4: uitgeschakelde ladingdragers mogen niet meer kiesbaar zijn.",
|
|
293
|
-
body: `AANVULLING op koppelprompt 1, 2, 3 en 4 (die blijven gewoon geldig).
|
|
294
|
-
|
|
295
|
-
In de Rule Engine (stap Beladingindeling) staat welke ladingdragers zijn toegestaan.
|
|
296
|
-
Staat een ladingdrager uit, dan mag die in de Verkoop-module nergens meer te kiezen
|
|
297
|
-
zijn.
|
|
298
|
-
|
|
299
|
-
Haal weg: elke eigen, vaste lijst met ladingdragers / verzendmethodes in de code,
|
|
300
|
-
in constanten, in dropdowns of in filters.
|
|
301
|
-
|
|
302
|
-
Nieuwe verplichting: haal de lijst op bij de Engine.
|
|
303
|
-
|
|
304
|
-
const { data: dragers } = await supabase.rpc("logistics_allowed_load_carriers", {
|
|
305
|
-
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
306
|
-
});
|
|
307
|
-
// dragers = {
|
|
308
|
-
// allowed: ["trolley","pallet"],
|
|
309
|
-
// default: "trolley",
|
|
310
|
-
// carriers: [{ code, label, enabled, isDefault }, ...]
|
|
311
|
-
// }
|
|
312
|
-
|
|
313
|
-
Codes en namen (gebruik exact deze codes):
|
|
314
|
-
trolley Stapelwagen
|
|
315
|
-
danish_container Deense container
|
|
316
|
-
euro_rolcontainer Euro-rolcontainer
|
|
317
|
-
pallet Pallet
|
|
318
|
-
euro_pallet Euro-pallet
|
|
319
|
-
loose Geen ladingdrager
|
|
320
|
-
|
|
321
|
-
Regels:
|
|
322
|
-
- Toon in elk keuzeveld (order, orderregel, verzendmethode, filter) alleen de
|
|
323
|
-
dragers met enabled === true. Uitgeschakelde dragers niet grijs tonen: weglaten.
|
|
324
|
-
- Voorselectie = dragers.default.
|
|
325
|
-
- Blokkeer opslaan als een order een ladingdrager heeft die niet in allowed staat,
|
|
326
|
-
met melding: "Deze ladingdrager is uitgeschakeld in de Logistics Engine."
|
|
327
|
-
- Cache de lijst niet langer dan één schermsessie; de instelling kan wijzigen.
|
|
328
|
-
- Bestaande, nog niet verwerkte orders met een inmiddels uitgeschakelde drager:
|
|
329
|
-
markeer die in het overzicht zodat een medewerker een andere drager kiest.
|
|
330
|
-
- Stuur loadCarrierType in logistics_emit_event en logistics_buffer_decision altijd
|
|
293
|
+
body: `AANVULLING op koppelprompt 1, 2, 3 en 4 (die blijven gewoon geldig).
|
|
294
|
+
|
|
295
|
+
In de Rule Engine (stap Beladingindeling) staat welke ladingdragers zijn toegestaan.
|
|
296
|
+
Staat een ladingdrager uit, dan mag die in de Verkoop-module nergens meer te kiezen
|
|
297
|
+
zijn.
|
|
298
|
+
|
|
299
|
+
Haal weg: elke eigen, vaste lijst met ladingdragers / verzendmethodes in de code,
|
|
300
|
+
in constanten, in dropdowns of in filters.
|
|
301
|
+
|
|
302
|
+
Nieuwe verplichting: haal de lijst op bij de Engine.
|
|
303
|
+
|
|
304
|
+
const { data: dragers } = await supabase.rpc("logistics_allowed_load_carriers", {
|
|
305
|
+
p_strategy_id: null, // uuid van logistics_strategies indien bekend
|
|
306
|
+
});
|
|
307
|
+
// dragers = {
|
|
308
|
+
// allowed: ["trolley","pallet"],
|
|
309
|
+
// default: "trolley",
|
|
310
|
+
// carriers: [{ code, label, enabled, isDefault }, ...]
|
|
311
|
+
// }
|
|
312
|
+
|
|
313
|
+
Codes en namen (gebruik exact deze codes):
|
|
314
|
+
trolley Stapelwagen
|
|
315
|
+
danish_container Deense container
|
|
316
|
+
euro_rolcontainer Euro-rolcontainer
|
|
317
|
+
pallet Pallet
|
|
318
|
+
euro_pallet Euro-pallet
|
|
319
|
+
loose Geen ladingdrager
|
|
320
|
+
|
|
321
|
+
Regels:
|
|
322
|
+
- Toon in elk keuzeveld (order, orderregel, verzendmethode, filter) alleen de
|
|
323
|
+
dragers met enabled === true. Uitgeschakelde dragers niet grijs tonen: weglaten.
|
|
324
|
+
- Voorselectie = dragers.default.
|
|
325
|
+
- Blokkeer opslaan als een order een ladingdrager heeft die niet in allowed staat,
|
|
326
|
+
met melding: "Deze ladingdrager is uitgeschakeld in de Logistics Engine."
|
|
327
|
+
- Cache de lijst niet langer dan één schermsessie; de instelling kan wijzigen.
|
|
328
|
+
- Bestaande, nog niet verwerkte orders met een inmiddels uitgeschakelde drager:
|
|
329
|
+
markeer die in het overzicht zodat een medewerker een andere drager kiest.
|
|
330
|
+
- Stuur loadCarrierType in logistics_emit_event en logistics_buffer_decision altijd
|
|
331
331
|
met een van bovenstaande codes mee, nooit met een eigen naam of vrije tekst.`,
|
|
332
332
|
},
|
|
333
|
+
{
|
|
334
|
+
number: 6,
|
|
335
|
+
title: "Karindeling: eigen planner eruit, Engine-planner erin",
|
|
336
|
+
date: "2026-08-27",
|
|
337
|
+
summary: "Nieuwe eis bovenop prompt 1 t/m 5: /api/public/cron/replan-carts schrijft nog eigen karren met algorithm_version 1 en valt terug op 1×1×1.",
|
|
338
|
+
body: `AANVULLING op koppelprompt 1 t/m 5 (die blijven gewoon geldig).
|
|
339
|
+
|
|
340
|
+
GEMETEN PROBLEEM (Mathot productie, 27-08-2026)
|
|
341
|
+
public.order_carts bevat 11.560 rijen met algorithm_version = 1, nog steeds
|
|
342
|
+
groeiend (laatste 13:12:59). Zetten we cron 113 (elke minuut naar
|
|
343
|
+
/api/public/cron/replan-carts) uit, dan stopt de aanwas onmiddellijk. De
|
|
344
|
+
schrijver is dus de Verkoop-module.
|
|
345
|
+
|
|
346
|
+
Bewijs in de Verkoop-module:
|
|
347
|
+
- src/lib/cart-replan.functions.ts, regel ~178-190: INSERT in order_carts met
|
|
348
|
+
algorithm_version: CART_PLANNER_VERSION.
|
|
349
|
+
- src/lib/cart-planner.ts, regel 14: export const CART_PLANNER_VERSION = 1.
|
|
350
|
+
- src/lib/cart-replan.functions.ts, regel ~208: INSERT in order_cart_items.
|
|
351
|
+
- src/lib/create-order.functions.ts, regel ~1196 + ~1203 en ~1296 + ~1313:
|
|
352
|
+
INSERTs die algorithm_version en source helemaal niet zetten, dus de
|
|
353
|
+
kolomdefaults ('auto', 1) gebruiken.
|
|
354
|
+
- Dit pad rekent zélf (planCarts uit src/lib/cart-planner.ts). Het roept de
|
|
355
|
+
gedeelde Engine-planner (loadCarrierPlanning / planByFloridayPacking,
|
|
356
|
+
LOAD_CARRIER_PLANNER_VERSION = 3) NIET aan.
|
|
357
|
+
- Terugval bij ontbrekende belading: in de mapping naar PlannerInputItem staat
|
|
358
|
+
overal \`?? 1\` (plants_per_crate, crates_per_layer, layers_per_cart). Bij een
|
|
359
|
+
order zonder bekende belading levert dat stilzwijgend 1×1×1 op — precies wat de
|
|
360
|
+
beslisregel van 26-08 verbiedt. De guard (B1/B2/B3) zit niet in dit pad.
|
|
361
|
+
|
|
362
|
+
WAT ER MOET GEBEUREN — voorkeur A, minimaal B.
|
|
363
|
+
|
|
364
|
+
A (voorkeur). Laat /api/public/cron/replan-carts niet meer zelf rekenen.
|
|
365
|
+
Roep de gedeelde planner van de Logistics Engine aan
|
|
366
|
+
(@flowselections/logistiek-engine → loadCarrierPlanning /
|
|
367
|
+
planByFloridayPacking) en schrijf uitsluitend het resultaat weg. Verwijder
|
|
368
|
+
src/lib/cart-planner.ts als schrijfpad. Reden: één rekenhart, dus geen derde
|
|
369
|
+
afwijkende indeling naast TS en SQL.
|
|
370
|
+
|
|
371
|
+
B (alleen als A nu te groot is, en dan als tussenstap):
|
|
372
|
+
- Zet in ELKE INSERT in order_carts expliciet
|
|
373
|
+
algorithm_version: LOAD_CARRIER_PLANNER_VERSION (nu 3) en source
|
|
374
|
+
('auto' | 'manual' | 'floriday'). Ook in create-order.functions.ts regel
|
|
375
|
+
~1196 en ~1296. Vertrouw nooit op de kolomdefault.
|
|
376
|
+
- Neem dezelfde guard over als de Engine: is de belading van een orderregel
|
|
377
|
+
onbekend (geen plants_per_crate / crates_per_layer / layers_per_cart op de
|
|
378
|
+
regel én niet op het product), dan wordt die regel NIET ingedeeld. Geen
|
|
379
|
+
\`?? 1\`, nooit terugvallen op 1×1×1. Meld het als blokkade op de order,
|
|
380
|
+
zodat een medewerker de belading invult.
|
|
381
|
+
- Verwijder alle bestaande rijen met algorithm_version < 3 pas nadat A of B
|
|
382
|
+
live is; anders komen ze binnen een minuut terug.
|
|
383
|
+
|
|
384
|
+
NIET DOEN
|
|
385
|
+
- De kolomdefaults van order_carts niet weghalen en algorithm_version niet
|
|
386
|
+
NOT NULL maken; dat kan pas als alle schrijfpaden de kolom zetten.
|
|
387
|
+
- De beslisregel van 26-08 (B1/B2/B3) niet wijzigen — alleen overnemen.`,
|
|
388
|
+
},
|
|
333
389
|
],
|
|
334
390
|
},
|
|
335
391
|
afhandeling: {
|
|
@@ -342,15 +398,15 @@ Regels:
|
|
|
342
398
|
date: "2026-07-24",
|
|
343
399
|
summary: "Eigen beladings- en documentlogica eruit, taken uitvoeren.",
|
|
344
400
|
withSharedContract: true,
|
|
345
|
-
body: `Haal weg: eigen beladingindeling, eigen documentmomenten, eigen controle-instellingen.
|
|
346
|
-
|
|
347
|
-
Consumeer deze taaktypes:
|
|
348
|
-
- load.compose payload: loadCarriers, fillMode (generated | manual_scan)
|
|
349
|
-
- control.execute payload: controlMode (paper), noticeAt
|
|
350
|
-
- print.control_note payload: printItems (control_note | control_note_and_shipping)
|
|
351
|
-
- print.shipping_note payload: moment (with_packing_slip | with_control | after_control | after_scan)
|
|
352
|
-
- transport.dispatch
|
|
353
|
-
|
|
401
|
+
body: `Haal weg: eigen beladingindeling, eigen documentmomenten, eigen controle-instellingen.
|
|
402
|
+
|
|
403
|
+
Consumeer deze taaktypes:
|
|
404
|
+
- load.compose payload: loadCarriers, fillMode (generated | manual_scan)
|
|
405
|
+
- control.execute payload: controlMode (paper), noticeAt
|
|
406
|
+
- print.control_note payload: printItems (control_note | control_note_and_shipping)
|
|
407
|
+
- print.shipping_note payload: moment (with_packing_slip | with_control | after_control | after_scan)
|
|
408
|
+
- transport.dispatch
|
|
409
|
+
|
|
354
410
|
Wat er geprint wordt en wanneer komt volledig uit de taak-payload. Geen eigen keuzes meer.`,
|
|
355
411
|
},
|
|
356
412
|
{
|
|
@@ -358,28 +414,28 @@ Wat er geprint wordt en wanneer komt volledig uit de taak-payload. Geen eigen ke
|
|
|
358
414
|
title: "Documentvrijgave komt volledig van de Engine",
|
|
359
415
|
date: "2026-08-03",
|
|
360
416
|
summary: "Pakbon, stickers, verzendbrief en productiebon alleen nog via Engine-taken.",
|
|
361
|
-
body: `Deze prompt vervangt niets uit prompt 1; hij komt er bovenop.
|
|
362
|
-
|
|
363
|
-
Haal weg: elke eigen regel over wanneer een pakbon, sticker, verzendbrief of
|
|
364
|
-
productiebon wordt vrijgegeven of geprint. De Logistics Engine beslist dit nu.
|
|
365
|
-
|
|
366
|
-
Nieuwe taaktypes die je moet verwerken (tabel logistics_tasks):
|
|
367
|
-
- print.packing_slip payload: release (with_pick_release | hours_before_pick),
|
|
368
|
-
pickStationId, pickStationTypeId, requiresApproval
|
|
369
|
-
- print.sticker payload: idem als print.packing_slip
|
|
370
|
-
- print.shipping_note payload: release (after_checkin | after_scan |
|
|
371
|
-
with_packing_slip | manual_approval), pickStationId,
|
|
372
|
-
pickStationTypeId, requiresApproval
|
|
373
|
-
- print.production_note payload: release (on_stock_upgrade |
|
|
374
|
-
manual_approval_after_upgrade), trigger, pickStationId,
|
|
375
|
-
pickStationTypeId, requiresApproval
|
|
376
|
-
|
|
377
|
-
Regels:
|
|
378
|
-
- planned_start van de taak is het vrijgavemoment. Nooit eerder printen.
|
|
379
|
-
- pickStationId verwijst naar public.pick_stations.id; pickStationTypeId naar
|
|
380
|
-
public.pick_station_types.id. Stuur het document uitsluitend naar dat station.
|
|
381
|
-
- requiresApproval = true: het document blijft in de wachtrij tot iemand het op
|
|
382
|
-
het pickstation goedkeurt. Meld de goedkeuring met logistics_complete_task.
|
|
417
|
+
body: `Deze prompt vervangt niets uit prompt 1; hij komt er bovenop.
|
|
418
|
+
|
|
419
|
+
Haal weg: elke eigen regel over wanneer een pakbon, sticker, verzendbrief of
|
|
420
|
+
productiebon wordt vrijgegeven of geprint. De Logistics Engine beslist dit nu.
|
|
421
|
+
|
|
422
|
+
Nieuwe taaktypes die je moet verwerken (tabel logistics_tasks):
|
|
423
|
+
- print.packing_slip payload: release (with_pick_release | hours_before_pick),
|
|
424
|
+
pickStationId, pickStationTypeId, requiresApproval
|
|
425
|
+
- print.sticker payload: idem als print.packing_slip
|
|
426
|
+
- print.shipping_note payload: release (after_checkin | after_scan |
|
|
427
|
+
with_packing_slip | manual_approval), pickStationId,
|
|
428
|
+
pickStationTypeId, requiresApproval
|
|
429
|
+
- print.production_note payload: release (on_stock_upgrade |
|
|
430
|
+
manual_approval_after_upgrade), trigger, pickStationId,
|
|
431
|
+
pickStationTypeId, requiresApproval
|
|
432
|
+
|
|
433
|
+
Regels:
|
|
434
|
+
- planned_start van de taak is het vrijgavemoment. Nooit eerder printen.
|
|
435
|
+
- pickStationId verwijst naar public.pick_stations.id; pickStationTypeId naar
|
|
436
|
+
public.pick_station_types.id. Stuur het document uitsluitend naar dat station.
|
|
437
|
+
- requiresApproval = true: het document blijft in de wachtrij tot iemand het op
|
|
438
|
+
het pickstation goedkeurt. Meld de goedkeuring met logistics_complete_task.
|
|
383
439
|
- Is er geen taak voor een document, dan wordt dat document niet geprint.`,
|
|
384
440
|
},
|
|
385
441
|
{
|
|
@@ -387,53 +443,53 @@ Regels:
|
|
|
387
443
|
title: "Order- en karindeling altijd via de Logistics Engine",
|
|
388
444
|
date: "2026-08-04",
|
|
389
445
|
summary: "Nieuwe eis bovenop prompt 1 en 2: geen eigen indeling van orders en karren meer; stap 3 'Order picken' van de Rule Engine is leidend.",
|
|
390
|
-
body: `Deze prompt vervangt niets uit prompt 1 en 2; hij komt er bovenop.
|
|
391
|
-
|
|
392
|
-
Geconstateerd probleem: deze module deelt orders en karren nog zelf in en houdt
|
|
393
|
-
zich daardoor niet aan stap 3 "Order picken" van de Rule Engine. Dat moet stoppen.
|
|
394
|
-
|
|
395
|
-
Haal weg: elke eigen berekening van
|
|
396
|
-
- welke orders samen op één belading/kar komen,
|
|
397
|
-
- hoeveel orders, klanten, lagen of dozen er op een drager passen,
|
|
398
|
-
- wanneer er met picken gestart wordt,
|
|
399
|
-
- of er met of zonder scanner gewerkt wordt.
|
|
400
|
-
|
|
401
|
-
Zo werkt het vanaf nu:
|
|
402
|
-
|
|
403
|
-
1) Vraag altijd eerst het besluit op voordat je iets indeelt:
|
|
404
|
-
const { data: besluit } = await supabase.rpc("logistics_buffer_decision", {
|
|
405
|
-
p_order_ref: "SO-12345",
|
|
406
|
-
p_customer_ref: "CUST-1",
|
|
407
|
-
p_delivery_location_ref: "LOC-1",
|
|
408
|
-
p_checkin_at: "2026-08-01T10:00:00Z",
|
|
409
|
-
p_pickup_at: "2026-08-01T14:00:00Z",
|
|
410
|
-
p_load_carrier_type: "trolley",
|
|
411
|
-
p_strategy_id: null,
|
|
412
|
-
});
|
|
413
|
-
// besluit = { buffer, bufferRef, matchCriteria, release, trace }
|
|
414
|
-
Deel de order uitsluitend in bij bufferRef. Is buffer=false, dan blijft de order
|
|
415
|
-
los staan: nooit zelf alsnog samenvoegen.
|
|
416
|
-
|
|
417
|
-
2) De feitelijke belading komt uit de taak load.compose in logistics_tasks
|
|
418
|
-
(owner_module = "afhandeling"). De payload bevat loadCarriers, fillMode
|
|
419
|
-
(generated | manual_scan) en de picksettings uit stap 3: pickMode,
|
|
420
|
-
pickStartMode, pickMinutes, staff, reserveMinutes, scanner.
|
|
421
|
-
- fillMode = generated: neem de indeling exact over zoals aangeleverd.
|
|
422
|
-
- fillMode = manual_scan: laat de medewerker scannen en meld het resultaat
|
|
423
|
-
terug; corrigeer de indeling niet zelf.
|
|
424
|
-
- scanner = required: geen afronding zonder scan.
|
|
425
|
-
|
|
426
|
-
3) planned_start en planned_end van de taak zijn leidend voor het pickmoment.
|
|
427
|
-
Herbereken die nooit zelf, ook niet bij drukte.
|
|
428
|
-
|
|
429
|
-
4) Is er nog geen load.compose taak voor een order, dan meld je dat met
|
|
430
|
-
logistics_emit_event (order.received of order.changed) en wacht je op de taak.
|
|
431
|
-
Zelf alvast indelen is niet toegestaan.
|
|
432
|
-
|
|
433
|
-
5) Elke taak draagt rule_version. Rond een lopende belading altijd af op de
|
|
434
|
-
rule_version van de taak, ook als de Rule Engine intussen is gewijzigd.
|
|
435
|
-
|
|
436
|
-
Meld afwijkingen terug met logistics_fail_task inclusief toelichting, zodat de
|
|
446
|
+
body: `Deze prompt vervangt niets uit prompt 1 en 2; hij komt er bovenop.
|
|
447
|
+
|
|
448
|
+
Geconstateerd probleem: deze module deelt orders en karren nog zelf in en houdt
|
|
449
|
+
zich daardoor niet aan stap 3 "Order picken" van de Rule Engine. Dat moet stoppen.
|
|
450
|
+
|
|
451
|
+
Haal weg: elke eigen berekening van
|
|
452
|
+
- welke orders samen op één belading/kar komen,
|
|
453
|
+
- hoeveel orders, klanten, lagen of dozen er op een drager passen,
|
|
454
|
+
- wanneer er met picken gestart wordt,
|
|
455
|
+
- of er met of zonder scanner gewerkt wordt.
|
|
456
|
+
|
|
457
|
+
Zo werkt het vanaf nu:
|
|
458
|
+
|
|
459
|
+
1) Vraag altijd eerst het besluit op voordat je iets indeelt:
|
|
460
|
+
const { data: besluit } = await supabase.rpc("logistics_buffer_decision", {
|
|
461
|
+
p_order_ref: "SO-12345",
|
|
462
|
+
p_customer_ref: "CUST-1",
|
|
463
|
+
p_delivery_location_ref: "LOC-1",
|
|
464
|
+
p_checkin_at: "2026-08-01T10:00:00Z",
|
|
465
|
+
p_pickup_at: "2026-08-01T14:00:00Z",
|
|
466
|
+
p_load_carrier_type: "trolley",
|
|
467
|
+
p_strategy_id: null,
|
|
468
|
+
});
|
|
469
|
+
// besluit = { buffer, bufferRef, matchCriteria, release, trace }
|
|
470
|
+
Deel de order uitsluitend in bij bufferRef. Is buffer=false, dan blijft de order
|
|
471
|
+
los staan: nooit zelf alsnog samenvoegen.
|
|
472
|
+
|
|
473
|
+
2) De feitelijke belading komt uit de taak load.compose in logistics_tasks
|
|
474
|
+
(owner_module = "afhandeling"). De payload bevat loadCarriers, fillMode
|
|
475
|
+
(generated | manual_scan) en de picksettings uit stap 3: pickMode,
|
|
476
|
+
pickStartMode, pickMinutes, staff, reserveMinutes, scanner.
|
|
477
|
+
- fillMode = generated: neem de indeling exact over zoals aangeleverd.
|
|
478
|
+
- fillMode = manual_scan: laat de medewerker scannen en meld het resultaat
|
|
479
|
+
terug; corrigeer de indeling niet zelf.
|
|
480
|
+
- scanner = required: geen afronding zonder scan.
|
|
481
|
+
|
|
482
|
+
3) planned_start en planned_end van de taak zijn leidend voor het pickmoment.
|
|
483
|
+
Herbereken die nooit zelf, ook niet bij drukte.
|
|
484
|
+
|
|
485
|
+
4) Is er nog geen load.compose taak voor een order, dan meld je dat met
|
|
486
|
+
logistics_emit_event (order.received of order.changed) en wacht je op de taak.
|
|
487
|
+
Zelf alvast indelen is niet toegestaan.
|
|
488
|
+
|
|
489
|
+
5) Elke taak draagt rule_version. Rond een lopende belading altijd af op de
|
|
490
|
+
rule_version van de taak, ook als de Rule Engine intussen is gewijzigd.
|
|
491
|
+
|
|
492
|
+
Meld afwijkingen terug met logistics_fail_task inclusief toelichting, zodat de
|
|
437
493
|
Engine kan herplannen. Val nooit terug op eigen logica.`,
|
|
438
494
|
},
|
|
439
495
|
{
|
|
@@ -441,50 +497,50 @@ Engine kan herplannen. Val nooit terug op eigen logica.`,
|
|
|
441
497
|
title: "Karren verdelen over meerdere ophaalmomenten",
|
|
442
498
|
date: "2026-08-04",
|
|
443
499
|
summary: "Nieuwe eis bovenop prompt 1 t/m 4: de Engine verdeelt complete karren over de ophaalmomenten van een dag; deze module toont dat en verzet nooit zelf.",
|
|
444
|
-
body: `LEES DIT EERST — hoe je deze prompt uitvoert
|
|
445
|
-
|
|
446
|
-
Alles uit prompt 1 t/m 4 blijft gelden. Hier komt er één ding bij: een dag kan
|
|
447
|
-
MEERDERE ophaalmomenten hebben, en de Logistics Engine bepaalt welke kar bij
|
|
448
|
-
welk ophaalmoment hoort. Jij rekent NIETS zelf uit en verplaatst NOOIT zelf een
|
|
449
|
-
kar op basis van eigen logica.
|
|
450
|
-
|
|
451
|
-
1) Ophaalmomenten lezen
|
|
452
|
-
Tabel: public.logistics_pickup_moments
|
|
453
|
-
Kolommen: id, moment_date, sequence, label, pickup_time, carrier_ref
|
|
454
|
-
Toon per dag de ophaalmomenten op volgorde van sequence/pickup_time.
|
|
455
|
-
|
|
456
|
-
2) Karren per ophaalmoment
|
|
457
|
-
Tabel public.order_carts heeft nieuwe kolommen:
|
|
458
|
-
- pickup_moment_id → bij welk ophaalmoment de kar hoort
|
|
459
|
-
- moved_from_moment_id → het ophaalmoment waar de kar oorspronkelijk stond
|
|
460
|
-
- moved_reason → 'capacity_shift' als de Engine hem doorschoof
|
|
461
|
-
- moved_at → wanneer dat gebeurde
|
|
462
|
-
- pickup_locked → true = deze kar mag NIET doorgeschoven worden
|
|
463
|
-
|
|
464
|
-
Groepeer de pickagenda en de leveringsplanning voortaan op pickup_moment_id,
|
|
465
|
-
niet meer alleen op de dag. Een kar met moved_reason = 'capacity_shift' toon
|
|
466
|
-
je met een duidelijk label "doorgeschoven vanaf <label vorig moment>".
|
|
467
|
-
|
|
468
|
-
3) Regels die je moet respecteren
|
|
469
|
-
- Alleen COMPLETE karren wisselen van ophaalmoment. Splits nooit een kar en
|
|
470
|
-
verplaats nooit losse orderregels naar een ander moment.
|
|
471
|
-
- Karren uit een buffer mogen mee, maar alleen als geheel.
|
|
472
|
-
- Wil een gebruiker een kar vastzetten op een moment, zet dan
|
|
473
|
-
pickup_locked = true. Meer doe je niet; de Engine slaat die kar over.
|
|
474
|
-
|
|
475
|
-
4) Herberekenen
|
|
476
|
-
Na elke wijziging die de planning raakt (nieuwe order, annulering, andere
|
|
477
|
-
ophaaltijd, andere kar-indeling) roep je aan:
|
|
478
|
-
await supabase.rpc("logistics_capacity_plan_day", { p_date: "2026-08-04" })
|
|
479
|
-
De functie geeft per ophaalmoment terug: requiredMinutes, availableMinutes,
|
|
480
|
-
feasible en movedCarts. Toon die uitkomst; verzin geen eigen berekening.
|
|
481
|
-
|
|
482
|
-
5) Tekort tonen
|
|
483
|
-
Tabel public.logistics_capacity_alerts bevat per dag/ophaalmoment het tekort
|
|
484
|
-
(shortage_minutes, carts_short, moved_carts, unplanned_carts). Staat er een
|
|
485
|
-
rij met status = 'open', toon dan bij dat ophaalmoment een rode waarschuwing
|
|
486
|
-
met het tekort en het aantal karren dat niet op tijd verwerkt kan worden.
|
|
487
|
-
|
|
500
|
+
body: `LEES DIT EERST — hoe je deze prompt uitvoert
|
|
501
|
+
|
|
502
|
+
Alles uit prompt 1 t/m 4 blijft gelden. Hier komt er één ding bij: een dag kan
|
|
503
|
+
MEERDERE ophaalmomenten hebben, en de Logistics Engine bepaalt welke kar bij
|
|
504
|
+
welk ophaalmoment hoort. Jij rekent NIETS zelf uit en verplaatst NOOIT zelf een
|
|
505
|
+
kar op basis van eigen logica.
|
|
506
|
+
|
|
507
|
+
1) Ophaalmomenten lezen
|
|
508
|
+
Tabel: public.logistics_pickup_moments
|
|
509
|
+
Kolommen: id, moment_date, sequence, label, pickup_time, carrier_ref
|
|
510
|
+
Toon per dag de ophaalmomenten op volgorde van sequence/pickup_time.
|
|
511
|
+
|
|
512
|
+
2) Karren per ophaalmoment
|
|
513
|
+
Tabel public.order_carts heeft nieuwe kolommen:
|
|
514
|
+
- pickup_moment_id → bij welk ophaalmoment de kar hoort
|
|
515
|
+
- moved_from_moment_id → het ophaalmoment waar de kar oorspronkelijk stond
|
|
516
|
+
- moved_reason → 'capacity_shift' als de Engine hem doorschoof
|
|
517
|
+
- moved_at → wanneer dat gebeurde
|
|
518
|
+
- pickup_locked → true = deze kar mag NIET doorgeschoven worden
|
|
519
|
+
|
|
520
|
+
Groepeer de pickagenda en de leveringsplanning voortaan op pickup_moment_id,
|
|
521
|
+
niet meer alleen op de dag. Een kar met moved_reason = 'capacity_shift' toon
|
|
522
|
+
je met een duidelijk label "doorgeschoven vanaf <label vorig moment>".
|
|
523
|
+
|
|
524
|
+
3) Regels die je moet respecteren
|
|
525
|
+
- Alleen COMPLETE karren wisselen van ophaalmoment. Splits nooit een kar en
|
|
526
|
+
verplaats nooit losse orderregels naar een ander moment.
|
|
527
|
+
- Karren uit een buffer mogen mee, maar alleen als geheel.
|
|
528
|
+
- Wil een gebruiker een kar vastzetten op een moment, zet dan
|
|
529
|
+
pickup_locked = true. Meer doe je niet; de Engine slaat die kar over.
|
|
530
|
+
|
|
531
|
+
4) Herberekenen
|
|
532
|
+
Na elke wijziging die de planning raakt (nieuwe order, annulering, andere
|
|
533
|
+
ophaaltijd, andere kar-indeling) roep je aan:
|
|
534
|
+
await supabase.rpc("logistics_capacity_plan_day", { p_date: "2026-08-04" })
|
|
535
|
+
De functie geeft per ophaalmoment terug: requiredMinutes, availableMinutes,
|
|
536
|
+
feasible en movedCarts. Toon die uitkomst; verzin geen eigen berekening.
|
|
537
|
+
|
|
538
|
+
5) Tekort tonen
|
|
539
|
+
Tabel public.logistics_capacity_alerts bevat per dag/ophaalmoment het tekort
|
|
540
|
+
(shortage_minutes, carts_short, moved_carts, unplanned_carts). Staat er een
|
|
541
|
+
rij met status = 'open', toon dan bij dat ophaalmoment een rode waarschuwing
|
|
542
|
+
met het tekort en het aantal karren dat niet op tijd verwerkt kan worden.
|
|
543
|
+
|
|
488
544
|
Val nooit terug op eigen logica. Wat de Engine teruggeeft, is leidend.`,
|
|
489
545
|
},
|
|
490
546
|
{
|
|
@@ -492,131 +548,131 @@ Val nooit terug op eigen logica. Wat de Engine teruggeeft, is leidend.`,
|
|
|
492
548
|
title: "Order handmatig verzetten en ophaaltijd wijzigen",
|
|
493
549
|
date: "2026-08-04",
|
|
494
550
|
summary: "Nieuwe eis bovenop prompt 1 t/m 3: een medewerker mag een order handmatig naar een andere dag en/of ophaaltijd zetten, via twee vaste RPC's van de Engine.",
|
|
495
|
-
body: `LEES DIT EERST — hoe je deze prompt uitvoert
|
|
496
|
-
|
|
497
|
-
Deze prompt beschrijft één nieuwe functie in de Afhandeling-module: "Order
|
|
498
|
-
verzetten". Je bouwt hem volledig, niet gedeeltelijk. Alles wat hieronder staat
|
|
499
|
-
is verplicht. Er is GEEN eigen rekenwerk: de Logistics Engine levert twee kant-en-
|
|
500
|
-
klare database-functies, jij bouwt alleen het scherm eromheen en toont wat de
|
|
501
|
-
Engine teruggeeft.
|
|
502
|
-
|
|
503
|
-
Concreet ben je klaar als dit alle vier waar is:
|
|
504
|
-
1. Er is een knop "Verzetten" bij een order (planning-/agenda-/leverscherm).
|
|
505
|
-
2. Het dialoogvenster toont een DAGKEUZE en een OPHAALTIJD (van/tot).
|
|
506
|
-
3. Voor het opslaan is logistics_reschedule_preview aangeroepen en wordt de
|
|
507
|
-
uitkomst daarvan letterlijk aan de gebruiker getoond.
|
|
508
|
-
4. Opslaan gebeurt uitsluitend met logistics_reschedule_order.
|
|
509
|
-
|
|
510
|
-
------------------------------------------------------------------
|
|
511
|
-
DE TWEE REGELS DIE DE GEBRUIKER WIL
|
|
512
|
-
------------------------------------------------------------------
|
|
513
|
-
|
|
514
|
-
A. Order gaat NAAR VOREN (nieuwe ophaaldag is eerder dan de huidige)
|
|
515
|
-
-> Het AFLEVERMOMENT (leverdatum naar de klant) blijft ONGEWIJZIGD.
|
|
516
|
-
De order wordt dus eerder klaargemaakt en opgehaald, maar de klant krijgt
|
|
517
|
-
hem op dezelfde dag als afgesproken. Je verandert de leverdatum NIET.
|
|
518
|
-
Er gaat GEEN melding naar de klant.
|
|
519
|
-
|
|
520
|
-
B. Order gaat NAAR ACHTEREN (nieuwe ophaaldag is later)
|
|
521
|
-
-> Het aflevermoment schuift mee.
|
|
522
|
-
-> De gebruiker MOET in het dialoogvenster de keuze krijgen:
|
|
523
|
-
"Klant informeren over de nieuwe leverdatum" (aan/uit) plus een reden.
|
|
524
|
-
Staat het aan, dan zorgt de Engine voor de klantmelding. Bouw daar zelf
|
|
525
|
-
geen mailflow voor.
|
|
526
|
-
|
|
527
|
-
C. Alleen de OPHAALTIJD wijzigen (zelfde dag, andere van/tot-tijd) mag altijd
|
|
528
|
-
en geldt niet als verzetten: geen klantmelding, leverdatum blijft gelijk.
|
|
529
|
-
|
|
530
|
-
------------------------------------------------------------------
|
|
531
|
-
STAP 1 — VOORVERTONING (verplicht vóór opslaan)
|
|
532
|
-
------------------------------------------------------------------
|
|
533
|
-
const { data: preview } = await supabase.rpc("logistics_reschedule_preview", {
|
|
534
|
-
p_order_ref: "SO-12345", // orders.order_number
|
|
535
|
-
p_pickup_date: "2026-08-07", // nieuwe ophaaldag (YYYY-MM-DD), null = ongewijzigd
|
|
536
|
-
p_pickup_from: "06:00", // nieuwe starttijd, null = ongewijzigd
|
|
537
|
-
p_pickup_to: "09:00", // nieuwe eindtijd, null = ongewijzigd
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
preview bevat:
|
|
541
|
-
{
|
|
542
|
-
ok: true,
|
|
543
|
-
orderRef, orderId, bufferId, planLocked,
|
|
544
|
-
current: { pickupDate, pickupFrom, pickupTo, deliveryDate },
|
|
545
|
-
next: { pickupDate, pickupFrom, pickupTo, deliveryDate },
|
|
546
|
-
direction: "earlier" | "later" | "same",
|
|
547
|
-
dayShift: -2, // aantal dagen verschil
|
|
548
|
-
timeChanged: true,
|
|
549
|
-
keepDeliveryMoment: true, // true bij naar voren: leverdatum blijft
|
|
550
|
-
customerNoticeRequired: true, // true bij naar achteren: toon de klantoptie
|
|
551
|
-
affectedTasks: 8 // aantal taken dat opnieuw wordt ingepland
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
Wat je met deze velden DOET in het scherm:
|
|
555
|
-
- ok === false -> toon preview.error en blokkeer opslaan.
|
|
556
|
-
- direction === "earlier" -> toon: "Order wordt X dag(en) eerder opgehaald. Het
|
|
557
|
-
aflevermoment blijft {current.deliveryDate}." Verberg de klantoptie.
|
|
558
|
-
- direction === "later" -> toon: "Order wordt X dag(en) later. Nieuwe leverdatum:
|
|
559
|
-
{next.deliveryDate}." Toon de schakelaar "Klant informeren" (standaard AAN) en
|
|
560
|
-
een verplicht redenveld.
|
|
561
|
-
- direction === "same" && timeChanged -> toon alleen de nieuwe ophaaltijd.
|
|
562
|
-
- Toon altijd affectedTasks: "X taken worden opnieuw ingepland."
|
|
563
|
-
|
|
564
|
-
------------------------------------------------------------------
|
|
565
|
-
STAP 2 — OPSLAAN
|
|
566
|
-
------------------------------------------------------------------
|
|
567
|
-
const { data: result } = await supabase.rpc("logistics_reschedule_order", {
|
|
568
|
-
p_order_ref: "SO-12345",
|
|
569
|
-
p_pickup_date: "2026-08-07",
|
|
570
|
-
p_pickup_from: "06:00",
|
|
571
|
-
p_pickup_to: "09:00",
|
|
572
|
-
p_notify_customer: true, // alleen relevant bij direction "later"
|
|
573
|
-
p_reason: "Aanvoer bloemen vertraagd",
|
|
574
|
-
p_source_module: "afhandeling",
|
|
575
|
-
p_user_id: null,
|
|
576
|
-
});
|
|
577
|
-
// result = preview-velden + { applied: true, rescheduleId, delayAlertId,
|
|
578
|
-
// customerNotified, pickupMoment }
|
|
579
|
-
|
|
580
|
-
De Engine doet hierbij zelf al ALLES hieronder — doe dit dus niet nogmaals:
|
|
581
|
-
- orders.custom_fields.pickup_moment bijwerken ("YYYY-MM-DD|van|tot");
|
|
582
|
-
- leverdatum alleen aanpassen bij naar achteren;
|
|
583
|
-
- de order uit zijn orderbuffer halen zodat hij niet aan de oude dag vastzit;
|
|
584
|
-
- de klantmelding aanmaken als p_notify_customer true is;
|
|
585
|
-
- een order.changed-melding sturen en de hele takenketen (buffer, pick, controle,
|
|
586
|
-
printen, transport) opnieuw inplannen met logistics_schedule_tasks;
|
|
587
|
-
- het verzetten vastleggen in public.logistics_reschedules.
|
|
588
|
-
|
|
589
|
-
------------------------------------------------------------------
|
|
590
|
-
WAT JE ABSOLUUT NIET DOET
|
|
591
|
-
------------------------------------------------------------------
|
|
592
|
-
- Geen eigen UPDATE op orders, order_buffers, order_carts of logistics_tasks om
|
|
593
|
-
een datum of tijd te verzetten. Uitsluitend via de twee RPC's hierboven.
|
|
594
|
-
- Zelf planned_start / planned_end / due_at van taken herberekenen. Na het
|
|
595
|
-
opslaan lees je de taken gewoon opnieuw; ze staan dan al goed.
|
|
596
|
-
- Bij naar voren de leverdatum meeschuiven. Dat is expliciet fout.
|
|
597
|
-
- Bij naar achteren de klant informeren zonder dat de gebruiker dat heeft
|
|
598
|
-
aangevinkt, of een eigen mail sturen buiten de Engine om.
|
|
599
|
-
|
|
600
|
-
------------------------------------------------------------------
|
|
601
|
-
NA HET OPSLAAN
|
|
602
|
-
------------------------------------------------------------------
|
|
603
|
-
1. Herlaad de taken van deze order uit logistics_tasks (planned_start bepaalt
|
|
604
|
-
waar de order in de pickagenda en het leverscherm verschijnt).
|
|
605
|
-
2. Toon een bevestiging met de nieuwe ophaaldag, de ophaaltijd, de leverdatum en
|
|
606
|
-
of de klant is geïnformeerd (result.customerNotified).
|
|
607
|
-
3. De verzetgeschiedenis kun je tonen met:
|
|
608
|
-
supabase.from("logistics_reschedules").select("*").eq("order_ref", ref)
|
|
609
|
-
.order("created_at", { ascending: false });
|
|
610
|
-
|
|
611
|
-
------------------------------------------------------------------
|
|
612
|
-
CONTROLELIJST VOOR JEZELF (loop deze af voor je klaar meldt)
|
|
613
|
-
------------------------------------------------------------------
|
|
614
|
-
[ ] Knop "Verzetten" bestaat bij een order.
|
|
615
|
-
[ ] Dagkeuze én ophaaltijd van/tot zijn in te vullen.
|
|
616
|
-
[ ] preview wordt live aangeroepen bij elke wijziging in het formulier.
|
|
617
|
-
[ ] Naar voren: leverdatum ongewijzigd, geen klantoptie zichtbaar.
|
|
618
|
-
[ ] Naar achteren: nieuwe leverdatum zichtbaar + klantoptie + reden.
|
|
619
|
-
[ ] Opslaan gaat via logistics_reschedule_order, nergens een eigen UPDATE.
|
|
551
|
+
body: `LEES DIT EERST — hoe je deze prompt uitvoert
|
|
552
|
+
|
|
553
|
+
Deze prompt beschrijft één nieuwe functie in de Afhandeling-module: "Order
|
|
554
|
+
verzetten". Je bouwt hem volledig, niet gedeeltelijk. Alles wat hieronder staat
|
|
555
|
+
is verplicht. Er is GEEN eigen rekenwerk: de Logistics Engine levert twee kant-en-
|
|
556
|
+
klare database-functies, jij bouwt alleen het scherm eromheen en toont wat de
|
|
557
|
+
Engine teruggeeft.
|
|
558
|
+
|
|
559
|
+
Concreet ben je klaar als dit alle vier waar is:
|
|
560
|
+
1. Er is een knop "Verzetten" bij een order (planning-/agenda-/leverscherm).
|
|
561
|
+
2. Het dialoogvenster toont een DAGKEUZE en een OPHAALTIJD (van/tot).
|
|
562
|
+
3. Voor het opslaan is logistics_reschedule_preview aangeroepen en wordt de
|
|
563
|
+
uitkomst daarvan letterlijk aan de gebruiker getoond.
|
|
564
|
+
4. Opslaan gebeurt uitsluitend met logistics_reschedule_order.
|
|
565
|
+
|
|
566
|
+
------------------------------------------------------------------
|
|
567
|
+
DE TWEE REGELS DIE DE GEBRUIKER WIL
|
|
568
|
+
------------------------------------------------------------------
|
|
569
|
+
|
|
570
|
+
A. Order gaat NAAR VOREN (nieuwe ophaaldag is eerder dan de huidige)
|
|
571
|
+
-> Het AFLEVERMOMENT (leverdatum naar de klant) blijft ONGEWIJZIGD.
|
|
572
|
+
De order wordt dus eerder klaargemaakt en opgehaald, maar de klant krijgt
|
|
573
|
+
hem op dezelfde dag als afgesproken. Je verandert de leverdatum NIET.
|
|
574
|
+
Er gaat GEEN melding naar de klant.
|
|
575
|
+
|
|
576
|
+
B. Order gaat NAAR ACHTEREN (nieuwe ophaaldag is later)
|
|
577
|
+
-> Het aflevermoment schuift mee.
|
|
578
|
+
-> De gebruiker MOET in het dialoogvenster de keuze krijgen:
|
|
579
|
+
"Klant informeren over de nieuwe leverdatum" (aan/uit) plus een reden.
|
|
580
|
+
Staat het aan, dan zorgt de Engine voor de klantmelding. Bouw daar zelf
|
|
581
|
+
geen mailflow voor.
|
|
582
|
+
|
|
583
|
+
C. Alleen de OPHAALTIJD wijzigen (zelfde dag, andere van/tot-tijd) mag altijd
|
|
584
|
+
en geldt niet als verzetten: geen klantmelding, leverdatum blijft gelijk.
|
|
585
|
+
|
|
586
|
+
------------------------------------------------------------------
|
|
587
|
+
STAP 1 — VOORVERTONING (verplicht vóór opslaan)
|
|
588
|
+
------------------------------------------------------------------
|
|
589
|
+
const { data: preview } = await supabase.rpc("logistics_reschedule_preview", {
|
|
590
|
+
p_order_ref: "SO-12345", // orders.order_number
|
|
591
|
+
p_pickup_date: "2026-08-07", // nieuwe ophaaldag (YYYY-MM-DD), null = ongewijzigd
|
|
592
|
+
p_pickup_from: "06:00", // nieuwe starttijd, null = ongewijzigd
|
|
593
|
+
p_pickup_to: "09:00", // nieuwe eindtijd, null = ongewijzigd
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
preview bevat:
|
|
597
|
+
{
|
|
598
|
+
ok: true,
|
|
599
|
+
orderRef, orderId, bufferId, planLocked,
|
|
600
|
+
current: { pickupDate, pickupFrom, pickupTo, deliveryDate },
|
|
601
|
+
next: { pickupDate, pickupFrom, pickupTo, deliveryDate },
|
|
602
|
+
direction: "earlier" | "later" | "same",
|
|
603
|
+
dayShift: -2, // aantal dagen verschil
|
|
604
|
+
timeChanged: true,
|
|
605
|
+
keepDeliveryMoment: true, // true bij naar voren: leverdatum blijft
|
|
606
|
+
customerNoticeRequired: true, // true bij naar achteren: toon de klantoptie
|
|
607
|
+
affectedTasks: 8 // aantal taken dat opnieuw wordt ingepland
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
Wat je met deze velden DOET in het scherm:
|
|
611
|
+
- ok === false -> toon preview.error en blokkeer opslaan.
|
|
612
|
+
- direction === "earlier" -> toon: "Order wordt X dag(en) eerder opgehaald. Het
|
|
613
|
+
aflevermoment blijft {current.deliveryDate}." Verberg de klantoptie.
|
|
614
|
+
- direction === "later" -> toon: "Order wordt X dag(en) later. Nieuwe leverdatum:
|
|
615
|
+
{next.deliveryDate}." Toon de schakelaar "Klant informeren" (standaard AAN) en
|
|
616
|
+
een verplicht redenveld.
|
|
617
|
+
- direction === "same" && timeChanged -> toon alleen de nieuwe ophaaltijd.
|
|
618
|
+
- Toon altijd affectedTasks: "X taken worden opnieuw ingepland."
|
|
619
|
+
|
|
620
|
+
------------------------------------------------------------------
|
|
621
|
+
STAP 2 — OPSLAAN
|
|
622
|
+
------------------------------------------------------------------
|
|
623
|
+
const { data: result } = await supabase.rpc("logistics_reschedule_order", {
|
|
624
|
+
p_order_ref: "SO-12345",
|
|
625
|
+
p_pickup_date: "2026-08-07",
|
|
626
|
+
p_pickup_from: "06:00",
|
|
627
|
+
p_pickup_to: "09:00",
|
|
628
|
+
p_notify_customer: true, // alleen relevant bij direction "later"
|
|
629
|
+
p_reason: "Aanvoer bloemen vertraagd",
|
|
630
|
+
p_source_module: "afhandeling",
|
|
631
|
+
p_user_id: null,
|
|
632
|
+
});
|
|
633
|
+
// result = preview-velden + { applied: true, rescheduleId, delayAlertId,
|
|
634
|
+
// customerNotified, pickupMoment }
|
|
635
|
+
|
|
636
|
+
De Engine doet hierbij zelf al ALLES hieronder — doe dit dus niet nogmaals:
|
|
637
|
+
- orders.custom_fields.pickup_moment bijwerken ("YYYY-MM-DD|van|tot");
|
|
638
|
+
- leverdatum alleen aanpassen bij naar achteren;
|
|
639
|
+
- de order uit zijn orderbuffer halen zodat hij niet aan de oude dag vastzit;
|
|
640
|
+
- de klantmelding aanmaken als p_notify_customer true is;
|
|
641
|
+
- een order.changed-melding sturen en de hele takenketen (buffer, pick, controle,
|
|
642
|
+
printen, transport) opnieuw inplannen met logistics_schedule_tasks;
|
|
643
|
+
- het verzetten vastleggen in public.logistics_reschedules.
|
|
644
|
+
|
|
645
|
+
------------------------------------------------------------------
|
|
646
|
+
WAT JE ABSOLUUT NIET DOET
|
|
647
|
+
------------------------------------------------------------------
|
|
648
|
+
- Geen eigen UPDATE op orders, order_buffers, order_carts of logistics_tasks om
|
|
649
|
+
een datum of tijd te verzetten. Uitsluitend via de twee RPC's hierboven.
|
|
650
|
+
- Zelf planned_start / planned_end / due_at van taken herberekenen. Na het
|
|
651
|
+
opslaan lees je de taken gewoon opnieuw; ze staan dan al goed.
|
|
652
|
+
- Bij naar voren de leverdatum meeschuiven. Dat is expliciet fout.
|
|
653
|
+
- Bij naar achteren de klant informeren zonder dat de gebruiker dat heeft
|
|
654
|
+
aangevinkt, of een eigen mail sturen buiten de Engine om.
|
|
655
|
+
|
|
656
|
+
------------------------------------------------------------------
|
|
657
|
+
NA HET OPSLAAN
|
|
658
|
+
------------------------------------------------------------------
|
|
659
|
+
1. Herlaad de taken van deze order uit logistics_tasks (planned_start bepaalt
|
|
660
|
+
waar de order in de pickagenda en het leverscherm verschijnt).
|
|
661
|
+
2. Toon een bevestiging met de nieuwe ophaaldag, de ophaaltijd, de leverdatum en
|
|
662
|
+
of de klant is geïnformeerd (result.customerNotified).
|
|
663
|
+
3. De verzetgeschiedenis kun je tonen met:
|
|
664
|
+
supabase.from("logistics_reschedules").select("*").eq("order_ref", ref)
|
|
665
|
+
.order("created_at", { ascending: false });
|
|
666
|
+
|
|
667
|
+
------------------------------------------------------------------
|
|
668
|
+
CONTROLELIJST VOOR JEZELF (loop deze af voor je klaar meldt)
|
|
669
|
+
------------------------------------------------------------------
|
|
670
|
+
[ ] Knop "Verzetten" bestaat bij een order.
|
|
671
|
+
[ ] Dagkeuze én ophaaltijd van/tot zijn in te vullen.
|
|
672
|
+
[ ] preview wordt live aangeroepen bij elke wijziging in het formulier.
|
|
673
|
+
[ ] Naar voren: leverdatum ongewijzigd, geen klantoptie zichtbaar.
|
|
674
|
+
[ ] Naar achteren: nieuwe leverdatum zichtbaar + klantoptie + reden.
|
|
675
|
+
[ ] Opslaan gaat via logistics_reschedule_order, nergens een eigen UPDATE.
|
|
620
676
|
[ ] Na opslaan worden de taken opnieuw geladen en klopt de agenda.`,
|
|
621
677
|
},
|
|
622
678
|
{
|
|
@@ -624,40 +680,40 @@ CONTROLELIJST VOOR JEZELF (loop deze af voor je klaar meldt)
|
|
|
624
680
|
title: "Capaciteitswaarschuwing tonen in de pick agenda",
|
|
625
681
|
date: "2026-08-04",
|
|
626
682
|
summary: "Nieuwe eis bovenop prompt 1 t/m 5: als er op een dag meer karren gepland staan dan er met het beschikbare personeel gepickt kunnen worden, moet de planning dat zichtbaar waarschuwen.",
|
|
627
|
-
body: `LEES DIT EERST
|
|
628
|
-
|
|
629
|
-
De Logistics Engine rekent per pickdag uit hoeveel picktijd alle geplande karren
|
|
630
|
-
kosten en hoeveel picktijd er beschikbaar is (aantal medewerkers x werktijden uit
|
|
631
|
-
"4. Pickstations"). Jij rekent NIETS zelf uit; je toont alleen wat de Engine geeft.
|
|
632
|
-
|
|
633
|
-
STAP 1 — BEREKENEN (bij het openen van een week/dag)
|
|
634
|
-
const { data: dagen } = await supabase.rpc("logistics_capacity_day_check", {
|
|
635
|
-
p_from: "2026-08-03", // eerste dag van de getoonde periode
|
|
636
|
-
p_to: "2026-08-09", // laatste dag
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
dagen is een array met per dag:
|
|
640
|
-
{ date, carts, requiredMinutes, availableMinutes, shortageMinutes, staff }
|
|
641
|
-
|
|
642
|
-
STAP 2 — OPEN WAARSCHUWINGEN LEZEN
|
|
643
|
-
const { data: alerts } = await supabase
|
|
644
|
-
.from("logistics_capacity_alerts")
|
|
645
|
-
.select("plan_date, required_minutes, available_minutes, shortage_minutes, carts_total, carts_short")
|
|
646
|
-
.eq("status", "open");
|
|
647
|
-
|
|
648
|
-
STAP 3 — TONEN (verplicht)
|
|
649
|
-
- Weekoverzicht: elke dag met shortageMinutes > 0 krijgt een duidelijk zichtbare
|
|
650
|
-
waarschuwing (amber/rood) met de tekst:
|
|
651
|
-
"Te weinig capaciteit: {carts} karren vragen {requiredMinutes} min picktijd,
|
|
652
|
-
beschikbaar is {availableMinutes} min ({staff} medewerkers).
|
|
653
|
-
Circa {carts_short} karren passen niet op deze dag."
|
|
654
|
-
- Dagdetails: dezelfde waarschuwing bovenaan het dagscherm.
|
|
655
|
-
- Dagen zonder tekort krijgen GEEN waarschuwing.
|
|
656
|
-
- Verzin geen eigen drempels, kleuren-logica of eigen berekening van picktijd.
|
|
657
|
-
|
|
658
|
-
CONTROLELIJST
|
|
659
|
-
[ ] logistics_capacity_day_check wordt aangeroepen bij elke periodewissel.
|
|
660
|
-
[ ] Dagen met tekort tonen de waarschuwing in het weekoverzicht én in dagdetails.
|
|
683
|
+
body: `LEES DIT EERST
|
|
684
|
+
|
|
685
|
+
De Logistics Engine rekent per pickdag uit hoeveel picktijd alle geplande karren
|
|
686
|
+
kosten en hoeveel picktijd er beschikbaar is (aantal medewerkers x werktijden uit
|
|
687
|
+
"4. Pickstations"). Jij rekent NIETS zelf uit; je toont alleen wat de Engine geeft.
|
|
688
|
+
|
|
689
|
+
STAP 1 — BEREKENEN (bij het openen van een week/dag)
|
|
690
|
+
const { data: dagen } = await supabase.rpc("logistics_capacity_day_check", {
|
|
691
|
+
p_from: "2026-08-03", // eerste dag van de getoonde periode
|
|
692
|
+
p_to: "2026-08-09", // laatste dag
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
dagen is een array met per dag:
|
|
696
|
+
{ date, carts, requiredMinutes, availableMinutes, shortageMinutes, staff }
|
|
697
|
+
|
|
698
|
+
STAP 2 — OPEN WAARSCHUWINGEN LEZEN
|
|
699
|
+
const { data: alerts } = await supabase
|
|
700
|
+
.from("logistics_capacity_alerts")
|
|
701
|
+
.select("plan_date, required_minutes, available_minutes, shortage_minutes, carts_total, carts_short")
|
|
702
|
+
.eq("status", "open");
|
|
703
|
+
|
|
704
|
+
STAP 3 — TONEN (verplicht)
|
|
705
|
+
- Weekoverzicht: elke dag met shortageMinutes > 0 krijgt een duidelijk zichtbare
|
|
706
|
+
waarschuwing (amber/rood) met de tekst:
|
|
707
|
+
"Te weinig capaciteit: {carts} karren vragen {requiredMinutes} min picktijd,
|
|
708
|
+
beschikbaar is {availableMinutes} min ({staff} medewerkers).
|
|
709
|
+
Circa {carts_short} karren passen niet op deze dag."
|
|
710
|
+
- Dagdetails: dezelfde waarschuwing bovenaan het dagscherm.
|
|
711
|
+
- Dagen zonder tekort krijgen GEEN waarschuwing.
|
|
712
|
+
- Verzin geen eigen drempels, kleuren-logica of eigen berekening van picktijd.
|
|
713
|
+
|
|
714
|
+
CONTROLELIJST
|
|
715
|
+
[ ] logistics_capacity_day_check wordt aangeroepen bij elke periodewissel.
|
|
716
|
+
[ ] Dagen met tekort tonen de waarschuwing in het weekoverzicht én in dagdetails.
|
|
661
717
|
[ ] De getoonde cijfers komen letterlijk uit de Engine.`,
|
|
662
718
|
},
|
|
663
719
|
{
|
|
@@ -665,31 +721,31 @@ CONTROLELIJST
|
|
|
665
721
|
title: "Geen capaciteitsmeldingen in Planning en leveringen",
|
|
666
722
|
date: "2026-08-04",
|
|
667
723
|
summary: "Nieuwe eis bovenop prompt 1 t/m 6: verwijder alle capaciteits- en foutmeldingen uit de agenda Planning en leveringen; de Engine blijft op de achtergrond controleren.",
|
|
668
|
-
body: `AANVULLING op prompt 1 t/m 6. Deze nieuwste eis vervangt uitsluitend de
|
|
669
|
-
zichtbare meldingen uit prompt 5 en 6 binnen het scherm "Planning en leveringen".
|
|
670
|
-
|
|
671
|
-
Verwijder uit het weekoverzicht en de dagdetails van "Planning en leveringen":
|
|
672
|
-
- de melding "Te weinig capaciteit";
|
|
673
|
-
- aantallen tekortkomende minuten, medewerkers of karren;
|
|
674
|
-
- rode, amberkleurige of andere fout-/waarschuwingsblokken uit
|
|
675
|
-
public.logistics_capacity_alerts;
|
|
676
|
-
- foutmeldingen die afkomstig zijn van logistics_capacity_day_check.
|
|
677
|
-
|
|
678
|
-
De agenda toont alleen de planning, bestellingen, karren, planten en statussen.
|
|
679
|
-
Een tekort mag de agenda niet visueel blokkeren of als foutmelding worden getoond.
|
|
680
|
-
|
|
681
|
-
BELANGRIJK — alleen de zichtbaarheid vervalt:
|
|
682
|
-
- Blijf logistics_capacity_day_check en logistics_capacity_plan_day uitvoeren waar
|
|
683
|
-
dat nodig is voor de planning en automatische herverdeling.
|
|
684
|
-
- Verwijder of sluit public.logistics_capacity_alerts niet.
|
|
685
|
-
- Capaciteitsmeldingen blijven beschikbaar in het Regieoverzicht van de Logistics
|
|
686
|
-
Engine en in het centrale Meldingencentrum.
|
|
687
|
-
- Verberg echte technische fouten niet: een mislukte laad- of opslagactie mag nog
|
|
688
|
-
steeds via een normale toast worden gemeld, maar niet als melding in de agenda.
|
|
689
|
-
|
|
690
|
-
CONTROLELIJST
|
|
691
|
-
[ ] In Planning en leveringen staat bij geen enkele dag een capaciteitsmelding.
|
|
692
|
-
[ ] Het openen en wisselen van weken blijft de Engine-berekening uitvoeren.
|
|
724
|
+
body: `AANVULLING op prompt 1 t/m 6. Deze nieuwste eis vervangt uitsluitend de
|
|
725
|
+
zichtbare meldingen uit prompt 5 en 6 binnen het scherm "Planning en leveringen".
|
|
726
|
+
|
|
727
|
+
Verwijder uit het weekoverzicht en de dagdetails van "Planning en leveringen":
|
|
728
|
+
- de melding "Te weinig capaciteit";
|
|
729
|
+
- aantallen tekortkomende minuten, medewerkers of karren;
|
|
730
|
+
- rode, amberkleurige of andere fout-/waarschuwingsblokken uit
|
|
731
|
+
public.logistics_capacity_alerts;
|
|
732
|
+
- foutmeldingen die afkomstig zijn van logistics_capacity_day_check.
|
|
733
|
+
|
|
734
|
+
De agenda toont alleen de planning, bestellingen, karren, planten en statussen.
|
|
735
|
+
Een tekort mag de agenda niet visueel blokkeren of als foutmelding worden getoond.
|
|
736
|
+
|
|
737
|
+
BELANGRIJK — alleen de zichtbaarheid vervalt:
|
|
738
|
+
- Blijf logistics_capacity_day_check en logistics_capacity_plan_day uitvoeren waar
|
|
739
|
+
dat nodig is voor de planning en automatische herverdeling.
|
|
740
|
+
- Verwijder of sluit public.logistics_capacity_alerts niet.
|
|
741
|
+
- Capaciteitsmeldingen blijven beschikbaar in het Regieoverzicht van de Logistics
|
|
742
|
+
Engine en in het centrale Meldingencentrum.
|
|
743
|
+
- Verberg echte technische fouten niet: een mislukte laad- of opslagactie mag nog
|
|
744
|
+
steeds via een normale toast worden gemeld, maar niet als melding in de agenda.
|
|
745
|
+
|
|
746
|
+
CONTROLELIJST
|
|
747
|
+
[ ] In Planning en leveringen staat bij geen enkele dag een capaciteitsmelding.
|
|
748
|
+
[ ] Het openen en wisselen van weken blijft de Engine-berekening uitvoeren.
|
|
693
749
|
[ ] Het Regieoverzicht kan de capaciteitsmeldingen nog steeds tonen.`,
|
|
694
750
|
},
|
|
695
751
|
{
|
|
@@ -697,28 +753,28 @@ CONTROLELIJST
|
|
|
697
753
|
title: "Tekort in medewerkers tonen in de capaciteitswaarschuwing",
|
|
698
754
|
date: "2026-08-04",
|
|
699
755
|
summary: "Nieuwe eis bovenop prompt 1 t/m 7: elke capaciteitswaarschuwing vermeldt hoeveel medewerkers er tekort zijn, niet alleen minuten en karren.",
|
|
700
|
-
body: `AANVULLING op prompt 6. De waarschuwing blijft weg uit "Planning en
|
|
701
|
-
leveringen" (prompt 7); overal waar je hem WEL toont (Regieoverzicht,
|
|
702
|
-
Meldingencentrum, dagdetails buiten de agenda) geldt onderstaande tekst.
|
|
703
|
-
|
|
704
|
-
BEREKENING (verplicht, geen eigen variant)
|
|
705
|
-
minutenPerMedewerker = availableMinutes / staff // staff > 0
|
|
706
|
-
medewerkersTekort = Math.ceil(shortageMinutes / minutenPerMedewerker)
|
|
707
|
-
Is staff 0 of availableMinutes 0, toon dan geen aantal maar de tekst
|
|
708
|
-
"vul het gemiddeld aantal medewerkers in bij 3. Order picken".
|
|
709
|
-
|
|
710
|
-
TEKST
|
|
711
|
-
"Te weinig capaciteit: {carts} karren vragen {requiredMinutes} min picktijd,
|
|
712
|
-
beschikbaar is {availableMinutes} min ({staff} medewerkers).
|
|
713
|
-
Je komt {medewerkersTekort} medewerker(s) tekort — samen
|
|
714
|
-
{staff + medewerkersTekort} nodig. Circa {carts_short} karren passen niet
|
|
715
|
-
op deze dag."
|
|
716
|
-
|
|
717
|
-
Gebruik enkelvoud "medewerker" bij 1, anders "medewerkers".
|
|
718
|
-
|
|
719
|
-
CONTROLELIJST
|
|
720
|
-
[ ] Elke zichtbare capaciteitswaarschuwing noemt het tekort in medewerkers.
|
|
721
|
-
[ ] Het aantal komt uit de formule hierboven, niet uit een eigen aanname.
|
|
756
|
+
body: `AANVULLING op prompt 6. De waarschuwing blijft weg uit "Planning en
|
|
757
|
+
leveringen" (prompt 7); overal waar je hem WEL toont (Regieoverzicht,
|
|
758
|
+
Meldingencentrum, dagdetails buiten de agenda) geldt onderstaande tekst.
|
|
759
|
+
|
|
760
|
+
BEREKENING (verplicht, geen eigen variant)
|
|
761
|
+
minutenPerMedewerker = availableMinutes / staff // staff > 0
|
|
762
|
+
medewerkersTekort = Math.ceil(shortageMinutes / minutenPerMedewerker)
|
|
763
|
+
Is staff 0 of availableMinutes 0, toon dan geen aantal maar de tekst
|
|
764
|
+
"vul het gemiddeld aantal medewerkers in bij 3. Order picken".
|
|
765
|
+
|
|
766
|
+
TEKST
|
|
767
|
+
"Te weinig capaciteit: {carts} karren vragen {requiredMinutes} min picktijd,
|
|
768
|
+
beschikbaar is {availableMinutes} min ({staff} medewerkers).
|
|
769
|
+
Je komt {medewerkersTekort} medewerker(s) tekort — samen
|
|
770
|
+
{staff + medewerkersTekort} nodig. Circa {carts_short} karren passen niet
|
|
771
|
+
op deze dag."
|
|
772
|
+
|
|
773
|
+
Gebruik enkelvoud "medewerker" bij 1, anders "medewerkers".
|
|
774
|
+
|
|
775
|
+
CONTROLELIJST
|
|
776
|
+
[ ] Elke zichtbare capaciteitswaarschuwing noemt het tekort in medewerkers.
|
|
777
|
+
[ ] Het aantal komt uit de formule hierboven, niet uit een eigen aanname.
|
|
722
778
|
[ ] Zonder ingevuld personeel toont de melding de invulhint in plaats van 0.`,
|
|
723
779
|
},
|
|
724
780
|
{
|
|
@@ -727,23 +783,23 @@ CONTROLELIJST
|
|
|
727
783
|
date: "2026-08-19",
|
|
728
784
|
summary: "Nieuwe orders worden binnen seconden automatisch ingedeeld door de Engine.",
|
|
729
785
|
withSharedContract: false,
|
|
730
|
-
body: `De Logistics Engine deelt nieuwe en gewijzigde orders voortaan automatisch in.
|
|
731
|
-
Een order komt bij binnenkomst in de wachtrij public.logistics_plan_queue en wordt
|
|
732
|
-
direct verwerkt (doorgaans binnen enkele seconden, uiterlijk binnen 2 minuten).
|
|
733
|
-
|
|
734
|
-
REGELS
|
|
735
|
-
- Deel NOOIT zelf orders in en maak geen eigen taken aan als er nog geen indeling is.
|
|
736
|
-
- Toon de melding "wacht op een indeling van de Logistics Engine" pas als de order
|
|
737
|
-
langer dan 2 minuten geleden is aangemaakt/gewijzigd EN er nog geen taken zijn.
|
|
738
|
-
Binnen die marge toon je niets — dat is normale verwerkingstijd.
|
|
739
|
-
- Ververs de weergave automatisch (realtime of polling) zodra taken verschijnen,
|
|
740
|
-
zodat de gebruiker niets hoeft te doen.
|
|
741
|
-
- Reserveringen (orders.is_reservation = true) en vastgezette orders
|
|
742
|
-
(orders.plan_locked_at gevuld) tel je nooit mee in deze melding.
|
|
743
|
-
|
|
744
|
-
CONTROLELIJST
|
|
745
|
-
[ ] Geen melding binnen 2 minuten na aanmaken/wijzigen van een order.
|
|
746
|
-
[ ] Geen eigen indeling of eigen taken als fallback.
|
|
786
|
+
body: `De Logistics Engine deelt nieuwe en gewijzigde orders voortaan automatisch in.
|
|
787
|
+
Een order komt bij binnenkomst in de wachtrij public.logistics_plan_queue en wordt
|
|
788
|
+
direct verwerkt (doorgaans binnen enkele seconden, uiterlijk binnen 2 minuten).
|
|
789
|
+
|
|
790
|
+
REGELS
|
|
791
|
+
- Deel NOOIT zelf orders in en maak geen eigen taken aan als er nog geen indeling is.
|
|
792
|
+
- Toon de melding "wacht op een indeling van de Logistics Engine" pas als de order
|
|
793
|
+
langer dan 2 minuten geleden is aangemaakt/gewijzigd EN er nog geen taken zijn.
|
|
794
|
+
Binnen die marge toon je niets — dat is normale verwerkingstijd.
|
|
795
|
+
- Ververs de weergave automatisch (realtime of polling) zodra taken verschijnen,
|
|
796
|
+
zodat de gebruiker niets hoeft te doen.
|
|
797
|
+
- Reserveringen (orders.is_reservation = true) en vastgezette orders
|
|
798
|
+
(orders.plan_locked_at gevuld) tel je nooit mee in deze melding.
|
|
799
|
+
|
|
800
|
+
CONTROLELIJST
|
|
801
|
+
[ ] Geen melding binnen 2 minuten na aanmaken/wijzigen van een order.
|
|
802
|
+
[ ] Geen eigen indeling of eigen taken als fallback.
|
|
747
803
|
[ ] Weergave werkt bij zonder handmatig verversen.`,
|
|
748
804
|
},
|
|
749
805
|
{
|
|
@@ -751,72 +807,72 @@ CONTROLELIJST
|
|
|
751
807
|
title: "Instellingen opschonen: planning en printen komen van de Engine/Layout maker",
|
|
752
808
|
date: "2026-08-27",
|
|
753
809
|
summary: "Nieuwe eis bovenop prompt 1 t/m 9: de settingscard 'Afhandeling — Planning' wordt opgeruimd.",
|
|
754
|
-
body: `AANVULLING op prompt 1 t/m 9 (die blijven gewoon geldig).
|
|
755
|
-
|
|
756
|
-
De settingscard "Afhandeling — Planning" bevat een aantal velden die inmiddels
|
|
757
|
-
worden bepaald door de Logistics Engine of de Layout maker. Deze module mag die
|
|
758
|
-
velden niet meer zelf uitlezen of tonen.
|
|
759
|
-
|
|
760
|
-
Haal weg uit de settingscard en bijbehorende schermen:
|
|
761
|
-
|
|
762
|
-
1. "Aantal pickdagen (werkdagen vóór ophaaldag)"
|
|
763
|
-
2. "Extra pickdagen bij stickers"
|
|
764
|
-
3. "Orderpickdagen (werkdagen)"
|
|
765
|
-
4. "Pickverdeling over werkdagen"
|
|
766
|
-
5. "Automatische Floriday-verwerking pauzeren"
|
|
767
|
-
6. "Afleverbrief automatisch printen"
|
|
768
|
-
7. "Werkplek (voor printen)"
|
|
769
|
-
|
|
770
|
-
Waarom deze velden overbodig zijn:
|
|
771
|
-
- Aantal pickdagen, extra pickdagen, orderpickdagen en pickverdeling worden
|
|
772
|
-
volledig bepaald door de Logistics Engine (stap 3 "Order picken" en
|
|
773
|
-
ophaalmomenten). De Engine plant planned_start en planned_end per taak.
|
|
774
|
-
- "Automatische Floriday-verwerking pauzeren" heeft geen lezer meer in deze
|
|
775
|
-
module.
|
|
776
|
-
- "Afleverbrief automatisch printen" is geen printerkeuze maar een trigger.
|
|
777
|
-
De Logistics Engine neemt die trigger over: Afhandeling maakt zelf geen
|
|
778
|
-
printopdrachten meer aan voor afleverbrieven, maar consumeert
|
|
779
|
-
print.shipping_note-taken uit public.logistics_tasks. De Engine bepaalt of
|
|
780
|
-
en wanneer een afleverbrief wordt vrijgegeven voor printen.
|
|
781
|
-
- "Werkplek (voor printen)" is overbodig omdat locatiegebonden printen het
|
|
782
|
-
domein is van de Logistics Engine (via print_plek_id in de taak-payload).
|
|
783
|
-
Zonder werkplek en zonder print_plek_id valt de Layout maker terug op de
|
|
784
|
-
standaardlayout of standaardregels voor documenttype "afleverbrief".
|
|
785
|
-
|
|
786
|
-
Printer-beslisvolgorde in de Layout maker:
|
|
787
|
-
|
|
788
|
-
1. printer_id op de opdracht (expliciet meegegeven)
|
|
789
|
-
2. print_plek_id -> regel van de printplek
|
|
790
|
-
3. werkplek -> printplek van die computer, dan werkplek-uitzondering
|
|
791
|
-
4. printer gekoppeld aan de (standaard)layout van het documenttype
|
|
792
|
-
5. standaardregel: documenttype + papierformaat
|
|
793
|
-
6. standaardregel: documenttype alleen
|
|
794
|
-
|
|
795
|
-
Zonder werkplek en zonder print_plek_id slaat een afleverbrief-print stap 1-3
|
|
796
|
-
over en komt hij op de printer van de standaardlayout of de standaardregels
|
|
797
|
-
uit. Wil men locatiegebonden printen, dan moet dat via de Logistics Engine
|
|
798
|
-
(print_plek_id) of een expliciete printer_id op de opdracht.
|
|
799
|
-
|
|
800
|
-
Wat blijft staan:
|
|
801
|
-
- "Aanmeldmail vervoerders" (+ minuten vóór aanmelddeadline en e-mail-doeleinde)
|
|
802
|
-
blijft bestaan. Dat is eigen functionaliteit van de Afhandeling-module.
|
|
803
|
-
|
|
804
|
-
Voorwaarde:
|
|
805
|
-
Er moet minstens één printer voor documenttype "afleverbrief" zijn ingesteld
|
|
806
|
-
in de Layout maker: hetzij aan de standaardlayout, hetzij via
|
|
807
|
-
Layouts en printers -> Standaardregels. Ontbreekt die, dan mislukt de
|
|
808
|
-
automatische print met de leesbare foutmelding:
|
|
809
|
-
"Geen printer voor afleverbrief — stel dit in bij Layouts en printers → Routering".
|
|
810
|
-
|
|
811
|
-
Database:
|
|
812
|
-
- Droppen geen kolommen of rijen. De kolommen in afhandeling_settings blijven
|
|
813
|
-
staan, maar worden niet meer gelezen of getoond.
|
|
814
|
-
|
|
815
|
-
CONTROLELIJST
|
|
816
|
-
[ ] Alle zeven velden zijn verwijderd uit de settingscard.
|
|
817
|
-
[ ] Aanmeldmail-instellingen zijn nog zichtbaar en werken nog.
|
|
818
|
-
[ ] Er worden geen eigen planningsberekeningen meer gedaan; alles komt uit public.logistics_tasks.
|
|
819
|
-
[ ] Afleverbrieven worden alleen nog aangemaakt via print.shipping_note-taken, niet spontaan.
|
|
810
|
+
body: `AANVULLING op prompt 1 t/m 9 (die blijven gewoon geldig).
|
|
811
|
+
|
|
812
|
+
De settingscard "Afhandeling — Planning" bevat een aantal velden die inmiddels
|
|
813
|
+
worden bepaald door de Logistics Engine of de Layout maker. Deze module mag die
|
|
814
|
+
velden niet meer zelf uitlezen of tonen.
|
|
815
|
+
|
|
816
|
+
Haal weg uit de settingscard en bijbehorende schermen:
|
|
817
|
+
|
|
818
|
+
1. "Aantal pickdagen (werkdagen vóór ophaaldag)"
|
|
819
|
+
2. "Extra pickdagen bij stickers"
|
|
820
|
+
3. "Orderpickdagen (werkdagen)"
|
|
821
|
+
4. "Pickverdeling over werkdagen"
|
|
822
|
+
5. "Automatische Floriday-verwerking pauzeren"
|
|
823
|
+
6. "Afleverbrief automatisch printen"
|
|
824
|
+
7. "Werkplek (voor printen)"
|
|
825
|
+
|
|
826
|
+
Waarom deze velden overbodig zijn:
|
|
827
|
+
- Aantal pickdagen, extra pickdagen, orderpickdagen en pickverdeling worden
|
|
828
|
+
volledig bepaald door de Logistics Engine (stap 3 "Order picken" en
|
|
829
|
+
ophaalmomenten). De Engine plant planned_start en planned_end per taak.
|
|
830
|
+
- "Automatische Floriday-verwerking pauzeren" heeft geen lezer meer in deze
|
|
831
|
+
module.
|
|
832
|
+
- "Afleverbrief automatisch printen" is geen printerkeuze maar een trigger.
|
|
833
|
+
De Logistics Engine neemt die trigger over: Afhandeling maakt zelf geen
|
|
834
|
+
printopdrachten meer aan voor afleverbrieven, maar consumeert
|
|
835
|
+
print.shipping_note-taken uit public.logistics_tasks. De Engine bepaalt of
|
|
836
|
+
en wanneer een afleverbrief wordt vrijgegeven voor printen.
|
|
837
|
+
- "Werkplek (voor printen)" is overbodig omdat locatiegebonden printen het
|
|
838
|
+
domein is van de Logistics Engine (via print_plek_id in de taak-payload).
|
|
839
|
+
Zonder werkplek en zonder print_plek_id valt de Layout maker terug op de
|
|
840
|
+
standaardlayout of standaardregels voor documenttype "afleverbrief".
|
|
841
|
+
|
|
842
|
+
Printer-beslisvolgorde in de Layout maker:
|
|
843
|
+
|
|
844
|
+
1. printer_id op de opdracht (expliciet meegegeven)
|
|
845
|
+
2. print_plek_id -> regel van de printplek
|
|
846
|
+
3. werkplek -> printplek van die computer, dan werkplek-uitzondering
|
|
847
|
+
4. printer gekoppeld aan de (standaard)layout van het documenttype
|
|
848
|
+
5. standaardregel: documenttype + papierformaat
|
|
849
|
+
6. standaardregel: documenttype alleen
|
|
850
|
+
|
|
851
|
+
Zonder werkplek en zonder print_plek_id slaat een afleverbrief-print stap 1-3
|
|
852
|
+
over en komt hij op de printer van de standaardlayout of de standaardregels
|
|
853
|
+
uit. Wil men locatiegebonden printen, dan moet dat via de Logistics Engine
|
|
854
|
+
(print_plek_id) of een expliciete printer_id op de opdracht.
|
|
855
|
+
|
|
856
|
+
Wat blijft staan:
|
|
857
|
+
- "Aanmeldmail vervoerders" (+ minuten vóór aanmelddeadline en e-mail-doeleinde)
|
|
858
|
+
blijft bestaan. Dat is eigen functionaliteit van de Afhandeling-module.
|
|
859
|
+
|
|
860
|
+
Voorwaarde:
|
|
861
|
+
Er moet minstens één printer voor documenttype "afleverbrief" zijn ingesteld
|
|
862
|
+
in de Layout maker: hetzij aan de standaardlayout, hetzij via
|
|
863
|
+
Layouts en printers -> Standaardregels. Ontbreekt die, dan mislukt de
|
|
864
|
+
automatische print met de leesbare foutmelding:
|
|
865
|
+
"Geen printer voor afleverbrief — stel dit in bij Layouts en printers → Routering".
|
|
866
|
+
|
|
867
|
+
Database:
|
|
868
|
+
- Droppen geen kolommen of rijen. De kolommen in afhandeling_settings blijven
|
|
869
|
+
staan, maar worden niet meer gelezen of getoond.
|
|
870
|
+
|
|
871
|
+
CONTROLELIJST
|
|
872
|
+
[ ] Alle zeven velden zijn verwijderd uit de settingscard.
|
|
873
|
+
[ ] Aanmeldmail-instellingen zijn nog zichtbaar en werken nog.
|
|
874
|
+
[ ] Er worden geen eigen planningsberekeningen meer gedaan; alles komt uit public.logistics_tasks.
|
|
875
|
+
[ ] Afleverbrieven worden alleen nog aangemaakt via print.shipping_note-taken, niet spontaan.
|
|
820
876
|
[ ] De kolommen in afhandeling_settings zijn niet gedropt.`,
|
|
821
877
|
},
|
|
822
878
|
],
|
|
@@ -831,12 +887,12 @@ CONTROLELIJST
|
|
|
831
887
|
date: "2026-07-24",
|
|
832
888
|
summary: "Pick-taken tonen en terugmelden.",
|
|
833
889
|
withSharedContract: true,
|
|
834
|
-
body: `Haal weg: eigen pickvolgorde en eigen bepaling van de starttijd.
|
|
835
|
-
|
|
836
|
-
Bouw:
|
|
837
|
-
- pick.execute taken tonen, gesorteerd op planned_start.
|
|
838
|
-
- Payload: pickMode, pickStartMode, pickMinutes, staff, reserveMinutes, scanner, loadCarriers.
|
|
839
|
-
- Voortgang terugmelden via RPC: logistics_claim_task bij starten, logistics_complete_task bij afronden.
|
|
890
|
+
body: `Haal weg: eigen pickvolgorde en eigen bepaling van de starttijd.
|
|
891
|
+
|
|
892
|
+
Bouw:
|
|
893
|
+
- pick.execute taken tonen, gesorteerd op planned_start.
|
|
894
|
+
- Payload: pickMode, pickStartMode, pickMinutes, staff, reserveMinutes, scanner, loadCarriers.
|
|
895
|
+
- Voortgang terugmelden via RPC: logistics_claim_task bij starten, logistics_complete_task bij afronden.
|
|
840
896
|
- Te-laat-dreigende belading markeren op basis van planned_end; niet zelf herrekenen.`,
|
|
841
897
|
},
|
|
842
898
|
{
|
|
@@ -844,26 +900,26 @@ Bouw:
|
|
|
844
900
|
title: "Documenten per pickstation vanuit de Engine",
|
|
845
901
|
date: "2026-08-03",
|
|
846
902
|
summary: "Documenttaken tonen op het juiste pickstation, inclusief goedkeuring.",
|
|
847
|
-
body: `Deze prompt vervangt niets uit prompt 1; hij komt er bovenop.
|
|
848
|
-
|
|
849
|
-
Haal weg: eigen logica over welk document op welk pickstation verschijnt en
|
|
850
|
-
wanneer. De Logistics Engine bepaalt dit volledig.
|
|
851
|
-
|
|
852
|
-
Verwerk deze taaktypes uit logistics_tasks:
|
|
853
|
-
- print.packing_slip, print.sticker, print.shipping_note, print.production_note
|
|
854
|
-
|
|
855
|
-
Payload per taak:
|
|
856
|
-
- release wanneer het document vrijkomt
|
|
857
|
-
- pickStationId public.pick_stations.id waar het document heen moet
|
|
858
|
-
- pickStationTypeId public.pick_station_types.id dat het document mag ontvangen
|
|
859
|
-
- requiresApproval true = eerst handmatige goedkeuring op het pickstation
|
|
860
|
-
|
|
861
|
-
Regels:
|
|
862
|
-
- Toon een document pas vanaf planned_start van de taak.
|
|
863
|
-
- Filter de wachtrij van een pickstation op pickStationId; is die leeg, gebruik
|
|
864
|
-
dan pickStationTypeId. Toon nooit documenten van een ander station.
|
|
865
|
-
- requiresApproval = true: toon een goedkeurknop; pas na goedkeuren printen en
|
|
866
|
-
daarna logistics_complete_task aanroepen (bij weigeren logistics_fail_task).
|
|
903
|
+
body: `Deze prompt vervangt niets uit prompt 1; hij komt er bovenop.
|
|
904
|
+
|
|
905
|
+
Haal weg: eigen logica over welk document op welk pickstation verschijnt en
|
|
906
|
+
wanneer. De Logistics Engine bepaalt dit volledig.
|
|
907
|
+
|
|
908
|
+
Verwerk deze taaktypes uit logistics_tasks:
|
|
909
|
+
- print.packing_slip, print.sticker, print.shipping_note, print.production_note
|
|
910
|
+
|
|
911
|
+
Payload per taak:
|
|
912
|
+
- release wanneer het document vrijkomt
|
|
913
|
+
- pickStationId public.pick_stations.id waar het document heen moet
|
|
914
|
+
- pickStationTypeId public.pick_station_types.id dat het document mag ontvangen
|
|
915
|
+
- requiresApproval true = eerst handmatige goedkeuring op het pickstation
|
|
916
|
+
|
|
917
|
+
Regels:
|
|
918
|
+
- Toon een document pas vanaf planned_start van de taak.
|
|
919
|
+
- Filter de wachtrij van een pickstation op pickStationId; is die leeg, gebruik
|
|
920
|
+
dan pickStationTypeId. Toon nooit documenten van een ander station.
|
|
921
|
+
- requiresApproval = true: toon een goedkeurknop; pas na goedkeuren printen en
|
|
922
|
+
daarna logistics_complete_task aanroepen (bij weigeren logistics_fail_task).
|
|
867
923
|
- Bepaal nooit zelf een vrijgavemoment en print nooit vooruit.`,
|
|
868
924
|
},
|
|
869
925
|
{
|
|
@@ -871,32 +927,32 @@ Regels:
|
|
|
871
927
|
title: "Documenten ophalen via de Floriday-gateway",
|
|
872
928
|
date: "2026-08-04",
|
|
873
929
|
summary: "Geen eigen Floriday-token of florydayFetch meer; gebundeld printen per kar.",
|
|
874
|
-
body: `Deze prompt vervangt niets uit prompt 1 en 2; hij komt er bovenop.
|
|
875
|
-
|
|
876
|
-
Haal weg: eigen Floriday-tokenlogica, eigen florydayFetch, eigen keuze van
|
|
877
|
-
staging/live en eigen HTTP-aanroepen naar de Floriday-gateway.
|
|
878
|
-
|
|
879
|
-
Alle modules draaien in dezelfde shell op dezelfde database. Importeer de
|
|
880
|
-
gateway daarom rechtstreeks en geef de service-role supabase-client van de
|
|
881
|
-
shell mee:
|
|
882
|
-
|
|
883
|
-
import {
|
|
884
|
-
runActiveEnvironment,
|
|
885
|
-
runPdf,
|
|
886
|
-
runPdfBulkMerged,
|
|
887
|
-
} from "@flowselections/floriday-authenticatie-module/gateway";
|
|
888
|
-
|
|
889
|
-
Regels:
|
|
890
|
-
- De omgeving komt altijd uit runActiveEnvironment(supabase). Nooit zelf kiezen.
|
|
891
|
-
- Eén document (print.packing_slip, print.sticker, print.shipping_note,
|
|
892
|
-
print.production_note): runPdf.
|
|
893
|
-
- Trigger "kar afgemeld" of "kar-scan": bundel alle regels van die kar en roep
|
|
894
|
-
runPdfBulkMerged aan, zodat het pickstation één printjob krijgt in plaats van
|
|
895
|
-
losse documenten.
|
|
896
|
-
- Toon bovenin het scherm welke koppeling actief is (label, GLN, staging/live).
|
|
897
|
-
- Print nooit twee keer hetzelfde: controleer public.logistics_document_prints
|
|
898
|
-
op (order_ref, document_type, trigger) voordat je print.
|
|
899
|
-
- Trigger en pickstation blijven van de Logistics Engine; de gateway levert
|
|
930
|
+
body: `Deze prompt vervangt niets uit prompt 1 en 2; hij komt er bovenop.
|
|
931
|
+
|
|
932
|
+
Haal weg: eigen Floriday-tokenlogica, eigen florydayFetch, eigen keuze van
|
|
933
|
+
staging/live en eigen HTTP-aanroepen naar de Floriday-gateway.
|
|
934
|
+
|
|
935
|
+
Alle modules draaien in dezelfde shell op dezelfde database. Importeer de
|
|
936
|
+
gateway daarom rechtstreeks en geef de service-role supabase-client van de
|
|
937
|
+
shell mee:
|
|
938
|
+
|
|
939
|
+
import {
|
|
940
|
+
runActiveEnvironment,
|
|
941
|
+
runPdf,
|
|
942
|
+
runPdfBulkMerged,
|
|
943
|
+
} from "@flowselections/floriday-authenticatie-module/gateway";
|
|
944
|
+
|
|
945
|
+
Regels:
|
|
946
|
+
- De omgeving komt altijd uit runActiveEnvironment(supabase). Nooit zelf kiezen.
|
|
947
|
+
- Eén document (print.packing_slip, print.sticker, print.shipping_note,
|
|
948
|
+
print.production_note): runPdf.
|
|
949
|
+
- Trigger "kar afgemeld" of "kar-scan": bundel alle regels van die kar en roep
|
|
950
|
+
runPdfBulkMerged aan, zodat het pickstation één printjob krijgt in plaats van
|
|
951
|
+
losse documenten.
|
|
952
|
+
- Toon bovenin het scherm welke koppeling actief is (label, GLN, staging/live).
|
|
953
|
+
- Print nooit twee keer hetzelfde: controleer public.logistics_document_prints
|
|
954
|
+
op (order_ref, document_type, trigger) voordat je print.
|
|
955
|
+
- Trigger en pickstation blijven van de Logistics Engine; de gateway levert
|
|
900
956
|
alleen het PDF-bestand.`,
|
|
901
957
|
},
|
|
902
958
|
{
|
|
@@ -904,29 +960,29 @@ Regels:
|
|
|
904
960
|
title: "Strikte documentroutering per pickstation",
|
|
905
961
|
date: "2026-08-04",
|
|
906
962
|
summary: "Een pickstation toont uitsluitend de documentsoorten die eraan gekoppeld zijn.",
|
|
907
|
-
body: `Deze prompt vervangt niets uit prompt 1 t/m 3; hij komt er bovenop.
|
|
908
|
-
|
|
909
|
-
Probleem: op "Pickstation Orders" verschenen naast pakbonnen ook veilingbrieven
|
|
910
|
-
en transportbrieven. Dat mag nooit.
|
|
911
|
-
|
|
912
|
-
Haal weg: elke query die de wachtrij alleen op station_id filtert, en elke
|
|
913
|
-
fallback die "overige documenten" toch ergens toont.
|
|
914
|
-
|
|
915
|
-
Regels:
|
|
916
|
-
- Filter de wachtrij ALTIJD op screen_id van het geopende scherm, niet op
|
|
917
|
-
station_id. Elk scherm heeft via public.pick_screen_document_types precies de
|
|
918
|
-
documenttypes die het mag tonen.
|
|
919
|
-
- Toon nooit een document waarvan het document_type_id niet aan dat scherm is
|
|
920
|
-
gekoppeld. Geen "rest"-categorie, geen samengevoegde stationweergave.
|
|
921
|
-
- De koppeling documentsoort -> pickstation komt uit de Logistiek Engine
|
|
922
|
-
(Rule Engine, stap "Pickstations"). In de database is dat opvraagbaar met
|
|
923
|
-
select public.logistics_document_station('pakbon').
|
|
924
|
-
- De printwachtrij public.pick_queue heeft een trigger die station_id en
|
|
925
|
-
screen_id herschrijft volgens die instelling. Schrijf zelf nooit een
|
|
926
|
-
station_id dat daarvan afwijkt; dat wordt overschreven of geweigerd.
|
|
927
|
-
- Taken uit logistics_tasks dragen payload.documentType en payload.pickStationId.
|
|
928
|
-
Gebruik die twee samen; nooit alleen het taaktype.
|
|
929
|
-
- Standaardweergave is "documenten van vandaag". Oudere, niet-geprinte regels
|
|
963
|
+
body: `Deze prompt vervangt niets uit prompt 1 t/m 3; hij komt er bovenop.
|
|
964
|
+
|
|
965
|
+
Probleem: op "Pickstation Orders" verschenen naast pakbonnen ook veilingbrieven
|
|
966
|
+
en transportbrieven. Dat mag nooit.
|
|
967
|
+
|
|
968
|
+
Haal weg: elke query die de wachtrij alleen op station_id filtert, en elke
|
|
969
|
+
fallback die "overige documenten" toch ergens toont.
|
|
970
|
+
|
|
971
|
+
Regels:
|
|
972
|
+
- Filter de wachtrij ALTIJD op screen_id van het geopende scherm, niet op
|
|
973
|
+
station_id. Elk scherm heeft via public.pick_screen_document_types precies de
|
|
974
|
+
documenttypes die het mag tonen.
|
|
975
|
+
- Toon nooit een document waarvan het document_type_id niet aan dat scherm is
|
|
976
|
+
gekoppeld. Geen "rest"-categorie, geen samengevoegde stationweergave.
|
|
977
|
+
- De koppeling documentsoort -> pickstation komt uit de Logistiek Engine
|
|
978
|
+
(Rule Engine, stap "Pickstations"). In de database is dat opvraagbaar met
|
|
979
|
+
select public.logistics_document_station('pakbon').
|
|
980
|
+
- De printwachtrij public.pick_queue heeft een trigger die station_id en
|
|
981
|
+
screen_id herschrijft volgens die instelling. Schrijf zelf nooit een
|
|
982
|
+
station_id dat daarvan afwijkt; dat wordt overschreven of geweigerd.
|
|
983
|
+
- Taken uit logistics_tasks dragen payload.documentType en payload.pickStationId.
|
|
984
|
+
Gebruik die twee samen; nooit alleen het taaktype.
|
|
985
|
+
- Standaardweergave is "documenten van vandaag". Oudere, niet-geprinte regels
|
|
930
986
|
horen in een apart tabblad, niet in de dagwachtrij.`,
|
|
931
987
|
},
|
|
932
988
|
{
|
|
@@ -934,41 +990,41 @@ Regels:
|
|
|
934
990
|
title: "Documenten altijd renderen met de layout uit de Layout maker",
|
|
935
991
|
date: "2026-08-04",
|
|
936
992
|
summary: "Geen eigen pakbon-opmaak meer; de layout komt uit public.document_layouts.",
|
|
937
|
-
body: `Deze prompt vervangt niets uit prompt 1 t/m 4; hij komt er bovenop.
|
|
938
|
-
|
|
939
|
-
Probleem: het pickstation print een eigen, hardgecodeerde pakbon. De pakbon die
|
|
940
|
-
in de module "Layout maker (pakbonnen, verzendbrieven, extra)" is ontworpen
|
|
941
|
-
wordt genegeerd.
|
|
942
|
-
|
|
943
|
-
Haal weg: elke eigen HTML/PDF-opmaak van pakbonnen, verzendbrieven, stickers,
|
|
944
|
-
productiebonnen en controlelijsten. Ook alle vaste kolommen, logo's, marges en
|
|
945
|
-
papierformaten die in de pickstation-code staan.
|
|
946
|
-
|
|
947
|
-
Regels:
|
|
948
|
-
- De opmaak komt ALTIJD uit public.document_layouts (+ document_layout_elements,
|
|
949
|
-
document_layout_variables, document_layout_versions, layout_logos). Nooit een
|
|
950
|
-
eigen sjabloon, ook niet als fallback.
|
|
951
|
-
- Welke layout bij een documentsoort hoort, bepaal je niet zelf. Gebruik:
|
|
952
|
-
select public.logistics_document_layout('pakbon');
|
|
953
|
-
Dat geeft { layoutId, layoutName, layoutVersion, layoutDocumentType } van de
|
|
954
|
-
actieve layout (voorkeur: is_standaard).
|
|
955
|
-
- Elke regel in public.pick_queue draagt deze gegevens al mee in payload:
|
|
956
|
-
documentType, layoutId, layoutName, layoutVersion. Gebruik payload.layoutId
|
|
957
|
-
als die er staat; val alleen terug op de functie hierboven als hij ontbreekt.
|
|
958
|
-
- Render met de renderer van de Layout maker, niet met eigen code. Papierformaat,
|
|
959
|
-
oriëntatie en marges komen uit de layoutrij (papierformaat, breedte_mm,
|
|
960
|
-
hoogte_mm, marge_*, orientatie, page_settings).
|
|
961
|
-
- Ontbreekt er een actieve layout voor een documentsoort? Print dan niet, maar
|
|
962
|
-
toon "Geen layout ingesteld voor <documentsoort>" met een verwijzing naar de
|
|
963
|
-
Layout maker. Nooit stilzwijgend een eigen pakbon printen.
|
|
964
|
-
- Floriday-documenten (prompt 3) blijven via de gateway lopen; alles wat we zelf
|
|
965
|
-
opmaken loopt via de Layout maker.
|
|
966
|
-
- Log bij het afronden van de taak welke layoutId en layoutVersion zijn gebruikt
|
|
967
|
-
in het result van logistics_complete_task.
|
|
968
|
-
|
|
969
|
-
CONTROLELIJST
|
|
970
|
-
[ ] Geen enkel eigen documentsjabloon meer in de code.
|
|
971
|
-
[ ] Pakbon in het pickstation is visueel identiek aan de preview in de Layout maker.
|
|
993
|
+
body: `Deze prompt vervangt niets uit prompt 1 t/m 4; hij komt er bovenop.
|
|
994
|
+
|
|
995
|
+
Probleem: het pickstation print een eigen, hardgecodeerde pakbon. De pakbon die
|
|
996
|
+
in de module "Layout maker (pakbonnen, verzendbrieven, extra)" is ontworpen
|
|
997
|
+
wordt genegeerd.
|
|
998
|
+
|
|
999
|
+
Haal weg: elke eigen HTML/PDF-opmaak van pakbonnen, verzendbrieven, stickers,
|
|
1000
|
+
productiebonnen en controlelijsten. Ook alle vaste kolommen, logo's, marges en
|
|
1001
|
+
papierformaten die in de pickstation-code staan.
|
|
1002
|
+
|
|
1003
|
+
Regels:
|
|
1004
|
+
- De opmaak komt ALTIJD uit public.document_layouts (+ document_layout_elements,
|
|
1005
|
+
document_layout_variables, document_layout_versions, layout_logos). Nooit een
|
|
1006
|
+
eigen sjabloon, ook niet als fallback.
|
|
1007
|
+
- Welke layout bij een documentsoort hoort, bepaal je niet zelf. Gebruik:
|
|
1008
|
+
select public.logistics_document_layout('pakbon');
|
|
1009
|
+
Dat geeft { layoutId, layoutName, layoutVersion, layoutDocumentType } van de
|
|
1010
|
+
actieve layout (voorkeur: is_standaard).
|
|
1011
|
+
- Elke regel in public.pick_queue draagt deze gegevens al mee in payload:
|
|
1012
|
+
documentType, layoutId, layoutName, layoutVersion. Gebruik payload.layoutId
|
|
1013
|
+
als die er staat; val alleen terug op de functie hierboven als hij ontbreekt.
|
|
1014
|
+
- Render met de renderer van de Layout maker, niet met eigen code. Papierformaat,
|
|
1015
|
+
oriëntatie en marges komen uit de layoutrij (papierformaat, breedte_mm,
|
|
1016
|
+
hoogte_mm, marge_*, orientatie, page_settings).
|
|
1017
|
+
- Ontbreekt er een actieve layout voor een documentsoort? Print dan niet, maar
|
|
1018
|
+
toon "Geen layout ingesteld voor <documentsoort>" met een verwijzing naar de
|
|
1019
|
+
Layout maker. Nooit stilzwijgend een eigen pakbon printen.
|
|
1020
|
+
- Floriday-documenten (prompt 3) blijven via de gateway lopen; alles wat we zelf
|
|
1021
|
+
opmaken loopt via de Layout maker.
|
|
1022
|
+
- Log bij het afronden van de taak welke layoutId en layoutVersion zijn gebruikt
|
|
1023
|
+
in het result van logistics_complete_task.
|
|
1024
|
+
|
|
1025
|
+
CONTROLELIJST
|
|
1026
|
+
[ ] Geen enkel eigen documentsjabloon meer in de code.
|
|
1027
|
+
[ ] Pakbon in het pickstation is visueel identiek aan de preview in de Layout maker.
|
|
972
1028
|
[ ] Ontbrekende layout geeft een duidelijke melding in plaats van een print.`,
|
|
973
1029
|
},
|
|
974
1030
|
{
|
|
@@ -976,50 +1032,50 @@ CONTROLELIJST
|
|
|
976
1032
|
title: "Sectie-layouts uit de Layout maker correct printen",
|
|
977
1033
|
date: "2026-08-04",
|
|
978
1034
|
summary: "Een geldige pakbon in document_layouts.config mag nooit als ontbrekende layout worden afgewezen.",
|
|
979
|
-
body: `Deze prompt vervangt niets uit prompt 1 t/m 5; hij komt er bovenop.
|
|
980
|
-
|
|
981
|
-
Probleem: de gekoppelde layout "packbon hoofd" is een geldige sectie-layout.
|
|
982
|
-
De opbouw staat in public.document_layouts.config.pakbon.secties en niet in
|
|
983
|
-
public.document_layout_elements. Het pickstation ondersteunt nu alleen
|
|
984
|
-
canvas-elementen en toont daardoor ten onrechte "Geen layout ingesteld".
|
|
985
|
-
|
|
986
|
-
Haal weg:
|
|
987
|
-
- elke controle die een layout als ontbrekend beschouwt wanneer
|
|
988
|
-
document_layout_elements leeg is;
|
|
989
|
-
- elke renderer die uitsluitend document_layout_elements ondersteunt;
|
|
990
|
-
- de algemene MissingLayoutError voor een wel bestaande, actieve layoutrij.
|
|
991
|
-
|
|
992
|
-
Regels:
|
|
993
|
-
- Een layout ontbreekt uitsluitend als public.document_layouts geen actieve rij
|
|
994
|
-
voor het door de Engine aangeleverde layoutId bevat. Nul canvas-elementen is
|
|
995
|
-
geen ontbrekende layout.
|
|
996
|
-
- Lees eerst payload.layoutId (of payload.layout_id) uit public.pick_queue.
|
|
997
|
-
De huidige pakbonnen verwijzen daarmee naar de gekoppelde layoutrij.
|
|
998
|
-
- Kies daarna de renderer op basis van de opgeslagen layoutvorm:
|
|
999
|
-
1. config.pakbon.secties is een array: gebruik dezelfde sectie-/pakbonrenderer
|
|
1000
|
-
en dezelfde datamapping als de preview van de Layout maker;
|
|
1001
|
-
2. document_layout_elements bevat rijen: gebruik de canvasrenderer;
|
|
1002
|
-
3. geen van beide bevat inhoud: meld "Layout heeft nog geen inhoud", niet
|
|
1003
|
-
"Geen layout ingesteld".
|
|
1004
|
-
- Importeer de renderer en bijbehorende types bij voorkeur rechtstreeks uit de
|
|
1005
|
-
Layout maker-module. Kopieer geen pakbonsjabloon naar deze module. Als de
|
|
1006
|
-
Layout maker de renderer nog niet exporteert, voeg daar named exports toe voor
|
|
1007
|
-
de sectierenderer en de order-naar-pakbon-datamapping en gebruik die hier.
|
|
1008
|
-
- Respecteer config.pakbon.secties volledig: volgorde, zichtbaar, condities,
|
|
1009
|
-
opties, karren, lagen, producten, totalen en logo. Respecteer daarnaast
|
|
1010
|
-
papierformaat, oriëntatie, marges en page_settings van document_layouts.
|
|
1011
|
-
- Vul vóór renderen de volledige ordercontext voor payload.orderId of
|
|
1012
|
-
order_number: order, klant, afleveradres, orderregels, karren, lagen,
|
|
1013
|
-
producten en fusten. De wachtrijregel alleen bevat hiervoor onvoldoende data.
|
|
1014
|
-
- Markeer de wachtrijregel pas als geprint nadat renderen is gelukt en de
|
|
1015
|
-
printdialoog is geopend. Laat de regel bij een renderfout in de wachtrij staan.
|
|
1016
|
-
|
|
1017
|
-
CONTROLELIJST
|
|
1018
|
-
[ ] "packbon hoofd" opent vanuit Pickstation Orders zonder MissingLayoutError.
|
|
1019
|
-
[ ] De afdruk is visueel gelijk aan de preview in de Layout maker.
|
|
1020
|
-
[ ] Karren, lagen en producten van de gekozen order staan op de pakbon.
|
|
1021
|
-
[ ] Een lege layout geeft "Layout heeft nog geen inhoud".
|
|
1022
|
-
[ ] Een werkelijk ontbrekende/inactieve layoutrij geeft pas "Geen layout ingesteld".
|
|
1035
|
+
body: `Deze prompt vervangt niets uit prompt 1 t/m 5; hij komt er bovenop.
|
|
1036
|
+
|
|
1037
|
+
Probleem: de gekoppelde layout "packbon hoofd" is een geldige sectie-layout.
|
|
1038
|
+
De opbouw staat in public.document_layouts.config.pakbon.secties en niet in
|
|
1039
|
+
public.document_layout_elements. Het pickstation ondersteunt nu alleen
|
|
1040
|
+
canvas-elementen en toont daardoor ten onrechte "Geen layout ingesteld".
|
|
1041
|
+
|
|
1042
|
+
Haal weg:
|
|
1043
|
+
- elke controle die een layout als ontbrekend beschouwt wanneer
|
|
1044
|
+
document_layout_elements leeg is;
|
|
1045
|
+
- elke renderer die uitsluitend document_layout_elements ondersteunt;
|
|
1046
|
+
- de algemene MissingLayoutError voor een wel bestaande, actieve layoutrij.
|
|
1047
|
+
|
|
1048
|
+
Regels:
|
|
1049
|
+
- Een layout ontbreekt uitsluitend als public.document_layouts geen actieve rij
|
|
1050
|
+
voor het door de Engine aangeleverde layoutId bevat. Nul canvas-elementen is
|
|
1051
|
+
geen ontbrekende layout.
|
|
1052
|
+
- Lees eerst payload.layoutId (of payload.layout_id) uit public.pick_queue.
|
|
1053
|
+
De huidige pakbonnen verwijzen daarmee naar de gekoppelde layoutrij.
|
|
1054
|
+
- Kies daarna de renderer op basis van de opgeslagen layoutvorm:
|
|
1055
|
+
1. config.pakbon.secties is een array: gebruik dezelfde sectie-/pakbonrenderer
|
|
1056
|
+
en dezelfde datamapping als de preview van de Layout maker;
|
|
1057
|
+
2. document_layout_elements bevat rijen: gebruik de canvasrenderer;
|
|
1058
|
+
3. geen van beide bevat inhoud: meld "Layout heeft nog geen inhoud", niet
|
|
1059
|
+
"Geen layout ingesteld".
|
|
1060
|
+
- Importeer de renderer en bijbehorende types bij voorkeur rechtstreeks uit de
|
|
1061
|
+
Layout maker-module. Kopieer geen pakbonsjabloon naar deze module. Als de
|
|
1062
|
+
Layout maker de renderer nog niet exporteert, voeg daar named exports toe voor
|
|
1063
|
+
de sectierenderer en de order-naar-pakbon-datamapping en gebruik die hier.
|
|
1064
|
+
- Respecteer config.pakbon.secties volledig: volgorde, zichtbaar, condities,
|
|
1065
|
+
opties, karren, lagen, producten, totalen en logo. Respecteer daarnaast
|
|
1066
|
+
papierformaat, oriëntatie, marges en page_settings van document_layouts.
|
|
1067
|
+
- Vul vóór renderen de volledige ordercontext voor payload.orderId of
|
|
1068
|
+
order_number: order, klant, afleveradres, orderregels, karren, lagen,
|
|
1069
|
+
producten en fusten. De wachtrijregel alleen bevat hiervoor onvoldoende data.
|
|
1070
|
+
- Markeer de wachtrijregel pas als geprint nadat renderen is gelukt en de
|
|
1071
|
+
printdialoog is geopend. Laat de regel bij een renderfout in de wachtrij staan.
|
|
1072
|
+
|
|
1073
|
+
CONTROLELIJST
|
|
1074
|
+
[ ] "packbon hoofd" opent vanuit Pickstation Orders zonder MissingLayoutError.
|
|
1075
|
+
[ ] De afdruk is visueel gelijk aan de preview in de Layout maker.
|
|
1076
|
+
[ ] Karren, lagen en producten van de gekozen order staan op de pakbon.
|
|
1077
|
+
[ ] Een lege layout geeft "Layout heeft nog geen inhoud".
|
|
1078
|
+
[ ] Een werkelijk ontbrekende/inactieve layoutrij geeft pas "Geen layout ingesteld".
|
|
1023
1079
|
[ ] De wachtrij wordt alleen afgerond na een geslaagde render/printactie.`,
|
|
1024
1080
|
},
|
|
1025
1081
|
{
|
|
@@ -1027,37 +1083,37 @@ CONTROLELIJST
|
|
|
1027
1083
|
title: "Altijd de actuele layout, behalve bij kant-en-klare PDF's",
|
|
1028
1084
|
date: "2026-08-14",
|
|
1029
1085
|
summary: "Layout wint boven meegestuurde HTML; klantstickers en Floriday-documenten gaan als bestaande PDF ongewijzigd naar de printer.",
|
|
1030
|
-
body: `Deze prompt vervangt niets uit prompt 1 t/m 6; hij komt er bovenop.
|
|
1031
|
-
|
|
1032
|
-
Uitgangspunt: wat er geprint wordt is ALTIJD de actuele layout uit de Layout
|
|
1033
|
-
maker, gevuld met de echte gegevens van de order en de klant. Enige uitzondering:
|
|
1034
|
-
documenten die al als kant-en-klare PDF bestaan (klantstickers en
|
|
1035
|
-
Floriday-documenten). Die worden ongewijzigd doorgestuurd.
|
|
1036
|
-
|
|
1037
|
-
Volgorde van beslissen bij een printopdracht in public.print_jobs:
|
|
1038
|
-
1. Is er een kant-en-klare PDF meegegeven (pdf-veld op de opdracht / bron uit
|
|
1039
|
-
floriday_customer_sticker_pdfs_cache): die PDF ongewijzigd naar de printer.
|
|
1040
|
-
Niet opnieuw opmaken, niet renderen.
|
|
1041
|
-
2. Is print_jobs.layout_id gevuld: die layout wint. Negeer een eventueel
|
|
1042
|
-
meegestuurde render_html en render vers uit public.document_layouts.
|
|
1043
|
-
3. Pas als beide leeg zijn: meegestuurde render_html, en anders de actieve
|
|
1044
|
-
layout bij het documenttype.
|
|
1045
|
-
|
|
1046
|
-
Haal weg:
|
|
1047
|
-
- elke eigen HTML-sjabloon die om de layout heen print;
|
|
1048
|
-
- elke gecachte kopie van een layout; de layout wordt per opdracht live gelezen.
|
|
1049
|
-
|
|
1050
|
-
Regels:
|
|
1051
|
-
- layout_id en printer_id komen uit de Engine (public.pick_enqueue_print_job).
|
|
1052
|
-
Kies zelf nooit een andere layout of printer wanneer die velden gevuld zijn.
|
|
1053
|
-
- Statussen blijven binnen de enum print_job_status: wachtend, bezig, voltooid,
|
|
1054
|
-
mislukt, geannuleerd. Andere modules luisteren daarop.
|
|
1055
|
-
- Geen PDF én geen layout: markeer de opdracht als mislukt met een leesbare
|
|
1056
|
-
reden in foutmelding. Nooit blanco printen.
|
|
1057
|
-
|
|
1058
|
-
CONTROLELIJST
|
|
1059
|
-
[ ] Layout aangepast in de Layout maker -> eerstvolgende print toont de wijziging.
|
|
1060
|
-
[ ] Klantsticker en Floriday-document komen er exact uit zoals aangeleverd.
|
|
1086
|
+
body: `Deze prompt vervangt niets uit prompt 1 t/m 6; hij komt er bovenop.
|
|
1087
|
+
|
|
1088
|
+
Uitgangspunt: wat er geprint wordt is ALTIJD de actuele layout uit de Layout
|
|
1089
|
+
maker, gevuld met de echte gegevens van de order en de klant. Enige uitzondering:
|
|
1090
|
+
documenten die al als kant-en-klare PDF bestaan (klantstickers en
|
|
1091
|
+
Floriday-documenten). Die worden ongewijzigd doorgestuurd.
|
|
1092
|
+
|
|
1093
|
+
Volgorde van beslissen bij een printopdracht in public.print_jobs:
|
|
1094
|
+
1. Is er een kant-en-klare PDF meegegeven (pdf-veld op de opdracht / bron uit
|
|
1095
|
+
floriday_customer_sticker_pdfs_cache): die PDF ongewijzigd naar de printer.
|
|
1096
|
+
Niet opnieuw opmaken, niet renderen.
|
|
1097
|
+
2. Is print_jobs.layout_id gevuld: die layout wint. Negeer een eventueel
|
|
1098
|
+
meegestuurde render_html en render vers uit public.document_layouts.
|
|
1099
|
+
3. Pas als beide leeg zijn: meegestuurde render_html, en anders de actieve
|
|
1100
|
+
layout bij het documenttype.
|
|
1101
|
+
|
|
1102
|
+
Haal weg:
|
|
1103
|
+
- elke eigen HTML-sjabloon die om de layout heen print;
|
|
1104
|
+
- elke gecachte kopie van een layout; de layout wordt per opdracht live gelezen.
|
|
1105
|
+
|
|
1106
|
+
Regels:
|
|
1107
|
+
- layout_id en printer_id komen uit de Engine (public.pick_enqueue_print_job).
|
|
1108
|
+
Kies zelf nooit een andere layout of printer wanneer die velden gevuld zijn.
|
|
1109
|
+
- Statussen blijven binnen de enum print_job_status: wachtend, bezig, voltooid,
|
|
1110
|
+
mislukt, geannuleerd. Andere modules luisteren daarop.
|
|
1111
|
+
- Geen PDF én geen layout: markeer de opdracht als mislukt met een leesbare
|
|
1112
|
+
reden in foutmelding. Nooit blanco printen.
|
|
1113
|
+
|
|
1114
|
+
CONTROLELIJST
|
|
1115
|
+
[ ] Layout aangepast in de Layout maker -> eerstvolgende print toont de wijziging.
|
|
1116
|
+
[ ] Klantsticker en Floriday-document komen er exact uit zoals aangeleverd.
|
|
1061
1117
|
[ ] Geen enkele printer- of layoutnaam hardcoded in deze module.`,
|
|
1062
1118
|
},
|
|
1063
1119
|
{
|
|
@@ -1065,38 +1121,38 @@ CONTROLELIJST
|
|
|
1065
1121
|
title: "Pickstation koppelen aan een printplek",
|
|
1066
1122
|
date: "2026-08-25",
|
|
1067
1123
|
summary: "Elk pickstation krijgt een printplek uit de Layout maker; de Engine stuurt die printplek mee en kiest zelf geen printer meer.",
|
|
1068
|
-
body: `Deze prompt vervangt niets uit prompt 1 t/m 7; hij komt er bovenop.
|
|
1069
|
-
|
|
1070
|
-
Wat er verandert in de Logistiek Engine: public.pick_enqueue_print_job kiest
|
|
1071
|
-
geen printer meer. De opdracht krijgt de printplek van het pickstation mee
|
|
1072
|
-
(top-level in payload.print_plek_id en in payload.data.print_plek_id) en gaat
|
|
1073
|
-
altijd als status 'wachtend' de wachtrij in. De Layout maker bepaalt daarna de
|
|
1074
|
-
printer: printplek -> bedrijfsbrede standaardregel, en meldt zelf de reden als
|
|
1075
|
-
dat niet lukt.
|
|
1076
|
-
|
|
1077
|
-
Wat deze module moet doen:
|
|
1078
|
-
- Beheer per pickstation de koppeling naar een printplek in
|
|
1079
|
-
public.print_plek_koppelingen met bron = 'pickstation', bron_id =
|
|
1080
|
-
public.pick_stations.id als tekst, print_plek_id = de gekozen rij uit
|
|
1081
|
-
public.print_plekken. Eén actieve koppeling per pickstation.
|
|
1082
|
-
- Toon bij het aanmaken en wijzigen van een pickstation een keuzelijst met
|
|
1083
|
-
actieve printplekken uit public.print_plekken (naam + omschrijving).
|
|
1084
|
-
Verwijder je een pickstation, verwijder dan ook de koppelrij.
|
|
1085
|
-
- Hardcode nooit een printplek-, printer- of stationsnaam of -id; alles komt
|
|
1086
|
-
uit de database.
|
|
1087
|
-
- Geef _printer_id alleen mee aan pick_enqueue_print_job wanneer een gebruiker
|
|
1088
|
-
bewust handmatig een printer kiest (bijvoorbeeld opnieuw printen). Anders
|
|
1089
|
-
leeg laten.
|
|
1090
|
-
- Een pickstation zonder printplek: toon een duidelijke waarschuwing
|
|
1091
|
-
("Nog geen printplek gekoppeld — de opdracht blijft in de wachtrij staan")
|
|
1092
|
-
in plaats van zelf een printer te kiezen.
|
|
1093
|
-
- Blijf de status van public.print_jobs volgen (wachtend, bezig, voltooid,
|
|
1094
|
-
mislukt, geannuleerd) en toon foutmelding van de Layout maker met een knop
|
|
1095
|
-
"opnieuw printen".
|
|
1096
|
-
|
|
1097
|
-
CONTROLELIJST
|
|
1098
|
-
[ ] Elk pickstation heeft een rij in print_plek_koppelingen.
|
|
1099
|
-
[ ] Nieuwe printopdrachten bevatten payload.print_plek_id.
|
|
1124
|
+
body: `Deze prompt vervangt niets uit prompt 1 t/m 7; hij komt er bovenop.
|
|
1125
|
+
|
|
1126
|
+
Wat er verandert in de Logistiek Engine: public.pick_enqueue_print_job kiest
|
|
1127
|
+
geen printer meer. De opdracht krijgt de printplek van het pickstation mee
|
|
1128
|
+
(top-level in payload.print_plek_id en in payload.data.print_plek_id) en gaat
|
|
1129
|
+
altijd als status 'wachtend' de wachtrij in. De Layout maker bepaalt daarna de
|
|
1130
|
+
printer: printplek -> bedrijfsbrede standaardregel, en meldt zelf de reden als
|
|
1131
|
+
dat niet lukt.
|
|
1132
|
+
|
|
1133
|
+
Wat deze module moet doen:
|
|
1134
|
+
- Beheer per pickstation de koppeling naar een printplek in
|
|
1135
|
+
public.print_plek_koppelingen met bron = 'pickstation', bron_id =
|
|
1136
|
+
public.pick_stations.id als tekst, print_plek_id = de gekozen rij uit
|
|
1137
|
+
public.print_plekken. Eén actieve koppeling per pickstation.
|
|
1138
|
+
- Toon bij het aanmaken en wijzigen van een pickstation een keuzelijst met
|
|
1139
|
+
actieve printplekken uit public.print_plekken (naam + omschrijving).
|
|
1140
|
+
Verwijder je een pickstation, verwijder dan ook de koppelrij.
|
|
1141
|
+
- Hardcode nooit een printplek-, printer- of stationsnaam of -id; alles komt
|
|
1142
|
+
uit de database.
|
|
1143
|
+
- Geef _printer_id alleen mee aan pick_enqueue_print_job wanneer een gebruiker
|
|
1144
|
+
bewust handmatig een printer kiest (bijvoorbeeld opnieuw printen). Anders
|
|
1145
|
+
leeg laten.
|
|
1146
|
+
- Een pickstation zonder printplek: toon een duidelijke waarschuwing
|
|
1147
|
+
("Nog geen printplek gekoppeld — de opdracht blijft in de wachtrij staan")
|
|
1148
|
+
in plaats van zelf een printer te kiezen.
|
|
1149
|
+
- Blijf de status van public.print_jobs volgen (wachtend, bezig, voltooid,
|
|
1150
|
+
mislukt, geannuleerd) en toon foutmelding van de Layout maker met een knop
|
|
1151
|
+
"opnieuw printen".
|
|
1152
|
+
|
|
1153
|
+
CONTROLELIJST
|
|
1154
|
+
[ ] Elk pickstation heeft een rij in print_plek_koppelingen.
|
|
1155
|
+
[ ] Nieuwe printopdrachten bevatten payload.print_plek_id.
|
|
1100
1156
|
[ ] Deze module kiest nergens zelf een printer.`,
|
|
1101
1157
|
},
|
|
1102
1158
|
{
|
|
@@ -1104,29 +1160,29 @@ CONTROLELIJST
|
|
|
1104
1160
|
title: "Layout per ordersoort uit de Engine, anders de actieve layout",
|
|
1105
1161
|
date: "2026-08-26",
|
|
1106
1162
|
summary: "De Engine stuurt per werkwijze (ordersoort) een layout mee; is dat veld leeg, dan wint de actieve layout uit de Layout maker.",
|
|
1107
|
-
body: `Deze prompt vervangt niets uit prompt 1 t/m 8; hij komt er bovenop.
|
|
1108
|
-
|
|
1109
|
-
Wat er verandert in de Logistiek Engine: per werkwijze (ordersoort) kan een
|
|
1110
|
-
gebruiker voor pakbon, sticker, verzendbrief en productiebon kiezen welke
|
|
1111
|
-
layout gebruikt wordt. Kiest hij "Automatisch", dan blijft print_jobs.layout_id
|
|
1112
|
-
leeg. Dat is een geldige situatie, geen fout.
|
|
1113
|
-
|
|
1114
|
-
Vaste volgorde bij het bepalen van wat er geprint wordt:
|
|
1115
|
-
1. Kant-en-klare PDF (pdf_url / pdf_base64, bijvoorbeeld Floriday- of
|
|
1116
|
-
klantstickers): ongewijzigd printen, layout negeren.
|
|
1117
|
-
2. print_jobs.layout_id gevuld: exact die layout renderen.
|
|
1118
|
-
3. Layout_id leeg: de layout die bij dat documenttype op actief staat.
|
|
1119
|
-
4. Geen van alle: opdracht op mislukt met de leesbare reden
|
|
1120
|
-
"Maak een layout aan en zet die op actief."
|
|
1121
|
-
|
|
1122
|
-
Regels:
|
|
1123
|
-
- Kies nooit zelf een andere layout wanneer layout_id gevuld is.
|
|
1124
|
-
- Verander de meegestuurde printplek niet; de printer komt uit de Layout maker.
|
|
1125
|
-
- Hardcode geen layout-, printer- of documenttypenamen.
|
|
1126
|
-
|
|
1127
|
-
CONTROLELIJST
|
|
1128
|
-
[ ] Order met meegestuurde layout gebruikt exact die layout.
|
|
1129
|
-
[ ] Order zonder layout gebruikt de actieve layout van dat documenttype.
|
|
1163
|
+
body: `Deze prompt vervangt niets uit prompt 1 t/m 8; hij komt er bovenop.
|
|
1164
|
+
|
|
1165
|
+
Wat er verandert in de Logistiek Engine: per werkwijze (ordersoort) kan een
|
|
1166
|
+
gebruiker voor pakbon, sticker, verzendbrief en productiebon kiezen welke
|
|
1167
|
+
layout gebruikt wordt. Kiest hij "Automatisch", dan blijft print_jobs.layout_id
|
|
1168
|
+
leeg. Dat is een geldige situatie, geen fout.
|
|
1169
|
+
|
|
1170
|
+
Vaste volgorde bij het bepalen van wat er geprint wordt:
|
|
1171
|
+
1. Kant-en-klare PDF (pdf_url / pdf_base64, bijvoorbeeld Floriday- of
|
|
1172
|
+
klantstickers): ongewijzigd printen, layout negeren.
|
|
1173
|
+
2. print_jobs.layout_id gevuld: exact die layout renderen.
|
|
1174
|
+
3. Layout_id leeg: de layout die bij dat documenttype op actief staat.
|
|
1175
|
+
4. Geen van alle: opdracht op mislukt met de leesbare reden
|
|
1176
|
+
"Maak een layout aan en zet die op actief."
|
|
1177
|
+
|
|
1178
|
+
Regels:
|
|
1179
|
+
- Kies nooit zelf een andere layout wanneer layout_id gevuld is.
|
|
1180
|
+
- Verander de meegestuurde printplek niet; de printer komt uit de Layout maker.
|
|
1181
|
+
- Hardcode geen layout-, printer- of documenttypenamen.
|
|
1182
|
+
|
|
1183
|
+
CONTROLELIJST
|
|
1184
|
+
[ ] Order met meegestuurde layout gebruikt exact die layout.
|
|
1185
|
+
[ ] Order zonder layout gebruikt de actieve layout van dat documenttype.
|
|
1130
1186
|
[ ] Floriday-PDF wordt ongewijzigd geprint.`,
|
|
1131
1187
|
},
|
|
1132
1188
|
],
|
|
@@ -1141,12 +1197,12 @@ CONTROLELIJST
|
|
|
1141
1197
|
date: "2026-07-24",
|
|
1142
1198
|
summary: "Scan- en controletaken uitvoeren.",
|
|
1143
1199
|
withSharedContract: true,
|
|
1144
|
-
body: `Haal weg: eigen aannames over wat en wanneer er gescand moet worden.
|
|
1145
|
-
|
|
1146
|
-
Bouw:
|
|
1147
|
-
- scan.verify taken; payload reason = pick_scanner_required of kar_vullen_manual_scan.
|
|
1148
|
-
- control.execute taken met controlMode "scanner" = de scancontrole.
|
|
1149
|
-
- Scanresultaat meesturen in logistics_complete_task (p_result).
|
|
1200
|
+
body: `Haal weg: eigen aannames over wat en wanneer er gescand moet worden.
|
|
1201
|
+
|
|
1202
|
+
Bouw:
|
|
1203
|
+
- scan.verify taken; payload reason = pick_scanner_required of kar_vullen_manual_scan.
|
|
1204
|
+
- control.execute taken met controlMode "scanner" = de scancontrole.
|
|
1205
|
+
- Scanresultaat meesturen in logistics_complete_task (p_result).
|
|
1150
1206
|
- Bij afwijking logistics_fail_task met toelichting.`,
|
|
1151
1207
|
},
|
|
1152
1208
|
],
|
|
@@ -1161,11 +1217,11 @@ Bouw:
|
|
|
1161
1217
|
date: "2026-07-24",
|
|
1162
1218
|
summary: "Reserveringstaken uitvoeren en voorraadwijzigingen melden.",
|
|
1163
1219
|
withSharedContract: true,
|
|
1164
|
-
body: `Haal weg: eigen beslissing wanneer er gereserveerd of afgeboekt wordt.
|
|
1165
|
-
|
|
1166
|
-
Bouw:
|
|
1167
|
-
- stock.reserve taken uitvoeren; payload bevat loadCarriers.
|
|
1168
|
-
- Bij relevante voorraadwijziging een gebeurtenis melden met event_type
|
|
1220
|
+
body: `Haal weg: eigen beslissing wanneer er gereserveerd of afgeboekt wordt.
|
|
1221
|
+
|
|
1222
|
+
Bouw:
|
|
1223
|
+
- stock.reserve taken uitvoeren; payload bevat loadCarriers.
|
|
1224
|
+
- Bij relevante voorraadwijziging een gebeurtenis melden met event_type
|
|
1169
1225
|
stock.changed en dezelfde order_ref, zodat de Engine kan herplannen.`,
|
|
1170
1226
|
},
|
|
1171
1227
|
],
|
|
@@ -1180,10 +1236,10 @@ Bouw:
|
|
|
1180
1236
|
date: "2026-07-24",
|
|
1181
1237
|
summary: "Strategie koppelen aan klant en klantgroep.",
|
|
1182
1238
|
withSharedContract: true,
|
|
1183
|
-
body: `Bouw:
|
|
1184
|
-
- Per klant en per klantgroep een koppelveld naar de logistieke strategie
|
|
1185
|
-
(logistics_strategies.id), zodat de Engine weet welke rule config geldt.
|
|
1186
|
-
- Dit veld meegeven als strategy_id bij logistics_emit_event, of beschikbaar
|
|
1239
|
+
body: `Bouw:
|
|
1240
|
+
- Per klant en per klantgroep een koppelveld naar de logistieke strategie
|
|
1241
|
+
(logistics_strategies.id), zodat de Engine weet welke rule config geldt.
|
|
1242
|
+
- Dit veld meegeven als strategy_id bij logistics_emit_event, of beschikbaar
|
|
1187
1243
|
maken zodat de Verkoop-module het kan meegeven.`,
|
|
1188
1244
|
},
|
|
1189
1245
|
],
|
|
@@ -1198,18 +1254,18 @@ Bouw:
|
|
|
1198
1254
|
date: "2026-07-31",
|
|
1199
1255
|
summary: "Eerste koppelprompt: mail alleen omzetten naar order als de Engine dat toestaat.",
|
|
1200
1256
|
withSharedContract: true,
|
|
1201
|
-
body: `Haal weg: eigen aannames over of een bestelling met te weinig voorraad
|
|
1202
|
-
toch mag worden aangemaakt.
|
|
1203
|
-
|
|
1204
|
-
${STOCK_CONTRACT}
|
|
1205
|
-
|
|
1206
|
-
In de Mailbox-module concreet:
|
|
1207
|
-
- Vóór het omzetten van een mail naar een bestelling altijd
|
|
1208
|
-
logistics_check_order_allowed aanroepen met alle orderregels.
|
|
1209
|
-
- allowed = false -> maak de bestelling NIET aan. Zet de mail op status
|
|
1210
|
-
"geblokkeerd - onvoldoende voorraad" en toon per product wanted/available/missing
|
|
1211
|
-
uit check.shortages, zodat een medewerker het handmatig kan oplossen.
|
|
1212
|
-
- allowed = true -> bestelling normaal aanmaken en daarna de gebeurtenis melden
|
|
1257
|
+
body: `Haal weg: eigen aannames over of een bestelling met te weinig voorraad
|
|
1258
|
+
toch mag worden aangemaakt.
|
|
1259
|
+
|
|
1260
|
+
${STOCK_CONTRACT}
|
|
1261
|
+
|
|
1262
|
+
In de Mailbox-module concreet:
|
|
1263
|
+
- Vóór het omzetten van een mail naar een bestelling altijd
|
|
1264
|
+
logistics_check_order_allowed aanroepen met alle orderregels.
|
|
1265
|
+
- allowed = false -> maak de bestelling NIET aan. Zet de mail op status
|
|
1266
|
+
"geblokkeerd - onvoldoende voorraad" en toon per product wanted/available/missing
|
|
1267
|
+
uit check.shortages, zodat een medewerker het handmatig kan oplossen.
|
|
1268
|
+
- allowed = true -> bestelling normaal aanmaken en daarna de gebeurtenis melden
|
|
1213
1269
|
via logistics_emit_event (order.received) met een unieke p_idempotency_key.`,
|
|
1214
1270
|
},
|
|
1215
1271
|
{
|
|
@@ -1217,39 +1273,39 @@ In de Mailbox-module concreet:
|
|
|
1217
1273
|
title: "Bufferbesluit altijd bij de Engine opvragen",
|
|
1218
1274
|
date: "2026-08-02",
|
|
1219
1275
|
summary: "Nieuwe eis bovenop prompt 1: geen eigen bufferlogica; bufferRef komt uit logistics_buffer_decision.",
|
|
1220
|
-
body: `AANVULLING op koppelprompt 1 (die blijft gewoon geldig).
|
|
1221
|
-
|
|
1222
|
-
Haal weg: elke eigen regel of aanname over het samenvoegen van bestellingen uit
|
|
1223
|
-
dezelfde mail, dezelfde afzender of hetzelfde afleveradres.
|
|
1224
|
-
|
|
1225
|
-
Nieuwe verplichting: vraag na de voorraadcontrole, vóór het aanmaken van de
|
|
1226
|
-
bestelling, het bufferbesluit op bij de Engine:
|
|
1227
|
-
|
|
1228
|
-
const { data: besluit } = await supabase.rpc("logistics_buffer_decision", {
|
|
1229
|
-
p_order: {
|
|
1230
|
-
orderRef: "MAIL-12345",
|
|
1231
|
-
checkinAt: "2026-08-03T09:00:00Z",
|
|
1232
|
-
deliveryDate: "2026-08-03",
|
|
1233
|
-
customerRef: "CUST-1",
|
|
1234
|
-
floridayCustomerRef: "FLOR-1",
|
|
1235
|
-
bvoCustomerRef: "BVO-1",
|
|
1236
|
-
deliveryLocationRef: "LOC-1",
|
|
1237
|
-
carrierRef: "TRANS-1",
|
|
1238
|
-
loadCarrierType: "trolley",
|
|
1239
|
-
orderType: "standaard",
|
|
1240
|
-
},
|
|
1241
|
-
p_strategy_id: null,
|
|
1242
|
-
});
|
|
1243
|
-
// besluit = { buffer, reason, bufferRef, bufferKey, matchCriteria,
|
|
1244
|
-
// closeBeforeMinutes, bufferCloseAt, release, trace }
|
|
1245
|
-
|
|
1246
|
-
Regels:
|
|
1247
|
-
- besluit.buffer === false -> bestelling los aanmaken, geen buffer toewijzen.
|
|
1248
|
-
- besluit.buffer === true -> gebruik exact besluit.bufferRef en stuur die mee in de
|
|
1249
|
-
payload van logistics_emit_event.
|
|
1250
|
-
- Ontbrekende velden zorgen ervoor dat de Engine NIET combineert; vul daarom altijd
|
|
1251
|
-
alle bovenstaande velden zo compleet mogelijk uit de mail/klantgegevens.
|
|
1252
|
-
- Toon besluit.reason en besluit.trace in het mailscherm, zodat een medewerker ziet
|
|
1276
|
+
body: `AANVULLING op koppelprompt 1 (die blijft gewoon geldig).
|
|
1277
|
+
|
|
1278
|
+
Haal weg: elke eigen regel of aanname over het samenvoegen van bestellingen uit
|
|
1279
|
+
dezelfde mail, dezelfde afzender of hetzelfde afleveradres.
|
|
1280
|
+
|
|
1281
|
+
Nieuwe verplichting: vraag na de voorraadcontrole, vóór het aanmaken van de
|
|
1282
|
+
bestelling, het bufferbesluit op bij de Engine:
|
|
1283
|
+
|
|
1284
|
+
const { data: besluit } = await supabase.rpc("logistics_buffer_decision", {
|
|
1285
|
+
p_order: {
|
|
1286
|
+
orderRef: "MAIL-12345",
|
|
1287
|
+
checkinAt: "2026-08-03T09:00:00Z",
|
|
1288
|
+
deliveryDate: "2026-08-03",
|
|
1289
|
+
customerRef: "CUST-1",
|
|
1290
|
+
floridayCustomerRef: "FLOR-1",
|
|
1291
|
+
bvoCustomerRef: "BVO-1",
|
|
1292
|
+
deliveryLocationRef: "LOC-1",
|
|
1293
|
+
carrierRef: "TRANS-1",
|
|
1294
|
+
loadCarrierType: "trolley",
|
|
1295
|
+
orderType: "standaard",
|
|
1296
|
+
},
|
|
1297
|
+
p_strategy_id: null,
|
|
1298
|
+
});
|
|
1299
|
+
// besluit = { buffer, reason, bufferRef, bufferKey, matchCriteria,
|
|
1300
|
+
// closeBeforeMinutes, bufferCloseAt, release, trace }
|
|
1301
|
+
|
|
1302
|
+
Regels:
|
|
1303
|
+
- besluit.buffer === false -> bestelling los aanmaken, geen buffer toewijzen.
|
|
1304
|
+
- besluit.buffer === true -> gebruik exact besluit.bufferRef en stuur die mee in de
|
|
1305
|
+
payload van logistics_emit_event.
|
|
1306
|
+
- Ontbrekende velden zorgen ervoor dat de Engine NIET combineert; vul daarom altijd
|
|
1307
|
+
alle bovenstaande velden zo compleet mogelijk uit de mail/klantgegevens.
|
|
1308
|
+
- Toon besluit.reason en besluit.trace in het mailscherm, zodat een medewerker ziet
|
|
1253
1309
|
waarom een bestelling wel of niet is samengevoegd.`,
|
|
1254
1310
|
},
|
|
1255
1311
|
{
|
|
@@ -1257,39 +1313,39 @@ Regels:
|
|
|
1257
1313
|
title: "Alleen ladingdragers gebruiken die de Engine toestaat",
|
|
1258
1314
|
date: "2026-08-03",
|
|
1259
1315
|
summary: "Nieuwe eis bovenop prompt 1 en 2: uitgeschakelde ladingdragers mogen niet meer worden gekozen of ingelezen.",
|
|
1260
|
-
body: `AANVULLING op koppelprompt 1 en 2 (die blijven gewoon geldig).
|
|
1261
|
-
|
|
1262
|
-
In de Rule Engine (stap Beladingindeling) staat welke ladingdragers zijn toegestaan.
|
|
1263
|
-
Staat een ladingdrager uit, dan mag de Mailbox-module die niet meer kiezen of
|
|
1264
|
-
automatisch invullen.
|
|
1265
|
-
|
|
1266
|
-
Haal weg: elke eigen lijst met ladingdragers / verzendmethodes en elke eigen
|
|
1267
|
-
vertaling van tekst uit een mail naar een ladingdrager die niet uit de Engine komt.
|
|
1268
|
-
|
|
1269
|
-
Nieuwe verplichting: haal de lijst op bij de Engine.
|
|
1270
|
-
|
|
1271
|
-
const { data: dragers } = await supabase.rpc("logistics_allowed_load_carriers", {
|
|
1272
|
-
p_strategy_id: null,
|
|
1273
|
-
});
|
|
1274
|
-
// dragers = { allowed: [...], default: "trolley",
|
|
1275
|
-
// carriers: [{ code, label, enabled, isDefault }, ...] }
|
|
1276
|
-
|
|
1277
|
-
Codes en namen (gebruik exact deze codes):
|
|
1278
|
-
trolley Stapelwagen
|
|
1279
|
-
danish_container Deense container
|
|
1280
|
-
euro_rolcontainer Euro-rolcontainer
|
|
1281
|
-
pallet Pallet
|
|
1282
|
-
euro_pallet Euro-pallet
|
|
1283
|
-
loose Geen ladingdrager
|
|
1284
|
-
|
|
1285
|
-
Regels:
|
|
1286
|
-
- In het mailscherm alleen dragers met enabled === true tonen; de rest weglaten.
|
|
1287
|
-
- Herkent de mail een ladingdrager die niet in allowed staat, maak de bestelling dan
|
|
1288
|
-
NIET automatisch aan. Zet de mail op "handmatig controleren - ladingdrager
|
|
1289
|
-
uitgeschakeld" en toon welke drager in de mail stond.
|
|
1290
|
-
- Is er niets herkend, gebruik dan dragers.default.
|
|
1291
|
-
- Stuur loadCarrierType in logistics_check_order_allowed, logistics_buffer_decision
|
|
1292
|
-
en logistics_emit_event altijd met een van bovenstaande codes mee.
|
|
1316
|
+
body: `AANVULLING op koppelprompt 1 en 2 (die blijven gewoon geldig).
|
|
1317
|
+
|
|
1318
|
+
In de Rule Engine (stap Beladingindeling) staat welke ladingdragers zijn toegestaan.
|
|
1319
|
+
Staat een ladingdrager uit, dan mag de Mailbox-module die niet meer kiezen of
|
|
1320
|
+
automatisch invullen.
|
|
1321
|
+
|
|
1322
|
+
Haal weg: elke eigen lijst met ladingdragers / verzendmethodes en elke eigen
|
|
1323
|
+
vertaling van tekst uit een mail naar een ladingdrager die niet uit de Engine komt.
|
|
1324
|
+
|
|
1325
|
+
Nieuwe verplichting: haal de lijst op bij de Engine.
|
|
1326
|
+
|
|
1327
|
+
const { data: dragers } = await supabase.rpc("logistics_allowed_load_carriers", {
|
|
1328
|
+
p_strategy_id: null,
|
|
1329
|
+
});
|
|
1330
|
+
// dragers = { allowed: [...], default: "trolley",
|
|
1331
|
+
// carriers: [{ code, label, enabled, isDefault }, ...] }
|
|
1332
|
+
|
|
1333
|
+
Codes en namen (gebruik exact deze codes):
|
|
1334
|
+
trolley Stapelwagen
|
|
1335
|
+
danish_container Deense container
|
|
1336
|
+
euro_rolcontainer Euro-rolcontainer
|
|
1337
|
+
pallet Pallet
|
|
1338
|
+
euro_pallet Euro-pallet
|
|
1339
|
+
loose Geen ladingdrager
|
|
1340
|
+
|
|
1341
|
+
Regels:
|
|
1342
|
+
- In het mailscherm alleen dragers met enabled === true tonen; de rest weglaten.
|
|
1343
|
+
- Herkent de mail een ladingdrager die niet in allowed staat, maak de bestelling dan
|
|
1344
|
+
NIET automatisch aan. Zet de mail op "handmatig controleren - ladingdrager
|
|
1345
|
+
uitgeschakeld" en toon welke drager in de mail stond.
|
|
1346
|
+
- Is er niets herkend, gebruik dan dragers.default.
|
|
1347
|
+
- Stuur loadCarrierType in logistics_check_order_allowed, logistics_buffer_decision
|
|
1348
|
+
en logistics_emit_event altijd met een van bovenstaande codes mee.
|
|
1293
1349
|
- Cache de lijst niet; de instelling kan op elk moment wijzigen.`,
|
|
1294
1350
|
},
|
|
1295
1351
|
],
|
|
@@ -1304,56 +1360,56 @@ Regels:
|
|
|
1304
1360
|
date: "2026-08-04",
|
|
1305
1361
|
withSharedContract: true,
|
|
1306
1362
|
summary: "Deze module schrijft de dagbezetting weg en toont per dag of de Logistics Engine alle ophaalmomenten haalt.",
|
|
1307
|
-
body: `LEES DIT EERST — hoe je deze prompt uitvoert
|
|
1308
|
-
|
|
1309
|
-
Deze module is de bron van de bezetting. De Logistics Engine rekent daarmee uit
|
|
1310
|
-
of alle karren voor ieder ophaalmoment op tijd gepickt kunnen worden. Je bouwt
|
|
1311
|
-
twee dingen: wegschrijven van de planning, en het tonen van de waarschuwing.
|
|
1312
|
-
Zelf rekenen doe je niet.
|
|
1313
|
-
|
|
1314
|
-
1) Dagbezetting wegschrijven
|
|
1315
|
-
Tabel: public.logistics_staff_planning
|
|
1316
|
-
Kolommen: plan_date (date), staff_count (aantal medewerkers),
|
|
1317
|
-
start_time, end_time (werktijden), source_module, note.
|
|
1318
|
-
Eén rij per dag (uniek op gebruiker + plan_date). Schrijf of update deze rij
|
|
1319
|
-
telkens wanneer de gebruiker de bezetting of de werktijden van een dag
|
|
1320
|
-
wijzigt:
|
|
1321
|
-
|
|
1322
|
-
await supabase.from("logistics_staff_planning").upsert({
|
|
1323
|
-
plan_date: "2026-08-04",
|
|
1324
|
-
staff_count: 7,
|
|
1325
|
-
start_time: "06:00",
|
|
1326
|
-
end_time: "16:00",
|
|
1327
|
-
source_module: "personeelsplanning",
|
|
1328
|
-
}, { onConflict: "user_id,plan_date" })
|
|
1329
|
-
|
|
1330
|
-
2) Direct laten herrekenen
|
|
1331
|
-
Roep na iedere wijziging aan:
|
|
1332
|
-
await supabase.rpc("logistics_capacity_plan_day", { p_date: "2026-08-04" })
|
|
1333
|
-
De Engine berekent dan opnieuw of alle ophaalmomenten haalbaar zijn en
|
|
1334
|
-
verplaatst waar nodig automatisch COMPLETE karren naar een later
|
|
1335
|
-
ophaalmoment. Jij verplaatst zelf nooit karren.
|
|
1336
|
-
|
|
1337
|
-
3) Rode waarschuwing tonen
|
|
1338
|
-
Tabel: public.logistics_capacity_alerts, filter op plan_date en
|
|
1339
|
-
status = 'open'. Toon op de betreffende dag een duidelijk rode melding met:
|
|
1340
|
-
- shortage_minutes → hoeveel capaciteit tekort is (toon in uren + minuten)
|
|
1341
|
-
- pickup_label / pickup_time → welk ophaalmoment niet gehaald wordt
|
|
1342
|
-
- carts_short → hoeveel karren niet op tijd verwerkt kunnen worden
|
|
1343
|
-
- moved_carts → welke karren automatisch zijn doorgeschoven
|
|
1344
|
-
- unplanned_carts → welke karren nog steeds niet ingepland kunnen worden
|
|
1345
|
-
Zijn er geen open rijen, toon dan géén waarschuwing (groen/neutraal).
|
|
1346
|
-
|
|
1347
|
-
4) Ophaalmomenten
|
|
1348
|
-
Tabel public.logistics_pickup_moments bevat per dag de ophaalmomenten
|
|
1349
|
-
(sequence, label, pickup_time). Gebruik die om de waarschuwing per
|
|
1350
|
-
ophaalmoment te tonen. Aanmaken of wijzigen van ophaalmomenten mag alleen
|
|
1351
|
-
als de gebruiker daar in deze module om vraagt; anders alleen lezen.
|
|
1352
|
-
|
|
1353
|
-
5) Wat je NIET doet
|
|
1354
|
-
- Geen eigen capaciteitsberekening of eigen picktijden.
|
|
1355
|
-
- Geen karren splitsen of verplaatsen.
|
|
1356
|
-
- Geen eigen mail sturen bij een tekort; de Engine regelt e-mail en het
|
|
1363
|
+
body: `LEES DIT EERST — hoe je deze prompt uitvoert
|
|
1364
|
+
|
|
1365
|
+
Deze module is de bron van de bezetting. De Logistics Engine rekent daarmee uit
|
|
1366
|
+
of alle karren voor ieder ophaalmoment op tijd gepickt kunnen worden. Je bouwt
|
|
1367
|
+
twee dingen: wegschrijven van de planning, en het tonen van de waarschuwing.
|
|
1368
|
+
Zelf rekenen doe je niet.
|
|
1369
|
+
|
|
1370
|
+
1) Dagbezetting wegschrijven
|
|
1371
|
+
Tabel: public.logistics_staff_planning
|
|
1372
|
+
Kolommen: plan_date (date), staff_count (aantal medewerkers),
|
|
1373
|
+
start_time, end_time (werktijden), source_module, note.
|
|
1374
|
+
Eén rij per dag (uniek op gebruiker + plan_date). Schrijf of update deze rij
|
|
1375
|
+
telkens wanneer de gebruiker de bezetting of de werktijden van een dag
|
|
1376
|
+
wijzigt:
|
|
1377
|
+
|
|
1378
|
+
await supabase.from("logistics_staff_planning").upsert({
|
|
1379
|
+
plan_date: "2026-08-04",
|
|
1380
|
+
staff_count: 7,
|
|
1381
|
+
start_time: "06:00",
|
|
1382
|
+
end_time: "16:00",
|
|
1383
|
+
source_module: "personeelsplanning",
|
|
1384
|
+
}, { onConflict: "user_id,plan_date" })
|
|
1385
|
+
|
|
1386
|
+
2) Direct laten herrekenen
|
|
1387
|
+
Roep na iedere wijziging aan:
|
|
1388
|
+
await supabase.rpc("logistics_capacity_plan_day", { p_date: "2026-08-04" })
|
|
1389
|
+
De Engine berekent dan opnieuw of alle ophaalmomenten haalbaar zijn en
|
|
1390
|
+
verplaatst waar nodig automatisch COMPLETE karren naar een later
|
|
1391
|
+
ophaalmoment. Jij verplaatst zelf nooit karren.
|
|
1392
|
+
|
|
1393
|
+
3) Rode waarschuwing tonen
|
|
1394
|
+
Tabel: public.logistics_capacity_alerts, filter op plan_date en
|
|
1395
|
+
status = 'open'. Toon op de betreffende dag een duidelijk rode melding met:
|
|
1396
|
+
- shortage_minutes → hoeveel capaciteit tekort is (toon in uren + minuten)
|
|
1397
|
+
- pickup_label / pickup_time → welk ophaalmoment niet gehaald wordt
|
|
1398
|
+
- carts_short → hoeveel karren niet op tijd verwerkt kunnen worden
|
|
1399
|
+
- moved_carts → welke karren automatisch zijn doorgeschoven
|
|
1400
|
+
- unplanned_carts → welke karren nog steeds niet ingepland kunnen worden
|
|
1401
|
+
Zijn er geen open rijen, toon dan géén waarschuwing (groen/neutraal).
|
|
1402
|
+
|
|
1403
|
+
4) Ophaalmomenten
|
|
1404
|
+
Tabel public.logistics_pickup_moments bevat per dag de ophaalmomenten
|
|
1405
|
+
(sequence, label, pickup_time). Gebruik die om de waarschuwing per
|
|
1406
|
+
ophaalmoment te tonen. Aanmaken of wijzigen van ophaalmomenten mag alleen
|
|
1407
|
+
als de gebruiker daar in deze module om vraagt; anders alleen lezen.
|
|
1408
|
+
|
|
1409
|
+
5) Wat je NIET doet
|
|
1410
|
+
- Geen eigen capaciteitsberekening of eigen picktijden.
|
|
1411
|
+
- Geen karren splitsen of verplaatsen.
|
|
1412
|
+
- Geen eigen mail sturen bij een tekort; de Engine regelt e-mail en het
|
|
1357
1413
|
Meldingencentrum via de instellingen in de Rule Engine.`,
|
|
1358
1414
|
},
|
|
1359
1415
|
],
|
|
@@ -1372,16 +1428,16 @@ export const MODULE_PROMPTS = Object.keys(MODULES)
|
|
|
1372
1428
|
export function buildRevisionPrompt(prompt, revision) {
|
|
1373
1429
|
const shared = revision.withSharedContract
|
|
1374
1430
|
? `\n## Gedeeld contract\n\n${sharedBlock(prompt.moduleKey)}\n`
|
|
1375
|
-
: `\n(Deze prompt is een aanvulling. Het gedeelde contract uit koppelprompt 1 blijft
|
|
1431
|
+
: `\n(Deze prompt is een aanvulling. Het gedeelde contract uit koppelprompt 1 blijft
|
|
1376
1432
|
onverkort gelden — niets terugdraaien.)\n`;
|
|
1377
|
-
return `# Koppelprompt ${revision.number} — ${prompt.label}
|
|
1378
|
-
## ${revision.title} (${revision.date})
|
|
1379
|
-
|
|
1380
|
-
${revision.summary}
|
|
1381
|
-
${shared}
|
|
1382
|
-
## Wat deze module moet doen
|
|
1383
|
-
|
|
1384
|
-
${revision.body}
|
|
1433
|
+
return `# Koppelprompt ${revision.number} — ${prompt.label}
|
|
1434
|
+
## ${revision.title} (${revision.date})
|
|
1435
|
+
|
|
1436
|
+
${revision.summary}
|
|
1437
|
+
${shared}
|
|
1438
|
+
## Wat deze module moet doen
|
|
1439
|
+
|
|
1440
|
+
${revision.body}
|
|
1385
1441
|
`;
|
|
1386
1442
|
}
|
|
1387
1443
|
export function buildModulePrompt(prompt) {
|
|
@@ -1389,18 +1445,18 @@ export function buildModulePrompt(prompt) {
|
|
|
1389
1445
|
}
|
|
1390
1446
|
/** Alle modules, met per module de volledige promptgeschiedenis. */
|
|
1391
1447
|
export function buildAllModulePrompts() {
|
|
1392
|
-
const sections = MODULE_PROMPTS.map((p) => `# ${p.order}. ${p.label} (module: ${p.moduleKey})
|
|
1393
|
-
|
|
1394
|
-
${p.summary}
|
|
1395
|
-
|
|
1448
|
+
const sections = MODULE_PROMPTS.map((p) => `# ${p.order}. ${p.label} (module: ${p.moduleKey})
|
|
1449
|
+
|
|
1450
|
+
${p.summary}
|
|
1451
|
+
|
|
1396
1452
|
${p.revisions.map((r) => buildRevisionPrompt(p, r)).join("\n---\n\n")}`).join("\n\n====================\n\n");
|
|
1397
|
-
return `# Koppelprompts voor de aangesloten modules
|
|
1398
|
-
|
|
1399
|
-
Per module staan de prompts op volgorde. Een nieuwe eis komt er altijd als
|
|
1400
|
-
NIEUWE prompt bij; eerdere prompts blijven geldig en worden niet herschreven.
|
|
1401
|
-
Er worden geen secrets gebruikt: alle communicatie loopt via de gedeelde
|
|
1402
|
-
Supabase-database.
|
|
1403
|
-
|
|
1453
|
+
return `# Koppelprompts voor de aangesloten modules
|
|
1454
|
+
|
|
1455
|
+
Per module staan de prompts op volgorde. Een nieuwe eis komt er altijd als
|
|
1456
|
+
NIEUWE prompt bij; eerdere prompts blijven geldig en worden niet herschreven.
|
|
1457
|
+
Er worden geen secrets gebruikt: alle communicatie loopt via de gedeelde
|
|
1458
|
+
Supabase-database.
|
|
1459
|
+
|
|
1404
1460
|
${sections}`;
|
|
1405
1461
|
}
|
|
1406
1462
|
export function modulePromptFilename(moduleKey, revisionNumber) {
|