@flowselections/logistiek-engine 1.0.177 → 1.0.180
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 +850 -0
- package/dist-lib/components/BeladingIndelingCard.d.ts.map +1 -1
- package/dist-lib/components/BeladingIndelingCard.js +2 -0
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +11 -5
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.js +38 -21
- package/dist-lib/integrations/supabase/types.d.ts +137 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/beladingRegels.d.ts +78 -0
- package/dist-lib/lib/beladingRegels.d.ts.map +1 -0
- package/dist-lib/lib/beladingRegels.js +143 -0
- package/dist-lib/lib/bulkLoadCarrierPlanning.server.js +2 -2
- package/dist-lib/lib/eigenTraysticker.d.ts +17 -0
- package/dist-lib/lib/eigenTraysticker.d.ts.map +1 -0
- package/dist-lib/lib/eigenTraysticker.js +32 -0
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts +35 -3
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +251 -89
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +76 -0
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +26 -2
- package/dist-lib/lib/stickerQueue.server.d.ts +1 -1
- package/dist-lib/lib/stickerQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/stickerQueue.server.js +88 -0
- package/package.json +1 -1
|
@@ -29523,3 +29523,853 @@ BEGIN
|
|
|
29523
29523
|
'documenttype', v_type, 'breedte_mm', v_l.breedte_mm, 'hoogte_mm', v_l.hoogte_mm, 'reden', NULL) || v_extra;
|
|
29524
29524
|
END;
|
|
29525
29525
|
$function$;
|
|
29526
|
+
|
|
29527
|
+
|
|
29528
|
+
-- ===== 1.0.178: fusten en land per kar, eigen traystickers =====
|
|
29529
|
+
-- 1.0.178 A: fusten en land per kar in control_get_todays_carts (achteraan toegevoegd)
|
|
29530
|
+
DO $m$ BEGIN
|
|
29531
|
+
IF pg_get_function_result('public.control_get_todays_carts()'::regprocedure) NOT LIKE '%crates_on_cart%' THEN
|
|
29532
|
+
DROP FUNCTION public.control_get_todays_carts();
|
|
29533
|
+
END IF;
|
|
29534
|
+
END $m$;
|
|
29535
|
+
|
|
29536
|
+
CREATE OR REPLACE FUNCTION public.control_get_todays_carts()
|
|
29537
|
+
RETURNS TABLE(cart_number_id uuid, cart_number text, order_source text, order_id text, cart_index integer, order_number text, pick_date date, status text, printed_at timestamp with time zone, printed_today boolean, crates_on_cart integer, country_code text)
|
|
29538
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
29539
|
+
AS $function$
|
|
29540
|
+
WITH vandaag AS (
|
|
29541
|
+
SELECT (now() AT TIME ZONE public.logistics_tz())::date AS d
|
|
29542
|
+
),
|
|
29543
|
+
idx AS (
|
|
29544
|
+
SELECT DISTINCT ON (i.cart_id) i.*
|
|
29545
|
+
FROM public.logistics_cart_index((SELECT d FROM vandaag), (SELECT d FROM vandaag)) i
|
|
29546
|
+
ORDER BY i.cart_id, i.order_number
|
|
29547
|
+
),
|
|
29548
|
+
gecontroleerd AS (
|
|
29549
|
+
SELECT cci.cart_number_id, cci.order_source, cci.order_id, cci.cart_index
|
|
29550
|
+
FROM public.cart_control_items cci
|
|
29551
|
+
JOIN public.cart_control_sessions ccs ON ccs.id = cci.session_id
|
|
29552
|
+
WHERE ccs.control_date = (SELECT d FROM vandaag)
|
|
29553
|
+
AND cci.action = 'checked'
|
|
29554
|
+
)
|
|
29555
|
+
SELECT
|
|
29556
|
+
i.cart_id,
|
|
29557
|
+
COALESCE(cn.cart_number, i.cart_label),
|
|
29558
|
+
i.order_source,
|
|
29559
|
+
i.order_uuid::text,
|
|
29560
|
+
i.cart_index,
|
|
29561
|
+
i.order_number,
|
|
29562
|
+
i.pick_date,
|
|
29563
|
+
COALESCE(cn.status, 'pending'),
|
|
29564
|
+
i.printed_at,
|
|
29565
|
+
(i.printed_at >= (SELECT d FROM vandaag)::timestamptz),
|
|
29566
|
+
(SELECT sum(ci.crates)::int FROM public.order_cart_items ci WHERE ci.cart_id = i.cart_id),
|
|
29567
|
+
(SELECT CASE WHEN upper(btrim(l.country)) ~ '^[A-Z]{2}$' THEN upper(btrim(l.country)) END
|
|
29568
|
+
FROM public.orders o
|
|
29569
|
+
JOIN public.customer_delivery_locations l
|
|
29570
|
+
ON l.id = public.logistics_try_uuid(o.custom_fields->>'delivery_location')
|
|
29571
|
+
WHERE o.id = i.order_uuid
|
|
29572
|
+
LIMIT 1)
|
|
29573
|
+
FROM idx i
|
|
29574
|
+
LEFT JOIN public.cart_numbers cn
|
|
29575
|
+
ON cn.order_source = i.order_source
|
|
29576
|
+
AND cn.order_id = i.order_uuid::text
|
|
29577
|
+
AND cn.cart_index = i.cart_index
|
|
29578
|
+
LEFT JOIN gecontroleerd g1 ON g1.cart_number_id = i.cart_id
|
|
29579
|
+
LEFT JOIN gecontroleerd g2
|
|
29580
|
+
ON g2.order_source = i.order_source
|
|
29581
|
+
AND g2.order_id = i.order_uuid::text
|
|
29582
|
+
AND g2.cart_index = i.cart_index
|
|
29583
|
+
WHERE COALESCE(cn.status, 'pending') <> 'delivered'
|
|
29584
|
+
AND g1.cart_number_id IS NULL
|
|
29585
|
+
AND g2.order_id IS NULL
|
|
29586
|
+
ORDER BY i.order_number, i.cart_index;
|
|
29587
|
+
$function$;
|
|
29588
|
+
REVOKE ALL ON FUNCTION public.control_get_todays_carts() FROM PUBLIC, anon;
|
|
29589
|
+
GRANT EXECUTE ON FUNCTION public.control_get_todays_carts() TO authenticated, service_role;
|
|
29590
|
+
|
|
29591
|
+
-- 1.0.178 B: eigen traystickers
|
|
29592
|
+
ALTER TABLE public.logistics_sticker_prints DROP CONSTRAINT IF EXISTS logistics_sticker_prints_soort_check;
|
|
29593
|
+
ALTER TABLE public.logistics_sticker_prints ADD CONSTRAINT logistics_sticker_prints_soort_check
|
|
29594
|
+
CHECK (soort = ANY (ARRAY['sticker','traysticker','eigen_sticker','eigen_traysticker']));
|
|
29595
|
+
|
|
29596
|
+
CREATE OR REPLACE FUNCTION public.logistics_own_traysticker_sync(p_limit integer DEFAULT 200)
|
|
29597
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
29598
|
+
AS $function$
|
|
29599
|
+
DECLARE
|
|
29600
|
+
s jsonb; v_tray text; v_rel text; v_station text;
|
|
29601
|
+
r record; v_bron text; v_keep text[] := '{}'; n int := 0; n_geblokkeerd int := 0; n_vrij int := 0; n_uit int := 0;
|
|
29602
|
+
BEGIN
|
|
29603
|
+
SELECT settings INTO s FROM public.logistics_rule_configs
|
|
29604
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
29605
|
+
v_tray := public.logistics_rule_text(s, 'pickstations', 'traysticker_release', 'uit');
|
|
29606
|
+
IF v_tray = 'uit' THEN
|
|
29607
|
+
RETURN jsonb_build_object('trayRelease', v_tray, 'regels', 0);
|
|
29608
|
+
END IF;
|
|
29609
|
+
v_rel := public.logistics_rule_text(s, 'pickstations', 'sticker_release', 'with_pick_release');
|
|
29610
|
+
v_station := CASE WHEN v_rel = 'with_packing_slip'
|
|
29611
|
+
THEN public.logistics_rule_text(s, 'pickstations', 'packing_slip_station', '')
|
|
29612
|
+
ELSE public.logistics_rule_text(s, 'pickstations', 'sticker_station', '') END;
|
|
29613
|
+
|
|
29614
|
+
FOR r IN
|
|
29615
|
+
SELECT o.id AS order_id, o.order_number, ci.cart_id,
|
|
29616
|
+
bool_or(ci.layer_index IS NULL) AS zonder_indeling,
|
|
29617
|
+
array_agg(DISTINCT ci.layer_index) FILTER (WHERE ci.layer_index IS NOT NULL) AS lagen
|
|
29618
|
+
FROM public.orders o
|
|
29619
|
+
JOIN public.order_items oi ON oi.order_id = o.id
|
|
29620
|
+
JOIN public.order_cart_items ci ON ci.order_item_id = oi.id
|
|
29621
|
+
WHERE coalesce(o.order_source, '') <> 'floriday'
|
|
29622
|
+
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
29623
|
+
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
29624
|
+
AND oi.quarantined_at IS NULL
|
|
29625
|
+
AND o.delivery_date >= current_date - 1
|
|
29626
|
+
GROUP BY o.id, o.order_number, ci.cart_id
|
|
29627
|
+
LIMIT greatest(1, p_limit)
|
|
29628
|
+
LOOP
|
|
29629
|
+
IF r.zonder_indeling OR r.lagen IS NULL THEN
|
|
29630
|
+
v_bron := r.order_id::text || ':' || r.cart_id::text || ':geen-indeling';
|
|
29631
|
+
v_keep := v_keep || v_bron;
|
|
29632
|
+
INSERT INTO public.logistics_sticker_prints (soort, bron_id, order_id, order_number, cart_id, kopieen, status, reden)
|
|
29633
|
+
VALUES ('eigen_traysticker', v_bron, r.order_id, r.order_number, r.cart_id, 1, 'geblokkeerd',
|
|
29634
|
+
'Trayindeling ontbreekt voor deze kar: niet elke orderregel heeft een tray (laag). Deel de kar opnieuw in; de rest van de order gaat door.')
|
|
29635
|
+
ON CONFLICT DO NOTHING;
|
|
29636
|
+
n_geblokkeerd := n_geblokkeerd + 1;
|
|
29637
|
+
CONTINUE;
|
|
29638
|
+
END IF;
|
|
29639
|
+
FOR i IN 1 .. array_length(r.lagen, 1) LOOP
|
|
29640
|
+
v_bron := r.order_id::text || ':' || r.cart_id::text || ':' || r.lagen[i]::text;
|
|
29641
|
+
v_keep := v_keep || v_bron;
|
|
29642
|
+
INSERT INTO public.logistics_sticker_prints (soort, bron_id, order_id, order_number, cart_id, kopieen, print_plek_id, status, reden)
|
|
29643
|
+
VALUES ('eigen_traysticker', v_bron, r.order_id, r.order_number, r.cart_id, 1,
|
|
29644
|
+
public.logistics_sticker_cart_plek(r.cart_id, v_station), 'wacht_op_moment', 'Wacht op de pakbon van deze kar.')
|
|
29645
|
+
ON CONFLICT DO NOTHING;
|
|
29646
|
+
n := n + 1;
|
|
29647
|
+
END LOOP;
|
|
29648
|
+
END LOOP;
|
|
29649
|
+
|
|
29650
|
+
-- Indeling hersteld of tray vervallen: niet meer printen (alleen nog niet geprinte rijen).
|
|
29651
|
+
UPDATE public.logistics_sticker_prints p
|
|
29652
|
+
SET status = 'niet_printen', reden = 'Tray hoort niet meer bij deze kar of order vervallen.', updated_at = now()
|
|
29653
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status IN ('wacht_op_moment', 'geblokkeerd', 'klaar')
|
|
29654
|
+
AND NOT (p.bron_id = ANY (v_keep))
|
|
29655
|
+
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE o.delivery_date >= current_date - 1);
|
|
29656
|
+
GET DIAGNOSTICS n_uit = ROW_COUNT;
|
|
29657
|
+
|
|
29658
|
+
-- Vrijgave: met de pakbon van de kar (zoals eigen stickers).
|
|
29659
|
+
UPDATE public.logistics_sticker_prints p
|
|
29660
|
+
SET status = 'klaar', reden = NULL,
|
|
29661
|
+
print_plek_id = coalesce(p.print_plek_id, public.logistics_sticker_cart_plek(p.cart_id, v_station)),
|
|
29662
|
+
updated_at = now()
|
|
29663
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status = 'wacht_op_moment'
|
|
29664
|
+
AND p.cart_id IS NOT NULL AND public.logistics_cart_slip_queued(p.cart_id);
|
|
29665
|
+
GET DIAGNOSTICS n_vrij = ROW_COUNT;
|
|
29666
|
+
|
|
29667
|
+
RETURN jsonb_build_object('trayRelease', v_tray, 'trays', n, 'geblokkeerd', n_geblokkeerd, 'vrijgegeven', n_vrij, 'niet_printen', n_uit);
|
|
29668
|
+
END; $function$;
|
|
29669
|
+
REVOKE ALL ON FUNCTION public.logistics_own_traysticker_sync(integer) FROM PUBLIC, anon, authenticated;
|
|
29670
|
+
GRANT EXECUTE ON FUNCTION public.logistics_own_traysticker_sync(integer) TO service_role;
|
|
29671
|
+
|
|
29672
|
+
CREATE OR REPLACE FUNCTION public.logistics_own_traysticker_payload(p_id uuid)
|
|
29673
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
29674
|
+
AS $function$
|
|
29675
|
+
DECLARE p record; o record; v_laag int; v_nr int; v_tot int; v_loc text; v_prod jsonb;
|
|
29676
|
+
BEGIN
|
|
29677
|
+
SELECT * INTO p FROM public.logistics_sticker_prints WHERE id = p_id AND soort = 'eigen_traysticker';
|
|
29678
|
+
IF p.id IS NULL THEN RETURN jsonb_build_object('ok', false, 'reden', 'Traysticker niet gevonden.'); END IF;
|
|
29679
|
+
v_laag := nullif(split_part(p.bron_id, ':', 3), '')::int;
|
|
29680
|
+
SELECT * INTO o FROM public.orders WHERE id = p.order_id;
|
|
29681
|
+
SELECT count(DISTINCT ci.layer_index),
|
|
29682
|
+
count(DISTINCT ci.layer_index) FILTER (WHERE ci.layer_index <= v_laag)
|
|
29683
|
+
INTO v_tot, v_nr
|
|
29684
|
+
FROM public.order_cart_items ci JOIN public.order_items oi ON oi.id = ci.order_item_id
|
|
29685
|
+
WHERE oi.order_id = p.order_id AND ci.cart_id = p.cart_id AND ci.layer_index IS NOT NULL;
|
|
29686
|
+
SELECT coalesce(jsonb_agg(jsonb_build_object(
|
|
29687
|
+
'artikelnummer', prd.article_number,
|
|
29688
|
+
'naam', coalesce(ci.product_name, oi.product_name),
|
|
29689
|
+
'aantal', coalesce(ci.crates_in_layer, ci.crates)) ORDER BY coalesce(ci.product_name, oi.product_name)), '[]'::jsonb)
|
|
29690
|
+
INTO v_prod
|
|
29691
|
+
FROM public.order_cart_items ci JOIN public.order_items oi ON oi.id = ci.order_item_id
|
|
29692
|
+
LEFT JOIN public.products prd ON prd.id = coalesce(ci.product_id, oi.product_id)
|
|
29693
|
+
WHERE oi.order_id = p.order_id AND ci.cart_id = p.cart_id AND ci.layer_index = v_laag;
|
|
29694
|
+
SELECT nullif(btrim(concat_ws(', ', nullif(btrim(l.name), ''), nullif(btrim(l.city), ''), nullif(btrim(l.country), ''))), '')
|
|
29695
|
+
INTO v_loc
|
|
29696
|
+
FROM public.customer_delivery_locations l
|
|
29697
|
+
WHERE l.id = public.logistics_try_uuid(o.custom_fields->>'delivery_location');
|
|
29698
|
+
IF v_tot IS NULL OR v_tot = 0 OR jsonb_array_length(v_prod) = 0 THEN
|
|
29699
|
+
RETURN jsonb_build_object('ok', false, 'reden', 'Trayindeling ontbreekt voor deze tray. Deel de kar opnieuw in.');
|
|
29700
|
+
END IF;
|
|
29701
|
+
RETURN jsonb_build_object('ok', true, 'payload', jsonb_build_object(
|
|
29702
|
+
'order_id', o.id, 'order_number', o.order_number, 'ordernummer', o.order_number,
|
|
29703
|
+
'klantnaam', o.customer_name, 'leverdatum', o.delivery_date, 'afleverlocatie', v_loc,
|
|
29704
|
+
'cart_id', p.cart_id, 'tray_nummer', v_nr, 'tray_totaal', v_tot, 'tray_producten', v_prod));
|
|
29705
|
+
END; $function$;
|
|
29706
|
+
REVOKE ALL ON FUNCTION public.logistics_own_traysticker_payload(uuid) FROM PUBLIC, anon, authenticated;
|
|
29707
|
+
GRANT EXECUTE ON FUNCTION public.logistics_own_traysticker_payload(uuid) TO service_role;
|
|
29708
|
+
-- ===== 1.0.178 correctie: eigen traysticker per fust =====
|
|
29709
|
+
-- 1.0.178 correctie: eigen traysticker per FUST (niet per laag).
|
|
29710
|
+
-- Sleutel: order:kar:karregel:fustnummer. Crates onbekend: één geblokkeerde rij per karregel.
|
|
29711
|
+
-- Planten op fust x van y binnen een orderregel: ppc, laatste fust = de rest (nooit <= 0).
|
|
29712
|
+
CREATE OR REPLACE FUNCTION public.logistics_tray_plants(p_ppc integer, p_regel_totaal integer, p_fust integer, p_fusten integer)
|
|
29713
|
+
RETURNS integer LANGUAGE sql IMMUTABLE SET search_path = public AS $tp$
|
|
29714
|
+
SELECT CASE
|
|
29715
|
+
WHEN p_ppc IS NULL OR p_ppc <= 0 THEN NULL
|
|
29716
|
+
WHEN p_fust < p_fusten OR p_regel_totaal IS NULL THEN p_ppc
|
|
29717
|
+
WHEN p_regel_totaal - p_ppc * (p_fusten - 1) > 0 THEN p_regel_totaal - p_ppc * (p_fusten - 1)
|
|
29718
|
+
ELSE p_ppc
|
|
29719
|
+
END
|
|
29720
|
+
$tp$;
|
|
29721
|
+
|
|
29722
|
+
CREATE OR REPLACE FUNCTION public.logistics_own_traysticker_sync(p_limit integer DEFAULT 200)
|
|
29723
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
29724
|
+
AS $function$
|
|
29725
|
+
DECLARE
|
|
29726
|
+
s jsonb; v_tray text; v_rel text; v_station text;
|
|
29727
|
+
r record; v_bron text; v_keep text[] := '{}'; n int := 0; n_geblokkeerd int := 0; n_vrij int := 0; n_uit int := 0;
|
|
29728
|
+
BEGIN
|
|
29729
|
+
SELECT settings INTO s FROM public.logistics_rule_configs
|
|
29730
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
29731
|
+
v_tray := public.logistics_rule_text(s, 'pickstations', 'traysticker_release', 'uit');
|
|
29732
|
+
IF v_tray = 'uit' THEN
|
|
29733
|
+
RETURN jsonb_build_object('trayRelease', v_tray, 'regels', 0);
|
|
29734
|
+
END IF;
|
|
29735
|
+
v_rel := public.logistics_rule_text(s, 'pickstations', 'sticker_release', 'with_pick_release');
|
|
29736
|
+
v_station := CASE WHEN v_rel = 'with_packing_slip'
|
|
29737
|
+
THEN public.logistics_rule_text(s, 'pickstations', 'packing_slip_station', '')
|
|
29738
|
+
ELSE public.logistics_rule_text(s, 'pickstations', 'sticker_station', '') END;
|
|
29739
|
+
|
|
29740
|
+
FOR r IN
|
|
29741
|
+
SELECT o.id AS order_id, o.order_number, ci.cart_id, ci.id AS ci_id, ci.crates
|
|
29742
|
+
FROM public.orders o
|
|
29743
|
+
JOIN public.order_items oi ON oi.order_id = o.id
|
|
29744
|
+
JOIN public.order_cart_items ci ON ci.order_item_id = oi.id
|
|
29745
|
+
WHERE coalesce(o.order_source, '') <> 'floriday'
|
|
29746
|
+
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
29747
|
+
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
29748
|
+
AND oi.quarantined_at IS NULL
|
|
29749
|
+
AND o.delivery_date >= current_date - 1
|
|
29750
|
+
ORDER BY o.order_number, ci.cart_id, ci.created_at, ci.id
|
|
29751
|
+
LIMIT greatest(1, p_limit)
|
|
29752
|
+
LOOP
|
|
29753
|
+
IF r.crates IS NULL OR r.crates <= 0 THEN
|
|
29754
|
+
v_bron := r.order_id::text || ':' || r.cart_id::text || ':' || r.ci_id::text || ':onbekend';
|
|
29755
|
+
v_keep := v_keep || v_bron;
|
|
29756
|
+
INSERT INTO public.logistics_sticker_prints (soort, bron_id, order_id, order_number, cart_id, kopieen, status, reden)
|
|
29757
|
+
VALUES ('eigen_traysticker', v_bron, r.order_id, r.order_number, r.cart_id, 1, 'geblokkeerd',
|
|
29758
|
+
'Aantal fusten onbekend voor deze regel op de kar. De rest van de order gaat door.')
|
|
29759
|
+
ON CONFLICT DO NOTHING;
|
|
29760
|
+
n_geblokkeerd := n_geblokkeerd + 1;
|
|
29761
|
+
CONTINUE;
|
|
29762
|
+
END IF;
|
|
29763
|
+
FOR k IN 1 .. r.crates LOOP
|
|
29764
|
+
v_bron := r.order_id::text || ':' || r.cart_id::text || ':' || r.ci_id::text || ':' || k::text;
|
|
29765
|
+
v_keep := v_keep || v_bron;
|
|
29766
|
+
INSERT INTO public.logistics_sticker_prints (soort, bron_id, order_id, order_number, cart_id, kopieen, print_plek_id, status, reden)
|
|
29767
|
+
VALUES ('eigen_traysticker', v_bron, r.order_id, r.order_number, r.cart_id, 1,
|
|
29768
|
+
public.logistics_sticker_cart_plek(r.cart_id, v_station), 'wacht_op_moment', 'Wacht op de pakbon van deze kar.')
|
|
29769
|
+
ON CONFLICT DO NOTHING;
|
|
29770
|
+
n := n + 1;
|
|
29771
|
+
END LOOP;
|
|
29772
|
+
END LOOP;
|
|
29773
|
+
|
|
29774
|
+
-- Oude laagsleutels, vervallen fusten of orders: niet meer printen (alleen nog niet geprinte rijen, geen DELETE).
|
|
29775
|
+
UPDATE public.logistics_sticker_prints p
|
|
29776
|
+
SET status = 'niet_printen', reden = 'Fust hoort niet meer bij deze kar of order vervallen.', updated_at = now()
|
|
29777
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status IN ('wacht_op_moment', 'geblokkeerd', 'klaar')
|
|
29778
|
+
AND NOT (p.bron_id = ANY (v_keep))
|
|
29779
|
+
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE o.delivery_date >= current_date - 1);
|
|
29780
|
+
GET DIAGNOSTICS n_uit = ROW_COUNT;
|
|
29781
|
+
|
|
29782
|
+
UPDATE public.logistics_sticker_prints p
|
|
29783
|
+
SET status = 'klaar', reden = NULL,
|
|
29784
|
+
print_plek_id = coalesce(p.print_plek_id, public.logistics_sticker_cart_plek(p.cart_id, v_station)),
|
|
29785
|
+
updated_at = now()
|
|
29786
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status = 'wacht_op_moment'
|
|
29787
|
+
AND p.cart_id IS NOT NULL AND public.logistics_cart_slip_queued(p.cart_id);
|
|
29788
|
+
GET DIAGNOSTICS n_vrij = ROW_COUNT;
|
|
29789
|
+
|
|
29790
|
+
RETURN jsonb_build_object('trayRelease', v_tray, 'fusten', n, 'geblokkeerd', n_geblokkeerd, 'vrijgegeven', n_vrij, 'niet_printen', n_uit);
|
|
29791
|
+
END; $function$;
|
|
29792
|
+
REVOKE ALL ON FUNCTION public.logistics_own_traysticker_sync(integer) FROM PUBLIC, anon, authenticated;
|
|
29793
|
+
GRANT EXECUTE ON FUNCTION public.logistics_own_traysticker_sync(integer) TO service_role;
|
|
29794
|
+
|
|
29795
|
+
CREATE OR REPLACE FUNCTION public.logistics_own_traysticker_payload(p_id uuid)
|
|
29796
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
29797
|
+
AS $function$
|
|
29798
|
+
DECLARE
|
|
29799
|
+
p record; o record; c record; v_ci uuid; v_k int; v_nr int; v_tot int; v_loc text;
|
|
29800
|
+
v_ppc int; v_regel_tot int; v_item_voor int; v_item_fusten int; v_aantal int; v_prod jsonb;
|
|
29801
|
+
BEGIN
|
|
29802
|
+
SELECT * INTO p FROM public.logistics_sticker_prints WHERE id = p_id AND soort = 'eigen_traysticker';
|
|
29803
|
+
IF p.id IS NULL THEN RETURN jsonb_build_object('ok', false, 'reden', 'Traysticker niet gevonden.'); END IF;
|
|
29804
|
+
v_ci := public.logistics_try_uuid(split_part(p.bron_id, ':', 3));
|
|
29805
|
+
v_k := CASE WHEN split_part(p.bron_id, ':', 4) ~ '^[0-9]+$' THEN split_part(p.bron_id, ':', 4)::int END;
|
|
29806
|
+
IF v_ci IS NULL OR v_k IS NULL THEN
|
|
29807
|
+
RETURN jsonb_build_object('ok', false, 'reden', 'Aantal fusten onbekend');
|
|
29808
|
+
END IF;
|
|
29809
|
+
SELECT ci.*, oi.unit, oi.quantity, oi.plants_per_crate AS ppc_regel, oi.product_name AS oi_naam,
|
|
29810
|
+
prd.article_number, prd.plants_per_crate AS ppc_product, ci.order_item_id AS item_id
|
|
29811
|
+
INTO c
|
|
29812
|
+
FROM public.order_cart_items ci JOIN public.order_items oi ON oi.id = ci.order_item_id
|
|
29813
|
+
LEFT JOIN public.products prd ON prd.id = coalesce(ci.product_id, oi.product_id)
|
|
29814
|
+
WHERE ci.id = v_ci;
|
|
29815
|
+
IF c.id IS NULL OR c.crates IS NULL OR c.crates < v_k THEN
|
|
29816
|
+
RETURN jsonb_build_object('ok', false, 'reden', 'Aantal fusten onbekend');
|
|
29817
|
+
END IF;
|
|
29818
|
+
SELECT * INTO o FROM public.orders WHERE id = p.order_id;
|
|
29819
|
+
|
|
29820
|
+
-- Fustnummer x van y binnen de order (alle karren), volgorde kar, regel, fust.
|
|
29821
|
+
WITH alle AS (
|
|
29822
|
+
SELECT ci.id, ci.crates, row_number() OVER (ORDER BY ci.cart_id, ci.created_at, ci.id) AS rn
|
|
29823
|
+
FROM public.order_cart_items ci JOIN public.order_items oi ON oi.id = ci.order_item_id
|
|
29824
|
+
WHERE oi.order_id = p.order_id AND oi.quarantined_at IS NULL AND coalesce(ci.crates, 0) > 0
|
|
29825
|
+
)
|
|
29826
|
+
SELECT sum(crates)::int,
|
|
29827
|
+
coalesce(sum(crates) FILTER (WHERE rn < (SELECT rn FROM alle WHERE id = v_ci)), 0)::int + v_k
|
|
29828
|
+
INTO v_tot, v_nr FROM alle;
|
|
29829
|
+
|
|
29830
|
+
-- Planten per fust: karregel, dan orderregel, dan product. Laatste fust van de regel: de rest.
|
|
29831
|
+
v_ppc := coalesce(nullif(c.plants_per_crate, 0), nullif(c.ppc_regel, 0), nullif(c.ppc_product, 0))::int;
|
|
29832
|
+
IF v_ppc IS NULL THEN
|
|
29833
|
+
RETURN jsonb_build_object('ok', false, 'reden', 'Planten per fust onbekend (niet op de regel en niet bij het product). Vul planten per fust in.');
|
|
29834
|
+
END IF;
|
|
29835
|
+
v_regel_tot := public.logistics_own_sticker_count(c.unit, c.quantity, c.ppc_regel, c.ppc_product);
|
|
29836
|
+
SELECT coalesce(sum(ci.crates) FILTER (WHERE (ci.cart_id, ci.created_at, ci.id) < (c.cart_id, c.created_at, c.id)), 0)::int,
|
|
29837
|
+
coalesce(sum(ci.crates), 0)::int
|
|
29838
|
+
INTO v_item_voor, v_item_fusten
|
|
29839
|
+
FROM public.order_cart_items ci WHERE ci.order_item_id = c.item_id AND coalesce(ci.crates, 0) > 0;
|
|
29840
|
+
v_aantal := public.logistics_tray_plants(v_ppc, v_regel_tot, v_item_voor + v_k, v_item_fusten);
|
|
29841
|
+
|
|
29842
|
+
v_prod := jsonb_build_array(jsonb_strip_nulls(jsonb_build_object(
|
|
29843
|
+
'artikelnummer', c.article_number,
|
|
29844
|
+
'naam', coalesce(c.product_name, c.oi_naam),
|
|
29845
|
+
'aantal', v_aantal,
|
|
29846
|
+
'onderdelen', CASE WHEN jsonb_typeof(to_jsonb(c.components)) = 'array' AND jsonb_array_length(to_jsonb(c.components)) > 0
|
|
29847
|
+
THEN to_jsonb(c.components) END)));
|
|
29848
|
+
|
|
29849
|
+
SELECT nullif(btrim(concat_ws(', ', nullif(btrim(l.name), ''), nullif(btrim(l.city), ''), nullif(btrim(l.country), ''))), '')
|
|
29850
|
+
INTO v_loc
|
|
29851
|
+
FROM public.customer_delivery_locations l
|
|
29852
|
+
WHERE l.id = public.logistics_try_uuid(o.custom_fields->>'delivery_location');
|
|
29853
|
+
|
|
29854
|
+
RETURN jsonb_build_object('ok', true, 'payload', jsonb_build_object(
|
|
29855
|
+
'order_id', o.id, 'order_number', o.order_number, 'ordernummer', o.order_number,
|
|
29856
|
+
'klantnaam', o.customer_name, 'leverdatum', o.delivery_date, 'afleverlocatie', v_loc,
|
|
29857
|
+
'cart_id', p.cart_id, 'tray_nummer', v_nr, 'tray_totaal', v_tot, 'tray_producten', v_prod));
|
|
29858
|
+
END; $function$;
|
|
29859
|
+
REVOKE ALL ON FUNCTION public.logistics_own_traysticker_payload(uuid) FROM PUBLIC, anon, authenticated;
|
|
29860
|
+
GRANT EXECUTE ON FUNCTION public.logistics_own_traysticker_payload(uuid) TO service_role;
|
|
29861
|
+
|
|
29862
|
+
-- ===== 1.0.179: noodreparaties karindeling =====
|
|
29863
|
+
-- 1.0.179 fase 1: noodreparaties karindeling (alle ordersoorten FO/HO/MO/AO).
|
|
29864
|
+
-- Alleen eigen Engine-objecten; idempotent; geen omgevingswaarden; geen datacorrectie.
|
|
29865
|
+
|
|
29866
|
+
-- 3. Bevestigingen van een onwaarschijnlijke belading: één per order en verpakking.
|
|
29867
|
+
CREATE TABLE IF NOT EXISTS public.logistics_belading_bevestigingen (
|
|
29868
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
29869
|
+
order_id uuid NOT NULL,
|
|
29870
|
+
verpakking_sleutel text NOT NULL,
|
|
29871
|
+
redenen text[] NOT NULL DEFAULT '{}',
|
|
29872
|
+
bevestigd_door uuid,
|
|
29873
|
+
bevestigd_op timestamptz NOT NULL DEFAULT now(),
|
|
29874
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
29875
|
+
UNIQUE (order_id, verpakking_sleutel)
|
|
29876
|
+
);
|
|
29877
|
+
GRANT SELECT ON public.logistics_belading_bevestigingen TO authenticated;
|
|
29878
|
+
GRANT ALL ON public.logistics_belading_bevestigingen TO service_role;
|
|
29879
|
+
ALTER TABLE public.logistics_belading_bevestigingen ENABLE ROW LEVEL SECURITY;
|
|
29880
|
+
DO $p$ BEGIN
|
|
29881
|
+
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename = 'logistics_belading_bevestigingen' AND policyname = 'beheer leest bevestigingen') THEN
|
|
29882
|
+
CREATE POLICY "beheer leest bevestigingen" ON public.logistics_belading_bevestigingen
|
|
29883
|
+
FOR SELECT TO authenticated USING (public.logistics_is_beheer());
|
|
29884
|
+
END IF;
|
|
29885
|
+
END $p$;
|
|
29886
|
+
|
|
29887
|
+
CREATE OR REPLACE FUNCTION public.logistics_belading_bevestig(p_order_id uuid, p_sleutel text, p_redenen text[] DEFAULT '{}')
|
|
29888
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
29889
|
+
AS $function$
|
|
29890
|
+
BEGIN
|
|
29891
|
+
IF NOT public.logistics_is_beheer() THEN
|
|
29892
|
+
RAISE EXCEPTION 'Alleen beheer mag een belading bevestigen.';
|
|
29893
|
+
END IF;
|
|
29894
|
+
IF p_order_id IS NULL OR coalesce(btrim(p_sleutel), '') = '' THEN
|
|
29895
|
+
RAISE EXCEPTION 'Order en verpakking zijn verplicht.';
|
|
29896
|
+
END IF;
|
|
29897
|
+
INSERT INTO public.logistics_belading_bevestigingen (order_id, verpakking_sleutel, redenen, bevestigd_door)
|
|
29898
|
+
VALUES (p_order_id, p_sleutel, coalesce(p_redenen, '{}'), auth.uid())
|
|
29899
|
+
ON CONFLICT (order_id, verpakking_sleutel) DO NOTHING;
|
|
29900
|
+
PERFORM public.logistics_plan_enqueue(p_order_id, 'belading bevestigd');
|
|
29901
|
+
RETURN jsonb_build_object('ok', true);
|
|
29902
|
+
END; $function$;
|
|
29903
|
+
REVOKE ALL ON FUNCTION public.logistics_belading_bevestig(uuid, text, text[]) FROM PUBLIC, anon;
|
|
29904
|
+
GRANT EXECUTE ON FUNCTION public.logistics_belading_bevestig(uuid, text, text[]) TO authenticated, service_role;
|
|
29905
|
+
|
|
29906
|
+
-- 5. Lease bezet: opdracht blijft open en komt later terug (nooit 'done' zonder indeling).
|
|
29907
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_retry_later(p_id uuid, p_seconds integer DEFAULT 30)
|
|
29908
|
+
RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
29909
|
+
AS $function$
|
|
29910
|
+
BEGIN
|
|
29911
|
+
UPDATE public.logistics_plan_queue
|
|
29912
|
+
SET status = 'pending', claimed_at = NULL,
|
|
29913
|
+
next_attempt_at = now() + make_interval(secs => greatest(5, least(coalesce(p_seconds, 30), 600))),
|
|
29914
|
+
error = 'Indeling van deze buffer was bezet; later opnieuw.', updated_at = now()
|
|
29915
|
+
WHERE id = p_id AND status IN ('running', 'pending');
|
|
29916
|
+
END; $function$;
|
|
29917
|
+
REVOKE ALL ON FUNCTION public.logistics_plan_retry_later(uuid, integer) FROM PUBLIC, anon, authenticated;
|
|
29918
|
+
GRANT EXECUTE ON FUNCTION public.logistics_plan_retry_later(uuid, integer) TO service_role;
|
|
29919
|
+
|
|
29920
|
+
-- 6. Oude SQL-indeler onbruikbaar: geen EXECUTE voor PUBLIC, anon of authenticated.
|
|
29921
|
+
DO $r$ BEGIN
|
|
29922
|
+
IF to_regprocedure('public.logistics_plan_all(uuid)') IS NOT NULL THEN
|
|
29923
|
+
REVOKE ALL ON FUNCTION public.logistics_plan_all(uuid) FROM PUBLIC, anon, authenticated;
|
|
29924
|
+
END IF;
|
|
29925
|
+
IF to_regprocedure('public.logistics_plan_buffer_sql(uuid)') IS NOT NULL THEN
|
|
29926
|
+
REVOKE ALL ON FUNCTION public.logistics_plan_buffer_sql(uuid) FROM PUBLIC, anon, authenticated;
|
|
29927
|
+
END IF;
|
|
29928
|
+
END $r$;
|
|
29929
|
+
|
|
29930
|
+
-- 7. Karnummers aan het kar-id (stabiel na herindeling). Kolom en index alleen toevoegen.
|
|
29931
|
+
DO $c$ BEGIN
|
|
29932
|
+
IF to_regclass('public.cart_numbers') IS NULL THEN
|
|
29933
|
+
RAISE NOTICE 'logistiek-engine: cart_numbers ontbreekt (andere module), kar-id-koppeling overgeslagen';
|
|
29934
|
+
ELSE
|
|
29935
|
+
ALTER TABLE public.cart_numbers ADD COLUMN IF NOT EXISTS cart_id uuid;
|
|
29936
|
+
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'cart_numbers_pick_date_cart_id_uniq') THEN
|
|
29937
|
+
IF EXISTS (SELECT 1 FROM public.cart_numbers WHERE cart_id IS NOT NULL GROUP BY pick_date, cart_id HAVING count(*) > 1) THEN
|
|
29938
|
+
RAISE NOTICE 'logistiek-engine: dubbele kar-id per dag in cart_numbers; unieke index niet aangemaakt';
|
|
29939
|
+
ELSE
|
|
29940
|
+
CREATE UNIQUE INDEX cart_numbers_pick_date_cart_id_uniq ON public.cart_numbers (pick_date, cart_id) WHERE cart_id IS NOT NULL;
|
|
29941
|
+
END IF;
|
|
29942
|
+
END IF;
|
|
29943
|
+
END IF;
|
|
29944
|
+
END $c$;
|
|
29945
|
+
|
|
29946
|
+
-- Dubbele kar-indexen per order (twee karren met hetzelfde volgnummer): alleen-lezen lijst.
|
|
29947
|
+
CREATE OR REPLACE FUNCTION public.logistics_cart_seq_dubbel(p_order_uuid uuid DEFAULT NULL)
|
|
29948
|
+
RETURNS TABLE(order_uuid uuid, cart_index integer, cart_ids uuid[])
|
|
29949
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
29950
|
+
AS $function$
|
|
29951
|
+
WITH ruw AS (
|
|
29952
|
+
SELECT oc.id AS cart_id, oc.cart_number AS cart_index, oc.order_id AS order_uuid
|
|
29953
|
+
FROM logistics_active.order_carts oc
|
|
29954
|
+
WHERE oc.order_id IS NOT NULL AND (p_order_uuid IS NULL OR oc.order_id = p_order_uuid)
|
|
29955
|
+
UNION
|
|
29956
|
+
SELECT oc.id, oc.cart_number, oi.order_id
|
|
29957
|
+
FROM logistics_active.order_carts oc
|
|
29958
|
+
JOIN public.order_cart_items oci ON oci.cart_id = oc.id
|
|
29959
|
+
JOIN logistics_active.order_items oi ON oi.id = oci.order_item_id
|
|
29960
|
+
WHERE oc.order_id IS NULL AND oi.order_id IS NOT NULL AND (p_order_uuid IS NULL OR oi.order_id = p_order_uuid)
|
|
29961
|
+
)
|
|
29962
|
+
SELECT order_uuid, cart_index, array_agg(DISTINCT cart_id ORDER BY cart_id)
|
|
29963
|
+
FROM ruw GROUP BY order_uuid, cart_index HAVING count(DISTINCT cart_id) > 1;
|
|
29964
|
+
$function$;
|
|
29965
|
+
REVOKE ALL ON FUNCTION public.logistics_cart_seq_dubbel(uuid) FROM PUBLIC, anon, authenticated;
|
|
29966
|
+
GRANT EXECUTE ON FUNCTION public.logistics_cart_seq_dubbel(uuid) TO service_role;
|
|
29967
|
+
|
|
29968
|
+
-- logistics_cart_seq: nooit stil een kar laten vallen. Bij een dubbel volgnummer: fout.
|
|
29969
|
+
-- Karnummer eerst via kar-id, anders via order + index (bestaande nummers).
|
|
29970
|
+
CREATE OR REPLACE FUNCTION public.logistics_cart_seq(p_order_uuid uuid DEFAULT NULL::uuid)
|
|
29971
|
+
RETURNS TABLE(order_uuid uuid, cart_id uuid, cart_index integer, cart_seq integer, cart_number text, cart_total integer)
|
|
29972
|
+
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
29973
|
+
AS $function$
|
|
29974
|
+
DECLARE d record;
|
|
29975
|
+
BEGIN
|
|
29976
|
+
SELECT * INTO d FROM public.logistics_cart_seq_dubbel(p_order_uuid) LIMIT 1;
|
|
29977
|
+
IF d.order_uuid IS NOT NULL THEN
|
|
29978
|
+
RAISE EXCEPTION 'Karnummering ongeldig: order % heeft % karren met volgnummer %. Deel de order opnieuw in; er wordt geen kar weggelaten.',
|
|
29979
|
+
d.order_uuid, array_length(d.cart_ids, 1), d.cart_index;
|
|
29980
|
+
END IF;
|
|
29981
|
+
RETURN QUERY
|
|
29982
|
+
WITH deelname AS (
|
|
29983
|
+
SELECT oc.id AS cart_id, oc.cart_number AS cart_index, oc.order_id AS order_uuid
|
|
29984
|
+
FROM public.order_carts oc
|
|
29985
|
+
WHERE oc.order_id IS NOT NULL AND (p_order_uuid IS NULL OR oc.order_id = p_order_uuid)
|
|
29986
|
+
UNION
|
|
29987
|
+
SELECT oc.id, oc.cart_number, oi.order_id
|
|
29988
|
+
FROM public.order_carts oc
|
|
29989
|
+
JOIN public.order_cart_items oci ON oci.cart_id = oc.id
|
|
29990
|
+
JOIN logistics_active.order_items oi ON oi.id = oci.order_item_id
|
|
29991
|
+
WHERE oc.order_id IS NULL AND oi.order_id IS NOT NULL AND (p_order_uuid IS NULL OR oi.order_id = p_order_uuid)
|
|
29992
|
+
),
|
|
29993
|
+
genummerd AS (
|
|
29994
|
+
SELECT dd.order_uuid, dd.cart_id, dd.cart_index,
|
|
29995
|
+
dense_rank() OVER (PARTITION BY dd.order_uuid ORDER BY dd.cart_index)::int AS cart_seq,
|
|
29996
|
+
count(*) OVER (PARTITION BY dd.order_uuid)::int AS cart_total
|
|
29997
|
+
FROM deelname dd
|
|
29998
|
+
)
|
|
29999
|
+
SELECT g.order_uuid, g.cart_id, g.cart_index, g.cart_seq,
|
|
30000
|
+
COALESCE(
|
|
30001
|
+
(SELECT cn.cart_number FROM public.cart_numbers cn WHERE cn.cart_id = g.cart_id ORDER BY cn.assigned_at DESC LIMIT 1),
|
|
30002
|
+
(SELECT cn.cart_number FROM public.cart_numbers cn WHERE cn.order_id = g.order_uuid::text AND cn.cart_index = g.cart_index LIMIT 1),
|
|
30003
|
+
g.cart_seq::text),
|
|
30004
|
+
g.cart_total
|
|
30005
|
+
FROM genummerd g;
|
|
30006
|
+
END; $function$;
|
|
30007
|
+
REVOKE ALL ON FUNCTION public.logistics_cart_seq(uuid) FROM PUBLIC, anon;
|
|
30008
|
+
GRANT EXECUTE ON FUNCTION public.logistics_cart_seq(uuid) TO authenticated, service_role;
|
|
30009
|
+
|
|
30010
|
+
-- 8. Kar wisselen: eerst vergrendelen en pickup_locked controleren, dan pas verwijderen; geen stille 1.
|
|
30011
|
+
CREATE OR REPLACE FUNCTION public.logistics_apply_cart_swap(p_delete_ids uuid[], p_new_carts jsonb)
|
|
30012
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
30013
|
+
AS $function$
|
|
30014
|
+
DECLARE
|
|
30015
|
+
v_del uuid[] := COALESCE(p_delete_ids, ARRAY[]::uuid[]);
|
|
30016
|
+
v_cart jsonb; v_row jsonb; v_id uuid; v_map jsonb := '[]'::jsonb;
|
|
30017
|
+
v_jobs int := 0; v_carts int := 0; v_items int := 0; v_locked int;
|
|
30018
|
+
BEGIN
|
|
30019
|
+
IF jsonb_typeof(COALESCE(p_new_carts, '[]'::jsonb)) <> 'array' THEN
|
|
30020
|
+
RAISE EXCEPTION 'Nieuwe karren ontbreken of zijn ongeldig.';
|
|
30021
|
+
END IF;
|
|
30022
|
+
IF EXISTS (
|
|
30023
|
+
SELECT 1 FROM jsonb_array_elements(COALESCE(p_new_carts, '[]'::jsonb)) c,
|
|
30024
|
+
jsonb_array_elements(COALESCE(c.value->'items', '[]'::jsonb)) i
|
|
30025
|
+
WHERE coalesce((i.value->>'plants_per_crate')::numeric, 0) <= 0
|
|
30026
|
+
OR coalesce((i.value->>'crates')::numeric, 0) < 0) THEN
|
|
30027
|
+
RAISE EXCEPTION 'Karwissel geweigerd: een karregel mist planten per fust (belading_onvolledig).';
|
|
30028
|
+
END IF;
|
|
30029
|
+
|
|
30030
|
+
IF array_length(v_del, 1) IS NOT NULL THEN
|
|
30031
|
+
PERFORM 1 FROM public.order_carts WHERE id = ANY(v_del) ORDER BY id FOR UPDATE;
|
|
30032
|
+
SELECT count(*) INTO v_locked FROM public.order_carts WHERE id = ANY(v_del) AND COALESCE(pickup_locked, false);
|
|
30033
|
+
IF v_locked > 0 THEN
|
|
30034
|
+
RAISE EXCEPTION 'Karwissel geweigerd: % kar(ren) zijn al vastgezet (opgehaald). Er is niets gewijzigd.', v_locked;
|
|
30035
|
+
END IF;
|
|
30036
|
+
UPDATE public.print_jobs
|
|
30037
|
+
SET status = 'geannuleerd'::print_job_status,
|
|
30038
|
+
foutmelding = 'Vervallen: kar verwijderd bij herindeling',
|
|
30039
|
+
updated_at = now()
|
|
30040
|
+
WHERE status IN ('wachtend'::print_job_status, 'bezig'::print_job_status)
|
|
30041
|
+
AND (payload->>'cart_id') = ANY(SELECT id::text FROM unnest(v_del) AS id);
|
|
30042
|
+
GET DIAGNOSTICS v_jobs = ROW_COUNT;
|
|
30043
|
+
DELETE FROM public.pakbon_barcode_inhoud WHERE cart_id = ANY(SELECT id::text FROM unnest(v_del) AS id);
|
|
30044
|
+
DELETE FROM public.order_cart_layer_positions WHERE cart_id = ANY(v_del);
|
|
30045
|
+
DELETE FROM public.order_cart_items WHERE cart_id = ANY(v_del);
|
|
30046
|
+
DELETE FROM public.order_carts WHERE id = ANY(v_del);
|
|
30047
|
+
GET DIAGNOSTICS v_carts = ROW_COUNT;
|
|
30048
|
+
END IF;
|
|
30049
|
+
|
|
30050
|
+
FOR v_cart IN SELECT value FROM jsonb_array_elements(COALESCE(p_new_carts, '[]'::jsonb)) LOOP
|
|
30051
|
+
v_row := v_cart->'row';
|
|
30052
|
+
v_id := gen_random_uuid();
|
|
30053
|
+
INSERT INTO public.order_carts (id, order_id, buffer_id, cart_number, total_carts, is_auto, is_complete, source,
|
|
30054
|
+
occupancy_pct, total_layers_used, carrier_type, carrier_type_id, max_layers, weight_kg, algorithm_version, layout_method)
|
|
30055
|
+
SELECT v_id, r.order_id, r.buffer_id, r.cart_number, r.total_carts, COALESCE(r.is_auto, true), COALESCE(r.is_complete, false),
|
|
30056
|
+
COALESCE(r.source, 'auto'), COALESCE(r.occupancy_pct, 0), COALESCE(r.total_layers_used, 0),
|
|
30057
|
+
COALESCE(r.carrier_type, 'trolley'), r.carrier_type_id, r.max_layers, r.weight_kg, COALESCE(r.algorithm_version, 1), r.layout_method
|
|
30058
|
+
FROM jsonb_to_record(v_row) AS r(order_id uuid, buffer_id uuid, cart_number integer, total_carts integer, is_auto boolean,
|
|
30059
|
+
is_complete boolean, source text, occupancy_pct numeric, total_layers_used numeric, carrier_type text, carrier_type_id uuid,
|
|
30060
|
+
max_layers integer, weight_kg numeric, algorithm_version integer, layout_method text);
|
|
30061
|
+
|
|
30062
|
+
INSERT INTO public.order_cart_items (cart_id, order_item_id, product_id, product_name, crates, boxes, weight_kg,
|
|
30063
|
+
plants_per_crate, crates_per_layer, layers_per_cart, layer_fraction, layer_share_pct, layer_index, crates_in_layer, components)
|
|
30064
|
+
SELECT v_id, i.order_item_id, i.product_id, i.product_name, i.crates, i.boxes, i.weight_kg,
|
|
30065
|
+
i.plants_per_crate, COALESCE(i.crates_per_layer, 1), COALESCE(i.layers_per_cart, 1),
|
|
30066
|
+
COALESCE(i.layer_fraction, 0), COALESCE(i.layer_share_pct, 0), i.layer_index, i.crates_in_layer,
|
|
30067
|
+
CASE WHEN jsonb_typeof(i.components) = 'array' THEN i.components END
|
|
30068
|
+
FROM jsonb_to_recordset(COALESCE(v_cart->'items', '[]'::jsonb)) AS i(order_item_id uuid, product_id uuid, product_name text,
|
|
30069
|
+
crates integer, boxes integer, weight_kg numeric, plants_per_crate integer, crates_per_layer integer, layers_per_cart integer,
|
|
30070
|
+
layer_fraction numeric, layer_share_pct numeric, layer_index integer, crates_in_layer integer, components jsonb);
|
|
30071
|
+
v_items := v_items + jsonb_array_length(COALESCE(v_cart->'items', '[]'::jsonb));
|
|
30072
|
+
v_map := v_map || jsonb_build_object('planIndex', (v_cart->>'planIndex')::integer, 'id', v_id);
|
|
30073
|
+
END LOOP;
|
|
30074
|
+
|
|
30075
|
+
RETURN jsonb_build_object('karren', v_map, 'verwijderd', v_carts, 'printopdrachtenGeannuleerd', v_jobs, 'regels', v_items);
|
|
30076
|
+
END;
|
|
30077
|
+
$function$;
|
|
30078
|
+
REVOKE ALL ON FUNCTION public.logistics_apply_cart_swap(uuid[], jsonb) FROM PUBLIC, anon, authenticated;
|
|
30079
|
+
GRANT EXECUTE ON FUNCTION public.logistics_apply_cart_swap(uuid[], jsonb) TO service_role;
|
|
30080
|
+
|
|
30081
|
+
-- 1. Autofix schrijft alleen een volledige, positieve Floriday-verpakking weg (0 = onbekend).
|
|
30082
|
+
CREATE OR REPLACE FUNCTION public.logistics_packing_autofix(p_limit integer DEFAULT 100)
|
|
30083
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
30084
|
+
AS $function$
|
|
30085
|
+
DECLARE r record; v_reden text; v_aantal integer := 0; v_ppc int; v_cpl int; v_lpc int;
|
|
30086
|
+
BEGIN
|
|
30087
|
+
FOR r IN
|
|
30088
|
+
SELECT d.* FROM public.logistics_packing_deviations d
|
|
30089
|
+
WHERE d.resolved_at IS NULL AND d.scope = 'order_line' AND d.needs_human = false
|
|
30090
|
+
AND d.order_id IS NOT NULL AND d.order_item_id IS NOT NULL
|
|
30091
|
+
ORDER BY d.first_seen_at
|
|
30092
|
+
LIMIT GREATEST(1, LEAST(p_limit, 500))
|
|
30093
|
+
LOOP
|
|
30094
|
+
v_reden := public.logistics_packing_block_reason(r.order_id, r.order_item_id);
|
|
30095
|
+
IF v_reden IS NOT NULL THEN
|
|
30096
|
+
UPDATE public.logistics_packing_deviations SET needs_human = true, human_reason = v_reden WHERE id = r.id;
|
|
30097
|
+
CONTINUE;
|
|
30098
|
+
END IF;
|
|
30099
|
+
v_ppc := nullif(greatest(coalesce((r.floriday_packing->>'pieces_per_package')::numeric, 0), 0), 0)::int;
|
|
30100
|
+
v_cpl := nullif(greatest(coalesce((r.floriday_packing->>'packages_per_layer')::numeric, 0), 0), 0)::int;
|
|
30101
|
+
v_lpc := nullif(greatest(coalesce((r.floriday_packing->>'layers_per_load_carrier')::numeric, 0), 0), 0)::int;
|
|
30102
|
+
IF v_ppc IS NULL OR v_cpl IS NULL OR v_lpc IS NULL THEN
|
|
30103
|
+
UPDATE public.logistics_packing_deviations
|
|
30104
|
+
SET needs_human = true,
|
|
30105
|
+
human_reason = 'Floriday-verpakking onvolledig (0 of leeg = onbekend); niet automatisch overgenomen.'
|
|
30106
|
+
WHERE id = r.id;
|
|
30107
|
+
CONTINUE;
|
|
30108
|
+
END IF;
|
|
30109
|
+
UPDATE public.order_items oi
|
|
30110
|
+
SET plants_per_crate = v_ppc, crates_per_layer = v_cpl, layers_per_cart = v_lpc
|
|
30111
|
+
WHERE oi.id = r.order_item_id AND oi.packing_locked_at IS NULL;
|
|
30112
|
+
IF FOUND THEN
|
|
30113
|
+
v_aantal := v_aantal + 1;
|
|
30114
|
+
UPDATE public.logistics_packing_deviations
|
|
30115
|
+
SET auto_fixed_at = now(), resolved_at = now(), human_reason = 'automatisch bijgewerkt naar de Floriday-stand'
|
|
30116
|
+
WHERE id = r.id;
|
|
30117
|
+
PERFORM public.logistics_trace_event(r.order_id, 'stap:belading_synchronisatie', 'ok', 'belading bijgewerkt naar de Floriday-stand');
|
|
30118
|
+
END IF;
|
|
30119
|
+
END LOOP;
|
|
30120
|
+
RETURN v_aantal;
|
|
30121
|
+
END;
|
|
30122
|
+
$function$;
|
|
30123
|
+
|
|
30124
|
+
-- 9. Reconcile alleen bij een echte wijziging sinds de laatste afgeronde of geblokkeerde opdracht; kleinere porties.
|
|
30125
|
+
CREATE OR REPLACE FUNCTION public.logistics_reconcile_missing_plan_queue()
|
|
30126
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
30127
|
+
AS $function$
|
|
30128
|
+
DECLARE r record; n integer := 0;
|
|
30129
|
+
BEGIN
|
|
30130
|
+
FOR r IN
|
|
30131
|
+
SELECT o.id FROM public.orders o
|
|
30132
|
+
WHERE o.deleted_at IS NULL
|
|
30133
|
+
AND COALESCE(o.is_reservation,false) = false
|
|
30134
|
+
AND o.plan_locked_at IS NULL
|
|
30135
|
+
AND o.order_number IS NOT NULL
|
|
30136
|
+
AND (o.created_at >= now() - interval '14 days' OR o.updated_at >= now() - interval '14 days')
|
|
30137
|
+
AND NOT EXISTS (SELECT 1 FROM public.logistics_tasks t WHERE t.order_ref = o.order_number)
|
|
30138
|
+
AND NOT EXISTS (SELECT 1 FROM public.logistics_plan_queue q
|
|
30139
|
+
WHERE q.order_id = o.id AND q.status IN ('pending','running'))
|
|
30140
|
+
AND NOT EXISTS (
|
|
30141
|
+
SELECT 1 FROM public.logistics_plan_queue q
|
|
30142
|
+
WHERE q.order_id = o.id AND q.status IN ('geblokkeerd', 'done', 'opgelost')
|
|
30143
|
+
AND q.updated_at >= COALESCE(o.updated_at, o.created_at)
|
|
30144
|
+
AND NOT EXISTS (SELECT 1 FROM logistics_active.order_items oi WHERE oi.order_id = o.id AND oi.created_at > q.updated_at)
|
|
30145
|
+
AND NOT EXISTS (SELECT 1 FROM logistics_active.order_items oi JOIN public.products p ON p.id = oi.product_id
|
|
30146
|
+
WHERE oi.order_id = o.id AND p.updated_at > q.updated_at))
|
|
30147
|
+
ORDER BY o.created_at ASC
|
|
30148
|
+
LIMIT 100
|
|
30149
|
+
LOOP
|
|
30150
|
+
PERFORM public.logistics_plan_enqueue(r.id, 'reconcile');
|
|
30151
|
+
n := n + 1;
|
|
30152
|
+
END LOOP;
|
|
30153
|
+
RETURN n;
|
|
30154
|
+
END;
|
|
30155
|
+
$function$;
|
|
30156
|
+
|
|
30157
|
+
-- 9. Eén open opdracht per order (index alleen als er geen dubbele open opdrachten zijn).
|
|
30158
|
+
DO $q$ BEGIN
|
|
30159
|
+
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'logistics_plan_queue_open_uniq') THEN
|
|
30160
|
+
IF EXISTS (SELECT 1 FROM public.logistics_plan_queue WHERE status IN ('pending','running','geblokkeerd')
|
|
30161
|
+
GROUP BY order_id HAVING count(*) > 1) THEN
|
|
30162
|
+
RAISE NOTICE 'logistiek-engine: dubbele open planopdrachten; unieke index wacht op samenvoegen (akkoord nodig)';
|
|
30163
|
+
ELSE
|
|
30164
|
+
CREATE UNIQUE INDEX logistics_plan_queue_open_uniq ON public.logistics_plan_queue (order_id)
|
|
30165
|
+
WHERE status IN ('pending','running','geblokkeerd');
|
|
30166
|
+
END IF;
|
|
30167
|
+
END IF;
|
|
30168
|
+
END $q$;
|
|
30169
|
+
|
|
30170
|
+
-- Alleen-lezen lijst: orders met meer dan één open planopdracht.
|
|
30171
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_queue_dubbel()
|
|
30172
|
+
RETURNS TABLE(order_id uuid, open_opdrachten bigint, oudste timestamptz, nieuwste timestamptz)
|
|
30173
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
30174
|
+
AS $function$
|
|
30175
|
+
SELECT q.order_id, count(*), min(q.enqueued_at), max(q.enqueued_at)
|
|
30176
|
+
FROM public.logistics_plan_queue q
|
|
30177
|
+
WHERE q.status IN ('pending','running','geblokkeerd')
|
|
30178
|
+
GROUP BY q.order_id HAVING count(*) > 1;
|
|
30179
|
+
$function$;
|
|
30180
|
+
REVOKE ALL ON FUNCTION public.logistics_plan_queue_dubbel() FROM PUBLIC, anon, authenticated;
|
|
30181
|
+
GRANT EXECUTE ON FUNCTION public.logistics_plan_queue_dubbel() TO service_role;
|
|
30182
|
+
|
|
30183
|
+
-- 10. Buffer uit: elke order krijgt een eigen buffer (sleutel solo:<order-id>) en wordt dus per order ingedeeld.
|
|
30184
|
+
CREATE OR REPLACE FUNCTION public.logistics_apply_buffer_decision(p_order_id uuid)
|
|
30185
|
+
RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
30186
|
+
AS $function$
|
|
30187
|
+
DECLARE
|
|
30188
|
+
o public.orders%ROWTYPE;
|
|
30189
|
+
cf jsonb; d jsonb; v_ref text; v_close timestamptz; v_key text;
|
|
30190
|
+
v_buffer uuid; v_closed boolean; v_try int := 0; v_on_cart boolean; v_solo boolean := false;
|
|
30191
|
+
BEGIN
|
|
30192
|
+
SELECT * INTO o FROM public.orders WHERE id = p_order_id;
|
|
30193
|
+
IF NOT FOUND OR o.deleted_at IS NOT NULL THEN RETURN NULL; END IF;
|
|
30194
|
+
cf := COALESCE(o.custom_fields, '{}'::jsonb);
|
|
30195
|
+
|
|
30196
|
+
IF public.logistics_order_buffer_excluded(o.id) THEN
|
|
30197
|
+
IF o.buffer_id IS NOT NULL THEN
|
|
30198
|
+
SELECT EXISTS (SELECT 1 FROM public.order_items oi
|
|
30199
|
+
JOIN logistics_active.order_cart_items ci ON ci.order_item_id = oi.id
|
|
30200
|
+
JOIN logistics_active.order_carts oc ON oc.id = ci.cart_id
|
|
30201
|
+
WHERE oi.order_id = o.id AND oc.buffer_id = o.buffer_id)
|
|
30202
|
+
INTO v_on_cart;
|
|
30203
|
+
IF NOT v_on_cart THEN
|
|
30204
|
+
PERFORM set_config('logistics.buffer_writer', 'engine', true);
|
|
30205
|
+
UPDATE public.orders SET buffer_id = NULL WHERE id = o.id;
|
|
30206
|
+
BEGIN
|
|
30207
|
+
INSERT INTO public.logistics_planner_trace(order_id, message)
|
|
30208
|
+
VALUES (o.id, 'afgemeld; uit buffer gehaald');
|
|
30209
|
+
EXCEPTION WHEN others THEN NULL; END;
|
|
30210
|
+
END IF;
|
|
30211
|
+
END IF;
|
|
30212
|
+
RETURN NULL;
|
|
30213
|
+
END IF;
|
|
30214
|
+
|
|
30215
|
+
d := public.logistics_buffer_decision(public.logistics_buffer_payload(o.id), NULL);
|
|
30216
|
+
|
|
30217
|
+
IF (d ->> 'reason') = 'buffering_disabled' THEN
|
|
30218
|
+
v_solo := true;
|
|
30219
|
+
ELSIF COALESCE((d ->> 'buffer')::boolean, false) IS NOT TRUE OR (d ->> 'bufferRef') IS NULL THEN
|
|
30220
|
+
IF o.buffer_id IS NOT NULL THEN
|
|
30221
|
+
UPDATE public.order_carts SET buffer_id = NULL WHERE order_id = o.id;
|
|
30222
|
+
PERFORM set_config('logistics.buffer_writer', 'engine', true);
|
|
30223
|
+
UPDATE public.orders SET buffer_id = NULL WHERE id = o.id;
|
|
30224
|
+
END IF;
|
|
30225
|
+
DELETE FROM public.order_buffers b
|
|
30226
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.orders x WHERE x.buffer_id = b.id)
|
|
30227
|
+
AND NOT EXISTS (SELECT 1 FROM public.order_carts oc WHERE oc.buffer_id = b.id);
|
|
30228
|
+
RETURN NULL;
|
|
30229
|
+
END IF;
|
|
30230
|
+
|
|
30231
|
+
IF v_solo THEN
|
|
30232
|
+
v_ref := 'solo:' || o.id::text;
|
|
30233
|
+
v_close := NULL;
|
|
30234
|
+
ELSE
|
|
30235
|
+
v_ref := d ->> 'bufferRef';
|
|
30236
|
+
BEGIN v_close := NULLIF(d ->> 'bufferCloseAt', '')::timestamptz;
|
|
30237
|
+
EXCEPTION WHEN others THEN v_close := NULL; END;
|
|
30238
|
+
END IF;
|
|
30239
|
+
|
|
30240
|
+
LOOP
|
|
30241
|
+
v_key := CASE WHEN v_try = 0 THEN v_ref ELSE v_ref || '#' || v_try END;
|
|
30242
|
+
SELECT id INTO v_buffer FROM public.order_buffers WHERE buffer_key = v_key;
|
|
30243
|
+
IF v_buffer IS NULL THEN
|
|
30244
|
+
INSERT INTO public.order_buffers (buffer_key, grouping_mode, pickup_date, pickup_location, customer_id, close_at)
|
|
30245
|
+
VALUES (v_key, CASE WHEN v_solo THEN 'solo' ELSE 'engine' END,
|
|
30246
|
+
COALESCE(cf ->> 'pickup_moment', cf ->> 'pickup_date', o.delivery_date::text),
|
|
30247
|
+
COALESCE(cf ->> 'delivery_location_gln', cf ->> 'delivery_location_id', cf ->> 'delivery_location'),
|
|
30248
|
+
o.customer_id, v_close)
|
|
30249
|
+
ON CONFLICT (buffer_key) DO UPDATE SET grouping_mode = EXCLUDED.grouping_mode
|
|
30250
|
+
RETURNING id INTO v_buffer;
|
|
30251
|
+
EXIT;
|
|
30252
|
+
END IF;
|
|
30253
|
+
IF o.buffer_id = v_buffer OR v_solo THEN EXIT; END IF;
|
|
30254
|
+
|
|
30255
|
+
v_closed := public.logistics_buffer_closed_for_join(v_buffer);
|
|
30256
|
+
IF NOT COALESCE(v_closed, false) THEN
|
|
30257
|
+
UPDATE public.order_buffers
|
|
30258
|
+
SET close_at = LEAST(COALESCE(close_at, v_close), COALESCE(v_close, close_at)), updated_at = now()
|
|
30259
|
+
WHERE id = v_buffer;
|
|
30260
|
+
EXIT;
|
|
30261
|
+
END IF;
|
|
30262
|
+
UPDATE public.order_buffers SET closed_at = COALESCE(closed_at, now()), updated_at = now() WHERE id = v_buffer;
|
|
30263
|
+
v_try := v_try + 1; v_buffer := NULL;
|
|
30264
|
+
IF v_try > 50 THEN RAISE EXCEPTION 'Kan geen open orderbuffer vinden voor sleutel %', v_ref; END IF;
|
|
30265
|
+
END LOOP;
|
|
30266
|
+
|
|
30267
|
+
IF o.buffer_id IS DISTINCT FROM v_buffer THEN
|
|
30268
|
+
PERFORM set_config('logistics.buffer_writer', 'engine', true);
|
|
30269
|
+
UPDATE public.orders SET buffer_id = v_buffer WHERE id = o.id;
|
|
30270
|
+
DELETE FROM public.order_buffers b
|
|
30271
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.orders x WHERE x.buffer_id = b.id)
|
|
30272
|
+
AND NOT EXISTS (SELECT 1 FROM public.order_carts oc WHERE oc.buffer_id = b.id);
|
|
30273
|
+
END IF;
|
|
30274
|
+
RETURN v_buffer;
|
|
30275
|
+
END;
|
|
30276
|
+
$function$;
|
|
30277
|
+
|
|
30278
|
+
-- 13. Eigen traystickers: zolang bij één regel van de order het fustaantal onbekend is, wachten ALLE
|
|
30279
|
+
-- eigen traystickers van die order ("Fustaantal van regel X onbekend"), zodat x van y klopt.
|
|
30280
|
+
CREATE OR REPLACE FUNCTION public.logistics_own_traysticker_sync(p_limit integer DEFAULT 200)
|
|
30281
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
30282
|
+
AS $function$
|
|
30283
|
+
DECLARE
|
|
30284
|
+
s jsonb; v_tray text; v_rel text; v_station text;
|
|
30285
|
+
r record; v_bron text; v_keep text[] := '{}'; v_wacht_orders uuid[] := '{}';
|
|
30286
|
+
n int := 0; n_geblokkeerd int := 0; n_vrij int := 0; n_uit int := 0;
|
|
30287
|
+
BEGIN
|
|
30288
|
+
SELECT settings INTO s FROM public.logistics_rule_configs
|
|
30289
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
30290
|
+
v_tray := public.logistics_rule_text(s, 'pickstations', 'traysticker_release', 'uit');
|
|
30291
|
+
IF v_tray = 'uit' THEN
|
|
30292
|
+
RETURN jsonb_build_object('trayRelease', v_tray, 'regels', 0);
|
|
30293
|
+
END IF;
|
|
30294
|
+
v_rel := public.logistics_rule_text(s, 'pickstations', 'sticker_release', 'with_pick_release');
|
|
30295
|
+
v_station := CASE WHEN v_rel = 'with_packing_slip'
|
|
30296
|
+
THEN public.logistics_rule_text(s, 'pickstations', 'packing_slip_station', '')
|
|
30297
|
+
ELSE public.logistics_rule_text(s, 'pickstations', 'sticker_station', '') END;
|
|
30298
|
+
|
|
30299
|
+
FOR r IN
|
|
30300
|
+
WITH regels AS (
|
|
30301
|
+
SELECT o.id AS order_id, o.order_number, ci.cart_id, ci.id AS ci_id, ci.crates, ci.created_at,
|
|
30302
|
+
coalesce(ci.product_name, oi.product_name, 'onbekend') AS regelnaam
|
|
30303
|
+
FROM public.orders o
|
|
30304
|
+
JOIN public.order_items oi ON oi.order_id = o.id
|
|
30305
|
+
JOIN public.order_cart_items ci ON ci.order_item_id = oi.id
|
|
30306
|
+
WHERE coalesce(o.order_source, '') <> 'floriday'
|
|
30307
|
+
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
30308
|
+
AND coalesce(o.status, '') <> 'geannuleerd'
|
|
30309
|
+
AND oi.quarantined_at IS NULL
|
|
30310
|
+
AND o.delivery_date >= current_date - 1
|
|
30311
|
+
)
|
|
30312
|
+
SELECT g.*,
|
|
30313
|
+
(SELECT min(x.regelnaam) FROM regels x WHERE x.order_id = g.order_id AND coalesce(x.crates, 0) <= 0) AS onbekende_regel
|
|
30314
|
+
FROM regels g
|
|
30315
|
+
ORDER BY g.order_number, g.cart_id, g.created_at, g.ci_id
|
|
30316
|
+
LIMIT greatest(1, p_limit)
|
|
30317
|
+
LOOP
|
|
30318
|
+
IF r.onbekende_regel IS NOT NULL THEN
|
|
30319
|
+
v_wacht_orders := v_wacht_orders || r.order_id;
|
|
30320
|
+
v_bron := r.order_id::text || ':fustaantal-onbekend';
|
|
30321
|
+
v_keep := v_keep || v_bron;
|
|
30322
|
+
INSERT INTO public.logistics_sticker_prints (soort, bron_id, order_id, order_number, cart_id, kopieen, status, reden)
|
|
30323
|
+
VALUES ('eigen_traysticker', v_bron, r.order_id, r.order_number, NULL, 1, 'geblokkeerd',
|
|
30324
|
+
'Fustaantal van regel ' || r.onbekende_regel || ' onbekend. Alle traystickers van deze order wachten, zodat de nummering klopt.')
|
|
30325
|
+
ON CONFLICT DO NOTHING;
|
|
30326
|
+
n_geblokkeerd := n_geblokkeerd + 1;
|
|
30327
|
+
CONTINUE;
|
|
30328
|
+
END IF;
|
|
30329
|
+
FOR k IN 1 .. r.crates LOOP
|
|
30330
|
+
v_bron := r.order_id::text || ':' || r.cart_id::text || ':' || r.ci_id::text || ':' || k::text;
|
|
30331
|
+
v_keep := v_keep || v_bron;
|
|
30332
|
+
INSERT INTO public.logistics_sticker_prints (soort, bron_id, order_id, order_number, cart_id, kopieen, print_plek_id, status, reden)
|
|
30333
|
+
VALUES ('eigen_traysticker', v_bron, r.order_id, r.order_number, r.cart_id, 1,
|
|
30334
|
+
public.logistics_sticker_cart_plek(r.cart_id, v_station), 'wacht_op_moment', 'Wacht op de pakbon van deze kar.')
|
|
30335
|
+
ON CONFLICT DO NOTHING;
|
|
30336
|
+
-- Was hij eerder tegengehouden door een onbekend fustaantal: weer laten wachten op het moment.
|
|
30337
|
+
UPDATE public.logistics_sticker_prints
|
|
30338
|
+
SET status = 'wacht_op_moment', reden = 'Wacht op de pakbon van deze kar.', updated_at = now()
|
|
30339
|
+
WHERE soort = 'eigen_traysticker' AND bron_id = v_bron AND status = 'geblokkeerd'
|
|
30340
|
+
AND reden LIKE 'Fustaantal van regel %';
|
|
30341
|
+
n := n + 1;
|
|
30342
|
+
END LOOP;
|
|
30343
|
+
END LOOP;
|
|
30344
|
+
|
|
30345
|
+
-- Order met onbekend fustaantal: alle nog niet geprinte stickers wachten (niet vervallen).
|
|
30346
|
+
UPDATE public.logistics_sticker_prints p
|
|
30347
|
+
SET status = 'geblokkeerd',
|
|
30348
|
+
reden = (SELECT b.reden FROM public.logistics_sticker_prints b
|
|
30349
|
+
WHERE b.soort = 'eigen_traysticker' AND b.bron_id = p.order_id::text || ':fustaantal-onbekend' LIMIT 1),
|
|
30350
|
+
updated_at = now()
|
|
30351
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status IN ('wacht_op_moment', 'klaar')
|
|
30352
|
+
AND p.order_id = ANY (v_wacht_orders);
|
|
30353
|
+
v_keep := v_keep || ARRAY(SELECT p.bron_id FROM public.logistics_sticker_prints p
|
|
30354
|
+
WHERE p.soort = 'eigen_traysticker' AND p.order_id = ANY (v_wacht_orders)
|
|
30355
|
+
AND p.reden LIKE 'Fustaantal van regel %');
|
|
30356
|
+
|
|
30357
|
+
UPDATE public.logistics_sticker_prints p
|
|
30358
|
+
SET status = 'niet_printen', reden = 'Fust hoort niet meer bij deze kar of order vervallen.', updated_at = now()
|
|
30359
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status IN ('wacht_op_moment', 'geblokkeerd', 'klaar')
|
|
30360
|
+
AND NOT (p.bron_id = ANY (v_keep))
|
|
30361
|
+
AND p.order_id IN (SELECT o.id FROM public.orders o WHERE o.delivery_date >= current_date - 1);
|
|
30362
|
+
GET DIAGNOSTICS n_uit = ROW_COUNT;
|
|
30363
|
+
|
|
30364
|
+
UPDATE public.logistics_sticker_prints p
|
|
30365
|
+
SET status = 'klaar', reden = NULL,
|
|
30366
|
+
print_plek_id = coalesce(p.print_plek_id, public.logistics_sticker_cart_plek(p.cart_id, v_station)),
|
|
30367
|
+
updated_at = now()
|
|
30368
|
+
WHERE p.soort = 'eigen_traysticker' AND p.status = 'wacht_op_moment'
|
|
30369
|
+
AND p.cart_id IS NOT NULL AND public.logistics_cart_slip_queued(p.cart_id);
|
|
30370
|
+
GET DIAGNOSTICS n_vrij = ROW_COUNT;
|
|
30371
|
+
|
|
30372
|
+
RETURN jsonb_build_object('trayRelease', v_tray, 'fusten', n, 'geblokkeerd', n_geblokkeerd, 'vrijgegeven', n_vrij, 'niet_printen', n_uit);
|
|
30373
|
+
END; $function$;
|
|
30374
|
+
REVOKE ALL ON FUNCTION public.logistics_own_traysticker_sync(integer) FROM PUBLIC, anon, authenticated;
|
|
30375
|
+
GRANT EXECUTE ON FUNCTION public.logistics_own_traysticker_sync(integer) TO service_role;
|