@flowselections/logistiek-engine 1.0.238 → 1.0.239
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/db/schema/logistiek-engine.sql +1094 -10
- package/dist-lib/components/StandaardgegevensCard.d.ts.map +1 -1
- package/dist-lib/components/StandaardgegevensCard.js +23 -2
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.js +2 -1
- package/dist-lib/integrations/supabase/types.d.ts +422 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/package.json +1 -1
|
@@ -26892,7 +26892,8 @@ BEGIN
|
|
|
26892
26892
|
AND coalesce(o.order_source, '') <> 'floriday'
|
|
26893
26893
|
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
26894
26894
|
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
26895
|
-
AND public.logistics_order_date(o.delivery_date)
|
|
26895
|
+
AND public.logistics_order_date(o.delivery_date::text)::date
|
|
26896
|
+
>= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 1 -- type-vast: werkt bij text, date en timestamptz
|
|
26896
26897
|
GROUP BY o.id, o.order_number, o.customer_id, oi.product_id
|
|
26897
26898
|
LIMIT greatest(1, p_limit)
|
|
26898
26899
|
LOOP
|
|
@@ -28390,7 +28391,8 @@ BEGIN
|
|
|
28390
28391
|
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
28391
28392
|
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
28392
28393
|
AND oi.quarantined_at IS NULL
|
|
28393
|
-
AND public.logistics_order_date(o.delivery_date)
|
|
28394
|
+
AND public.logistics_order_date(o.delivery_date::text)::date
|
|
28395
|
+
>= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 1 -- type-vast: werkt bij text, date en timestamptz
|
|
28394
28396
|
)
|
|
28395
28397
|
SELECT g.*,
|
|
28396
28398
|
(SELECT min(x.regelnaam) FROM regels x WHERE x.order_id = g.order_id AND coalesce(x.crates, 0) <= 0) AS onbekende_regel
|
|
@@ -28439,7 +28441,7 @@ BEGIN
|
|
|
28439
28441
|
SET status = 'niet_printen', reden = 'Fust hoort niet meer bij deze kar of order vervallen.', updated_at = now()
|
|
28440
28442
|
WHERE p.soort = 'eigen_traysticker' AND p.status IN ('wacht_op_moment', 'geblokkeerd', 'klaar')
|
|
28441
28443
|
AND NOT (p.bron_id = ANY (v_keep))
|
|
28442
|
-
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE public.logistics_order_date(o.delivery_date) >=
|
|
28444
|
+
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE public.logistics_order_date(o.delivery_date::text)::date >= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 1);
|
|
28443
28445
|
GET DIAGNOSTICS n_uit = ROW_COUNT;
|
|
28444
28446
|
|
|
28445
28447
|
UPDATE public.logistics_sticker_prints p
|
|
@@ -28673,7 +28675,7 @@ BEGIN
|
|
|
28673
28675
|
FROM public.orders o
|
|
28674
28676
|
JOIN public.floriday_salesorders_cache s ON s.floriday_id = o.floriday_sales_order_id AND NOT coalesce(s.is_deleted,false)
|
|
28675
28677
|
CROSS JOIN LATERAL jsonb_array_elements(CASE WHEN jsonb_typeof(s.data->'additionalServices') = 'array' THEN s.data->'additionalServices' ELSE '[]'::jsonb END) e
|
|
28676
|
-
WHERE o.deleted_at IS NULL AND public.logistics_order_date(o.delivery_date) >=
|
|
28678
|
+
WHERE o.deleted_at IS NULL AND public.logistics_order_date(o.delivery_date::text)::date >= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 2
|
|
28677
28679
|
AND upper(coalesce(e->>'unit','')) = 'LABEL' AND (e->>'numberOfUnits') ~ '^\d+$'
|
|
28678
28680
|
AND nullif(btrim(coalesce(e->>'stickerId','')),'') IS NOT NULL
|
|
28679
28681
|
AND NOT EXISTS (SELECT 1 FROM public.floriday_customer_stickers_cache c WHERE c.floriday_id = e->>'stickerId')
|
|
@@ -28707,7 +28709,7 @@ BEGIN
|
|
|
28707
28709
|
SELECT o.id, o.order_number, nullif(btrim(o.floriday_sales_order_id),'') AS sales
|
|
28708
28710
|
FROM public.orders o
|
|
28709
28711
|
WHERE o.deleted_at IS NULL AND nullif(btrim(o.floriday_sales_order_id),'') IS NOT NULL
|
|
28710
|
-
AND public.logistics_order_date(o.delivery_date) >=
|
|
28712
|
+
AND public.logistics_order_date(o.delivery_date::text)::date >= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 2
|
|
28711
28713
|
AND EXISTS (SELECT 1 FROM logistics_active.order_carts oc WHERE oc.order_id = o.id)
|
|
28712
28714
|
ORDER BY o.delivery_date LIMIT greatest(p_limit,1)
|
|
28713
28715
|
LOOP
|
|
@@ -32233,7 +32235,8 @@ BEGIN
|
|
|
32233
32235
|
AND coalesce(o.order_source, '') <> 'floriday'
|
|
32234
32236
|
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
32235
32237
|
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
32236
|
-
AND public.logistics_order_date(o.delivery_date)
|
|
32238
|
+
AND public.logistics_order_date(o.delivery_date::text)::date
|
|
32239
|
+
>= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 1 -- type-vast: werkt bij text, date en timestamptz
|
|
32237
32240
|
GROUP BY o.id, o.order_number, o.customer_id, oi.product_id
|
|
32238
32241
|
LIMIT greatest(1, p_limit)
|
|
32239
32242
|
LOOP
|
|
@@ -32352,7 +32355,8 @@ BEGIN
|
|
|
32352
32355
|
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
32353
32356
|
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
32354
32357
|
AND oi.quarantined_at IS NULL
|
|
32355
|
-
AND public.logistics_order_date(o.delivery_date)
|
|
32358
|
+
AND public.logistics_order_date(o.delivery_date::text)::date
|
|
32359
|
+
>= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 1 -- type-vast: werkt bij text, date en timestamptz
|
|
32356
32360
|
)
|
|
32357
32361
|
SELECT g.*,
|
|
32358
32362
|
(SELECT min(x.regelnaam) FROM regels x WHERE x.order_id = g.order_id AND coalesce(x.crates, 0) <= 0) AS onbekende_regel
|
|
@@ -32401,7 +32405,7 @@ BEGIN
|
|
|
32401
32405
|
SET status = 'niet_printen', reden = 'Fust hoort niet meer bij deze kar of order vervallen.', updated_at = now()
|
|
32402
32406
|
WHERE p.soort = 'eigen_traysticker' AND p.status IN ('wacht_op_moment', 'geblokkeerd', 'klaar')
|
|
32403
32407
|
AND NOT (p.bron_id = ANY (v_keep))
|
|
32404
|
-
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE public.logistics_order_date(o.delivery_date) >=
|
|
32408
|
+
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE public.logistics_order_date(o.delivery_date::text)::date >= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 1);
|
|
32405
32409
|
GET DIAGNOSTICS n_uit = ROW_COUNT;
|
|
32406
32410
|
|
|
32407
32411
|
UPDATE public.logistics_sticker_prints p
|
|
@@ -32569,7 +32573,7 @@ BEGIN
|
|
|
32569
32573
|
FROM public.orders o
|
|
32570
32574
|
JOIN public.floriday_salesorders_cache s ON s.floriday_id = o.floriday_sales_order_id AND NOT coalesce(s.is_deleted,false)
|
|
32571
32575
|
CROSS JOIN LATERAL jsonb_array_elements(CASE WHEN jsonb_typeof(s.data->'additionalServices') = 'array' THEN s.data->'additionalServices' ELSE '[]'::jsonb END) e
|
|
32572
|
-
WHERE o.deleted_at IS NULL AND public.logistics_order_date(o.delivery_date) >=
|
|
32576
|
+
WHERE o.deleted_at IS NULL AND public.logistics_order_date(o.delivery_date::text)::date >= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 2
|
|
32573
32577
|
AND upper(coalesce(e->>'unit','')) = 'LABEL' AND (e->>'numberOfUnits') ~ '^\d+$'
|
|
32574
32578
|
AND nullif(btrim(coalesce(e->>'stickerId','')),'') IS NOT NULL
|
|
32575
32579
|
AND NOT EXISTS (SELECT 1 FROM public.floriday_customer_stickers_cache c WHERE c.floriday_id = e->>'stickerId')
|
|
@@ -32603,7 +32607,7 @@ BEGIN
|
|
|
32603
32607
|
SELECT o.id, o.order_number, nullif(btrim(o.floriday_sales_order_id),'') AS sales
|
|
32604
32608
|
FROM public.orders o
|
|
32605
32609
|
WHERE o.deleted_at IS NULL AND nullif(btrim(o.floriday_sales_order_id),'') IS NOT NULL
|
|
32606
|
-
AND public.logistics_order_date(o.delivery_date) >=
|
|
32610
|
+
AND public.logistics_order_date(o.delivery_date::text)::date >= (now() AT TIME ZONE 'Europe/Amsterdam')::date - 2
|
|
32607
32611
|
AND EXISTS (SELECT 1 FROM logistics_active.order_carts oc WHERE oc.order_id = o.id)
|
|
32608
32612
|
ORDER BY o.delivery_date LIMIT greatest(p_limit,1)
|
|
32609
32613
|
LOOP
|
|
@@ -41085,3 +41089,1083 @@ BEGIN
|
|
|
41085
41089
|
END IF;
|
|
41086
41090
|
RETURN v_res;
|
|
41087
41091
|
END $function$;
|
|
41092
|
+
|
|
41093
|
+
|
|
41094
|
+
-- ============================================================================
|
|
41095
|
+
-- Functies die alleen in de installatiecontrole of in andere functies voorkwamen,
|
|
41096
|
+
-- maar hier nergens werden aangemaakt. Volgorde: pickup_at vóór pickup_ts.
|
|
41097
|
+
-- ============================================================================
|
|
41098
|
+
|
|
41099
|
+
CREATE OR REPLACE FUNCTION public.logistics_pickup_at(p_value text, p_delivery_date date)
|
|
41100
|
+
RETURNS jsonb
|
|
41101
|
+
LANGUAGE plpgsql
|
|
41102
|
+
STABLE
|
|
41103
|
+
SET search_path TO 'public'
|
|
41104
|
+
AS $function$
|
|
41105
|
+
DECLARE
|
|
41106
|
+
v text := btrim(coalesce(p_value, ''));
|
|
41107
|
+
v_tz text;
|
|
41108
|
+
m text[];
|
|
41109
|
+
v_parts text[];
|
|
41110
|
+
v_date date;
|
|
41111
|
+
v_time time;
|
|
41112
|
+
v_pick timestamptz;
|
|
41113
|
+
v_sign timestamptz;
|
|
41114
|
+
BEGIN
|
|
41115
|
+
IF v = '' THEN
|
|
41116
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'leeg', 'reden', 'Het ophaalmoment ontbreekt.');
|
|
41117
|
+
END IF;
|
|
41118
|
+
v_tz := public.logistics_tz();
|
|
41119
|
+
IF v_tz IS NULL THEN
|
|
41120
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'onbekend',
|
|
41121
|
+
'reden', 'De tijdzone van de vestiging ontbreekt. Stel die in bij Werktijden.');
|
|
41122
|
+
END IF;
|
|
41123
|
+
|
|
41124
|
+
-- Momentsleutel van de vervoerder: ophalen n@HH:MM, optioneel aanmelden m@HH:MM.
|
|
41125
|
+
m := regexp_match(v, '^(\d{1,2})@(\d{1,2}:\d{2})(?::\d{2})?(?:\|(\d{1,2})@(\d{1,2}:\d{2})(?::\d{2})?)?$');
|
|
41126
|
+
IF m IS NOT NULL THEN
|
|
41127
|
+
IF p_delivery_date IS NULL THEN
|
|
41128
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'momentsleutel',
|
|
41129
|
+
'reden', 'De leverdatum ontbreekt, daardoor is het ophaalmoment niet te bepalen.');
|
|
41130
|
+
END IF;
|
|
41131
|
+
BEGIN
|
|
41132
|
+
v_pick := (public.logistics_subtract_pick_workdays(p_delivery_date, m[1]::int)::timestamp + m[2]::time) AT TIME ZONE v_tz;
|
|
41133
|
+
IF m[3] IS NOT NULL THEN
|
|
41134
|
+
v_sign := (public.logistics_subtract_pick_workdays(p_delivery_date, m[3]::int)::timestamp + m[4]::time) AT TIME ZONE v_tz;
|
|
41135
|
+
END IF;
|
|
41136
|
+
EXCEPTION WHEN invalid_datetime_format OR datetime_field_overflow THEN
|
|
41137
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'momentsleutel',
|
|
41138
|
+
'reden', 'De tijd in het ophaalmoment is ongeldig.');
|
|
41139
|
+
END;
|
|
41140
|
+
RETURN jsonb_build_object('ok', true, 'bron', 'momentsleutel', 'pickupAt', v_pick, 'signupAt', v_sign);
|
|
41141
|
+
END IF;
|
|
41142
|
+
|
|
41143
|
+
-- "YYYY-MM-DD|HH:MM[|HH:MM]"
|
|
41144
|
+
IF v ~ '^\d{4}-\d{2}-\d{2}\|' THEN
|
|
41145
|
+
v_parts := string_to_array(v, '|');
|
|
41146
|
+
BEGIN
|
|
41147
|
+
v_date := v_parts[1]::date;
|
|
41148
|
+
v_time := NULLIF(btrim(v_parts[2]), '')::time;
|
|
41149
|
+
EXCEPTION WHEN invalid_datetime_format OR datetime_field_overflow THEN
|
|
41150
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'datum_tijd', 'reden', 'De datum of tijd in het ophaalmoment is ongeldig.');
|
|
41151
|
+
END;
|
|
41152
|
+
IF v_time IS NULL THEN
|
|
41153
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'datum_tijd', 'pickupDate', v_date,
|
|
41154
|
+
'reden', 'De ophaaltijd ontbreekt.');
|
|
41155
|
+
END IF;
|
|
41156
|
+
RETURN jsonb_build_object('ok', true, 'bron', 'datum_tijd',
|
|
41157
|
+
'pickupAt', (v_date + v_time) AT TIME ZONE v_tz, 'signupAt', NULL);
|
|
41158
|
+
END IF;
|
|
41159
|
+
|
|
41160
|
+
-- Alleen een datum: geen tijd, dus geen ophaalmoment.
|
|
41161
|
+
IF v ~ '^\d{4}-\d{2}-\d{2}$' THEN
|
|
41162
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'datum', 'pickupDate', v,
|
|
41163
|
+
'reden', 'De ophaaltijd ontbreekt.');
|
|
41164
|
+
END IF;
|
|
41165
|
+
|
|
41166
|
+
-- Volledige tijdstempel.
|
|
41167
|
+
BEGIN
|
|
41168
|
+
v_pick := v::timestamptz;
|
|
41169
|
+
RETURN jsonb_build_object('ok', true, 'bron', 'tijdstempel', 'pickupAt', v_pick, 'signupAt', NULL);
|
|
41170
|
+
EXCEPTION WHEN others THEN
|
|
41171
|
+
RETURN jsonb_build_object('ok', false, 'bron', 'onbekend',
|
|
41172
|
+
'reden', 'Het ophaalmoment heeft een onbekende vorm.');
|
|
41173
|
+
END;
|
|
41174
|
+
END;
|
|
41175
|
+
$function$;
|
|
41176
|
+
REVOKE EXECUTE ON FUNCTION public.logistics_pickup_at(text, date) FROM PUBLIC, anon;
|
|
41177
|
+
GRANT EXECUTE ON FUNCTION public.logistics_pickup_at(text, date) TO authenticated, service_role;
|
|
41178
|
+
|
|
41179
|
+
CREATE OR REPLACE FUNCTION public.logistics_pickup_ts(p_value text, p_delivery_date date)
|
|
41180
|
+
RETURNS timestamp with time zone
|
|
41181
|
+
LANGUAGE sql
|
|
41182
|
+
STABLE
|
|
41183
|
+
SET search_path TO 'public'
|
|
41184
|
+
AS $function$
|
|
41185
|
+
SELECT CASE WHEN coalesce((r->>'ok')::boolean, false) THEN (r->>'pickupAt')::timestamptz END
|
|
41186
|
+
FROM (SELECT public.logistics_pickup_at(p_value, p_delivery_date) AS r) x
|
|
41187
|
+
$function$;
|
|
41188
|
+
REVOKE EXECUTE ON FUNCTION public.logistics_pickup_ts(text, date) FROM PUBLIC, anon;
|
|
41189
|
+
GRANT EXECUTE ON FUNCTION public.logistics_pickup_ts(text, date) TO authenticated, service_role;
|
|
41190
|
+
|
|
41191
|
+
CREATE OR REPLACE FUNCTION public.logistics_pickup_herbereken()
|
|
41192
|
+
RETURNS jsonb
|
|
41193
|
+
LANGUAGE plpgsql
|
|
41194
|
+
SECURITY DEFINER
|
|
41195
|
+
SET search_path TO 'public'
|
|
41196
|
+
AS $function$
|
|
41197
|
+
DECLARE
|
|
41198
|
+
r record;
|
|
41199
|
+
v_tz text := public.logistics_tz();
|
|
41200
|
+
v_today date;
|
|
41201
|
+
v_total int := 0; v_key int := 0; v_dt int := 0; v_fout int := 0; v_err int := 0;
|
|
41202
|
+
v_pk jsonb;
|
|
41203
|
+
BEGIN
|
|
41204
|
+
PERFORM public.logistics_acc_guard('beheer', 'logistics_pickup_herbereken');
|
|
41205
|
+
IF v_tz IS NULL THEN
|
|
41206
|
+
RETURN jsonb_build_object('ok', false, 'reden', 'De tijdzone van de vestiging ontbreekt. Stel die in bij Werktijden.');
|
|
41207
|
+
END IF;
|
|
41208
|
+
v_today := (now() AT TIME ZONE v_tz)::date;
|
|
41209
|
+
FOR r IN
|
|
41210
|
+
SELECT o.id, o.order_number, o.delivery_date, o.custom_fields->>'pickup_moment' AS pm
|
|
41211
|
+
FROM public.orders o
|
|
41212
|
+
WHERE o.deleted_at IS NULL
|
|
41213
|
+
AND o.plan_locked_at IS NULL
|
|
41214
|
+
AND nullif(btrim(o.custom_fields->>'pickup_moment'), '') IS NOT NULL
|
|
41215
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}'
|
|
41216
|
+
AND left(o.delivery_date, 10)::date >= v_today
|
|
41217
|
+
AND NOT public.logistics_order_geannuleerd(o.id)
|
|
41218
|
+
LOOP
|
|
41219
|
+
v_total := v_total + 1;
|
|
41220
|
+
v_pk := public.logistics_pickup_at(r.pm, left(r.delivery_date, 10)::date);
|
|
41221
|
+
IF NOT coalesce((v_pk->>'ok')::boolean, false) THEN v_fout := v_fout + 1;
|
|
41222
|
+
ELSIF v_pk->>'bron' = 'momentsleutel' THEN v_key := v_key + 1;
|
|
41223
|
+
ELSE v_dt := v_dt + 1; END IF;
|
|
41224
|
+
BEGIN
|
|
41225
|
+
PERFORM public.logistics_plan_enqueue(r.id, 'ophaalmoment herberekend');
|
|
41226
|
+
EXCEPTION WHEN others THEN
|
|
41227
|
+
v_err := v_err + 1;
|
|
41228
|
+
INSERT INTO public.logistics_planner_trace(order_id, message)
|
|
41229
|
+
VALUES (r.id, 'herberekenen ophaalmoment mislukt: ' || SQLERRM);
|
|
41230
|
+
END;
|
|
41231
|
+
END LOOP;
|
|
41232
|
+
RETURN jsonb_build_object('ok', v_err = 0, 'orders', v_total, 'momentsleutel', v_key,
|
|
41233
|
+
'datumTijd', v_dt, 'zonderLeesbaarMoment', v_fout, 'fouten', v_err);
|
|
41234
|
+
END;
|
|
41235
|
+
$function$;
|
|
41236
|
+
REVOKE EXECUTE ON FUNCTION public.logistics_pickup_herbereken() FROM PUBLIC, anon;
|
|
41237
|
+
GRANT EXECUTE ON FUNCTION public.logistics_pickup_herbereken() TO authenticated, service_role;
|
|
41238
|
+
|
|
41239
|
+
CREATE OR REPLACE FUNCTION public.process_logistics_event(p_event_id uuid)
|
|
41240
|
+
RETURNS uuid
|
|
41241
|
+
LANGUAGE plpgsql
|
|
41242
|
+
SECURITY DEFINER
|
|
41243
|
+
SET search_path TO 'public'
|
|
41244
|
+
AS $function$
|
|
41245
|
+
DECLARE
|
|
41246
|
+
ev public.logistics_events%ROWTYPE;
|
|
41247
|
+
cfg public.logistics_rule_configs%ROWTYPE;
|
|
41248
|
+
s jsonb; pl jsonb; carriers jsonb; c jsonb; base jsonb; child jsonb;
|
|
41249
|
+
snap_version integer; snap_hash text; warn_list jsonb := '[]'::jsonb;
|
|
41250
|
+
prio integer;
|
|
41251
|
+
checkin_at timestamptz; pickup_at timestamptz;
|
|
41252
|
+
buffer_on boolean; buffer_close timestamptz; buffer_release text;
|
|
41253
|
+
staff integer; total_minutes numeric := 0; pick_minutes integer;
|
|
41254
|
+
start_mode text; reserve_minutes integer := 0; lead_minutes numeric;
|
|
41255
|
+
pick_start timestamptz; pick_end timestamptz; pick_start_raw timestamptz;
|
|
41256
|
+
fill_mode text; scanner text;
|
|
41257
|
+
control_mode text; control_notice timestamptz; control_owner text;
|
|
41258
|
+
shipping_choice text; shipping_at timestamptz;
|
|
41259
|
+
run_id uuid; seq integer := 0; created integer := 0; revised integer := 0;
|
|
41260
|
+
outcome text; default_minutes numeric; keep text[] := ARRAY[]::text[]; stale integer := 0;
|
|
41261
|
+
cancelled_count integer := 0; child_count integer := 0; child_ref text;
|
|
41262
|
+
v_pk_dd date;
|
|
41263
|
+
BEGIN
|
|
41264
|
+
SELECT * INTO ev FROM public.logistics_events WHERE id = p_event_id FOR UPDATE;
|
|
41265
|
+
IF NOT FOUND THEN RETURN NULL; END IF;
|
|
41266
|
+
|
|
41267
|
+
pl := COALESCE(ev.payload, '{}'::jsonb);
|
|
41268
|
+
prio := COALESCE(NULLIF(pl ->> 'priority', '')::integer, NULLIF(ev.priority, 0), 0);
|
|
41269
|
+
IF ev.event_type = 'order.changed' AND lower(btrim(coalesce(pl->>'reason', ''))) = 'afgehandeld in floriday' THEN
|
|
41270
|
+
RETURN public.logistics_apply_external_fulfillment(p_event_id);
|
|
41271
|
+
END IF;
|
|
41272
|
+
|
|
41273
|
+
IF ev.event_type IN ('order.cancelled', 'order.canceled') THEN
|
|
41274
|
+
INSERT INTO public.logistics_plan_runs (
|
|
41275
|
+
user_id, order_ref, source_module, strategy_id, trigger, input, status
|
|
41276
|
+
) VALUES (
|
|
41277
|
+
ev.user_id, ev.order_ref, ev.source_module, ev.strategy_id, ev.event_type, pl, 'ok'
|
|
41278
|
+
) RETURNING id INTO run_id;
|
|
41279
|
+
|
|
41280
|
+
cancelled_count := public.logistics_cancel_order(
|
|
41281
|
+
ev.order_ref, COALESCE(pl ->> 'reason', 'order geannuleerd'), ev.user_id);
|
|
41282
|
+
|
|
41283
|
+
UPDATE public.logistics_plan_runs
|
|
41284
|
+
SET input = input || jsonb_build_object('tasksCancelled', cancelled_count), updated_at = now()
|
|
41285
|
+
WHERE id = run_id;
|
|
41286
|
+
|
|
41287
|
+
UPDATE public.logistics_events
|
|
41288
|
+
SET status = 'processed', plan_run_id = run_id, error = NULL,
|
|
41289
|
+
processed_at = now(), updated_at = now()
|
|
41290
|
+
WHERE id = p_event_id;
|
|
41291
|
+
RETURN run_id;
|
|
41292
|
+
END IF;
|
|
41293
|
+
|
|
41294
|
+
IF ev.event_type = 'order.split' THEN
|
|
41295
|
+
INSERT INTO public.logistics_plan_runs (
|
|
41296
|
+
user_id, order_ref, source_module, strategy_id, trigger, input, status
|
|
41297
|
+
) VALUES (
|
|
41298
|
+
ev.user_id, ev.order_ref, ev.source_module, ev.strategy_id, ev.event_type, pl, 'ok'
|
|
41299
|
+
) RETURNING id INTO run_id;
|
|
41300
|
+
|
|
41301
|
+
cancelled_count := public.logistics_cancel_order(ev.order_ref, 'order gesplitst', ev.user_id);
|
|
41302
|
+
|
|
41303
|
+
FOR child IN SELECT * FROM jsonb_array_elements(COALESCE(pl -> 'children', '[]'::jsonb)) LOOP
|
|
41304
|
+
child_ref := child ->> 'orderRef';
|
|
41305
|
+
CONTINUE WHEN child_ref IS NULL OR child_ref = '';
|
|
41306
|
+
INSERT INTO public.logistics_events (
|
|
41307
|
+
user_id, source_module, event_type, order_ref, strategy_id, shadow, priority,
|
|
41308
|
+
idempotency_key, payload
|
|
41309
|
+
) VALUES (
|
|
41310
|
+
ev.user_id, ev.source_module, 'order.received', child_ref, ev.strategy_id, ev.shadow, prio,
|
|
41311
|
+
'split:' || ev.id::text || ':' || child_ref,
|
|
41312
|
+
(pl - 'children') || child || jsonb_build_object('splitFrom', ev.order_ref, 'priority', prio)
|
|
41313
|
+
)
|
|
41314
|
+
ON CONFLICT (user_id, idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING;
|
|
41315
|
+
child_count := child_count + 1;
|
|
41316
|
+
END LOOP;
|
|
41317
|
+
|
|
41318
|
+
UPDATE public.logistics_plan_runs
|
|
41319
|
+
SET input = input || jsonb_build_object(
|
|
41320
|
+
'tasksCancelled', cancelled_count, 'childOrders', child_count), updated_at = now()
|
|
41321
|
+
WHERE id = run_id;
|
|
41322
|
+
|
|
41323
|
+
UPDATE public.logistics_events
|
|
41324
|
+
SET status = 'processed', plan_run_id = run_id, error = NULL,
|
|
41325
|
+
processed_at = now(), updated_at = now()
|
|
41326
|
+
WHERE id = p_event_id;
|
|
41327
|
+
RETURN run_id;
|
|
41328
|
+
END IF;
|
|
41329
|
+
|
|
41330
|
+
-- Ophaalmoment: een gewone tijdstempel blijft werken zoals altijd; anders (momentsleutel
|
|
41331
|
+
-- "n@HH:MM|m@HH:MM" of "datum|tijd") lezen via logistics_pickup_ts met de leverdatum.
|
|
41332
|
+
SELECT CASE WHEN coalesce(x.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' THEN left(x.delivery_date, 10)::date END
|
|
41333
|
+
INTO v_pk_dd
|
|
41334
|
+
FROM public.orders x
|
|
41335
|
+
WHERE (x.id = public.logistics_try_uuid(pl ->> 'orderId') OR x.order_number = ev.order_ref)
|
|
41336
|
+
AND x.deleted_at IS NULL
|
|
41337
|
+
ORDER BY (x.id = public.logistics_try_uuid(pl ->> 'orderId')) DESC NULLS LAST, x.created_at DESC
|
|
41338
|
+
LIMIT 1;
|
|
41339
|
+
BEGIN
|
|
41340
|
+
checkin_at := NULLIF(pl ->> 'checkinAt', '')::timestamptz;
|
|
41341
|
+
EXCEPTION WHEN others THEN
|
|
41342
|
+
checkin_at := public.logistics_pickup_ts(pl ->> 'checkinAt', v_pk_dd);
|
|
41343
|
+
END;
|
|
41344
|
+
checkin_at := COALESCE(checkin_at, now());
|
|
41345
|
+
BEGIN
|
|
41346
|
+
pickup_at := NULLIF(pl ->> 'pickupAt', '')::timestamptz;
|
|
41347
|
+
EXCEPTION WHEN others THEN
|
|
41348
|
+
pickup_at := public.logistics_pickup_ts(pl ->> 'pickupAt', v_pk_dd);
|
|
41349
|
+
END;
|
|
41350
|
+
pickup_at := COALESCE(pickup_at, checkin_at);
|
|
41351
|
+
pl := pl || jsonb_build_object('checkinAt', checkin_at, 'pickupAt', pickup_at);
|
|
41352
|
+
carriers := COALESCE(pl -> 'loadCarriers', '[]'::jsonb);
|
|
41353
|
+
|
|
41354
|
+
IF ev.strategy_id IS NOT NULL THEN
|
|
41355
|
+
SELECT * INTO cfg FROM public.logistics_rule_configs
|
|
41356
|
+
WHERE strategy_id = ev.strategy_id AND user_id = ev.user_id
|
|
41357
|
+
ORDER BY is_active DESC, updated_at DESC LIMIT 1;
|
|
41358
|
+
END IF;
|
|
41359
|
+
IF cfg.id IS NULL THEN
|
|
41360
|
+
SELECT * INTO cfg FROM public.logistics_rule_configs
|
|
41361
|
+
WHERE user_id = ev.user_id ORDER BY is_active DESC, updated_at DESC LIMIT 1;
|
|
41362
|
+
END IF;
|
|
41363
|
+
|
|
41364
|
+
BEGIN
|
|
41365
|
+
snap_version := NULLIF(pl ->> 'ruleVersion', '')::integer;
|
|
41366
|
+
EXCEPTION WHEN others THEN snap_version := NULL; END;
|
|
41367
|
+
|
|
41368
|
+
IF snap_version IS NOT NULL AND cfg.id IS NOT NULL THEN
|
|
41369
|
+
s := public.logistics_resolve_settings(ev.user_id, cfg.id, snap_version);
|
|
41370
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_rule_versions
|
|
41371
|
+
WHERE config_id = cfg.id AND user_id = ev.user_id AND version = snap_version) THEN
|
|
41372
|
+
warn_list := warn_list || jsonb_build_array(jsonb_build_object(
|
|
41373
|
+
'code', 'rule_version_not_found', 'requestedVersion', snap_version));
|
|
41374
|
+
snap_version := cfg.current_version;
|
|
41375
|
+
END IF;
|
|
41376
|
+
ELSE
|
|
41377
|
+
s := COALESCE(cfg.settings, '{}'::jsonb);
|
|
41378
|
+
snap_version := cfg.current_version;
|
|
41379
|
+
END IF;
|
|
41380
|
+
s := COALESCE(s, '{}'::jsonb);
|
|
41381
|
+
snap_hash := md5(s::text);
|
|
41382
|
+
|
|
41383
|
+
IF cfg.id IS NULL THEN
|
|
41384
|
+
warn_list := warn_list || jsonb_build_array(jsonb_build_object('code', 'no_rule_config'));
|
|
41385
|
+
END IF;
|
|
41386
|
+
|
|
41387
|
+
INSERT INTO public.logistics_plan_runs (
|
|
41388
|
+
user_id, order_ref, source_module, strategy_id, rule_config_id, rule_version, trigger, input,
|
|
41389
|
+
settings_snapshot, settings_hash
|
|
41390
|
+
) VALUES (
|
|
41391
|
+
ev.user_id, ev.order_ref, ev.source_module, ev.strategy_id, cfg.id, snap_version, ev.event_type, pl,
|
|
41392
|
+
s, snap_hash
|
|
41393
|
+
) RETURNING id INTO run_id;
|
|
41394
|
+
|
|
41395
|
+
base := jsonb_build_object(
|
|
41396
|
+
'orderRef', ev.order_ref,
|
|
41397
|
+
'customerRef', pl -> 'customerRef',
|
|
41398
|
+
'checkinAt', checkin_at,
|
|
41399
|
+
'pickupAt', pickup_at,
|
|
41400
|
+
'shadow', ev.shadow,
|
|
41401
|
+
'strategyId', ev.strategy_id,
|
|
41402
|
+
'ruleVersion', snap_version,
|
|
41403
|
+
'settingsHash', snap_hash,
|
|
41404
|
+
'priority', prio,
|
|
41405
|
+
'splitFrom', pl -> 'splitFrom'
|
|
41406
|
+
);
|
|
41407
|
+
|
|
41408
|
+
buffer_on := public.logistics_rule_bool(s, 'order_verwerking', 'buffer_enabled', true);
|
|
41409
|
+
buffer_release := public.logistics_rule_text(s, 'order_verwerking', 'buffer_release', 'auto');
|
|
41410
|
+
IF buffer_on THEN
|
|
41411
|
+
buffer_close := CASE
|
|
41412
|
+
WHEN public.logistics_rule_text(s, 'order_verwerking', 'buffer_close_reference', 'checkin') = 'pick_start'
|
|
41413
|
+
AND public.logistics_pick_start_estimate(s, pl) IS NOT NULL
|
|
41414
|
+
THEN public.logistics_pick_start_estimate(s, pl)
|
|
41415
|
+
ELSE checkin_at
|
|
41416
|
+
END - make_interval(mins =>
|
|
41417
|
+
public.logistics_rule_num(s, 'order_verwerking', 'buffer_close_before_minutes', 60)::int);
|
|
41418
|
+
END IF;
|
|
41419
|
+
|
|
41420
|
+
staff := GREATEST(1, ROUND(public.logistics_rule_num(s, 'pickstations', 'avg_staff', 5))::int);
|
|
41421
|
+
FOR c IN SELECT * FROM jsonb_array_elements(carriers) LOOP
|
|
41422
|
+
default_minutes := CASE c ->> 'type'
|
|
41423
|
+
WHEN 'trolley' THEN 15 WHEN 'danish_container' THEN 15 WHEN 'dense_container' THEN 12
|
|
41424
|
+
WHEN 'pallet' THEN 20 WHEN 'box' THEN 3 WHEN 'loose' THEN 5 ELSE 10 END;
|
|
41425
|
+
total_minutes := total_minutes + GREATEST(0, COALESCE((c ->> 'count')::numeric, 0)) *
|
|
41426
|
+
public.logistics_rule_num(s, 'pickstations', 'pick_time_' || (c ->> 'type'), default_minutes);
|
|
41427
|
+
END LOOP;
|
|
41428
|
+
pick_minutes := CEIL(total_minutes / staff)::int;
|
|
41429
|
+
|
|
41430
|
+
start_mode := public.logistics_rule_text(s, 'order_picken', 'pick_start_mode', 'as_late_as_possible');
|
|
41431
|
+
IF start_mode = 'as_late_as_possible' THEN
|
|
41432
|
+
IF public.logistics_rule_text(s, 'order_picken', 'pick_reserve_type', 'fixed') = 'percentage' THEN
|
|
41433
|
+
reserve_minutes := CEIL(pick_minutes *
|
|
41434
|
+
public.logistics_rule_num(s, 'order_picken', 'pick_reserve_percentage', 20) / 100)::int;
|
|
41435
|
+
ELSE
|
|
41436
|
+
reserve_minutes := public.logistics_rule_num(s, 'order_picken', 'pick_reserve_minutes', 30)::int;
|
|
41437
|
+
END IF;
|
|
41438
|
+
END IF;
|
|
41439
|
+
|
|
41440
|
+
IF start_mode = 'window_before_checkin' THEN
|
|
41441
|
+
IF public.logistics_rule_text(s, 'order_picken', 'pick_window_unit', 'hours') = 'days' THEN
|
|
41442
|
+
lead_minutes := public.logistics_rule_num(s, 'order_picken', 'pick_window_days', 1) * 24 * 60;
|
|
41443
|
+
ELSE
|
|
41444
|
+
lead_minutes := public.logistics_rule_num(s, 'order_picken', 'pick_window_hours', 4) * 60;
|
|
41445
|
+
END IF;
|
|
41446
|
+
pick_start := checkin_at - make_interval(mins => lead_minutes::int);
|
|
41447
|
+
pick_end := checkin_at;
|
|
41448
|
+
ELSE
|
|
41449
|
+
pick_end := pickup_at - make_interval(mins => reserve_minutes);
|
|
41450
|
+
pick_start := pick_end - make_interval(mins => pick_minutes);
|
|
41451
|
+
END IF;
|
|
41452
|
+
|
|
41453
|
+
pick_start_raw := pick_start;
|
|
41454
|
+
pick_start := public.logistics_not_past(pick_start);
|
|
41455
|
+
IF pick_start_raw < now() THEN
|
|
41456
|
+
warn_list := warn_list || jsonb_build_array(jsonb_build_object(
|
|
41457
|
+
'code', 'pick_start_in_past', 'plannedStart', pick_start_raw, 'shiftedTo', pick_start));
|
|
41458
|
+
END IF;
|
|
41459
|
+
IF pick_end IS NOT NULL AND pick_end < pick_start THEN
|
|
41460
|
+
pick_end := pick_start + make_interval(mins => GREATEST(pick_minutes, 1));
|
|
41461
|
+
warn_list := warn_list || jsonb_build_array(jsonb_build_object('code', 'pick_window_too_short'));
|
|
41462
|
+
END IF;
|
|
41463
|
+
IF pickup_at < now() THEN
|
|
41464
|
+
warn_list := warn_list || jsonb_build_array(jsonb_build_object('code', 'pickup_in_past', 'pickupAt', pickup_at));
|
|
41465
|
+
END IF;
|
|
41466
|
+
IF buffer_close IS NOT NULL AND buffer_close < now() THEN
|
|
41467
|
+
warn_list := warn_list || jsonb_build_array(jsonb_build_object('code', 'buffer_close_in_past', 'closeAt', buffer_close));
|
|
41468
|
+
buffer_close := public.logistics_not_past(buffer_close);
|
|
41469
|
+
END IF;
|
|
41470
|
+
|
|
41471
|
+
fill_mode := public.logistics_rule_text(s, 'kar_vullen', 'fill_mode', 'generated');
|
|
41472
|
+
scanner := public.logistics_rule_text(s, 'order_picken', 'scanner', 'required');
|
|
41473
|
+
|
|
41474
|
+
IF buffer_on AND buffer_close IS NOT NULL THEN
|
|
41475
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41476
|
+
cfg.id, snap_version, 'buffer.close', 'verkoop', seq, buffer_close, buffer_close, ev.shadow,
|
|
41477
|
+
base || jsonb_build_object('bufferRef', pl -> 'bufferRef', 'release', buffer_release,
|
|
41478
|
+
'matchCriteria', COALESCE(public.logistics_rule_value(s, 'order_verwerking', 'buffer_match'), '[]'::jsonb)));
|
|
41479
|
+
keep := array_append(keep, 'buffer.close'); seq := seq + 1;
|
|
41480
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41481
|
+
END IF;
|
|
41482
|
+
|
|
41483
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41484
|
+
cfg.id, snap_version, 'stock.reserve', 'voorraad', seq,
|
|
41485
|
+
public.logistics_not_past(COALESCE(buffer_close, pick_start)),
|
|
41486
|
+
public.logistics_not_past(COALESCE(buffer_close, pick_start)), ev.shadow,
|
|
41487
|
+
base || jsonb_build_object('loadCarriers', carriers));
|
|
41488
|
+
keep := array_append(keep, 'stock.reserve'); seq := seq + 1;
|
|
41489
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41490
|
+
|
|
41491
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41492
|
+
cfg.id, snap_version, 'load.compose', 'afhandeling', seq,
|
|
41493
|
+
public.logistics_not_past(pick_start - interval '10 minutes'), pick_start, ev.shadow,
|
|
41494
|
+
base || jsonb_build_object('loadCarriers', carriers, 'fillMode', fill_mode));
|
|
41495
|
+
keep := array_append(keep, 'load.compose'); seq := seq + 1;
|
|
41496
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41497
|
+
|
|
41498
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41499
|
+
cfg.id, snap_version, 'pick.execute', 'pickschermen', seq, pick_start, pick_end, ev.shadow,
|
|
41500
|
+
base || jsonb_build_object(
|
|
41501
|
+
'pickMode', public.logistics_rule_text(s, 'order_picken', 'pick_mode', 'cart'),
|
|
41502
|
+
'pickStartMode', start_mode, 'pickMinutes', pick_minutes, 'staff', staff,
|
|
41503
|
+
'reserveMinutes', reserve_minutes, 'scanner', scanner, 'loadCarriers', carriers));
|
|
41504
|
+
keep := array_append(keep, 'pick.execute'); seq := seq + 1;
|
|
41505
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41506
|
+
|
|
41507
|
+
IF fill_mode = 'manual_scan' THEN
|
|
41508
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41509
|
+
cfg.id, snap_version, 'scan.verify', 'scanners', seq, pick_end, pick_end, ev.shadow,
|
|
41510
|
+
base || jsonb_build_object('reason', 'kar_vullen_manual_scan'));
|
|
41511
|
+
keep := array_append(keep, 'scan.verify'); seq := seq + 1;
|
|
41512
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41513
|
+
ELSIF scanner = 'required' THEN
|
|
41514
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41515
|
+
cfg.id, snap_version, 'scan.verify', 'scanners', seq, pick_start, pick_end, ev.shadow,
|
|
41516
|
+
base || jsonb_build_object('reason', 'pick_scanner_required'));
|
|
41517
|
+
keep := array_append(keep, 'scan.verify'); seq := seq + 1;
|
|
41518
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41519
|
+
END IF;
|
|
41520
|
+
|
|
41521
|
+
control_mode := public.logistics_rule_text(s, 'controle', 'control_mode', 'scanner');
|
|
41522
|
+
IF control_mode <> 'skip' THEN
|
|
41523
|
+
control_notice := public.logistics_not_past(pickup_at - make_interval(mins =>
|
|
41524
|
+
public.logistics_rule_num(s, 'controle', 'control_notice_minutes', 60)::int));
|
|
41525
|
+
control_owner := CASE WHEN control_mode = 'scanner' THEN 'scanners' ELSE 'afhandeling' END;
|
|
41526
|
+
|
|
41527
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41528
|
+
cfg.id, snap_version, 'control.execute', control_owner, seq, control_notice,
|
|
41529
|
+
GREATEST(pickup_at, control_notice), ev.shadow,
|
|
41530
|
+
base || jsonb_build_object('controlMode', control_mode, 'noticeAt', control_notice));
|
|
41531
|
+
keep := array_append(keep, 'control.execute'); seq := seq + 1;
|
|
41532
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41533
|
+
|
|
41534
|
+
IF control_mode = 'paper' THEN
|
|
41535
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41536
|
+
cfg.id, snap_version, 'print.control_note', 'afhandeling', seq, control_notice, control_notice, ev.shadow,
|
|
41537
|
+
base || jsonb_build_object('printItems',
|
|
41538
|
+
public.logistics_rule_text(s, 'controle', 'control_print_items', 'control_note')));
|
|
41539
|
+
keep := array_append(keep, 'print.control_note'); seq := seq + 1;
|
|
41540
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41541
|
+
END IF;
|
|
41542
|
+
END IF;
|
|
41543
|
+
|
|
41544
|
+
IF fill_mode = 'generated' THEN
|
|
41545
|
+
shipping_choice := public.logistics_rule_text(s, 'kar_vullen', 'shipping_note_print_generated', 'with_packing_slip');
|
|
41546
|
+
ELSE
|
|
41547
|
+
shipping_choice := public.logistics_rule_text(s, 'kar_vullen', 'shipping_note_print_manual', 'after_control');
|
|
41548
|
+
END IF;
|
|
41549
|
+
shipping_at := CASE shipping_choice
|
|
41550
|
+
WHEN 'with_packing_slip' THEN pick_start
|
|
41551
|
+
WHEN 'with_control' THEN COALESCE(control_notice, pick_end)
|
|
41552
|
+
WHEN 'after_control' THEN COALESCE(control_notice, pick_end)
|
|
41553
|
+
ELSE pick_end END;
|
|
41554
|
+
shipping_at := public.logistics_not_past(shipping_at);
|
|
41555
|
+
|
|
41556
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41557
|
+
cfg.id, snap_version, 'print.shipping_note', 'afhandeling', seq, shipping_at, shipping_at, ev.shadow,
|
|
41558
|
+
base || jsonb_build_object('moment', shipping_choice));
|
|
41559
|
+
keep := array_append(keep, 'print.shipping_note'); seq := seq + 1;
|
|
41560
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41561
|
+
|
|
41562
|
+
outcome := public.logistics_upsert_task(ev.user_id, run_id, ev.order_ref, pl ->> 'bufferRef', ev.strategy_id,
|
|
41563
|
+
cfg.id, snap_version, 'transport.dispatch', 'afhandeling', seq,
|
|
41564
|
+
public.logistics_not_past(pickup_at), public.logistics_not_past(pickup_at), ev.shadow, base);
|
|
41565
|
+
keep := array_append(keep, 'transport.dispatch');
|
|
41566
|
+
IF outcome = 'created' THEN created := created + 1; ELSIF outcome = 'revised' THEN revised := revised + 1; END IF;
|
|
41567
|
+
|
|
41568
|
+
stale := public.logistics_supersede_stale_tasks(ev.user_id, ev.order_ref, run_id, keep);
|
|
41569
|
+
|
|
41570
|
+
UPDATE public.logistics_tasks
|
|
41571
|
+
SET priority = prio, updated_at = now()
|
|
41572
|
+
WHERE user_id = ev.user_id AND order_ref = ev.order_ref
|
|
41573
|
+
AND status NOT IN ('cancelled','superseded','done')
|
|
41574
|
+
AND priority IS DISTINCT FROM prio;
|
|
41575
|
+
|
|
41576
|
+
UPDATE public.logistics_plan_runs
|
|
41577
|
+
SET tasks_created = created, tasks_revised = revised, status = 'ok',
|
|
41578
|
+
warnings = warn_list,
|
|
41579
|
+
input = input || jsonb_build_object('tasksSuperseded', stale, 'priority', prio),
|
|
41580
|
+
updated_at = now()
|
|
41581
|
+
WHERE id = run_id;
|
|
41582
|
+
|
|
41583
|
+
UPDATE public.logistics_events
|
|
41584
|
+
SET status = 'processed', plan_run_id = run_id, error = NULL, processed_at = now(), updated_at = now()
|
|
41585
|
+
WHERE id = p_event_id;
|
|
41586
|
+
|
|
41587
|
+
RETURN run_id;
|
|
41588
|
+
END; $function$;
|
|
41589
|
+
REVOKE EXECUTE ON FUNCTION public.process_logistics_event(uuid) FROM PUBLIC, anon;
|
|
41590
|
+
GRANT EXECUTE ON FUNCTION public.process_logistics_event(uuid) TO authenticated, service_role;
|
|
41591
|
+
|
|
41592
|
+
-- Laatste uitkomst van de stickerstappen in de Engine-ronde (voor de Engine-status).
|
|
41593
|
+
CREATE OR REPLACE FUNCTION public.logistics_sticker_sync_status()
|
|
41594
|
+
RETURNS jsonb
|
|
41595
|
+
LANGUAGE plpgsql
|
|
41596
|
+
|
|
41597
|
+
SECURITY DEFINER
|
|
41598
|
+
SET search_path TO 'public'
|
|
41599
|
+
AS $function$
|
|
41600
|
+
DECLARE v jsonb;
|
|
41601
|
+
BEGIN
|
|
41602
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_sticker_sync_status');
|
|
41603
|
+
SELECT value INTO v FROM public.logistics_tick_state WHERE key = 'sticker_sync';
|
|
41604
|
+
IF v IS NULL THEN
|
|
41605
|
+
RETURN jsonb_build_object('bekend', false, 'fouten', '[]'::jsonb);
|
|
41606
|
+
END IF;
|
|
41607
|
+
RETURN jsonb_build_object('bekend', true, 'op', v->'at',
|
|
41608
|
+
'fouten', CASE WHEN jsonb_typeof(v->'fouten') = 'array' THEN v->'fouten' ELSE '[]'::jsonb END);
|
|
41609
|
+
END $function$;
|
|
41610
|
+
REVOKE EXECUTE ON FUNCTION public.logistics_sticker_sync_status() FROM PUBLIC, anon;
|
|
41611
|
+
GRANT EXECUTE ON FUNCTION public.logistics_sticker_sync_status() TO authenticated, service_role;
|
|
41612
|
+
|
|
41613
|
+
-- 1.0.238: logistics_trace_event, veilige beladingsovername, leverdatum altijd als datum (Nederlandse tijd), labels installatiecontrole.
|
|
41614
|
+
-- Orderverloopregel; mag nooit falen.
|
|
41615
|
+
CREATE OR REPLACE FUNCTION public.logistics_trace_event(p_order_id uuid, p_step text, p_status text, p_reason text)
|
|
41616
|
+
RETURNS void
|
|
41617
|
+
LANGUAGE plpgsql
|
|
41618
|
+
SECURITY DEFINER
|
|
41619
|
+
SET search_path TO 'public'
|
|
41620
|
+
AS $function$
|
|
41621
|
+
BEGIN
|
|
41622
|
+
BEGIN
|
|
41623
|
+
PERFORM public.logistics_trace_order_step(p_order_id, p_step, p_step, p_status, NULL, p_reason);
|
|
41624
|
+
EXCEPTION WHEN OTHERS THEN
|
|
41625
|
+
RAISE WARNING 'logistiek-engine: orderverloop schrijven mislukt (order %, stap %): %', p_order_id, p_step, SQLERRM;
|
|
41626
|
+
END;
|
|
41627
|
+
END;
|
|
41628
|
+
$function$;
|
|
41629
|
+
REVOKE ALL ON FUNCTION public.logistics_trace_event(uuid, text, text, text) FROM PUBLIC, anon;
|
|
41630
|
+
REVOKE EXECUTE ON FUNCTION public.logistics_trace_event(uuid, text, text, text) FROM authenticated;
|
|
41631
|
+
GRANT EXECUTE ON FUNCTION public.logistics_trace_event(uuid, text, text, text) TO service_role;
|
|
41632
|
+
|
|
41633
|
+
-- Automatische beladingsovername: alleen volledige Floriday-verpakking, nooit op handmatig vastgezette regels,
|
|
41634
|
+
-- en elke wijziging met oude en nieuwe belading in het orderverloop.
|
|
41635
|
+
CREATE OR REPLACE FUNCTION public.logistics_packing_autofix(p_limit integer DEFAULT 100)
|
|
41636
|
+
RETURNS integer
|
|
41637
|
+
LANGUAGE plpgsql
|
|
41638
|
+
SECURITY DEFINER
|
|
41639
|
+
SET search_path TO 'public'
|
|
41640
|
+
AS $function$
|
|
41641
|
+
DECLARE r record; v_reden text; v_aantal integer := 0; v_ppc int; v_cpl int; v_lpc int;
|
|
41642
|
+
v_oud record; v_tekst text;
|
|
41643
|
+
BEGIN
|
|
41644
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_packing_autofix');
|
|
41645
|
+
FOR r IN
|
|
41646
|
+
SELECT d.* FROM public.logistics_packing_deviations d
|
|
41647
|
+
WHERE d.resolved_at IS NULL AND d.scope = 'order_line' AND d.needs_human = false
|
|
41648
|
+
AND d.order_id IS NOT NULL AND d.order_item_id IS NOT NULL
|
|
41649
|
+
ORDER BY d.first_seen_at
|
|
41650
|
+
LIMIT GREATEST(1, LEAST(p_limit, 500))
|
|
41651
|
+
LOOP
|
|
41652
|
+
v_reden := public.logistics_packing_block_reason(r.order_id, r.order_item_id);
|
|
41653
|
+
IF v_reden IS NOT NULL THEN
|
|
41654
|
+
UPDATE public.logistics_packing_deviations SET needs_human = true, human_reason = v_reden WHERE id = r.id;
|
|
41655
|
+
CONTINUE;
|
|
41656
|
+
END IF;
|
|
41657
|
+
v_ppc := nullif(greatest(coalesce((r.floriday_packing->>'pieces_per_package')::numeric, 0), 0), 0)::int;
|
|
41658
|
+
v_cpl := nullif(greatest(coalesce((r.floriday_packing->>'packages_per_layer')::numeric, 0), 0), 0)::int;
|
|
41659
|
+
v_lpc := nullif(greatest(coalesce((r.floriday_packing->>'layers_per_load_carrier')::numeric, 0), 0), 0)::int;
|
|
41660
|
+
IF v_ppc IS NULL OR v_cpl IS NULL OR v_lpc IS NULL THEN
|
|
41661
|
+
UPDATE public.logistics_packing_deviations
|
|
41662
|
+
SET needs_human = true,
|
|
41663
|
+
human_reason = 'Floriday-verpakking onvolledig (0 of leeg = onbekend); niet automatisch overgenomen.'
|
|
41664
|
+
WHERE id = r.id;
|
|
41665
|
+
CONTINUE;
|
|
41666
|
+
END IF;
|
|
41667
|
+
SELECT oi.plants_per_crate, oi.crates_per_layer, oi.layers_per_cart, oi.packing_locked_at
|
|
41668
|
+
INTO v_oud FROM public.order_items oi WHERE oi.id = r.order_item_id FOR UPDATE;
|
|
41669
|
+
IF NOT FOUND THEN CONTINUE; END IF;
|
|
41670
|
+
IF v_oud.packing_locked_at IS NOT NULL THEN
|
|
41671
|
+
-- Handmatig vastgezet: nooit aanpassen; één keer ter beoordeling, niet elke ronde opnieuw.
|
|
41672
|
+
UPDATE public.logistics_packing_deviations
|
|
41673
|
+
SET needs_human = true, human_reason = 'handmatig vastgezet, niet automatisch aangepast'
|
|
41674
|
+
WHERE id = r.id;
|
|
41675
|
+
CONTINUE;
|
|
41676
|
+
END IF;
|
|
41677
|
+
UPDATE public.order_items oi
|
|
41678
|
+
SET plants_per_crate = v_ppc, crates_per_layer = v_cpl, layers_per_cart = v_lpc
|
|
41679
|
+
WHERE oi.id = r.order_item_id AND oi.packing_locked_at IS NULL;
|
|
41680
|
+
IF FOUND THEN
|
|
41681
|
+
v_aantal := v_aantal + 1;
|
|
41682
|
+
v_tekst := format('belading %s/%s/%s → %s/%s/%s (stuks per fust / fusten per laag / lagen per kar), automatisch naar de Floriday-stand',
|
|
41683
|
+
coalesce(v_oud.plants_per_crate::text, '?'), coalesce(v_oud.crates_per_layer::text, '?'), coalesce(v_oud.layers_per_cart::text, '?'),
|
|
41684
|
+
v_ppc, v_cpl, v_lpc);
|
|
41685
|
+
UPDATE public.logistics_packing_deviations
|
|
41686
|
+
SET auto_fixed_at = now(), resolved_at = now(), human_reason = v_tekst
|
|
41687
|
+
WHERE id = r.id;
|
|
41688
|
+
PERFORM public.logistics_trace_event(r.order_id, 'stap:belading_synchronisatie', 'ok', v_tekst);
|
|
41689
|
+
END IF;
|
|
41690
|
+
END LOOP;
|
|
41691
|
+
RETURN v_aantal;
|
|
41692
|
+
END;
|
|
41693
|
+
$function$;
|
|
41694
|
+
CREATE OR REPLACE FUNCTION public.logistics_shipping_note_ensure_accepted(p_order_id uuid DEFAULT NULL::uuid, p_limit integer DEFAULT 100)
|
|
41695
|
+
RETURNS integer
|
|
41696
|
+
LANGUAGE plpgsql
|
|
41697
|
+
SECURITY DEFINER
|
|
41698
|
+
SET search_path TO 'public'
|
|
41699
|
+
AS $function$
|
|
41700
|
+
DECLARE r record; v_cart uuid; v_n int := 0;
|
|
41701
|
+
BEGIN
|
|
41702
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_shipping_note_ensure_accepted');
|
|
41703
|
+
FOR r IN
|
|
41704
|
+
SELECT o.id, o.order_number FROM public.orders o
|
|
41705
|
+
WHERE o.deleted_at IS NULL
|
|
41706
|
+
AND (p_order_id IS NULL OR o.id = p_order_id OR o.buffer_id = (SELECT buffer_id FROM public.orders WHERE id = p_order_id))
|
|
41707
|
+
AND (nullif(o.floriday_sales_order_id,'') IS NOT NULL OR lower(coalesce(o.order_source,'')) LIKE '%floriday%')
|
|
41708
|
+
AND coalesce(o.status,'') <> 'geannuleerd'
|
|
41709
|
+
AND o.delivery_date ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date - 7
|
|
41710
|
+
AND EXISTS (SELECT 1 FROM unnest(public.logistics_order_cart_ids(o.id)) c
|
|
41711
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.logistics_slip_shipping_note s WHERE s.cart_id = c))
|
|
41712
|
+
ORDER BY o.updated_at DESC
|
|
41713
|
+
LIMIT greatest(coalesce(p_limit,100),1)
|
|
41714
|
+
LOOP
|
|
41715
|
+
IF NOT coalesce((public.logistics_afhandeling_fulfillment_order(r.id)->>'verstuurd')::boolean, false) THEN CONTINUE; END IF;
|
|
41716
|
+
FOREACH v_cart IN ARRAY public.logistics_order_cart_ids(r.id) LOOP
|
|
41717
|
+
IF EXISTS (SELECT 1 FROM public.logistics_slip_shipping_note s WHERE s.cart_id = v_cart) THEN CONTINUE; END IF;
|
|
41718
|
+
INSERT INTO public.logistics_slip_shipping_note(slip_job_id, cart_id, order_id, order_number, status, batch_key, next_attempt_at)
|
|
41719
|
+
VALUES (v_cart, v_cart, r.id, r.order_number, 'wachtend', 'na-acceptatie:' || r.id::text, now())
|
|
41720
|
+
ON CONFLICT (slip_job_id) DO NOTHING;
|
|
41721
|
+
IF FOUND THEN
|
|
41722
|
+
v_n := v_n + 1;
|
|
41723
|
+
BEGIN
|
|
41724
|
+
PERFORM public.logistics_trace_order_step(r.id, 'stap:verzendbrief', 'verzendbrief klaargezet', 'ok',
|
|
41725
|
+
'na acceptatie belading', 'Floriday accepteerde de belading; verzendbrief voor kar ' || v_cart::text || ' klaargezet.', 'Verzendbrief');
|
|
41726
|
+
EXCEPTION WHEN others THEN NULL; END;
|
|
41727
|
+
END IF;
|
|
41728
|
+
END LOOP;
|
|
41729
|
+
END LOOP;
|
|
41730
|
+
RETURN v_n;
|
|
41731
|
+
END $function$;
|
|
41732
|
+
|
|
41733
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_status()
|
|
41734
|
+
RETURNS jsonb
|
|
41735
|
+
LANGUAGE plpgsql
|
|
41736
|
+
SECURITY DEFINER
|
|
41737
|
+
SET search_path TO 'public'
|
|
41738
|
+
AS $function$
|
|
41739
|
+
DECLARE s record; v jsonb;
|
|
41740
|
+
BEGIN
|
|
41741
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_carrier_status');
|
|
41742
|
+
IF auth.uid() IS NULL AND coalesce(auth.role(), '') <> 'service_role' THEN RAISE EXCEPTION 'Niet ingelogd'; END IF;
|
|
41743
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
41744
|
+
WITH open_orders AS (
|
|
41745
|
+
SELECT o.id, o.order_number, o.delivery_date, o.carrier_source, o.carrier_reason, o.created_at
|
|
41746
|
+
FROM public.orders o
|
|
41747
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
41748
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
41749
|
+
)
|
|
41750
|
+
SELECT jsonb_build_object(
|
|
41751
|
+
'zonderVervoerder', count(*) FILTER (WHERE carrier_source = 'geen' OR (carrier_source IS NULL AND created_at >= s.installed_at)),
|
|
41752
|
+
'viaFavoriet', count(*) FILTER (WHERE carrier_source = 'favoriet'),
|
|
41753
|
+
'nogNietBerekend', count(*) FILTER (WHERE carrier_source IS NULL AND created_at < s.installed_at),
|
|
41754
|
+
'bronOud', count(*) FILTER (WHERE carrier_source = 'oud'),
|
|
41755
|
+
'lijstZonder', coalesce(jsonb_agg(jsonb_build_object('orderId', id, 'orderNumber', order_number, 'deliveryDate', delivery_date,
|
|
41756
|
+
'reden', coalesce(carrier_reason, 'Nog niet berekend.')) ORDER BY delivery_date, order_number)
|
|
41757
|
+
FILTER (WHERE carrier_source = 'geen' OR (carrier_source IS NULL AND created_at >= s.installed_at)), '[]'::jsonb),
|
|
41758
|
+
'lijstFavoriet', coalesce(jsonb_agg(jsonb_build_object('orderId', id, 'orderNumber', order_number, 'deliveryDate', delivery_date,
|
|
41759
|
+
'reden', carrier_reason) ORDER BY delivery_date, order_number) FILTER (WHERE carrier_source = 'favoriet'), '[]'::jsonb))
|
|
41760
|
+
INTO v FROM open_orders;
|
|
41761
|
+
RETURN v || jsonb_build_object('bufferFouten', (SELECT count(*) FROM public.logistics_carrier_events e
|
|
41762
|
+
WHERE e.soort = 'fout' AND e.created_at > now() - interval '7 days'), 'bestaandeOrders', coalesce(s.backfill_existing, false),
|
|
41763
|
+
'installedAt', s.installed_at, 'schakelaarGezetDoor', s.backfill_set_by, 'schakelaarGezetOp', s.backfill_set_at);
|
|
41764
|
+
END $function$;
|
|
41765
|
+
|
|
41766
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_preview_existing(p_limit integer DEFAULT 1000)
|
|
41767
|
+
RETURNS TABLE(order_id uuid, order_number text, order_source text, delivery_date text, huidig_custom_carrier text, carrier_id uuid, carrier_name text, carrier_kind text, bron text, reden text, bevroren text)
|
|
41768
|
+
LANGUAGE plpgsql
|
|
41769
|
+
STABLE SECURITY DEFINER
|
|
41770
|
+
SET search_path TO 'public'
|
|
41771
|
+
AS $function$
|
|
41772
|
+
BEGIN
|
|
41773
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_carrier_preview_existing');
|
|
41774
|
+
IF auth.uid() IS NOT NULL AND NOT public.logistics_is_beheer() THEN
|
|
41775
|
+
RAISE EXCEPTION 'Alleen beheer mag deze lijst bekijken.';
|
|
41776
|
+
END IF;
|
|
41777
|
+
RETURN QUERY
|
|
41778
|
+
SELECT o.id, o.order_number, o.order_source, o.delivery_date, o.custom_fields->>'carrier',
|
|
41779
|
+
public.logistics_try_uuid(v.r->>'carrier_id'), v.r->>'carrier_name', v.r->>'carrier_kind', v.r->>'bron', v.r->>'reden',
|
|
41780
|
+
public.logistics_carrier_frozen_reason(o.id)
|
|
41781
|
+
FROM public.orders o
|
|
41782
|
+
CROSS JOIN LATERAL (SELECT public.logistics_resolve_carrier_core(to_jsonb(o), false) AS r) v
|
|
41783
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL AND o.carrier_source IS NULL
|
|
41784
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
41785
|
+
ORDER BY o.delivery_date, o.order_number
|
|
41786
|
+
LIMIT greatest(1, coalesce(p_limit, 1000));
|
|
41787
|
+
END $function$;
|
|
41788
|
+
|
|
41789
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check()
|
|
41790
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text)
|
|
41791
|
+
LANGUAGE plpgsql
|
|
41792
|
+
SECURITY DEFINER
|
|
41793
|
+
SET search_path TO 'public'
|
|
41794
|
+
AS $function$
|
|
41795
|
+
DECLARE c text; f text; t text; v_fav text; n bigint; s record;
|
|
41796
|
+
BEGIN
|
|
41797
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_install_check');
|
|
41798
|
+
-- Alleen bestaan controleren: herberekenen nooit tijdens installatie uitvoeren.
|
|
41799
|
+
FOREACH f IN ARRAY ARRAY['logistics_pickup_at(text,date)',
|
|
41800
|
+
'logistics_pickup_ts(text,date)', 'logistics_pickup_herbereken()'] LOOP
|
|
41801
|
+
onderdeel := 'functie ' || f;
|
|
41802
|
+
ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
41803
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END;
|
|
41804
|
+
RETURN NEXT;
|
|
41805
|
+
END LOOP;
|
|
41806
|
+
FOREACH f IN ARRAY ARRAY[
|
|
41807
|
+
'f:logistics_try_uuid','f:logistics_tz','f:logistics_is_beheer','f:logistics_buffer_payload','f:logistics_apply_order_buffer',
|
|
41808
|
+
'f:logistics_apply_buffer_decision','f:logistics_rebuffer_pending','f:logistics_departure_calc','f:logistics_own_transport_departure',
|
|
41809
|
+
'f:logistics_order_departure','f:logistics_brief_transport','f:logistics_order_frozen','f:logistics_order_is_frozen',
|
|
41810
|
+
'f:logistics_order_finalize_run','f:run_logistics_tasks_dispatch','f:enqueue_cart_replan_if_unlocked','f:logistics_tick',
|
|
41811
|
+
't:logistics_tick_runs',
|
|
41812
|
+
'f:logistics_belading_bevestig','f:logistics_cart_seq_dubbel','f:logistics_plan_retry_later','f:logistics_own_traysticker_sync',
|
|
41813
|
+
't:logistics_belading_bevestigingen',
|
|
41814
|
+
'f:logistics_sticker_copies','f:logistics_sticker_etiket_status','f:logistics_sticker_order_counts','f:logistics_sticker_sync',
|
|
41815
|
+
'c:logistics_sticker_prints.kopieen_bron',
|
|
41816
|
+
'f:logistics_carrier_settings_ensure','t:logistics_carrier_settings','t:logistics_carrier_recalc_queue','t:logistics_carrier_events',
|
|
41817
|
+
'f:logistics_carrier_status','f:logistics_carrier_set_backfill','f:logistics_carrier_preview_existing','c:control_get_todays_carts.carrier_name',
|
|
41818
|
+
'f:logistics_plan_fail_log'] LOOP
|
|
41819
|
+
onderdeel := CASE substr(f, 3) WHEN 'run_logistics_tasks_dispatch' THEN 'Voorraad: ' WHEN 'enqueue_cart_replan_if_unlocked' THEN 'Verkoop: ' ELSE 'Engine: ' END || substr(f, 3);
|
|
41820
|
+
ok := CASE left(f, 1)
|
|
41821
|
+
WHEN 'f' THEN EXISTS (SELECT 1 FROM pg_proc p WHERE p.pronamespace = 'public'::regnamespace AND p.proname = substr(f, 3))
|
|
41822
|
+
WHEN 't' THEN to_regclass('public.' || substr(f, 3)) IS NOT NULL
|
|
41823
|
+
ELSE CASE WHEN split_part(substr(f, 3), '.', 1) = 'control_get_todays_carts'
|
|
41824
|
+
THEN coalesce(pg_get_function_result(to_regprocedure('public.control_get_todays_carts()')), '') LIKE '%carrier_name%'
|
|
41825
|
+
ELSE EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public'
|
|
41826
|
+
AND table_name = split_part(substr(f, 3), '.', 1) AND column_name = split_part(substr(f, 3), '.', 2)) END
|
|
41827
|
+
END;
|
|
41828
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' WHEN substr(f, 3) = 'run_logistics_tasks_dispatch' THEN 'ontbreekt: hoort bij Voorraad; werk Voorraad bij' WHEN substr(f, 3) = 'enqueue_cart_replan_if_unlocked' THEN 'ontbreekt: hoort bij Verkoop; werk Verkoop bij' ELSE 'ontbreekt: Engine-migratie (1.0.182 t/m 1.0.188) in dev uitvoeren en via schemasync verspreiden' END;
|
|
41829
|
+
RETURN NEXT;
|
|
41830
|
+
END LOOP;
|
|
41831
|
+
FOREACH c IN ARRAY ARRAY['carrier_id','carrier_source','carrier_reason','carrier_resolved_at','carrier_set_by','carrier_set_at'] LOOP
|
|
41832
|
+
onderdeel := 'orders.' || c;
|
|
41833
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='orders' AND column_name=c);
|
|
41834
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
41835
|
+
END LOOP;
|
|
41836
|
+
FOREACH f IN ARRAY ARRAY['logistics_resolve_carrier(uuid)','logistics_resolve_carrier_many(uuid[])',
|
|
41837
|
+
'logistics_resolve_carrier_for_location(uuid,uuid)','logistics_resolve_carrier_for_location_many(uuid[],uuid)',
|
|
41838
|
+
'logistics_resolve_carrier_for_location_many(jsonb)',
|
|
41839
|
+
'logistics_set_order_carrier(uuid,uuid)','logistics_carrier_recalc_run(integer)'] LOOP
|
|
41840
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
41841
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
41842
|
+
END LOOP;
|
|
41843
|
+
FOREACH t IN ARRAY ARRAY['orders:trg_logistics_orders_carrier_fill','orders:trg_logistics_orders_carrier_changed',
|
|
41844
|
+
'carriers:trg_logistics_carriers_enqueue','customer_delivery_locations:trg_logistics_locations_enqueue'] LOOP
|
|
41845
|
+
onderdeel := 'trigger ' || split_part(t, ':', 2);
|
|
41846
|
+
ok := EXISTS (SELECT 1 FROM pg_trigger g WHERE g.tgname = split_part(t, ':', 2)
|
|
41847
|
+
AND g.tgrelid = to_regclass('public.' || split_part(t, ':', 1)));
|
|
41848
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
41849
|
+
END LOOP;
|
|
41850
|
+
onderdeel := 'minuutronde rekent vervoerders';
|
|
41851
|
+
ok := EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'logistics_tick' AND prosrc LIKE '%logistics_carrier_recalc_run%');
|
|
41852
|
+
toelichting := CASE WHEN ok THEN 'ja' ELSE 'nee' END; RETURN NEXT;
|
|
41853
|
+
FOREACH c IN ARRAY ARRAY['carrier_kind','is_favorite','archived_at','delivery_location_glns'] LOOP
|
|
41854
|
+
onderdeel := 'Afhandeling: carriers.' || c;
|
|
41855
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='carriers' AND column_name=c);
|
|
41856
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Afhandeling' END; RETURN NEXT;
|
|
41857
|
+
END LOOP;
|
|
41858
|
+
FOREACH f IN ARRAY ARRAY['afh_favorite_carrier','afh_city_code','afh_normalize_country','afh_normalize_nl_province'] LOOP
|
|
41859
|
+
onderdeel := 'Afhandeling: ' || f || '()';
|
|
41860
|
+
ok := EXISTS (SELECT 1 FROM pg_proc p WHERE p.pronamespace = 'public'::regnamespace AND p.proname = f);
|
|
41861
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Afhandeling' END; RETURN NEXT;
|
|
41862
|
+
END LOOP;
|
|
41863
|
+
onderdeel := 'Favoriete vervoerder ingesteld en bruikbaar';
|
|
41864
|
+
IF to_regprocedure('public.afh_favorite_carrier()') IS NULL THEN ok := false; toelichting := 'functie ontbreekt';
|
|
41865
|
+
ELSE
|
|
41866
|
+
BEGIN v_fav := public.logistics_carrier_favorite_id()::text; EXCEPTION WHEN OTHERS THEN v_fav := NULL; END;
|
|
41867
|
+
ok := public.logistics_try_uuid(v_fav) IS NOT NULL AND public.logistics_carrier_skip_reason(public.logistics_try_uuid(v_fav)) IS NULL;
|
|
41868
|
+
toelichting := CASE WHEN ok THEN 'ja' WHEN v_fav IS NULL THEN 'geen favoriet ingesteld (Afhandeling → Vervoerders)'
|
|
41869
|
+
ELSE public.logistics_carrier_skip_reason(public.logistics_try_uuid(v_fav)) END;
|
|
41870
|
+
END IF;
|
|
41871
|
+
RETURN NEXT;
|
|
41872
|
+
onderdeel := 'Klanten: customers.default_carrier_id';
|
|
41873
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='customers' AND column_name='default_carrier_id');
|
|
41874
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Klanten' END; RETURN NEXT;
|
|
41875
|
+
IF to_regclass('public.logistics_carrier_settings') IS NOT NULL AND to_regclass('public.orders') IS NOT NULL
|
|
41876
|
+
AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='orders' AND column_name='carrier_source') THEN
|
|
41877
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
41878
|
+
EXECUTE $q$SELECT count(*) FROM public.orders o
|
|
41879
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
41880
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
41881
|
+
AND (o.carrier_source = 'geen' OR (o.carrier_source IS NULL AND o.created_at >= $1))$q$ INTO n USING s.installed_at;
|
|
41882
|
+
onderdeel := 'Open orders zonder vervoerder'; ok := n = 0; toelichting := n || ' order(s)'; RETURN NEXT;
|
|
41883
|
+
onderdeel := 'Schakelaar bestaande orders'; ok := true;
|
|
41884
|
+
toelichting := CASE WHEN coalesce(s.backfill_existing, false) THEN 'aan' ELSE 'uit (bestaande orders wachten op akkoord)' END; RETURN NEXT;
|
|
41885
|
+
END IF;
|
|
41886
|
+
SELECT count(*) INTO n FROM public.logistics_trace_events e
|
|
41887
|
+
WHERE e.actor IN ('trg_logistics_plan_order_items', 'trg_logistics_plan_orders')
|
|
41888
|
+
AND e.status = 'mislukt' AND e.created_at > now() - interval '24 hours';
|
|
41889
|
+
onderdeel := 'Mislukte herplanning (laatste 24 uur)'; ok := n = 0;
|
|
41890
|
+
toelichting := CASE WHEN n = 0 THEN 'geen' ELSE n || ' keer; laatste: ' || coalesce((SELECT coalesce(e.order_ref, '?') || ': ' || coalesce(e.error, '') FROM public.logistics_trace_events e
|
|
41891
|
+
WHERE e.actor IN ('trg_logistics_plan_order_items', 'trg_logistics_plan_orders') AND e.status = 'mislukt'
|
|
41892
|
+
ORDER BY e.created_at DESC LIMIT 1), '') END;
|
|
41893
|
+
RETURN NEXT;
|
|
41894
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_194();
|
|
41895
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_196();
|
|
41896
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_197();
|
|
41897
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_198();
|
|
41898
|
+
RETURN QUERY SELECT * FROM public.logistics_access_check();
|
|
41899
|
+
RETURN QUERY SELECT * FROM public.logistics_overload_check();
|
|
41900
|
+
RETURN QUERY SELECT * FROM public.logistics_check_190();
|
|
41901
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_productiebon();
|
|
41902
|
+
END $function$;
|
|
41903
|
+
|
|
41904
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_enqueue(p_order_ids uuid[], p_reden text)
|
|
41905
|
+
RETURNS integer
|
|
41906
|
+
LANGUAGE plpgsql
|
|
41907
|
+
SECURITY DEFINER
|
|
41908
|
+
SET search_path TO 'public'
|
|
41909
|
+
AS $function$
|
|
41910
|
+
DECLARE n int;
|
|
41911
|
+
BEGIN
|
|
41912
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_carrier_enqueue');
|
|
41913
|
+
PERFORM public.logistics_carrier_settings_ensure();
|
|
41914
|
+
INSERT INTO public.logistics_carrier_recalc_queue AS q (order_id, reden)
|
|
41915
|
+
SELECT o.id, p_reden FROM public.orders o
|
|
41916
|
+
JOIN public.logistics_carrier_settings s ON s.id
|
|
41917
|
+
WHERE o.id = ANY (p_order_ids)
|
|
41918
|
+
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
41919
|
+
AND o.carrier_source IS DISTINCT FROM 'handmatig'
|
|
41920
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
41921
|
+
AND (s.backfill_existing OR o.created_at >= s.installed_at)
|
|
41922
|
+
ON CONFLICT (order_id) DO UPDATE SET processed_at = NULL, queued_at = now(), reden = EXCLUDED.reden;
|
|
41923
|
+
GET DIAGNOSTICS n = ROW_COUNT;
|
|
41924
|
+
RETURN n;
|
|
41925
|
+
END $function$;
|
|
41926
|
+
|
|
41927
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_recalc_run(p_limit integer DEFAULT 200)
|
|
41928
|
+
RETURNS jsonb
|
|
41929
|
+
LANGUAGE plpgsql
|
|
41930
|
+
SECURITY DEFINER
|
|
41931
|
+
SET search_path TO 'public'
|
|
41932
|
+
AS $function$
|
|
41933
|
+
DECLARE s record; r record; o jsonb; v jsonb; v_fr text;
|
|
41934
|
+
n_chk int := 0; n_upd int := 0; n_frozen int := 0; n_hand int := 0; n_err int := 0;
|
|
41935
|
+
BEGIN
|
|
41936
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_carrier_recalc_run');
|
|
41937
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
41938
|
+
IF NOT FOUND THEN RETURN jsonb_build_object('overgeslagen', 'instellingen vervoerder ontbreken'); END IF;
|
|
41939
|
+
FOR r IN
|
|
41940
|
+
WITH kand_open AS (
|
|
41941
|
+
SELECT o.id FROM public.orders o
|
|
41942
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
41943
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
41944
|
+
AND (s.backfill_existing OR o.created_at >= s.installed_at)
|
|
41945
|
+
), cand AS (
|
|
41946
|
+
SELECT q.order_id AS id, 1 AS prio, q.queued_at AS t
|
|
41947
|
+
FROM public.logistics_carrier_recalc_queue q JOIN kand_open ON kand_open.id = q.order_id
|
|
41948
|
+
WHERE q.processed_at IS NULL
|
|
41949
|
+
UNION ALL
|
|
41950
|
+
SELECT kand_open.id, 2, coalesce(q.last_checked_at, '-infinity'::timestamptz)
|
|
41951
|
+
FROM kand_open LEFT JOIN public.logistics_carrier_recalc_queue q ON q.order_id = kand_open.id
|
|
41952
|
+
WHERE q.order_id IS NULL OR (q.processed_at IS NOT NULL
|
|
41953
|
+
AND (q.last_checked_at IS NULL OR q.last_checked_at < now() - interval '24 hours'))
|
|
41954
|
+
)
|
|
41955
|
+
SELECT c.id FROM (SELECT DISTINCT ON (cand.id) cand.id, cand.prio, cand.t FROM cand ORDER BY cand.id, cand.prio) c
|
|
41956
|
+
ORDER BY c.prio, c.t LIMIT greatest(1, least(coalesce(p_limit, 200), 1000))
|
|
41957
|
+
LOOP
|
|
41958
|
+
BEGIN
|
|
41959
|
+
SELECT to_jsonb(x) INTO o FROM public.orders x WHERE x.id = r.id FOR UPDATE SKIP LOCKED;
|
|
41960
|
+
IF o IS NULL THEN CONTINUE; END IF;
|
|
41961
|
+
n_chk := n_chk + 1;
|
|
41962
|
+
IF o->>'carrier_source' = 'handmatig' THEN
|
|
41963
|
+
n_hand := n_hand + 1;
|
|
41964
|
+
ELSE
|
|
41965
|
+
v_fr := public.logistics_carrier_frozen_reason(r.id);
|
|
41966
|
+
IF v_fr IS NOT NULL THEN
|
|
41967
|
+
n_frozen := n_frozen + 1;
|
|
41968
|
+
ELSE
|
|
41969
|
+
v := public.logistics_resolve_carrier_core(o, false);
|
|
41970
|
+
IF (v->>'carrier_id') IS DISTINCT FROM (o->>'carrier_id')
|
|
41971
|
+
OR (v->>'bron') IS DISTINCT FROM (o->>'carrier_source')
|
|
41972
|
+
OR (v->>'reden') IS DISTINCT FROM (o->>'carrier_reason') THEN
|
|
41973
|
+
PERFORM set_config('logistics.carrier_writer', 'engine', true);
|
|
41974
|
+
UPDATE public.orders
|
|
41975
|
+
SET carrier_id = public.logistics_try_uuid(v->>'carrier_id'), carrier_source = v->>'bron',
|
|
41976
|
+
carrier_reason = v->>'reden', carrier_resolved_at = now()
|
|
41977
|
+
WHERE id = r.id;
|
|
41978
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
41979
|
+
n_upd := n_upd + 1;
|
|
41980
|
+
END IF;
|
|
41981
|
+
END IF;
|
|
41982
|
+
END IF;
|
|
41983
|
+
INSERT INTO public.logistics_carrier_recalc_queue AS q (order_id, reden, processed_at, last_checked_at)
|
|
41984
|
+
VALUES (r.id, 'Vangnet', now(), now())
|
|
41985
|
+
ON CONFLICT (order_id) DO UPDATE SET processed_at = now(), last_checked_at = now();
|
|
41986
|
+
EXCEPTION WHEN OTHERS THEN
|
|
41987
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
41988
|
+
n_err := n_err + 1;
|
|
41989
|
+
END;
|
|
41990
|
+
END LOOP;
|
|
41991
|
+
RETURN jsonb_build_object('gecontroleerd', n_chk, 'gewijzigd', n_upd, 'bevroren', n_frozen,
|
|
41992
|
+
'handmatig', n_hand, 'fouten', n_err, 'bestaandeOrders', s.backfill_existing);
|
|
41993
|
+
END $function$;
|
|
41994
|
+
|
|
41995
|
+
CREATE OR REPLACE FUNCTION public.logistics_carriers_enqueue_orders()
|
|
41996
|
+
RETURNS trigger
|
|
41997
|
+
LANGUAGE plpgsql
|
|
41998
|
+
SECURITY DEFINER
|
|
41999
|
+
SET search_path TO 'public'
|
|
42000
|
+
AS $function$
|
|
42001
|
+
BEGIN
|
|
42002
|
+
BEGIN
|
|
42003
|
+
PERFORM public.logistics_carrier_enqueue(ARRAY(
|
|
42004
|
+
SELECT o.id FROM public.orders o
|
|
42005
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
42006
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date),
|
|
42007
|
+
'Vervoerdersinstellingen gewijzigd');
|
|
42008
|
+
EXCEPTION WHEN OTHERS THEN NULL; END;
|
|
42009
|
+
RETURN NULL;
|
|
42010
|
+
END $function$;
|
|
42011
|
+
|
|
42012
|
+
CREATE OR REPLACE FUNCTION public.logistics_scan_delays()
|
|
42013
|
+
RETURNS integer
|
|
42014
|
+
LANGUAGE plpgsql
|
|
42015
|
+
SECURITY DEFINER
|
|
42016
|
+
SET search_path TO 'public'
|
|
42017
|
+
AS $function$
|
|
42018
|
+
DECLARE
|
|
42019
|
+
rec record;
|
|
42020
|
+
cnt integer := 0;
|
|
42021
|
+
BEGIN
|
|
42022
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_scan_delays');
|
|
42023
|
+
FOR rec IN
|
|
42024
|
+
SELECT o.id
|
|
42025
|
+
FROM public.orders o
|
|
42026
|
+
WHERE o.deleted_at IS NULL
|
|
42027
|
+
AND o.delivery_date IS NOT NULL
|
|
42028
|
+
AND public.logistics_order_date(o.delivery_date::text) < (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
42029
|
+
AND COALESCE(o.status::text, '') NOT IN ('delivered', 'cancelled', 'Geleverd', 'Geannuleerd')
|
|
42030
|
+
AND NOT EXISTS (
|
|
42031
|
+
SELECT 1 FROM public.logistics_delay_alerts d
|
|
42032
|
+
WHERE d.order_id = o.id AND d.status = 'open')
|
|
42033
|
+
LIMIT 200
|
|
42034
|
+
LOOP
|
|
42035
|
+
PERFORM public.logistics_report_delay(p_order_id => rec.id, p_reason => 'Geplande leverdatum is verstreken', p_expected_date => NULL::date, p_force_customer_email => false);
|
|
42036
|
+
cnt := cnt + 1;
|
|
42037
|
+
END LOOP;
|
|
42038
|
+
RETURN cnt;
|
|
42039
|
+
END;
|
|
42040
|
+
$function$;
|
|
42041
|
+
|
|
42042
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_housekeeping()
|
|
42043
|
+
RETURNS jsonb
|
|
42044
|
+
LANGUAGE plpgsql
|
|
42045
|
+
SECURITY DEFINER
|
|
42046
|
+
SET search_path TO 'public'
|
|
42047
|
+
AS $function$
|
|
42048
|
+
DECLARE v_resolved int := 0; v_archived int := 0; v_nieuw int := 0; v_alerts int := 0; v_gone int := 0; v_refs text;
|
|
42049
|
+
BEGIN
|
|
42050
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_plan_housekeeping');
|
|
42051
|
+
UPDATE public.logistics_plan_queue q SET status='opgelost', error='opgelost: order is al verzonden',
|
|
42052
|
+
claimed_at=NULL, updated_at=now()
|
|
42053
|
+
FROM public.orders o
|
|
42054
|
+
WHERE o.id = q.order_id AND q.status IN ('geblokkeerd','failed')
|
|
42055
|
+
AND o.status IN ('Verzonden','Gereed voor facturatie');
|
|
42056
|
+
GET DIAGNOSTICS v_resolved = ROW_COUNT;
|
|
42057
|
+
UPDATE public.logistics_plan_queue q SET status='opgelost', error='order bestaat niet meer', claimed_at=NULL, updated_at=now()
|
|
42058
|
+
WHERE q.status IN ('geblokkeerd','failed')
|
|
42059
|
+
AND NOT EXISTS (SELECT 1 FROM public.orders o WHERE o.id = q.order_id AND o.deleted_at IS NULL);
|
|
42060
|
+
|
|
42061
|
+
WITH kand AS (
|
|
42062
|
+
SELECT q.id, q.order_id, o.order_number, public.logistics_plan_inhoud_fp(o.id) AS fp
|
|
42063
|
+
FROM public.logistics_plan_queue q JOIN public.orders o ON o.id = q.order_id
|
|
42064
|
+
WHERE q.status IN ('geblokkeerd','failed')
|
|
42065
|
+
AND o.deleted_at IS NULL
|
|
42066
|
+
AND COALESCE(o.status,'') NOT IN ('Verzonden','Gereed voor facturatie','geannuleerd')
|
|
42067
|
+
AND o.delivery_date IS NOT NULL AND public.logistics_order_date(o.delivery_date::text) < (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date - 2
|
|
42068
|
+
), a AS (
|
|
42069
|
+
UPDATE public.logistics_plan_queue q SET status='gearchiveerd', error=COALESCE(q.error, q.reason),
|
|
42070
|
+
order_fp = k.fp, claimed_at=NULL, updated_at=now()
|
|
42071
|
+
FROM kand k WHERE q.id = k.id
|
|
42072
|
+
RETURNING q.id, k.order_id, k.order_number, k.fp
|
|
42073
|
+
), nieuw AS (
|
|
42074
|
+
SELECT DISTINCT a.order_number FROM a
|
|
42075
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.logistics_plan_queue e
|
|
42076
|
+
WHERE e.order_id = a.order_id AND e.status = 'gearchiveerd' AND e.id <> a.id
|
|
42077
|
+
AND (e.order_fp IS NULL OR e.order_fp = a.fp))
|
|
42078
|
+
)
|
|
42079
|
+
SELECT (SELECT count(*) FROM a), (SELECT count(*) FROM nieuw), (SELECT string_agg(order_number, ', ' ORDER BY order_number) FROM nieuw)
|
|
42080
|
+
INTO v_archived, v_nieuw, v_refs;
|
|
42081
|
+
|
|
42082
|
+
IF v_nieuw > 0 THEN
|
|
42083
|
+
INSERT INTO public.notifications(user_id, title, message, read)
|
|
42084
|
+
SELECT DISTINCT ur.user_id, 'Niet geleverd en gearchiveerd',
|
|
42085
|
+
v_nieuw || ' geblokkeerde order(s) gearchiveerd (leverdatum voorbij): ' || v_refs ||
|
|
42086
|
+
'. Zie Engine › Wachtrij; "Opnieuw aanbieden" zet ze terug.', false
|
|
42087
|
+
FROM public.user_roles ur WHERE ur.role IN ('planner','admin');
|
|
42088
|
+
END IF;
|
|
42089
|
+
|
|
42090
|
+
UPDATE public.logistics_stock_alerts a SET status='resolved', resolved_at=now(),
|
|
42091
|
+
resolution_reason='automatisch opgelost: order verzonden/afgerond', updated_at=now()
|
|
42092
|
+
FROM public.orders o
|
|
42093
|
+
WHERE o.id = a.order_id AND a.status='open'
|
|
42094
|
+
AND o.status IN ('Verzonden','Gereed voor facturatie','geannuleerd');
|
|
42095
|
+
GET DIAGNOSTICS v_alerts = ROW_COUNT;
|
|
42096
|
+
|
|
42097
|
+
UPDATE public.logistics_stock_alerts a SET status='resolved', resolved_at=now(),
|
|
42098
|
+
resolution_reason='order bestaat niet meer', updated_at=now()
|
|
42099
|
+
WHERE a.status='open' AND a.order_id IS NOT NULL
|
|
42100
|
+
AND NOT EXISTS (SELECT 1 FROM public.orders o WHERE o.id = a.order_id AND o.deleted_at IS NULL);
|
|
42101
|
+
GET DIAGNOSTICS v_gone = ROW_COUNT;
|
|
42102
|
+
|
|
42103
|
+
RETURN jsonb_build_object('blokkadesOpgelost', v_resolved, 'gearchiveerd', v_archived, 'gemeld', v_nieuw,
|
|
42104
|
+
'meldingenOpgelost', v_alerts, 'meldingenZonderOrder', v_gone);
|
|
42105
|
+
END $function$;
|
|
42106
|
+
|
|
42107
|
+
CREATE OR REPLACE FUNCTION public.logistics_cart_plan_overview(p_days integer DEFAULT 2)
|
|
42108
|
+
RETURNS TABLE(order_ref text, delivery_date date, plan_ready boolean, cart_total integer, released boolean, reason text)
|
|
42109
|
+
LANGUAGE plpgsql
|
|
42110
|
+
STABLE SECURITY DEFINER
|
|
42111
|
+
SET search_path TO 'public'
|
|
42112
|
+
AS $function$
|
|
42113
|
+
DECLARE
|
|
42114
|
+
v_days integer := GREATEST(COALESCE(p_days, 2), 1);
|
|
42115
|
+
r record;
|
|
42116
|
+
v_status jsonb;
|
|
42117
|
+
BEGIN
|
|
42118
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_cart_plan_overview');
|
|
42119
|
+
FOR r IN
|
|
42120
|
+
SELECT o.order_number, public.logistics_order_date(o.delivery_date::text) AS ddate
|
|
42121
|
+
FROM public.orders o
|
|
42122
|
+
WHERE o.deleted_at IS NULL
|
|
42123
|
+
AND public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date
|
|
42124
|
+
AND public.logistics_order_date(o.delivery_date::text) < (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date + v_days
|
|
42125
|
+
ORDER BY 2, 1
|
|
42126
|
+
LOOP
|
|
42127
|
+
v_status := public.logistics_cart_plan_status(r.order_number);
|
|
42128
|
+
order_ref := r.order_number;
|
|
42129
|
+
delivery_date := r.ddate;
|
|
42130
|
+
plan_ready := COALESCE((v_status->>'ready')::boolean, false);
|
|
42131
|
+
cart_total := COALESCE((v_status->>'cartTotal')::integer, 0);
|
|
42132
|
+
released := COALESCE((v_status->>'released')::boolean, false);
|
|
42133
|
+
reason := v_status->>'reason';
|
|
42134
|
+
RETURN NEXT;
|
|
42135
|
+
END LOOP;
|
|
42136
|
+
END;
|
|
42137
|
+
$function$;
|
|
42138
|
+
|
|
42139
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_products_trg()
|
|
42140
|
+
RETURNS trigger
|
|
42141
|
+
LANGUAGE plpgsql
|
|
42142
|
+
SECURITY DEFINER
|
|
42143
|
+
SET search_path TO 'public'
|
|
42144
|
+
AS $function$
|
|
42145
|
+
DECLARE r record;
|
|
42146
|
+
BEGIN
|
|
42147
|
+
IF NEW.plant_height_cm IS NOT DISTINCT FROM OLD.plant_height_cm
|
|
42148
|
+
AND NEW.fust_type_id IS NOT DISTINCT FROM OLD.fust_type_id
|
|
42149
|
+
AND NEW.plants_per_crate IS NOT DISTINCT FROM OLD.plants_per_crate
|
|
42150
|
+
AND NEW.crates_per_layer IS NOT DISTINCT FROM OLD.crates_per_layer
|
|
42151
|
+
AND NEW.layers_per_cart IS NOT DISTINCT FROM OLD.layers_per_cart
|
|
42152
|
+
AND NEW.is_layer IS NOT DISTINCT FROM OLD.is_layer THEN
|
|
42153
|
+
RETURN NEW;
|
|
42154
|
+
END IF;
|
|
42155
|
+
|
|
42156
|
+
FOR r IN
|
|
42157
|
+
SELECT DISTINCT o.id
|
|
42158
|
+
FROM logistics_active.order_items oi
|
|
42159
|
+
JOIN public.orders o ON o.id = oi.order_id
|
|
42160
|
+
WHERE oi.product_id = NEW.id
|
|
42161
|
+
AND o.deleted_at IS NULL
|
|
42162
|
+
AND COALESCE(o.is_reservation, false) = false
|
|
42163
|
+
AND o.plan_locked_at IS NULL
|
|
42164
|
+
AND (o.delivery_date IS NULL OR public.logistics_order_date(o.delivery_date::text) >= (now() AT TIME ZONE coalesce(public.logistics_tz(), 'Europe/Amsterdam'))::date)
|
|
42165
|
+
LOOP
|
|
42166
|
+
PERFORM public.logistics_plan_enqueue(r.id, 'product');
|
|
42167
|
+
END LOOP;
|
|
42168
|
+
|
|
42169
|
+
RETURN NEW;
|
|
42170
|
+
END;
|
|
42171
|
+
$function$;
|