@flowselections/logistiek-engine 1.0.183 → 1.0.185
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 +1426 -0
- package/dist-lib/components/BeheerPage.d.ts.map +1 -1
- package/dist-lib/components/BeheerPage.js +2 -1
- package/dist-lib/components/VervoerderBewakingCard.d.ts +15 -0
- package/dist-lib/components/VervoerderBewakingCard.d.ts.map +1 -0
- package/dist-lib/components/VervoerderBewakingCard.js +56 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +1 -0
- package/dist-lib/integrations/supabase/types.d.ts +1100 -28
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +188 -0
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/package.json +2 -2
|
@@ -30674,3 +30674,1429 @@ AS $function$
|
|
|
30674
30674
|
$function$;
|
|
30675
30675
|
REVOKE ALL ON FUNCTION public.logistics_sticker_etiket_status() FROM PUBLIC, anon;
|
|
30676
30676
|
GRANT EXECUTE ON FUNCTION public.logistics_sticker_etiket_status() TO authenticated, service_role;
|
|
30677
|
+
|
|
30678
|
+
|
|
30679
|
+
-- ============================================================================
|
|
30680
|
+
-- 1.0.184 — Vervoerder per order (gedeeld contract; de Engine is eigenaar)
|
|
30681
|
+
-- ============================================================================
|
|
30682
|
+
-- * Kolommen op orders: carrier_id, carrier_source, carrier_reason,
|
|
30683
|
+
-- carrier_resolved_at, carrier_set_by, carrier_set_at.
|
|
30684
|
+
-- * Eén regel: logistics_resolve_carrier_core (vaste volgorde, op id).
|
|
30685
|
+
-- * BEFORE-trigger vult NEW.carrier_* direct (geen extra UPDATE, geen lus).
|
|
30686
|
+
-- * Herberekenlijst wordt alleen gevuld door triggers op carriers en
|
|
30687
|
+
-- customer_delivery_locations; nooit door de trigger op orders.
|
|
30688
|
+
-- * Bestaande orders (vóór installatie) pas na de schakelaar in Beheer.
|
|
30689
|
+
-- * Opslaan of wijzigen van een vervoerder verstuurt nooit een mail.
|
|
30690
|
+
-- Velden van Afhandeling/Klanten worden via to_jsonb gelezen, zodat dit ook
|
|
30691
|
+
-- werkt vóór hun koppelprompts (de stap wordt dan overgeslagen met reden).
|
|
30692
|
+
-- ============================================================================
|
|
30693
|
+
|
|
30694
|
+
ALTER TABLE public.orders ADD COLUMN IF NOT EXISTS carrier_id uuid;
|
|
30695
|
+
ALTER TABLE public.orders ADD COLUMN IF NOT EXISTS carrier_source text;
|
|
30696
|
+
ALTER TABLE public.orders ADD COLUMN IF NOT EXISTS carrier_reason text;
|
|
30697
|
+
ALTER TABLE public.orders ADD COLUMN IF NOT EXISTS carrier_resolved_at timestamptz;
|
|
30698
|
+
ALTER TABLE public.orders ADD COLUMN IF NOT EXISTS carrier_set_by uuid;
|
|
30699
|
+
ALTER TABLE public.orders ADD COLUMN IF NOT EXISTS carrier_set_at timestamptz;
|
|
30700
|
+
|
|
30701
|
+
DO $fs$ BEGIN
|
|
30702
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'orders_carrier_source_check') THEN
|
|
30703
|
+
ALTER TABLE public.orders ADD CONSTRAINT orders_carrier_source_check CHECK (carrier_source IS NULL OR carrier_source IN
|
|
30704
|
+
('handmatig','afleverlocatie','afleverlocatie_gln','klant','werkgebied','favoriet','geen','oud'));
|
|
30705
|
+
END IF;
|
|
30706
|
+
END $fs$;
|
|
30707
|
+
|
|
30708
|
+
DO $fs$ BEGIN
|
|
30709
|
+
IF to_regclass('public.carriers') IS NOT NULL
|
|
30710
|
+
AND NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'orders_carrier_id_fkey') THEN
|
|
30711
|
+
ALTER TABLE public.orders ADD CONSTRAINT orders_carrier_id_fkey FOREIGN KEY (carrier_id)
|
|
30712
|
+
REFERENCES public.carriers(id) ON DELETE SET NULL NOT VALID;
|
|
30713
|
+
END IF;
|
|
30714
|
+
END $fs$;
|
|
30715
|
+
|
|
30716
|
+
CREATE INDEX IF NOT EXISTS orders_carrier_source_idx ON public.orders (carrier_source);
|
|
30717
|
+
|
|
30718
|
+
CREATE TABLE IF NOT EXISTS public.logistics_carrier_settings (
|
|
30719
|
+
id boolean PRIMARY KEY DEFAULT true CHECK (id),
|
|
30720
|
+
installed_at timestamptz NOT NULL DEFAULT now(),
|
|
30721
|
+
backfill_existing boolean NOT NULL DEFAULT false,
|
|
30722
|
+
backfill_set_by uuid,
|
|
30723
|
+
backfill_set_at timestamptz,
|
|
30724
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
30725
|
+
);
|
|
30726
|
+
GRANT SELECT ON public.logistics_carrier_settings TO authenticated;
|
|
30727
|
+
GRANT ALL ON public.logistics_carrier_settings TO service_role;
|
|
30728
|
+
ALTER TABLE public.logistics_carrier_settings ENABLE ROW LEVEL SECURITY;
|
|
30729
|
+
DO $fs$ BEGIN
|
|
30730
|
+
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='logistics_carrier_settings' AND policyname='logistics_carrier_settings_read') THEN
|
|
30731
|
+
CREATE POLICY logistics_carrier_settings_read ON public.logistics_carrier_settings FOR SELECT TO authenticated USING (true);
|
|
30732
|
+
END IF;
|
|
30733
|
+
END $fs$;
|
|
30734
|
+
-- Eén rij per Shell; gegevens gaan niet mee met kloon of schemasync, dus de rij wordt
|
|
30735
|
+
-- bij gebruik aangemaakt (standaard "uit"). installed_at = moment van eerste gebruik in deze Shell.
|
|
30736
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_settings_ensure()
|
|
30737
|
+
RETURNS public.logistics_carrier_settings LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
|
|
30738
|
+
AS $function$
|
|
30739
|
+
DECLARE r public.logistics_carrier_settings;
|
|
30740
|
+
BEGIN
|
|
30741
|
+
SELECT * INTO r FROM public.logistics_carrier_settings WHERE id;
|
|
30742
|
+
IF NOT FOUND THEN
|
|
30743
|
+
INSERT INTO public.logistics_carrier_settings (id, backfill_existing) VALUES (true, false)
|
|
30744
|
+
ON CONFLICT (id) DO NOTHING;
|
|
30745
|
+
SELECT * INTO r FROM public.logistics_carrier_settings WHERE id;
|
|
30746
|
+
END IF;
|
|
30747
|
+
RETURN r;
|
|
30748
|
+
END $function$;
|
|
30749
|
+
REVOKE ALL ON FUNCTION public.logistics_carrier_settings_ensure() FROM PUBLIC, anon, authenticated;
|
|
30750
|
+
GRANT EXECUTE ON FUNCTION public.logistics_carrier_settings_ensure() TO service_role;
|
|
30751
|
+
|
|
30752
|
+
-- Zichtbare vastlegging van vervoerderwijzigingen en mislukte bufferherberekening.
|
|
30753
|
+
CREATE TABLE IF NOT EXISTS public.logistics_carrier_events (
|
|
30754
|
+
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
30755
|
+
order_id uuid NOT NULL,
|
|
30756
|
+
soort text NOT NULL DEFAULT 'info',
|
|
30757
|
+
bericht text NOT NULL,
|
|
30758
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
30759
|
+
);
|
|
30760
|
+
GRANT SELECT ON public.logistics_carrier_events TO authenticated;
|
|
30761
|
+
GRANT ALL ON public.logistics_carrier_events TO service_role;
|
|
30762
|
+
ALTER TABLE public.logistics_carrier_events ENABLE ROW LEVEL SECURITY;
|
|
30763
|
+
DO $fe$ BEGIN
|
|
30764
|
+
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='logistics_carrier_events' AND policyname='logistics_carrier_events_read') THEN
|
|
30765
|
+
CREATE POLICY logistics_carrier_events_read ON public.logistics_carrier_events FOR SELECT TO authenticated USING (true);
|
|
30766
|
+
END IF;
|
|
30767
|
+
END $fe$;
|
|
30768
|
+
CREATE INDEX IF NOT EXISTS logistics_carrier_events_order_idx ON public.logistics_carrier_events (order_id, created_at DESC);
|
|
30769
|
+
|
|
30770
|
+
CREATE TABLE IF NOT EXISTS public.logistics_carrier_recalc_queue (
|
|
30771
|
+
order_id uuid PRIMARY KEY,
|
|
30772
|
+
reden text NOT NULL,
|
|
30773
|
+
queued_at timestamptz NOT NULL DEFAULT now(),
|
|
30774
|
+
processed_at timestamptz,
|
|
30775
|
+
last_checked_at timestamptz
|
|
30776
|
+
);
|
|
30777
|
+
GRANT ALL ON public.logistics_carrier_recalc_queue TO service_role;
|
|
30778
|
+
ALTER TABLE public.logistics_carrier_recalc_queue ENABLE ROW LEVEL SECURITY;
|
|
30779
|
+
CREATE INDEX IF NOT EXISTS logistics_carrier_recalc_queue_open_idx
|
|
30780
|
+
ON public.logistics_carrier_recalc_queue (queued_at) WHERE processed_at IS NULL;
|
|
30781
|
+
|
|
30782
|
+
-- Waarom een vervoerder niet bruikbaar is (NULL = bruikbaar).
|
|
30783
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_skip_reason(p_carrier_id uuid)
|
|
30784
|
+
RETURNS text LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
30785
|
+
AS $function$
|
|
30786
|
+
DECLARE c jsonb;
|
|
30787
|
+
BEGIN
|
|
30788
|
+
IF p_carrier_id IS NULL THEN RETURN 'is leeg'; END IF;
|
|
30789
|
+
SELECT to_jsonb(ca) INTO c FROM public.carriers ca WHERE ca.id = p_carrier_id;
|
|
30790
|
+
IF c IS NULL THEN RETURN 'bestaat niet (meer)'; END IF;
|
|
30791
|
+
IF nullif(c->>'archived_at', '') IS NOT NULL THEN RETURN coalesce(c->>'name', '?') || ' is gearchiveerd'; END IF;
|
|
30792
|
+
IF NOT (c ? 'carrier_kind') THEN
|
|
30793
|
+
RETURN coalesce(c->>'name', '?') || ' heeft nog geen soort (veld carrier_kind ontbreekt nog; Afhandeling)';
|
|
30794
|
+
END IF;
|
|
30795
|
+
IF coalesce(c->>'carrier_kind', '') NOT IN ('extern', 'eigen_vervoer', 'klant_haalt_op') THEN
|
|
30796
|
+
RETURN coalesce(c->>'name', '?') || ' heeft geen soort ingesteld';
|
|
30797
|
+
END IF;
|
|
30798
|
+
IF c->>'carrier_kind' = 'extern' AND nullif(btrim(coalesce(c->>'email', '')), '') IS NULL THEN
|
|
30799
|
+
RETURN coalesce(c->>'name', '?') || ' heeft geen e-mailadres';
|
|
30800
|
+
END IF;
|
|
30801
|
+
RETURN NULL;
|
|
30802
|
+
END $function$;
|
|
30803
|
+
|
|
30804
|
+
-- Heeft de vervoerder een ophaalmoment voor deze leverdag?
|
|
30805
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_picks_up_for(p_carrier_id uuid, p_delivery_date date)
|
|
30806
|
+
RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
30807
|
+
AS $function$
|
|
30808
|
+
SELECT EXISTS (
|
|
30809
|
+
SELECT 1 FROM public.carriers ca
|
|
30810
|
+
CROSS JOIN LATERAL jsonb_array_elements(CASE WHEN jsonb_typeof(ca.pickup_moments) = 'array' THEN ca.pickup_moments ELSE '[]'::jsonb END) m
|
|
30811
|
+
WHERE ca.id = p_carrier_id AND nullif(m->>'pickup_time', '') IS NOT NULL
|
|
30812
|
+
AND (p_delivery_date IS NULL OR ca.pickup_weekdays IS NULL OR cardinality(ca.pickup_weekdays) = 0
|
|
30813
|
+
OR extract(isodow FROM p_delivery_date - coalesce(nullif(m->>'pickup_days', '')::int, 0))::int = ANY (ca.pickup_weekdays)))
|
|
30814
|
+
$function$;
|
|
30815
|
+
|
|
30816
|
+
-- Opgemaakt resultaat volgens het contract.
|
|
30817
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_result(p_carrier_id uuid, p_bron text, p_reden text, p_skips text[])
|
|
30818
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
30819
|
+
AS $function$
|
|
30820
|
+
DECLARE c jsonb; v_kind text; v_name text; v_reden text := p_reden;
|
|
30821
|
+
BEGIN
|
|
30822
|
+
IF p_carrier_id IS NOT NULL THEN
|
|
30823
|
+
SELECT to_jsonb(ca) INTO c FROM public.carriers ca WHERE ca.id = p_carrier_id;
|
|
30824
|
+
v_kind := c->>'carrier_kind';
|
|
30825
|
+
v_name := CASE v_kind WHEN 'eigen_vervoer' THEN 'Eigen vervoer' WHEN 'klant_haalt_op' THEN 'Afhalen' ELSE c->>'name' END;
|
|
30826
|
+
END IF;
|
|
30827
|
+
IF coalesce(cardinality(p_skips), 0) > 0 THEN
|
|
30828
|
+
v_reden := v_reden || ' Overgeslagen: ' || array_to_string(p_skips, '; ') || '.';
|
|
30829
|
+
END IF;
|
|
30830
|
+
RETURN jsonb_build_object('carrier_id', p_carrier_id, 'carrier_name', v_name, 'carrier_kind', v_kind,
|
|
30831
|
+
'bron', p_bron, 'reden', v_reden, 'waarschuwing', NULL, 'overgeslagen', to_jsonb(coalesce(p_skips, '{}'::text[])));
|
|
30832
|
+
END $function$;
|
|
30833
|
+
|
|
30834
|
+
-- Favoriet van Afhandeling op id (afh_favorite_carrier() geeft een rij met carrier_id).
|
|
30835
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_favorite_id()
|
|
30836
|
+
RETURNS uuid LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
30837
|
+
AS $function$
|
|
30838
|
+
DECLARE j jsonb;
|
|
30839
|
+
BEGIN
|
|
30840
|
+
IF to_regprocedure('public.afh_favorite_carrier()') IS NULL THEN RETURN NULL; END IF;
|
|
30841
|
+
EXECUTE 'SELECT to_jsonb(f) FROM public.afh_favorite_carrier() f LIMIT 1' INTO j;
|
|
30842
|
+
RETURN public.logistics_try_uuid(CASE jsonb_typeof(j) WHEN 'object' THEN coalesce(j->>'carrier_id', j->>'id')
|
|
30843
|
+
WHEN 'string' THEN j#>>'{}' END);
|
|
30844
|
+
END $function$;
|
|
30845
|
+
|
|
30846
|
+
-- DE regel. p_order = to_jsonb(orders-rij) (of een deel daarvan).
|
|
30847
|
+
-- Volgorde: 1 handmatig (en 'oud' uit custom_fields.carrier) -> 2 afleverlocatie
|
|
30848
|
+
-- -> 3 GLN-lijst per vervoerder -> 4 standaard van de klant -> 5 werkgebied
|
|
30849
|
+
-- (plaats > provincie > land, ophaalmoment op de leverdag) -> 6 favoriet.
|
|
30850
|
+
CREATE OR REPLACE FUNCTION public.logistics_resolve_carrier_core(p_order jsonb, p_skip_manual boolean DEFAULT false)
|
|
30851
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
30852
|
+
AS $function$
|
|
30853
|
+
DECLARE
|
|
30854
|
+
cf jsonb := CASE WHEN jsonb_typeof(p_order->'custom_fields') = 'object' THEN p_order->'custom_fields' ELSE '{}'::jsonb END;
|
|
30855
|
+
v_cust uuid := public.logistics_try_uuid(p_order->>'customer_id');
|
|
30856
|
+
v_zonder_datum boolean := coalesce((p_order->>'_zonder_datum')::boolean, false);
|
|
30857
|
+
v_date date; v_loc_raw text; v_loc_id uuid; v_gln text;
|
|
30858
|
+
l jsonb; cu jsonb; v_id uuid; v_skip text; v_skips text[] := '{}'::text[];
|
|
30859
|
+
v_country text; v_prov text; v_city text; v_lvl int; v_any boolean; r record; v_fav text;
|
|
30860
|
+
BEGIN
|
|
30861
|
+
IF coalesce(p_order->>'delivery_date', '') ~ '^\d{4}-\d{2}-\d{2}' THEN
|
|
30862
|
+
v_date := left(p_order->>'delivery_date', 10)::date;
|
|
30863
|
+
END IF;
|
|
30864
|
+
|
|
30865
|
+
-- 1. Handmatig gekozen op de order (alleen via logistics_set_order_carrier).
|
|
30866
|
+
IF NOT p_skip_manual AND p_order->>'carrier_source' = 'handmatig' THEN
|
|
30867
|
+
v_id := public.logistics_try_uuid(p_order->>'carrier_id');
|
|
30868
|
+
v_skip := public.logistics_carrier_skip_reason(v_id);
|
|
30869
|
+
IF v_skip IS NULL THEN
|
|
30870
|
+
RETURN public.logistics_carrier_result(v_id, 'handmatig', 'Handmatig gekozen op de order.', v_skips);
|
|
30871
|
+
END IF;
|
|
30872
|
+
v_skips := v_skips || ('handmatige keuze: ' || v_skip);
|
|
30873
|
+
END IF;
|
|
30874
|
+
-- 1b. Overgenomen uit een bestaande custom_fields.carrier (bron 'oud').
|
|
30875
|
+
v_id := public.logistics_try_uuid(cf->>'carrier');
|
|
30876
|
+
IF v_id IS NOT NULL THEN
|
|
30877
|
+
v_skip := public.logistics_carrier_skip_reason(v_id);
|
|
30878
|
+
IF v_skip IS NULL THEN
|
|
30879
|
+
RETURN public.logistics_carrier_result(v_id, 'oud', 'Overgenomen uit de bestaande vervoerder op de order.', v_skips);
|
|
30880
|
+
END IF;
|
|
30881
|
+
v_skips := v_skips || ('bestaande vervoerder op de order: ' || v_skip);
|
|
30882
|
+
END IF;
|
|
30883
|
+
|
|
30884
|
+
-- 2. Afleverlocatie (op id, anders op GLN).
|
|
30885
|
+
v_loc_raw := coalesce(nullif(btrim(cf->>'delivery_location_id'), ''), nullif(btrim(cf->>'delivery_location'), ''));
|
|
30886
|
+
v_loc_id := public.logistics_try_uuid(v_loc_raw);
|
|
30887
|
+
v_gln := coalesce(nullif(btrim(cf->>'delivery_location_gln'), ''), CASE WHEN v_loc_id IS NULL THEN v_loc_raw END);
|
|
30888
|
+
IF v_loc_id IS NOT NULL THEN
|
|
30889
|
+
SELECT to_jsonb(x) INTO l FROM public.customer_delivery_locations x WHERE x.id = v_loc_id;
|
|
30890
|
+
END IF;
|
|
30891
|
+
IF l IS NULL AND v_gln IS NOT NULL THEN
|
|
30892
|
+
SELECT to_jsonb(x) INTO l FROM public.customer_delivery_locations x
|
|
30893
|
+
WHERE x.gln = v_gln
|
|
30894
|
+
ORDER BY (x.customer_id IS NOT DISTINCT FROM v_cust) DESC, x.is_primary DESC NULLS LAST, x.created_at, x.id
|
|
30895
|
+
LIMIT 1;
|
|
30896
|
+
END IF;
|
|
30897
|
+
IF l IS NOT NULL THEN
|
|
30898
|
+
v_gln := coalesce(nullif(btrim(l->>'gln'), ''), v_gln);
|
|
30899
|
+
IF coalesce((l->>'self_pickup')::boolean, false) THEN
|
|
30900
|
+
RETURN jsonb_build_object('carrier_id', NULL, 'carrier_name', 'Afhalen', 'carrier_kind', 'klant_haalt_op',
|
|
30901
|
+
'bron', 'afleverlocatie', 'reden', 'Klant haalt zelf op (ingesteld bij de afleverlocatie).'
|
|
30902
|
+
|| CASE WHEN cardinality(v_skips) > 0 THEN ' Overgeslagen: ' || array_to_string(v_skips, '; ') || '.' ELSE '' END,
|
|
30903
|
+
'waarschuwing', NULL, 'overgeslagen', to_jsonb(v_skips));
|
|
30904
|
+
END IF;
|
|
30905
|
+
v_id := public.logistics_try_uuid(l->>'carrier_id');
|
|
30906
|
+
IF v_id IS NOT NULL THEN
|
|
30907
|
+
IF coalesce(l->>'carrier_assignment_source', '') <> 'manual' THEN
|
|
30908
|
+
v_skips := v_skips || 'vervoerder bij de afleverlocatie is geen handmatige keuze'::text;
|
|
30909
|
+
ELSE
|
|
30910
|
+
v_skip := public.logistics_carrier_skip_reason(v_id);
|
|
30911
|
+
IF v_skip IS NULL THEN
|
|
30912
|
+
RETURN public.logistics_carrier_result(v_id, 'afleverlocatie', 'Vervoerder van de afleverlocatie.', v_skips);
|
|
30913
|
+
END IF;
|
|
30914
|
+
v_skips := v_skips || ('afleverlocatie: ' || v_skip);
|
|
30915
|
+
END IF;
|
|
30916
|
+
END IF;
|
|
30917
|
+
END IF;
|
|
30918
|
+
|
|
30919
|
+
-- 3. Vervoerder die deze afleverlocatie-GLN bedient (lijst van Afhandeling).
|
|
30920
|
+
IF v_gln IS NOT NULL THEN
|
|
30921
|
+
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'carriers' AND column_name = 'delivery_location_glns') THEN
|
|
30922
|
+
FOR r IN SELECT ca.id FROM public.carriers ca
|
|
30923
|
+
WHERE coalesce(to_jsonb(ca)->'delivery_location_glns', '[]'::jsonb) ? v_gln
|
|
30924
|
+
ORDER BY ca.sort_order NULLS LAST, ca.id LOOP
|
|
30925
|
+
v_skip := public.logistics_carrier_skip_reason(r.id);
|
|
30926
|
+
IF v_skip IS NULL THEN
|
|
30927
|
+
RETURN public.logistics_carrier_result(r.id, 'afleverlocatie_gln', 'Vervoerder bedient afleverlocatie-GLN ' || v_gln || '.', v_skips);
|
|
30928
|
+
END IF;
|
|
30929
|
+
v_skips := v_skips || ('GLN-lijst: ' || v_skip);
|
|
30930
|
+
END LOOP;
|
|
30931
|
+
ELSE
|
|
30932
|
+
v_skips := v_skips || 'GLN-lijst per vervoerder bestaat nog niet (Afhandeling)'::text;
|
|
30933
|
+
END IF;
|
|
30934
|
+
END IF;
|
|
30935
|
+
|
|
30936
|
+
-- 4. Standaardvervoerder van de klant (veld van Klanten).
|
|
30937
|
+
IF v_cust IS NOT NULL THEN
|
|
30938
|
+
SELECT to_jsonb(x) INTO cu FROM public.customers x WHERE x.id = v_cust;
|
|
30939
|
+
IF cu IS NOT NULL AND NOT (cu ? 'default_carrier_id') THEN
|
|
30940
|
+
v_skips := v_skips || 'standaardvervoerder per klant bestaat nog niet (Klanten)'::text;
|
|
30941
|
+
ELSE
|
|
30942
|
+
v_id := public.logistics_try_uuid(cu->>'default_carrier_id');
|
|
30943
|
+
IF v_id IS NOT NULL THEN
|
|
30944
|
+
v_skip := public.logistics_carrier_skip_reason(v_id);
|
|
30945
|
+
IF v_skip IS NULL THEN
|
|
30946
|
+
RETURN public.logistics_carrier_result(v_id, 'klant', 'Standaardvervoerder van de klant.', v_skips);
|
|
30947
|
+
END IF;
|
|
30948
|
+
v_skips := v_skips || ('standaard van de klant: ' || v_skip);
|
|
30949
|
+
END IF;
|
|
30950
|
+
END IF;
|
|
30951
|
+
END IF;
|
|
30952
|
+
|
|
30953
|
+
-- 5. Werkgebied: plaats > provincie > land, met een ophaalmoment op de leverdag.
|
|
30954
|
+
IF v_date IS NULL AND NOT v_zonder_datum THEN
|
|
30955
|
+
v_skips := v_skips || 'werkgebied: leverdatum onbekend'::text;
|
|
30956
|
+
ELSE
|
|
30957
|
+
BEGIN
|
|
30958
|
+
v_country := public.afh_normalize_country(coalesce(l->>'country', cu->>'country'));
|
|
30959
|
+
v_city := public.afh_city_code(v_country, coalesce(l->>'city', cu->>'city'));
|
|
30960
|
+
v_prov := public.afh_normalize_nl_province(l->>'province');
|
|
30961
|
+
EXCEPTION WHEN undefined_function THEN
|
|
30962
|
+
v_country := upper(nullif(btrim(coalesce(l->>'country', cu->>'country')), ''));
|
|
30963
|
+
v_city := nullif(btrim(coalesce(l->>'city', cu->>'city')), '');
|
|
30964
|
+
v_prov := nullif(btrim(l->>'province'), '');
|
|
30965
|
+
END;
|
|
30966
|
+
FOR v_lvl IN 1..3 LOOP
|
|
30967
|
+
v_any := false;
|
|
30968
|
+
FOR r IN SELECT ca.id FROM public.carriers ca
|
|
30969
|
+
WHERE CASE v_lvl WHEN 1 THEN v_city IS NOT NULL AND v_city = ANY (ca.service_cities)
|
|
30970
|
+
WHEN 2 THEN v_prov IS NOT NULL AND v_prov = ANY (ca.service_provinces)
|
|
30971
|
+
ELSE v_country IS NOT NULL AND v_country = ANY (ca.service_countries) END
|
|
30972
|
+
ORDER BY ca.sort_order NULLS LAST, ca.id LOOP
|
|
30973
|
+
v_skip := public.logistics_carrier_skip_reason(r.id);
|
|
30974
|
+
IF v_skip IS NULL AND NOT public.logistics_carrier_picks_up_for(r.id, v_date) THEN
|
|
30975
|
+
v_skip := (SELECT name FROM public.carriers WHERE id = r.id) || ' heeft geen ophaalmoment op de leverdag';
|
|
30976
|
+
END IF;
|
|
30977
|
+
IF v_skip IS NULL THEN
|
|
30978
|
+
RETURN public.logistics_carrier_result(r.id, 'werkgebied',
|
|
30979
|
+
'Werkgebied (' || CASE v_lvl WHEN 1 THEN 'plaats' WHEN 2 THEN 'provincie' ELSE 'land' END || ').', v_skips);
|
|
30980
|
+
END IF;
|
|
30981
|
+
v_skips := v_skips || ('werkgebied: ' || v_skip);
|
|
30982
|
+
END LOOP;
|
|
30983
|
+
END LOOP;
|
|
30984
|
+
END IF;
|
|
30985
|
+
|
|
30986
|
+
-- 6. Favoriete vervoerder van de Shell (Afhandeling).
|
|
30987
|
+
IF to_regprocedure('public.afh_favorite_carrier()') IS NULL THEN
|
|
30988
|
+
v_skips := v_skips || 'favoriete vervoerder bestaat nog niet (Afhandeling)'::text;
|
|
30989
|
+
ELSE
|
|
30990
|
+
BEGIN
|
|
30991
|
+
v_fav := public.logistics_carrier_favorite_id()::text;
|
|
30992
|
+
EXCEPTION WHEN OTHERS THEN
|
|
30993
|
+
v_fav := NULL; v_skips := v_skips || ('favoriet niet te lezen: ' || SQLERRM);
|
|
30994
|
+
END;
|
|
30995
|
+
v_id := public.logistics_try_uuid(v_fav);
|
|
30996
|
+
IF v_id IS NULL THEN
|
|
30997
|
+
v_skips := v_skips || 'er is geen favoriete vervoerder ingesteld'::text;
|
|
30998
|
+
ELSE
|
|
30999
|
+
v_skip := public.logistics_carrier_skip_reason(v_id);
|
|
31000
|
+
IF v_skip IS NULL THEN
|
|
31001
|
+
RETURN public.logistics_carrier_result(v_id, 'favoriet', 'Favoriete vervoerder van de Shell.', v_skips);
|
|
31002
|
+
END IF;
|
|
31003
|
+
v_skips := v_skips || ('favoriet: ' || v_skip);
|
|
31004
|
+
END IF;
|
|
31005
|
+
END IF;
|
|
31006
|
+
|
|
31007
|
+
RETURN jsonb_build_object('carrier_id', NULL, 'carrier_name', NULL, 'carrier_kind', NULL, 'bron', 'geen',
|
|
31008
|
+
'reden', 'Geen vervoerder: stel een favoriete vervoerder in (Afhandeling → Vervoerders).'
|
|
31009
|
+
|| CASE WHEN cardinality(v_skips) > 0 THEN ' Overgeslagen: ' || array_to_string(v_skips, '; ') || '.' ELSE '' END,
|
|
31010
|
+
'waarschuwing', NULL, 'overgeslagen', to_jsonb(v_skips));
|
|
31011
|
+
END $function$;
|
|
31012
|
+
|
|
31013
|
+
-- Waarom de vervoerder van deze order niet meer automatisch wijzigt (NULL = mag).
|
|
31014
|
+
-- "Aangemeld" = vastlegging van Afhandeling in carrier_signup_dispatches (sent_at gevuld,
|
|
31015
|
+
-- order_ids bevat de order), gelezen via to_jsonb.
|
|
31016
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_frozen_reason(p_order_id uuid)
|
|
31017
|
+
RETURNS text LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31018
|
+
AS $function$
|
|
31019
|
+
DECLARE v_locked timestamptz; v_hit boolean;
|
|
31020
|
+
BEGIN
|
|
31021
|
+
SELECT plan_locked_at INTO v_locked FROM public.orders WHERE id = p_order_id;
|
|
31022
|
+
IF v_locked IS NOT NULL THEN RETURN 'de planning is vastgezet'; END IF;
|
|
31023
|
+
BEGIN
|
|
31024
|
+
IF public.logistics_order_is_frozen(p_order_id) THEN RETURN 'het picken is begonnen of de order staat op een vastgezette kar'; END IF;
|
|
31025
|
+
EXCEPTION WHEN undefined_function OR undefined_table THEN NULL; END;
|
|
31026
|
+
BEGIN
|
|
31027
|
+
IF public.logistics_order_frozen(p_order_id) THEN RETURN 'de order is gepickt, gecontroleerd of afgemeld'; END IF;
|
|
31028
|
+
EXCEPTION WHEN undefined_function OR undefined_table THEN NULL; END;
|
|
31029
|
+
IF to_regclass('public.carrier_signup_dispatches') IS NOT NULL THEN
|
|
31030
|
+
BEGIN
|
|
31031
|
+
EXECUTE 'SELECT EXISTS (SELECT 1 FROM public.carrier_signup_dispatches d
|
|
31032
|
+
WHERE nullif(to_jsonb(d)->>''sent_at'', '''') IS NOT NULL
|
|
31033
|
+
AND coalesce(to_jsonb(d)->''order_ids'', ''[]''::jsonb) ? $1)'
|
|
31034
|
+
INTO v_hit USING p_order_id::text;
|
|
31035
|
+
IF v_hit THEN RETURN 'de order is al bij de vervoerder aangemeld'; END IF;
|
|
31036
|
+
EXCEPTION WHEN OTHERS THEN NULL; END;
|
|
31037
|
+
END IF;
|
|
31038
|
+
RETURN NULL;
|
|
31039
|
+
END $function$;
|
|
31040
|
+
|
|
31041
|
+
-- Vervoerder van een order volgens het contract (alleen lezen).
|
|
31042
|
+
CREATE OR REPLACE FUNCTION public.logistics_resolve_carrier(p_order_id uuid)
|
|
31043
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31044
|
+
AS $function$
|
|
31045
|
+
DECLARE o jsonb; r jsonb; v_fr text;
|
|
31046
|
+
BEGIN
|
|
31047
|
+
SELECT to_jsonb(x) INTO o FROM public.orders x WHERE x.id = p_order_id;
|
|
31048
|
+
IF o IS NULL THEN
|
|
31049
|
+
RETURN jsonb_build_object('carrier_id', NULL, 'carrier_name', NULL, 'carrier_kind', NULL, 'bron', 'geen',
|
|
31050
|
+
'reden', 'Order niet gevonden.', 'waarschuwing', NULL);
|
|
31051
|
+
END IF;
|
|
31052
|
+
r := public.logistics_resolve_carrier_core(o, false);
|
|
31053
|
+
v_fr := public.logistics_carrier_frozen_reason(p_order_id);
|
|
31054
|
+
IF v_fr IS NOT NULL AND o->>'carrier_source' IS NOT NULL
|
|
31055
|
+
AND ((r->>'carrier_id') IS DISTINCT FROM (o->>'carrier_id') OR (r->>'bron') IS DISTINCT FROM (o->>'carrier_source')) THEN
|
|
31056
|
+
r := r || jsonb_build_object('waarschuwing',
|
|
31057
|
+
'Vervoerder zou nu ' || coalesce(r->>'carrier_name', 'geen') || ' zijn; niet aangepast omdat ' || v_fr || '.');
|
|
31058
|
+
END IF;
|
|
31059
|
+
RETURN r || jsonb_build_object('bevroren', v_fr);
|
|
31060
|
+
END $function$;
|
|
31061
|
+
|
|
31062
|
+
CREATE OR REPLACE FUNCTION public.logistics_resolve_carrier_many(p_order_ids uuid[])
|
|
31063
|
+
RETURNS TABLE(order_id uuid, resultaat jsonb) LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31064
|
+
AS $function$
|
|
31065
|
+
SELECT x.id, public.logistics_resolve_carrier(x.id) FROM unnest(coalesce(p_order_ids, '{}'::uuid[])) AS x(id)
|
|
31066
|
+
$function$;
|
|
31067
|
+
|
|
31068
|
+
-- Voor Klanten: dezelfde volgorde zonder stap 1 (geen order, dus geen leverdag).
|
|
31069
|
+
CREATE OR REPLACE FUNCTION public.logistics_resolve_carrier_for_location(p_location_id uuid, p_customer_id uuid)
|
|
31070
|
+
RETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31071
|
+
AS $function$
|
|
31072
|
+
SELECT public.logistics_resolve_carrier_core(jsonb_build_object(
|
|
31073
|
+
'customer_id', coalesce(p_customer_id, (SELECT l.customer_id FROM public.customer_delivery_locations l WHERE l.id = p_location_id)),
|
|
31074
|
+
'custom_fields', jsonb_build_object('delivery_location_id', p_location_id),
|
|
31075
|
+
'_zonder_datum', true), true)
|
|
31076
|
+
$function$;
|
|
31077
|
+
|
|
31078
|
+
CREATE OR REPLACE FUNCTION public.logistics_resolve_carrier_for_location_many(p_location_ids uuid[], p_customer_id uuid)
|
|
31079
|
+
RETURNS TABLE(location_id uuid, resultaat jsonb) LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31080
|
+
AS $function$
|
|
31081
|
+
SELECT x.id, public.logistics_resolve_carrier_for_location(x.id, p_customer_id)
|
|
31082
|
+
FROM unnest(coalesce(p_location_ids, '{}'::uuid[])) AS x(id)
|
|
31083
|
+
$function$;
|
|
31084
|
+
|
|
31085
|
+
-- Variant voor een hele klantenlijst: [{location_id, customer_id}, ...] (max. 1000 regels).
|
|
31086
|
+
CREATE OR REPLACE FUNCTION public.logistics_resolve_carrier_for_location_many(p_items jsonb)
|
|
31087
|
+
RETURNS TABLE(location_id uuid, customer_id uuid, carrier_id uuid, carrier_name text, carrier_kind text,
|
|
31088
|
+
bron text, reden text, waarschuwing text)
|
|
31089
|
+
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31090
|
+
AS $function$
|
|
31091
|
+
DECLARE it jsonb; r jsonb; v_loc uuid; v_cust uuid;
|
|
31092
|
+
BEGIN
|
|
31093
|
+
IF auth.uid() IS NULL AND coalesce(auth.role(), '') <> 'service_role' THEN RAISE EXCEPTION 'Niet ingelogd'; END IF;
|
|
31094
|
+
IF p_items IS NULL OR jsonb_typeof(p_items) <> 'array' THEN RAISE EXCEPTION 'p_items moet een lijst zijn: [{location_id, customer_id}, ...]'; END IF;
|
|
31095
|
+
IF jsonb_array_length(p_items) > 1000 THEN RAISE EXCEPTION 'Te veel regels (%); maximaal 1000 per aanroep.', jsonb_array_length(p_items); END IF;
|
|
31096
|
+
FOR it IN SELECT e FROM jsonb_array_elements(p_items) WITH ORDINALITY AS t(e, n) ORDER BY n LOOP
|
|
31097
|
+
v_loc := public.logistics_try_uuid(it->>'location_id');
|
|
31098
|
+
v_cust := public.logistics_try_uuid(it->>'customer_id');
|
|
31099
|
+
IF v_loc IS NULL AND v_cust IS NULL THEN
|
|
31100
|
+
location_id := NULL; customer_id := NULL; carrier_id := NULL; carrier_name := NULL; carrier_kind := NULL;
|
|
31101
|
+
bron := 'geen'; reden := 'Ongeldige regel: geen geldig location_id of customer_id.'; waarschuwing := NULL;
|
|
31102
|
+
RETURN NEXT; CONTINUE;
|
|
31103
|
+
END IF;
|
|
31104
|
+
r := public.logistics_resolve_carrier_for_location(v_loc, v_cust);
|
|
31105
|
+
location_id := v_loc; customer_id := v_cust;
|
|
31106
|
+
carrier_id := public.logistics_try_uuid(r->>'carrier_id'); carrier_name := r->>'carrier_name';
|
|
31107
|
+
carrier_kind := r->>'carrier_kind'; bron := r->>'bron'; reden := r->>'reden'; waarschuwing := r->>'waarschuwing';
|
|
31108
|
+
RETURN NEXT;
|
|
31109
|
+
END LOOP;
|
|
31110
|
+
END $function$;
|
|
31111
|
+
|
|
31112
|
+
-- Opgeslagen vervoerder (of, zolang nog niet opgeslagen, de regel live; niets schrijven).
|
|
31113
|
+
CREATE OR REPLACE FUNCTION public.logistics_order_carrier_info(p_order_id uuid)
|
|
31114
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31115
|
+
AS $function$
|
|
31116
|
+
DECLARE o jsonb;
|
|
31117
|
+
BEGIN
|
|
31118
|
+
SELECT to_jsonb(x) INTO o FROM public.orders x WHERE x.id = p_order_id;
|
|
31119
|
+
IF o IS NULL THEN RETURN jsonb_build_object('carrier_id', NULL, 'bron', 'geen', 'reden', 'Order niet gevonden.'); END IF;
|
|
31120
|
+
IF o->>'carrier_source' IS NOT NULL THEN
|
|
31121
|
+
IF o->>'carrier_source' = 'afleverlocatie' AND o->>'carrier_id' IS NULL THEN
|
|
31122
|
+
RETURN jsonb_build_object('carrier_id', NULL, 'carrier_name', 'Afhalen', 'carrier_kind', 'klant_haalt_op',
|
|
31123
|
+
'bron', o->>'carrier_source', 'reden', o->>'carrier_reason', 'opgeslagen', true);
|
|
31124
|
+
END IF;
|
|
31125
|
+
IF o->>'carrier_id' IS NULL THEN
|
|
31126
|
+
RETURN jsonb_build_object('carrier_id', NULL, 'carrier_name', NULL, 'carrier_kind', NULL,
|
|
31127
|
+
'bron', o->>'carrier_source', 'reden', o->>'carrier_reason', 'opgeslagen', true);
|
|
31128
|
+
END IF;
|
|
31129
|
+
RETURN public.logistics_carrier_result((o->>'carrier_id')::uuid, o->>'carrier_source', o->>'carrier_reason', '{}'::text[])
|
|
31130
|
+
|| jsonb_build_object('reden', o->>'carrier_reason', 'opgeslagen', true);
|
|
31131
|
+
END IF;
|
|
31132
|
+
RETURN public.logistics_resolve_carrier_core(o, false) || jsonb_build_object('opgeslagen', false);
|
|
31133
|
+
END $function$;
|
|
31134
|
+
|
|
31135
|
+
CREATE OR REPLACE FUNCTION public.logistics_order_carrier_label(p_order_id uuid)
|
|
31136
|
+
RETURNS text LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31137
|
+
AS $function$
|
|
31138
|
+
SELECT public.logistics_order_carrier_info(p_order_id)->>'carrier_name'
|
|
31139
|
+
$function$;
|
|
31140
|
+
|
|
31141
|
+
-- Bestaande functie: nu volgens dezelfde regel.
|
|
31142
|
+
CREATE OR REPLACE FUNCTION public.logistics_order_carrier_id(p_order_id uuid)
|
|
31143
|
+
RETURNS uuid LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31144
|
+
AS $function$
|
|
31145
|
+
SELECT public.logistics_try_uuid(public.logistics_order_carrier_info(p_order_id)->>'carrier_id')
|
|
31146
|
+
$function$;
|
|
31147
|
+
|
|
31148
|
+
-- Bestaande functie blijft; dezelfde regel (locatie op id of GLN).
|
|
31149
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_for_location(p_location text, p_customer_id uuid)
|
|
31150
|
+
RETURNS uuid LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31151
|
+
AS $function$
|
|
31152
|
+
SELECT public.logistics_try_uuid(public.logistics_resolve_carrier_core(jsonb_build_object(
|
|
31153
|
+
'customer_id', p_customer_id,
|
|
31154
|
+
'custom_fields', jsonb_build_object('delivery_location', nullif(btrim(coalesce(p_location, '')), '')),
|
|
31155
|
+
'_zonder_datum', true), true)->>'carrier_id')
|
|
31156
|
+
$function$;
|
|
31157
|
+
|
|
31158
|
+
-- BEFORE INSERT/UPDATE op orders: vult NEW.carrier_* direct in.
|
|
31159
|
+
-- Geen lus: deze trigger zet nooit iets op de herberekenlijst en schrijft
|
|
31160
|
+
-- niets anders weg. Engine-schrijvers zetten logistics.carrier_writer = 'engine'.
|
|
31161
|
+
CREATE OR REPLACE FUNCTION public.logistics_orders_carrier_fill()
|
|
31162
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31163
|
+
AS $function$
|
|
31164
|
+
DECLARE r jsonb; s record;
|
|
31165
|
+
BEGIN
|
|
31166
|
+
IF coalesce(current_setting('logistics.carrier_writer', true), '') = 'engine' THEN RETURN NEW; END IF;
|
|
31167
|
+
IF TG_OP = 'INSERT' THEN
|
|
31168
|
+
IF NEW.carrier_source = 'handmatig' THEN RETURN NEW; END IF;
|
|
31169
|
+
ELSE
|
|
31170
|
+
IF OLD.carrier_source = 'handmatig' THEN RETURN NEW; END IF;
|
|
31171
|
+
IF NEW.customer_id IS NOT DISTINCT FROM OLD.customer_id
|
|
31172
|
+
AND NEW.delivery_date IS NOT DISTINCT FROM OLD.delivery_date
|
|
31173
|
+
AND (NEW.custom_fields->>'delivery_location') IS NOT DISTINCT FROM (OLD.custom_fields->>'delivery_location')
|
|
31174
|
+
AND (NEW.custom_fields->>'delivery_location_id') IS NOT DISTINCT FROM (OLD.custom_fields->>'delivery_location_id')
|
|
31175
|
+
AND (NEW.custom_fields->>'delivery_location_gln') IS NOT DISTINCT FROM (OLD.custom_fields->>'delivery_location_gln')
|
|
31176
|
+
AND (NEW.custom_fields->>'carrier') IS NOT DISTINCT FROM (OLD.custom_fields->>'carrier') THEN
|
|
31177
|
+
RETURN NEW;
|
|
31178
|
+
END IF;
|
|
31179
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
31180
|
+
IF OLD.carrier_source IS NULL AND NOT coalesce(s.backfill_existing, false)
|
|
31181
|
+
AND OLD.created_at < coalesce(s.installed_at, now()) THEN
|
|
31182
|
+
RETURN NEW; -- bestaande order: pas na akkoord (schakelaar in Beheer)
|
|
31183
|
+
END IF;
|
|
31184
|
+
IF NEW.plan_locked_at IS NOT NULL OR public.logistics_carrier_frozen_reason(NEW.id) IS NOT NULL THEN
|
|
31185
|
+
RETURN NEW; -- bevroren: alleen waarschuwing bij het lezen
|
|
31186
|
+
END IF;
|
|
31187
|
+
END IF;
|
|
31188
|
+
BEGIN
|
|
31189
|
+
r := public.logistics_resolve_carrier_core(to_jsonb(NEW), false);
|
|
31190
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31191
|
+
r := jsonb_build_object('carrier_id', NULL, 'bron', 'geen',
|
|
31192
|
+
'reden', 'Geen vervoerder: de vervoerder kon niet worden bepaald (' || left(SQLERRM, 200) || ').');
|
|
31193
|
+
END;
|
|
31194
|
+
IF TG_OP = 'INSERT'
|
|
31195
|
+
OR public.logistics_try_uuid(r->>'carrier_id') IS DISTINCT FROM NEW.carrier_id
|
|
31196
|
+
OR (r->>'bron') IS DISTINCT FROM NEW.carrier_source
|
|
31197
|
+
OR (r->>'reden') IS DISTINCT FROM NEW.carrier_reason THEN
|
|
31198
|
+
NEW.carrier_id := public.logistics_try_uuid(r->>'carrier_id');
|
|
31199
|
+
NEW.carrier_source := r->>'bron';
|
|
31200
|
+
NEW.carrier_reason := r->>'reden';
|
|
31201
|
+
NEW.carrier_resolved_at := now();
|
|
31202
|
+
END IF;
|
|
31203
|
+
RETURN NEW;
|
|
31204
|
+
END $function$;
|
|
31205
|
+
|
|
31206
|
+
DROP TRIGGER IF EXISTS trg_logistics_orders_carrier_fill ON public.orders;
|
|
31207
|
+
CREATE TRIGGER trg_logistics_orders_carrier_fill BEFORE INSERT OR UPDATE ON public.orders
|
|
31208
|
+
FOR EACH ROW EXECUTE FUNCTION public.logistics_orders_carrier_fill();
|
|
31209
|
+
|
|
31210
|
+
-- AFTER UPDATE: alleen als carrier_id echt verandert en de order niet bevroren is:
|
|
31211
|
+
-- buffer opnieuw bepalen (bestaande regels) en de kar opnieuw laten indelen.
|
|
31212
|
+
CREATE OR REPLACE FUNCTION public.logistics_orders_carrier_changed()
|
|
31213
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31214
|
+
AS $function$
|
|
31215
|
+
DECLARE v_fr text;
|
|
31216
|
+
BEGIN
|
|
31217
|
+
IF NEW.deleted_at IS NOT NULL THEN RETURN NULL; END IF;
|
|
31218
|
+
v_fr := public.logistics_carrier_frozen_reason(NEW.id);
|
|
31219
|
+
IF v_fr IS NOT NULL THEN
|
|
31220
|
+
BEGIN
|
|
31221
|
+
INSERT INTO public.logistics_carrier_events(order_id, soort, bericht)
|
|
31222
|
+
VALUES (NEW.id, 'bevroren', 'Vervoerder gewijzigd, maar buffer en kar blijven: ' || v_fr || '.');
|
|
31223
|
+
EXCEPTION WHEN undefined_table THEN NULL; END;
|
|
31224
|
+
RETURN NULL;
|
|
31225
|
+
END IF;
|
|
31226
|
+
BEGIN
|
|
31227
|
+
PERFORM public.logistics_apply_order_buffer(NEW.id);
|
|
31228
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31229
|
+
BEGIN
|
|
31230
|
+
INSERT INTO public.logistics_carrier_events(order_id, soort, bericht)
|
|
31231
|
+
VALUES (NEW.id, 'fout', 'Vervoerder gewijzigd; buffer opnieuw bepalen mislukte: ' || left(SQLERRM, 200));
|
|
31232
|
+
EXCEPTION WHEN undefined_table THEN NULL; END;
|
|
31233
|
+
END;
|
|
31234
|
+
BEGIN
|
|
31235
|
+
PERFORM public.enqueue_cart_replan_if_unlocked(NEW.id);
|
|
31236
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31237
|
+
INSERT INTO public.logistics_carrier_events(order_id, soort, bericht)
|
|
31238
|
+
VALUES (NEW.id, 'fout', 'Vervoerder gewijzigd; opnieuw indelen aanvragen mislukte: ' || left(SQLERRM, 200));
|
|
31239
|
+
END;
|
|
31240
|
+
BEGIN
|
|
31241
|
+
INSERT INTO public.logistics_carrier_events(order_id, soort, bericht)
|
|
31242
|
+
VALUES (NEW.id, 'info', 'Vervoerder gewijzigd (' || coalesce(NEW.carrier_source, '?') || '); buffer en kar opnieuw bepaald.');
|
|
31243
|
+
EXCEPTION WHEN undefined_table THEN NULL; END;
|
|
31244
|
+
RETURN NULL;
|
|
31245
|
+
END $function$;
|
|
31246
|
+
|
|
31247
|
+
DROP TRIGGER IF EXISTS trg_logistics_orders_carrier_changed ON public.orders;
|
|
31248
|
+
CREATE TRIGGER trg_logistics_orders_carrier_changed AFTER UPDATE OF carrier_id ON public.orders
|
|
31249
|
+
FOR EACH ROW WHEN (OLD.carrier_id IS DISTINCT FROM NEW.carrier_id)
|
|
31250
|
+
EXECUTE FUNCTION public.logistics_orders_carrier_changed();
|
|
31251
|
+
|
|
31252
|
+
-- Herberekenlijst vullen: alleen open orders, nooit handmatig, bestaande orders pas na de schakelaar.
|
|
31253
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_enqueue(p_order_ids uuid[], p_reden text)
|
|
31254
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31255
|
+
AS $function$
|
|
31256
|
+
DECLARE n int;
|
|
31257
|
+
BEGIN
|
|
31258
|
+
PERFORM public.logistics_carrier_settings_ensure();
|
|
31259
|
+
INSERT INTO public.logistics_carrier_recalc_queue AS q (order_id, reden)
|
|
31260
|
+
SELECT o.id, p_reden FROM public.orders o
|
|
31261
|
+
JOIN public.logistics_carrier_settings s ON s.id
|
|
31262
|
+
WHERE o.id = ANY (p_order_ids)
|
|
31263
|
+
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
31264
|
+
AND o.carrier_source IS DISTINCT FROM 'handmatig'
|
|
31265
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date
|
|
31266
|
+
AND (s.backfill_existing OR o.created_at >= s.installed_at)
|
|
31267
|
+
ON CONFLICT (order_id) DO UPDATE SET processed_at = NULL, queued_at = now(), reden = EXCLUDED.reden;
|
|
31268
|
+
GET DIAGNOSTICS n = ROW_COUNT;
|
|
31269
|
+
RETURN n;
|
|
31270
|
+
END $function$;
|
|
31271
|
+
|
|
31272
|
+
CREATE OR REPLACE FUNCTION public.logistics_carriers_enqueue_orders()
|
|
31273
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31274
|
+
AS $function$
|
|
31275
|
+
BEGIN
|
|
31276
|
+
BEGIN
|
|
31277
|
+
PERFORM public.logistics_carrier_enqueue(ARRAY(
|
|
31278
|
+
SELECT o.id FROM public.orders o
|
|
31279
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
31280
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date),
|
|
31281
|
+
'Vervoerdersinstellingen gewijzigd');
|
|
31282
|
+
EXCEPTION WHEN OTHERS THEN NULL; END;
|
|
31283
|
+
RETURN NULL;
|
|
31284
|
+
END $function$;
|
|
31285
|
+
|
|
31286
|
+
CREATE OR REPLACE FUNCTION public.logistics_locations_enqueue_orders()
|
|
31287
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31288
|
+
AS $function$
|
|
31289
|
+
DECLARE v_old_gln text;
|
|
31290
|
+
BEGIN
|
|
31291
|
+
IF TG_OP = 'UPDATE' THEN v_old_gln := OLD.gln; END IF;
|
|
31292
|
+
BEGIN
|
|
31293
|
+
PERFORM public.logistics_carrier_enqueue(ARRAY(
|
|
31294
|
+
SELECT o.id FROM public.orders o
|
|
31295
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
31296
|
+
AND ((o.custom_fields->>'delivery_location_id') = NEW.id::text
|
|
31297
|
+
OR (o.custom_fields->>'delivery_location') = NEW.id::text
|
|
31298
|
+
OR (NEW.gln IS NOT NULL AND ((o.custom_fields->>'delivery_location_gln') = NEW.gln OR (o.custom_fields->>'delivery_location') = NEW.gln))
|
|
31299
|
+
OR (v_old_gln IS NOT NULL AND (o.custom_fields->>'delivery_location_gln') = v_old_gln))),
|
|
31300
|
+
'Afleverlocatie gewijzigd');
|
|
31301
|
+
EXCEPTION WHEN OTHERS THEN NULL; END;
|
|
31302
|
+
RETURN NULL;
|
|
31303
|
+
END $function$;
|
|
31304
|
+
|
|
31305
|
+
DO $fs$ BEGIN
|
|
31306
|
+
IF to_regclass('public.carriers') IS NOT NULL THEN
|
|
31307
|
+
DROP TRIGGER IF EXISTS trg_logistics_carriers_enqueue ON public.carriers;
|
|
31308
|
+
CREATE TRIGGER trg_logistics_carriers_enqueue AFTER INSERT OR UPDATE ON public.carriers
|
|
31309
|
+
FOR EACH STATEMENT EXECUTE FUNCTION public.logistics_carriers_enqueue_orders();
|
|
31310
|
+
ELSE
|
|
31311
|
+
RAISE NOTICE 'logistiek-engine: trigger trg_logistics_carriers_enqueue overgeslagen: tabel carriers ontbreekt';
|
|
31312
|
+
END IF;
|
|
31313
|
+
IF to_regclass('public.customer_delivery_locations') IS NOT NULL THEN
|
|
31314
|
+
DROP TRIGGER IF EXISTS trg_logistics_locations_enqueue ON public.customer_delivery_locations;
|
|
31315
|
+
CREATE TRIGGER trg_logistics_locations_enqueue
|
|
31316
|
+
AFTER INSERT OR UPDATE OF carrier_id, carrier_assignment_source, self_pickup, gln ON public.customer_delivery_locations
|
|
31317
|
+
FOR EACH ROW EXECUTE FUNCTION public.logistics_locations_enqueue_orders();
|
|
31318
|
+
ELSE
|
|
31319
|
+
RAISE NOTICE 'logistiek-engine: trigger trg_logistics_locations_enqueue overgeslagen: tabel customer_delivery_locations ontbreekt';
|
|
31320
|
+
END IF;
|
|
31321
|
+
END $fs$;
|
|
31322
|
+
|
|
31323
|
+
-- Minuutronde: eerst de herberekenlijst, dan het vangnet (open orders die
|
|
31324
|
+
-- langer dan 24 uur niet gecontroleerd zijn). Hooguit p_limit (200) orders per
|
|
31325
|
+
-- ronde. Schrijft ALLEEN als carrier_id, bron of reden verschilt.
|
|
31326
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_recalc_run(p_limit integer DEFAULT 200)
|
|
31327
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31328
|
+
AS $function$
|
|
31329
|
+
DECLARE s record; r record; o jsonb; v jsonb; v_fr text;
|
|
31330
|
+
n_chk int := 0; n_upd int := 0; n_frozen int := 0; n_hand int := 0; n_err int := 0;
|
|
31331
|
+
BEGIN
|
|
31332
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
31333
|
+
IF NOT FOUND THEN RETURN jsonb_build_object('overgeslagen', 'instellingen vervoerder ontbreken'); END IF;
|
|
31334
|
+
FOR r IN
|
|
31335
|
+
WITH kand_open AS (
|
|
31336
|
+
SELECT o.id FROM public.orders o
|
|
31337
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
31338
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date
|
|
31339
|
+
AND (s.backfill_existing OR o.created_at >= s.installed_at)
|
|
31340
|
+
), cand AS (
|
|
31341
|
+
SELECT q.order_id AS id, 1 AS prio, q.queued_at AS t
|
|
31342
|
+
FROM public.logistics_carrier_recalc_queue q JOIN kand_open ON kand_open.id = q.order_id
|
|
31343
|
+
WHERE q.processed_at IS NULL
|
|
31344
|
+
UNION ALL
|
|
31345
|
+
SELECT kand_open.id, 2, coalesce(q.last_checked_at, '-infinity'::timestamptz)
|
|
31346
|
+
FROM kand_open LEFT JOIN public.logistics_carrier_recalc_queue q ON q.order_id = kand_open.id
|
|
31347
|
+
WHERE q.order_id IS NULL OR (q.processed_at IS NOT NULL
|
|
31348
|
+
AND (q.last_checked_at IS NULL OR q.last_checked_at < now() - interval '24 hours'))
|
|
31349
|
+
)
|
|
31350
|
+
SELECT c.id FROM (SELECT DISTINCT ON (cand.id) cand.id, cand.prio, cand.t FROM cand ORDER BY cand.id, cand.prio) c
|
|
31351
|
+
ORDER BY c.prio, c.t LIMIT greatest(1, least(coalesce(p_limit, 200), 1000))
|
|
31352
|
+
LOOP
|
|
31353
|
+
BEGIN
|
|
31354
|
+
SELECT to_jsonb(x) INTO o FROM public.orders x WHERE x.id = r.id FOR UPDATE SKIP LOCKED;
|
|
31355
|
+
IF o IS NULL THEN CONTINUE; END IF;
|
|
31356
|
+
n_chk := n_chk + 1;
|
|
31357
|
+
IF o->>'carrier_source' = 'handmatig' THEN
|
|
31358
|
+
n_hand := n_hand + 1;
|
|
31359
|
+
ELSE
|
|
31360
|
+
v_fr := public.logistics_carrier_frozen_reason(r.id);
|
|
31361
|
+
IF v_fr IS NOT NULL THEN
|
|
31362
|
+
n_frozen := n_frozen + 1;
|
|
31363
|
+
ELSE
|
|
31364
|
+
v := public.logistics_resolve_carrier_core(o, false);
|
|
31365
|
+
IF (v->>'carrier_id') IS DISTINCT FROM (o->>'carrier_id')
|
|
31366
|
+
OR (v->>'bron') IS DISTINCT FROM (o->>'carrier_source')
|
|
31367
|
+
OR (v->>'reden') IS DISTINCT FROM (o->>'carrier_reason') THEN
|
|
31368
|
+
PERFORM set_config('logistics.carrier_writer', 'engine', true);
|
|
31369
|
+
UPDATE public.orders
|
|
31370
|
+
SET carrier_id = public.logistics_try_uuid(v->>'carrier_id'), carrier_source = v->>'bron',
|
|
31371
|
+
carrier_reason = v->>'reden', carrier_resolved_at = now()
|
|
31372
|
+
WHERE id = r.id;
|
|
31373
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
31374
|
+
n_upd := n_upd + 1;
|
|
31375
|
+
END IF;
|
|
31376
|
+
END IF;
|
|
31377
|
+
END IF;
|
|
31378
|
+
INSERT INTO public.logistics_carrier_recalc_queue AS q (order_id, reden, processed_at, last_checked_at)
|
|
31379
|
+
VALUES (r.id, 'Vangnet', now(), now())
|
|
31380
|
+
ON CONFLICT (order_id) DO UPDATE SET processed_at = now(), last_checked_at = now();
|
|
31381
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31382
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
31383
|
+
n_err := n_err + 1;
|
|
31384
|
+
END;
|
|
31385
|
+
END LOOP;
|
|
31386
|
+
RETURN jsonb_build_object('gecontroleerd', n_chk, 'gewijzigd', n_upd, 'bevroren', n_frozen,
|
|
31387
|
+
'handmatig', n_hand, 'fouten', n_err, 'bestaandeOrders', s.backfill_existing);
|
|
31388
|
+
END $function$;
|
|
31389
|
+
|
|
31390
|
+
-- Handmatig kiezen: de enige manier. NULL = terug naar automatisch. Verstuurt nooit een mail.
|
|
31391
|
+
CREATE OR REPLACE FUNCTION public.logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid)
|
|
31392
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31393
|
+
AS $function$
|
|
31394
|
+
DECLARE v_uid uuid := auth.uid(); o jsonb; v_skip text; r jsonb;
|
|
31395
|
+
BEGIN
|
|
31396
|
+
IF v_uid IS NULL AND coalesce(auth.role(), '') <> 'service_role' THEN RAISE EXCEPTION 'Niet ingelogd'; END IF;
|
|
31397
|
+
SELECT to_jsonb(x) INTO o FROM public.orders x WHERE x.id = p_order_id AND x.deleted_at IS NULL FOR UPDATE;
|
|
31398
|
+
IF o IS NULL THEN RAISE EXCEPTION 'Order niet gevonden.'; END IF;
|
|
31399
|
+
IF p_carrier_id IS NOT NULL THEN
|
|
31400
|
+
v_skip := public.logistics_carrier_skip_reason(p_carrier_id);
|
|
31401
|
+
IF v_skip IS NOT NULL THEN RAISE EXCEPTION 'Deze vervoerder kan niet gekozen worden: %.', v_skip; END IF;
|
|
31402
|
+
r := public.logistics_carrier_result(p_carrier_id, 'handmatig', 'Handmatig gekozen op de order.', '{}'::text[]);
|
|
31403
|
+
ELSE
|
|
31404
|
+
r := public.logistics_resolve_carrier_core(o, true);
|
|
31405
|
+
END IF;
|
|
31406
|
+
PERFORM set_config('logistics.carrier_writer', 'engine', true);
|
|
31407
|
+
UPDATE public.orders
|
|
31408
|
+
SET carrier_id = public.logistics_try_uuid(r->>'carrier_id'), carrier_source = r->>'bron',
|
|
31409
|
+
carrier_reason = r->>'reden', carrier_resolved_at = now(), carrier_set_by = v_uid, carrier_set_at = now()
|
|
31410
|
+
WHERE id = p_order_id;
|
|
31411
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
31412
|
+
RETURN r || jsonb_build_object('bevroren', public.logistics_carrier_frozen_reason(p_order_id));
|
|
31413
|
+
END $function$;
|
|
31414
|
+
|
|
31415
|
+
-- Lijst F: wat de regel per bestaande open order zou opslaan (alleen lezen).
|
|
31416
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_preview_existing(p_limit integer DEFAULT 1000)
|
|
31417
|
+
RETURNS TABLE(order_id uuid, order_number text, order_source text, delivery_date text, huidig_custom_carrier text,
|
|
31418
|
+
carrier_id uuid, carrier_name text, carrier_kind text, bron text, reden text, bevroren text)
|
|
31419
|
+
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31420
|
+
AS $function$
|
|
31421
|
+
BEGIN
|
|
31422
|
+
IF auth.uid() IS NOT NULL AND NOT public.logistics_is_beheer() THEN
|
|
31423
|
+
RAISE EXCEPTION 'Alleen beheer mag deze lijst bekijken.';
|
|
31424
|
+
END IF;
|
|
31425
|
+
RETURN QUERY
|
|
31426
|
+
SELECT o.id, o.order_number, o.order_source, o.delivery_date, o.custom_fields->>'carrier',
|
|
31427
|
+
public.logistics_try_uuid(v.r->>'carrier_id'), v.r->>'carrier_name', v.r->>'carrier_kind', v.r->>'bron', v.r->>'reden',
|
|
31428
|
+
public.logistics_carrier_frozen_reason(o.id)
|
|
31429
|
+
FROM public.orders o
|
|
31430
|
+
CROSS JOIN LATERAL (SELECT public.logistics_resolve_carrier_core(to_jsonb(o), false) AS r) v
|
|
31431
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL AND o.carrier_source IS NULL
|
|
31432
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date
|
|
31433
|
+
ORDER BY o.delivery_date, o.order_number
|
|
31434
|
+
LIMIT greatest(1, coalesce(p_limit, 1000));
|
|
31435
|
+
END $function$;
|
|
31436
|
+
|
|
31437
|
+
-- Schakelaar "Vervoerder berekenen voor bestaande orders" (alleen beheer).
|
|
31438
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_set_backfill(p_on boolean)
|
|
31439
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31440
|
+
AS $function$
|
|
31441
|
+
BEGIN
|
|
31442
|
+
IF auth.uid() IS NULL OR NOT public.logistics_is_beheer() THEN
|
|
31443
|
+
RAISE EXCEPTION 'Alleen beheer mag deze schakelaar wijzigen.';
|
|
31444
|
+
END IF;
|
|
31445
|
+
PERFORM public.logistics_carrier_settings_ensure();
|
|
31446
|
+
UPDATE public.logistics_carrier_settings
|
|
31447
|
+
SET backfill_existing = coalesce(p_on, false), backfill_set_by = auth.uid(), backfill_set_at = now(), updated_at = now()
|
|
31448
|
+
WHERE id;
|
|
31449
|
+
RETURN (SELECT to_jsonb(s) FROM public.logistics_carrier_settings s WHERE s.id);
|
|
31450
|
+
END $function$;
|
|
31451
|
+
|
|
31452
|
+
-- 'oud' -> 'handmatig', alleen na akkoord en met exact aantal (alleen beheer).
|
|
31453
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_promote_oud(p_order_ids uuid[], p_confirm_count integer)
|
|
31454
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
31455
|
+
AS $function$
|
|
31456
|
+
DECLARE n int;
|
|
31457
|
+
BEGIN
|
|
31458
|
+
IF auth.uid() IS NULL OR NOT public.logistics_is_beheer() THEN
|
|
31459
|
+
RAISE EXCEPTION 'Alleen beheer mag dit doen.';
|
|
31460
|
+
END IF;
|
|
31461
|
+
SELECT count(*) INTO n FROM public.orders WHERE id = ANY (p_order_ids) AND carrier_source = 'oud';
|
|
31462
|
+
IF n IS DISTINCT FROM p_confirm_count THEN
|
|
31463
|
+
RAISE EXCEPTION 'Aantal klopt niet: % orders met bron oud, bevestigd %.', n, p_confirm_count;
|
|
31464
|
+
END IF;
|
|
31465
|
+
PERFORM set_config('logistics.carrier_writer', 'engine', true);
|
|
31466
|
+
UPDATE public.orders SET carrier_source = 'handmatig', carrier_reason = 'Handmatig (overgenomen uit de bestaande vervoerder).',
|
|
31467
|
+
carrier_set_by = auth.uid(), carrier_set_at = now()
|
|
31468
|
+
WHERE id = ANY (p_order_ids) AND carrier_source = 'oud';
|
|
31469
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
31470
|
+
RETURN n;
|
|
31471
|
+
END $function$;
|
|
31472
|
+
|
|
31473
|
+
-- Bewaking in Beheer (alleen lezen).
|
|
31474
|
+
CREATE OR REPLACE FUNCTION public.logistics_carrier_status()
|
|
31475
|
+
RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
|
|
31476
|
+
AS $function$
|
|
31477
|
+
DECLARE s record; v jsonb;
|
|
31478
|
+
BEGIN
|
|
31479
|
+
IF auth.uid() IS NULL AND coalesce(auth.role(), '') <> 'service_role' THEN RAISE EXCEPTION 'Niet ingelogd'; END IF;
|
|
31480
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
31481
|
+
WITH open_orders AS (
|
|
31482
|
+
SELECT o.id, o.order_number, o.delivery_date, o.carrier_source, o.carrier_reason, o.created_at
|
|
31483
|
+
FROM public.orders o
|
|
31484
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
31485
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date
|
|
31486
|
+
)
|
|
31487
|
+
SELECT jsonb_build_object(
|
|
31488
|
+
'zonderVervoerder', count(*) FILTER (WHERE carrier_source = 'geen' OR (carrier_source IS NULL AND created_at >= s.installed_at)),
|
|
31489
|
+
'viaFavoriet', count(*) FILTER (WHERE carrier_source = 'favoriet'),
|
|
31490
|
+
'nogNietBerekend', count(*) FILTER (WHERE carrier_source IS NULL AND created_at < s.installed_at),
|
|
31491
|
+
'bronOud', count(*) FILTER (WHERE carrier_source = 'oud'),
|
|
31492
|
+
'lijstZonder', coalesce(jsonb_agg(jsonb_build_object('orderId', id, 'orderNumber', order_number, 'deliveryDate', delivery_date,
|
|
31493
|
+
'reden', coalesce(carrier_reason, 'Nog niet berekend.')) ORDER BY delivery_date, order_number)
|
|
31494
|
+
FILTER (WHERE carrier_source = 'geen' OR (carrier_source IS NULL AND created_at >= s.installed_at)), '[]'::jsonb),
|
|
31495
|
+
'lijstFavoriet', coalesce(jsonb_agg(jsonb_build_object('orderId', id, 'orderNumber', order_number, 'deliveryDate', delivery_date,
|
|
31496
|
+
'reden', carrier_reason) ORDER BY delivery_date, order_number) FILTER (WHERE carrier_source = 'favoriet'), '[]'::jsonb))
|
|
31497
|
+
INTO v FROM open_orders;
|
|
31498
|
+
RETURN v || jsonb_build_object('bufferFouten', (SELECT count(*) FROM public.logistics_carrier_events e
|
|
31499
|
+
WHERE e.soort = 'fout' AND e.created_at > now() - interval '7 days'), 'bestaandeOrders', coalesce(s.backfill_existing, false),
|
|
31500
|
+
'installedAt', s.installed_at, 'schakelaarGezetDoor', s.backfill_set_by, 'schakelaarGezetOp', s.backfill_set_at);
|
|
31501
|
+
END $function$;
|
|
31502
|
+
|
|
31503
|
+
-- Installatiecontrole voor de vervoerder-onderdelen (alleen lezen).
|
|
31504
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check()
|
|
31505
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text)
|
|
31506
|
+
LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
|
|
31507
|
+
AS $function$
|
|
31508
|
+
DECLARE c text; f text; t text; v_fav text; n bigint; s record;
|
|
31509
|
+
BEGIN
|
|
31510
|
+
-- Engine-onderdelen waar de vervoerder van afhangt + 1.0.179/1.0.182 (functie of tabel op naam).
|
|
31511
|
+
FOREACH f IN ARRAY ARRAY[
|
|
31512
|
+
'f:logistics_try_uuid','f:logistics_tz','f:logistics_is_beheer','f:logistics_buffer_payload','f:logistics_apply_order_buffer',
|
|
31513
|
+
'f:logistics_apply_buffer_decision','f:logistics_rebuffer_pending','f:logistics_departure_calc','f:logistics_own_transport_departure',
|
|
31514
|
+
'f:logistics_order_departure','f:logistics_brief_transport','f:logistics_order_frozen','f:logistics_order_is_frozen',
|
|
31515
|
+
'f:logistics_order_finalize_run','f:run_logistics_tasks_dispatch','f:enqueue_cart_replan_if_unlocked','f:logistics_tick',
|
|
31516
|
+
't:logistics_tick_runs',
|
|
31517
|
+
'f:logistics_belading_bevestig','f:logistics_cart_seq_dubbel','f:logistics_plan_retry_later','f:logistics_own_traysticker_sync',
|
|
31518
|
+
't:logistics_belading_bevestigingen',
|
|
31519
|
+
'f:logistics_sticker_copies','f:logistics_sticker_etiket_status','f:logistics_sticker_order_counts','f:logistics_sticker_sync',
|
|
31520
|
+
'c:logistics_sticker_prints.kopieen_bron',
|
|
31521
|
+
'f:logistics_carrier_settings_ensure','t:logistics_carrier_settings','t:logistics_carrier_recalc_queue','t:logistics_carrier_events',
|
|
31522
|
+
'f:logistics_carrier_status','f:logistics_carrier_set_backfill','f:logistics_carrier_preview_existing','c:control_get_todays_carts.carrier_name'] LOOP
|
|
31523
|
+
onderdeel := 'Engine: ' || substr(f, 3);
|
|
31524
|
+
ok := CASE left(f, 1)
|
|
31525
|
+
WHEN 'f' THEN EXISTS (SELECT 1 FROM pg_proc p WHERE p.pronamespace = 'public'::regnamespace AND p.proname = substr(f, 3))
|
|
31526
|
+
WHEN 't' THEN to_regclass('public.' || substr(f, 3)) IS NOT NULL
|
|
31527
|
+
ELSE CASE WHEN split_part(substr(f, 3), '.', 1) = 'control_get_todays_carts'
|
|
31528
|
+
THEN coalesce(pg_get_function_result(to_regprocedure('public.control_get_todays_carts()')), '') LIKE '%carrier_name%'
|
|
31529
|
+
ELSE EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public'
|
|
31530
|
+
AND table_name = split_part(substr(f, 3), '.', 1) AND column_name = split_part(substr(f, 3), '.', 2)) END
|
|
31531
|
+
END;
|
|
31532
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie (1.0.182 t/m 1.0.184) in dev uitvoeren en via schemasync verspreiden' END;
|
|
31533
|
+
RETURN NEXT;
|
|
31534
|
+
END LOOP;
|
|
31535
|
+
FOREACH c IN ARRAY ARRAY['carrier_id','carrier_source','carrier_reason','carrier_resolved_at','carrier_set_by','carrier_set_at'] LOOP
|
|
31536
|
+
onderdeel := 'orders.' || c;
|
|
31537
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='orders' AND column_name=c);
|
|
31538
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
31539
|
+
END LOOP;
|
|
31540
|
+
FOREACH f IN ARRAY ARRAY['logistics_resolve_carrier(uuid)','logistics_resolve_carrier_many(uuid[])',
|
|
31541
|
+
'logistics_resolve_carrier_for_location(uuid,uuid)','logistics_resolve_carrier_for_location_many(uuid[],uuid)',
|
|
31542
|
+
'logistics_resolve_carrier_for_location_many(jsonb)',
|
|
31543
|
+
'logistics_set_order_carrier(uuid,uuid)','logistics_carrier_recalc_run(integer)'] LOOP
|
|
31544
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
31545
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
31546
|
+
END LOOP;
|
|
31547
|
+
FOREACH t IN ARRAY ARRAY['orders:trg_logistics_orders_carrier_fill','orders:trg_logistics_orders_carrier_changed',
|
|
31548
|
+
'carriers:trg_logistics_carriers_enqueue','customer_delivery_locations:trg_logistics_locations_enqueue'] LOOP
|
|
31549
|
+
onderdeel := 'trigger ' || split_part(t, ':', 2);
|
|
31550
|
+
ok := EXISTS (SELECT 1 FROM pg_trigger g WHERE g.tgname = split_part(t, ':', 2)
|
|
31551
|
+
AND g.tgrelid = to_regclass('public.' || split_part(t, ':', 1)));
|
|
31552
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
31553
|
+
END LOOP;
|
|
31554
|
+
onderdeel := 'minuutronde rekent vervoerders';
|
|
31555
|
+
ok := EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'logistics_tick' AND prosrc LIKE '%logistics_carrier_recalc_run%');
|
|
31556
|
+
toelichting := CASE WHEN ok THEN 'ja' ELSE 'nee' END; RETURN NEXT;
|
|
31557
|
+
FOREACH c IN ARRAY ARRAY['carrier_kind','is_favorite','archived_at','delivery_location_glns'] LOOP
|
|
31558
|
+
onderdeel := 'Afhandeling: carriers.' || c;
|
|
31559
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='carriers' AND column_name=c);
|
|
31560
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Afhandeling' END; RETURN NEXT;
|
|
31561
|
+
END LOOP;
|
|
31562
|
+
FOREACH f IN ARRAY ARRAY['afh_favorite_carrier','afh_city_code','afh_normalize_country','afh_normalize_nl_province'] LOOP
|
|
31563
|
+
onderdeel := 'Afhandeling: ' || f || '()';
|
|
31564
|
+
ok := EXISTS (SELECT 1 FROM pg_proc p WHERE p.pronamespace = 'public'::regnamespace AND p.proname = f);
|
|
31565
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Afhandeling' END; RETURN NEXT;
|
|
31566
|
+
END LOOP;
|
|
31567
|
+
onderdeel := 'Favoriete vervoerder ingesteld en bruikbaar';
|
|
31568
|
+
IF to_regprocedure('public.afh_favorite_carrier()') IS NULL THEN ok := false; toelichting := 'functie ontbreekt';
|
|
31569
|
+
ELSE
|
|
31570
|
+
BEGIN v_fav := public.logistics_carrier_favorite_id()::text; EXCEPTION WHEN OTHERS THEN v_fav := NULL; END;
|
|
31571
|
+
ok := public.logistics_try_uuid(v_fav) IS NOT NULL AND public.logistics_carrier_skip_reason(public.logistics_try_uuid(v_fav)) IS NULL;
|
|
31572
|
+
toelichting := CASE WHEN ok THEN 'ja' WHEN v_fav IS NULL THEN 'geen favoriet ingesteld (Afhandeling → Vervoerders)'
|
|
31573
|
+
ELSE public.logistics_carrier_skip_reason(public.logistics_try_uuid(v_fav)) END;
|
|
31574
|
+
END IF;
|
|
31575
|
+
RETURN NEXT;
|
|
31576
|
+
onderdeel := 'Klanten: customers.default_carrier_id';
|
|
31577
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='customers' AND column_name='default_carrier_id');
|
|
31578
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Klanten' END; RETURN NEXT;
|
|
31579
|
+
IF to_regclass('public.logistics_carrier_settings') IS NOT NULL AND to_regclass('public.orders') IS NOT NULL
|
|
31580
|
+
AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='orders' AND column_name='carrier_source') THEN
|
|
31581
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
31582
|
+
EXECUTE $q$SELECT count(*) FROM public.orders o
|
|
31583
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
31584
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date
|
|
31585
|
+
AND (o.carrier_source = 'geen' OR (o.carrier_source IS NULL AND o.created_at >= $1))$q$ INTO n USING s.installed_at;
|
|
31586
|
+
onderdeel := 'Open orders zonder vervoerder'; ok := n = 0; toelichting := n || ' order(s)'; RETURN NEXT;
|
|
31587
|
+
onderdeel := 'Schakelaar bestaande orders'; ok := true;
|
|
31588
|
+
toelichting := CASE WHEN coalesce(s.backfill_existing, false) THEN 'aan' ELSE 'uit (bestaande orders wachten op akkoord)' END; RETURN NEXT;
|
|
31589
|
+
END IF;
|
|
31590
|
+
END $function$;
|
|
31591
|
+
|
|
31592
|
+
-- Buffergegevens: vervoerder van de order (kolom) gaat voor custom_fields.
|
|
31593
|
+
CREATE OR REPLACE FUNCTION public.logistics_buffer_payload(p_order_id uuid)
|
|
31594
|
+
RETURNS jsonb
|
|
31595
|
+
LANGUAGE sql
|
|
31596
|
+
STABLE SECURITY DEFINER
|
|
31597
|
+
SET search_path TO 'public'
|
|
31598
|
+
AS $function$
|
|
31599
|
+
SELECT jsonb_build_object(
|
|
31600
|
+
'orderRef', COALESCE(o.order_number, o.id::text),
|
|
31601
|
+
'checkinAt', COALESCE(cf ->> 'checkin_at', cf ->> 'checkin_moment', cf ->> 'pickup_moment', cf ->> 'pickup_datetime'),
|
|
31602
|
+
'pickupAt', COALESCE(cf ->> 'pickup_datetime', cf ->> 'pickup_moment', cf ->> 'checkin_at'),
|
|
31603
|
+
'customerRef', o.customer_id::text,
|
|
31604
|
+
'floridayCustomerRef', COALESCE(cf ->> 'floriday_customer_id', cf ->> 'floriday_customer_ref'),
|
|
31605
|
+
'floridaySalesOrderRef', COALESCE(o.floriday_sales_order_id::text, cf ->> 'floriday_sales_order_id'),
|
|
31606
|
+
'bvoCustomerRef', COALESCE(cf ->> 'bvo_customer_ref', cf ->> 'bvo_customer_id'),
|
|
31607
|
+
'deliveryLocationRef', COALESCE(cf ->> 'delivery_location_gln', cf ->> 'delivery_location_id', cf ->> 'delivery_location'),
|
|
31608
|
+
'deliveryDate', o.delivery_date::text,
|
|
31609
|
+
'carrierRef', CASE WHEN o.carrier_id IS NOT NULL THEN o.carrier_id::text
|
|
31610
|
+
WHEN o.carrier_source IS NOT NULL AND o.carrier_source <> 'geen' THEN 'klant_haalt_op'
|
|
31611
|
+
ELSE COALESCE(cf ->> 'carrier_id', cf ->> 'carrier') END,
|
|
31612
|
+
'loadCarrierType', COALESCE(cf ->> 'load_carrier_type', 'trolley'),
|
|
31613
|
+
'orderType', COALESCE(cf ->> 'order_type', o.order_source, 'standaard'),
|
|
31614
|
+
'isReservation', COALESCE(o.is_reservation, false)
|
|
31615
|
+
)
|
|
31616
|
+
FROM public.orders o
|
|
31617
|
+
CROSS JOIN LATERAL (SELECT COALESCE(o.custom_fields, '{}'::jsonb) AS cf) x
|
|
31618
|
+
WHERE o.id = p_order_id;
|
|
31619
|
+
$function$;
|
|
31620
|
+
|
|
31621
|
+
-- Vertrek per order: eigen vervoer en afhalen op soort; geen vervoerder = luide reden.
|
|
31622
|
+
CREATE OR REPLACE FUNCTION public.logistics_order_departure(p_order_id uuid)
|
|
31623
|
+
RETURNS jsonb
|
|
31624
|
+
LANGUAGE plpgsql
|
|
31625
|
+
STABLE SECURITY DEFINER
|
|
31626
|
+
SET search_path TO 'public'
|
|
31627
|
+
AS $function$
|
|
31628
|
+
DECLARE o record; v jsonb; v_own jsonb; v_txt text; v_at timestamptz; v_info jsonb;
|
|
31629
|
+
BEGIN
|
|
31630
|
+
IF public.logistics_tz() IS NULL THEN
|
|
31631
|
+
RETURN jsonb_build_object('ok', false, 'reason', 'De tijdzone van de vestiging ontbreekt. Stel die in bij Werktijden.');
|
|
31632
|
+
END IF;
|
|
31633
|
+
SELECT id, created_at, delivery_date, custom_fields INTO o FROM public.orders WHERE id = p_order_id;
|
|
31634
|
+
IF NOT FOUND OR coalesce(o.delivery_date,'') !~ '^\d{4}-\d{2}-\d{2}' THEN
|
|
31635
|
+
RETURN jsonb_build_object('ok', false, 'reason', 'De leverdatum van de order is onbekend.');
|
|
31636
|
+
END IF;
|
|
31637
|
+
|
|
31638
|
+
v_own := CASE WHEN jsonb_typeof(o.custom_fields->'own_transport') = 'object' THEN o.custom_fields->'own_transport' END;
|
|
31639
|
+
IF v_own IS NOT NULL THEN
|
|
31640
|
+
v_txt := nullif(btrim(coalesce(v_own->>'pickup_at', '')), '');
|
|
31641
|
+
IF v_txt IS NOT NULL THEN
|
|
31642
|
+
IF v_txt !~ '(Z|[+-]\d{2}(:?\d{2})?)$' THEN
|
|
31643
|
+
RETURN jsonb_build_object('ok', false, 'ownTransport', true,
|
|
31644
|
+
'reason', 'De ophaaltijd bij eigen vervoer mist een tijdzone.');
|
|
31645
|
+
END IF;
|
|
31646
|
+
BEGIN
|
|
31647
|
+
v_at := v_txt::timestamptz;
|
|
31648
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31649
|
+
RETURN jsonb_build_object('ok', false, 'ownTransport', true,
|
|
31650
|
+
'reason', 'De ophaaltijd bij eigen vervoer is geen geldige tijd.');
|
|
31651
|
+
END;
|
|
31652
|
+
END IF;
|
|
31653
|
+
RETURN public.logistics_own_transport_departure(left(o.delivery_date,10)::date, v_at);
|
|
31654
|
+
END IF;
|
|
31655
|
+
|
|
31656
|
+
v_info := public.logistics_order_carrier_info(p_order_id);
|
|
31657
|
+
IF v_info->>'carrier_kind' IN ('eigen_vervoer', 'klant_haalt_op') THEN
|
|
31658
|
+
RETURN public.logistics_own_transport_departure(left(o.delivery_date,10)::date, NULL)
|
|
31659
|
+
|| jsonb_build_object('carrierKind', v_info->>'carrier_kind', 'carrierLabel', v_info->>'carrier_name',
|
|
31660
|
+
'carrierSource', v_info->>'bron');
|
|
31661
|
+
END IF;
|
|
31662
|
+
IF public.logistics_try_uuid(v_info->>'carrier_id') IS NULL THEN
|
|
31663
|
+
RETURN jsonb_build_object('ok', false, 'carrierSource', coalesce(v_info->>'bron', 'geen'),
|
|
31664
|
+
'reason', coalesce(v_info->>'reden', 'Geen vervoerder: stel een favoriete vervoerder in (Afhandeling → Vervoerders).'));
|
|
31665
|
+
END IF;
|
|
31666
|
+
|
|
31667
|
+
v := public.logistics_departure_calc((v_info->>'carrier_id')::uuid, left(o.delivery_date,10)::date, o.created_at, NULL);
|
|
31668
|
+
RETURN (v - 'moments') || jsonb_build_object('carrierSource', v_info->>'bron', 'carrierLabel', v_info->>'carrier_name');
|
|
31669
|
+
END $function$;
|
|
31670
|
+
|
|
31671
|
+
-- Vervoerder op brieven: zelfde regel; eigen vervoer/afhalen als label, nooit "onbekend".
|
|
31672
|
+
CREATE OR REPLACE FUNCTION public.logistics_brief_transport(p_order_id uuid, p_cart_id uuid DEFAULT NULL::uuid)
|
|
31673
|
+
RETURNS jsonb
|
|
31674
|
+
LANGUAGE plpgsql
|
|
31675
|
+
STABLE SECURITY DEFINER
|
|
31676
|
+
SET search_path TO 'public'
|
|
31677
|
+
AS $function$
|
|
31678
|
+
DECLARE
|
|
31679
|
+
o record; v_carrier_id uuid; v_bron text; ca public.carriers%ROWTYPE; v_info jsonb; v_own jsonb;
|
|
31680
|
+
v_naam text; v_code text; v_date date; v_time time; n int;
|
|
31681
|
+
v_wens text; onbekend text[] := '{}'::text[]; uit jsonb := '{}'::jsonb;
|
|
31682
|
+
BEGIN
|
|
31683
|
+
SELECT id, custom_fields, floriday_sales_order_id, delivery_date INTO o FROM public.orders WHERE id = p_order_id AND deleted_at IS NULL;
|
|
31684
|
+
IF o.id IS NULL THEN
|
|
31685
|
+
RETURN jsonb_build_object('onbekend', jsonb_build_array('order'));
|
|
31686
|
+
END IF;
|
|
31687
|
+
|
|
31688
|
+
v_info := public.logistics_order_carrier_info(p_order_id);
|
|
31689
|
+
IF v_info->>'carrier_kind' IN ('eigen_vervoer', 'klant_haalt_op') THEN
|
|
31690
|
+
uit := jsonb_build_object('vervoerder', jsonb_build_object('naam', v_info->>'carrier_name'),
|
|
31691
|
+
'vervoerder_bron', v_info->>'bron', 'carrier_label', v_info->>'carrier_name', 'carrier_kind', v_info->>'carrier_kind');
|
|
31692
|
+
IF coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' THEN
|
|
31693
|
+
v_own := public.logistics_own_transport_departure(left(o.delivery_date, 10)::date, NULL);
|
|
31694
|
+
IF coalesce((v_own->>'ok')::boolean, false) AND v_own->>'departureAt' IS NOT NULL THEN
|
|
31695
|
+
uit := uit || jsonb_build_object('ophaalmoment', v_own->>'departureAt');
|
|
31696
|
+
ELSE
|
|
31697
|
+
onbekend := array_append(onbekend, 'ophaalmoment');
|
|
31698
|
+
END IF;
|
|
31699
|
+
ELSE
|
|
31700
|
+
onbekend := array_append(onbekend, 'ophaalmoment');
|
|
31701
|
+
END IF;
|
|
31702
|
+
RETURN uit || jsonb_build_object('onbekend', to_jsonb(onbekend));
|
|
31703
|
+
END IF;
|
|
31704
|
+
|
|
31705
|
+
v_carrier_id := public.logistics_try_uuid(v_info->>'carrier_id');
|
|
31706
|
+
v_bron := v_info->>'bron';
|
|
31707
|
+
IF v_carrier_id IS NOT NULL THEN
|
|
31708
|
+
SELECT * INTO ca FROM public.carriers WHERE id = v_carrier_id;
|
|
31709
|
+
END IF;
|
|
31710
|
+
|
|
31711
|
+
IF ca.id IS NOT NULL AND nullif(trim(ca.name),'') IS NOT NULL THEN
|
|
31712
|
+
uit := uit || jsonb_build_object('vervoerder', jsonb_build_object('naam', ca.name), 'vervoerder_bron', v_bron,
|
|
31713
|
+
'carrier_label', ca.name, 'carrier_kind', v_info->>'carrier_kind');
|
|
31714
|
+
ELSE
|
|
31715
|
+
SELECT count(*), min(fc.name), min(nullif(fc.gln_code,'')) INTO n, v_naam, v_code
|
|
31716
|
+
FROM public.floriday_delivery_orders_cache d
|
|
31717
|
+
JOIN public.floriday_carriers_cache fc ON fc.organization_id::text = d.data->>'carrierOrganizationId'
|
|
31718
|
+
WHERE o.floriday_sales_order_id IS NOT NULL
|
|
31719
|
+
AND d.data::text LIKE '%' || o.floriday_sales_order_id::text || '%'
|
|
31720
|
+
AND coalesce(d.is_deleted,false) = false;
|
|
31721
|
+
IF n = 1 AND nullif(trim(v_naam),'') IS NOT NULL THEN
|
|
31722
|
+
uit := uit || jsonb_build_object('vervoerder', jsonb_build_object('naam', v_naam) ||
|
|
31723
|
+
CASE WHEN v_code IS NOT NULL THEN jsonb_build_object('code', v_code) ELSE '{}'::jsonb END,
|
|
31724
|
+
'vervoerder_bron', 'floriday', 'carrier_label', v_naam);
|
|
31725
|
+
ELSE
|
|
31726
|
+
onbekend := array_append(onbekend, CASE WHEN n > 1 THEN 'vervoerder_niet_eenduidig' ELSE 'vervoerder' END);
|
|
31727
|
+
END IF;
|
|
31728
|
+
END IF;
|
|
31729
|
+
|
|
31730
|
+
SELECT pick_date INTO v_date FROM public.logistics_order_pick_day WHERE order_id = p_order_id;
|
|
31731
|
+
IF v_date IS NULL OR ca.id IS NULL OR jsonb_typeof(ca.pickup_moments) IS DISTINCT FROM 'array' THEN
|
|
31732
|
+
onbekend := array_append(onbekend, 'ophaalmoment');
|
|
31733
|
+
ELSIF ca.pickup_weekdays IS NOT NULL AND array_length(ca.pickup_weekdays,1) > 0
|
|
31734
|
+
AND NOT (extract(isodow FROM v_date)::int = ANY (ca.pickup_weekdays)) THEN
|
|
31735
|
+
onbekend := array_append(onbekend, 'ophaalmoment');
|
|
31736
|
+
ELSE
|
|
31737
|
+
v_wens := nullif(o.custom_fields->>'pickup_moment','');
|
|
31738
|
+
SELECT count(*), min(nullif(m->>'pickup_time','')::time) INTO n, v_time
|
|
31739
|
+
FROM jsonb_array_elements(ca.pickup_moments) m
|
|
31740
|
+
WHERE nullif(m->>'pickup_time','') IS NOT NULL
|
|
31741
|
+
AND coalesce(nullif(m->>'pickup_days',''),'0') = '0'
|
|
31742
|
+
AND (v_wens IS NULL OR left(m->>'pickup_time',5) = left(v_wens,5));
|
|
31743
|
+
IF n = 1 THEN
|
|
31744
|
+
uit := uit || jsonb_build_object('ophaalmoment',
|
|
31745
|
+
to_char(((v_date + v_time) AT TIME ZONE public.logistics_tz()) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'));
|
|
31746
|
+
ELSE
|
|
31747
|
+
onbekend := array_append(onbekend, CASE WHEN n > 1 THEN 'ophaalmoment_niet_eenduidig' ELSE 'ophaalmoment' END);
|
|
31748
|
+
END IF;
|
|
31749
|
+
END IF;
|
|
31750
|
+
|
|
31751
|
+
RETURN uit || jsonb_build_object('onbekend', to_jsonb(onbekend));
|
|
31752
|
+
END;
|
|
31753
|
+
$function$;
|
|
31754
|
+
|
|
31755
|
+
-- Minuutronde met stap 'vervoerder' (hooguit 200 orders per ronde).
|
|
31756
|
+
CREATE OR REPLACE FUNCTION public.logistics_tick()
|
|
31757
|
+
RETURNS jsonb
|
|
31758
|
+
LANGUAGE plpgsql
|
|
31759
|
+
SECURITY DEFINER
|
|
31760
|
+
SET search_path TO 'public'
|
|
31761
|
+
AS $function$
|
|
31762
|
+
DECLARE v_result jsonb := '{}'::jsonb; v_start timestamptz := clock_timestamp(); v_t timestamptz; v_err boolean := false;
|
|
31763
|
+
BEGIN
|
|
31764
|
+
v_t := clock_timestamp();
|
|
31765
|
+
BEGIN
|
|
31766
|
+
PERFORM set_config('statement_timeout', '10000', true);
|
|
31767
|
+
v_result := v_result || jsonb_build_object('vervoerder', public.logistics_carrier_recalc_run(200));
|
|
31768
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31769
|
+
v_err := true; v_result := v_result || jsonb_build_object('vervoerder', left(SQLERRM, 200));
|
|
31770
|
+
END;
|
|
31771
|
+
v_result := v_result || jsonb_build_object('vervoerder_ms', (extract(epoch from clock_timestamp()-v_t)*1000)::int);
|
|
31772
|
+
|
|
31773
|
+
v_t := clock_timestamp();
|
|
31774
|
+
BEGIN
|
|
31775
|
+
PERFORM set_config('statement_timeout', '15000', true);
|
|
31776
|
+
PERFORM public.logistics_rebuffer_pending();
|
|
31777
|
+
v_result := v_result || jsonb_build_object('rebuffer', 'ok');
|
|
31778
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31779
|
+
v_err := true;
|
|
31780
|
+
IF SQLERRM ILIKE '%tijdzone%' THEN
|
|
31781
|
+
v_result := v_result || jsonb_build_object('rebuffer', 'overgeslagen: tijdzone ontbreekt in Werktijden');
|
|
31782
|
+
BEGIN
|
|
31783
|
+
UPDATE public.logistics_rebuffer_state SET last_error = 'Herindelen overgeslagen: de tijdzone ontbreekt in Werktijden.', updated_at = now() WHERE id;
|
|
31784
|
+
EXCEPTION WHEN OTHERS THEN NULL; END;
|
|
31785
|
+
ELSE
|
|
31786
|
+
v_result := v_result || jsonb_build_object('rebuffer', left(SQLERRM, 200));
|
|
31787
|
+
END IF;
|
|
31788
|
+
END;
|
|
31789
|
+
v_result := v_result || jsonb_build_object('rebuffer_ms', (extract(epoch from clock_timestamp()-v_t)*1000)::int);
|
|
31790
|
+
|
|
31791
|
+
v_t := clock_timestamp();
|
|
31792
|
+
BEGIN
|
|
31793
|
+
PERFORM set_config('statement_timeout', '20000', true);
|
|
31794
|
+
PERFORM public.run_logistics_tasks_dispatch();
|
|
31795
|
+
v_result := v_result || jsonb_build_object('taken', 'ok');
|
|
31796
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31797
|
+
v_err := true; v_result := v_result || jsonb_build_object('taken', left(SQLERRM, 200));
|
|
31798
|
+
END;
|
|
31799
|
+
v_result := v_result || jsonb_build_object('taken_ms', (extract(epoch from clock_timestamp()-v_t)*1000)::int);
|
|
31800
|
+
|
|
31801
|
+
v_t := clock_timestamp();
|
|
31802
|
+
BEGIN
|
|
31803
|
+
PERFORM set_config('statement_timeout', '20000', true);
|
|
31804
|
+
v_result := v_result || jsonb_build_object('afgerond', public.logistics_order_finalize_run(25, 120));
|
|
31805
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31806
|
+
v_err := true; v_result := v_result || jsonb_build_object('afgerond', left(SQLERRM, 200));
|
|
31807
|
+
END;
|
|
31808
|
+
v_result := v_result || jsonb_build_object('afgerond_ms', (extract(epoch from clock_timestamp()-v_t)*1000)::int);
|
|
31809
|
+
|
|
31810
|
+
BEGIN
|
|
31811
|
+
INSERT INTO public.logistics_tick_runs(started_at, finished_at, duration_ms, has_error, steps)
|
|
31812
|
+
VALUES (v_start, clock_timestamp(), (extract(epoch from clock_timestamp()-v_start)*1000)::int, v_err, v_result);
|
|
31813
|
+
EXCEPTION WHEN OTHERS THEN NULL;
|
|
31814
|
+
END;
|
|
31815
|
+
PERFORM set_config('statement_timeout', '30000', true);
|
|
31816
|
+
RETURN v_result;
|
|
31817
|
+
END $function$;
|
|
31818
|
+
|
|
31819
|
+
-- Rechten: API-functies voor ingelogde gebruikers; interne functies alleen service_role.
|
|
31820
|
+
DO $fs$ DECLARE f text; BEGIN
|
|
31821
|
+
FOREACH f IN ARRAY ARRAY['logistics_resolve_carrier(uuid)','logistics_resolve_carrier_many(uuid[])',
|
|
31822
|
+
'logistics_resolve_carrier_for_location(uuid,uuid)','logistics_resolve_carrier_for_location_many(uuid[],uuid)',
|
|
31823
|
+
'logistics_set_order_carrier(uuid,uuid)','logistics_carrier_status()','logistics_carrier_set_backfill(boolean)',
|
|
31824
|
+
'logistics_carrier_preview_existing(integer)','logistics_carrier_promote_oud(uuid[],integer)',
|
|
31825
|
+
'logistics_order_carrier_label(uuid)','logistics_install_check()','logistics_order_departure(uuid)','logistics_resolve_carrier_for_location_many(jsonb)'] LOOP
|
|
31826
|
+
EXECUTE format('REVOKE ALL ON FUNCTION public.%s FROM PUBLIC, anon', f);
|
|
31827
|
+
EXECUTE format('GRANT EXECUTE ON FUNCTION public.%s TO authenticated, service_role', f);
|
|
31828
|
+
END LOOP;
|
|
31829
|
+
FOREACH f IN ARRAY ARRAY['logistics_carrier_skip_reason(uuid)','logistics_carrier_picks_up_for(uuid,date)','logistics_carrier_favorite_id()',
|
|
31830
|
+
'logistics_carrier_result(uuid,text,text,text[])','logistics_resolve_carrier_core(jsonb,boolean)',
|
|
31831
|
+
'logistics_carrier_frozen_reason(uuid)','logistics_order_carrier_info(uuid)','logistics_carrier_enqueue(uuid[],text)',
|
|
31832
|
+
'logistics_carrier_recalc_run(integer)','logistics_orders_carrier_fill()','logistics_orders_carrier_changed()',
|
|
31833
|
+
'logistics_carriers_enqueue_orders()','logistics_locations_enqueue_orders()',
|
|
31834
|
+
'logistics_order_carrier_id(uuid)','logistics_carrier_for_location(text,uuid)','logistics_buffer_payload(uuid)',
|
|
31835
|
+
'logistics_brief_transport(uuid,uuid)','logistics_tick()'] LOOP
|
|
31836
|
+
EXECUTE format('REVOKE ALL ON FUNCTION public.%s FROM PUBLIC, anon, authenticated', f);
|
|
31837
|
+
EXECUTE format('GRANT EXECUTE ON FUNCTION public.%s TO service_role', f);
|
|
31838
|
+
END LOOP;
|
|
31839
|
+
END $fs$;
|
|
31840
|
+
|
|
31841
|
+
-- 1.0.184: karrenlijst toont de vervoerder uit orders.carrier_id (achteraan toegevoegd).
|
|
31842
|
+
-- "Eigen vervoer" en "Afhalen" op carrier_kind / self_pickup, nooit op naam.
|
|
31843
|
+
DO $m$ BEGIN
|
|
31844
|
+
IF to_regprocedure('public.control_get_todays_carts()') IS NOT NULL
|
|
31845
|
+
AND pg_get_function_result('public.control_get_todays_carts()'::regprocedure) NOT LIKE '%carrier_name%' THEN
|
|
31846
|
+
DROP FUNCTION public.control_get_todays_carts();
|
|
31847
|
+
END IF;
|
|
31848
|
+
END $m$;
|
|
31849
|
+
|
|
31850
|
+
CREATE OR REPLACE FUNCTION public.control_get_todays_carts()
|
|
31851
|
+
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, carrier_name text)
|
|
31852
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
31853
|
+
AS $function$
|
|
31854
|
+
WITH vandaag AS (
|
|
31855
|
+
SELECT (now() AT TIME ZONE public.logistics_tz())::date AS d
|
|
31856
|
+
),
|
|
31857
|
+
idx AS (
|
|
31858
|
+
SELECT DISTINCT ON (i.cart_id) i.*
|
|
31859
|
+
FROM public.logistics_cart_index((SELECT d FROM vandaag), (SELECT d FROM vandaag)) i
|
|
31860
|
+
ORDER BY i.cart_id, i.order_number
|
|
31861
|
+
),
|
|
31862
|
+
gecontroleerd AS (
|
|
31863
|
+
SELECT cci.cart_number_id, cci.order_source, cci.order_id, cci.cart_index
|
|
31864
|
+
FROM public.cart_control_items cci
|
|
31865
|
+
JOIN public.cart_control_sessions ccs ON ccs.id = cci.session_id
|
|
31866
|
+
WHERE ccs.control_date = (SELECT d FROM vandaag)
|
|
31867
|
+
AND cci.action = 'checked'
|
|
31868
|
+
)
|
|
31869
|
+
SELECT
|
|
31870
|
+
i.cart_id,
|
|
31871
|
+
COALESCE(cn.cart_number, i.cart_label),
|
|
31872
|
+
i.order_source,
|
|
31873
|
+
i.order_uuid::text,
|
|
31874
|
+
i.cart_index,
|
|
31875
|
+
i.order_number,
|
|
31876
|
+
i.pick_date,
|
|
31877
|
+
COALESCE(cn.status, 'pending'),
|
|
31878
|
+
i.printed_at,
|
|
31879
|
+
(i.printed_at >= (SELECT d FROM vandaag)::timestamptz),
|
|
31880
|
+
(SELECT sum(ci.crates)::int FROM public.order_cart_items ci WHERE ci.cart_id = i.cart_id),
|
|
31881
|
+
(SELECT CASE WHEN upper(btrim(l.country)) ~ '^[A-Z]{2}$' THEN upper(btrim(l.country)) END
|
|
31882
|
+
FROM public.orders o
|
|
31883
|
+
JOIN public.customer_delivery_locations l
|
|
31884
|
+
ON l.id = public.logistics_try_uuid(o.custom_fields->>'delivery_location')
|
|
31885
|
+
WHERE o.id = i.order_uuid
|
|
31886
|
+
LIMIT 1),
|
|
31887
|
+
(SELECT CASE WHEN c.carrier_kind = 'eigen_vervoer' THEN 'Eigen vervoer'
|
|
31888
|
+
WHEN c.carrier_kind = 'klant_haalt_op' THEN 'Afhalen'
|
|
31889
|
+
WHEN o.carrier_id IS NULL AND o.carrier_source = 'afleverlocatie' THEN 'Afhalen'
|
|
31890
|
+
ELSE c.name END
|
|
31891
|
+
FROM public.orders o
|
|
31892
|
+
LEFT JOIN public.carriers c ON c.id = o.carrier_id
|
|
31893
|
+
WHERE o.id = i.order_uuid
|
|
31894
|
+
LIMIT 1)
|
|
31895
|
+
FROM idx i
|
|
31896
|
+
LEFT JOIN public.cart_numbers cn
|
|
31897
|
+
ON cn.order_source = i.order_source
|
|
31898
|
+
AND cn.order_id = i.order_uuid::text
|
|
31899
|
+
AND cn.cart_index = i.cart_index
|
|
31900
|
+
LEFT JOIN gecontroleerd g1 ON g1.cart_number_id = i.cart_id
|
|
31901
|
+
LEFT JOIN gecontroleerd g2
|
|
31902
|
+
ON g2.order_source = i.order_source
|
|
31903
|
+
AND g2.order_id = i.order_uuid::text
|
|
31904
|
+
AND g2.cart_index = i.cart_index
|
|
31905
|
+
WHERE COALESCE(cn.status, 'pending') <> 'delivered'
|
|
31906
|
+
AND g1.cart_number_id IS NULL
|
|
31907
|
+
AND g2.order_id IS NULL
|
|
31908
|
+
ORDER BY i.order_number, i.cart_index;
|
|
31909
|
+
$function$;
|
|
31910
|
+
REVOKE ALL ON FUNCTION public.control_get_todays_carts() FROM PUBLIC, anon;
|
|
31911
|
+
GRANT EXECUTE ON FUNCTION public.control_get_todays_carts() TO authenticated, service_role;
|
|
31912
|
+
|
|
31913
|
+
-- ===== 1.0.184 toegangscontrole in functies (overleeft schemasync) =====
|
|
31914
|
+
CREATE OR REPLACE FUNCTION public.logistics_acc_is_server()
|
|
31915
|
+
RETURNS boolean LANGUAGE sql STABLE SET search_path TO 'public'
|
|
31916
|
+
AS $function$
|
|
31917
|
+
SELECT coalesce(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role', '') = 'service_role'
|
|
31918
|
+
OR session_user::text <> 'authenticator'
|
|
31919
|
+
$function$;
|
|
31920
|
+
|
|
31921
|
+
CREATE OR REPLACE FUNCTION public.logistics_acc_direct(p_fn text)
|
|
31922
|
+
RETURNS boolean LANGUAGE sql STABLE SET search_path TO 'public'
|
|
31923
|
+
AS $function$
|
|
31924
|
+
SELECT coalesce(current_query(), '') ~* ('(^|[^a-z0-9_])' || p_fn || '([^a-z0-9_]|$)')
|
|
31925
|
+
$function$;
|
|
31926
|
+
|
|
31927
|
+
CREATE OR REPLACE FUNCTION public.logistics_acc_guard(p_level text, p_fn text)
|
|
31928
|
+
RETURNS void LANGUAGE plpgsql STABLE SET search_path TO 'public'
|
|
31929
|
+
AS $function$
|
|
31930
|
+
BEGIN
|
|
31931
|
+
IF public.logistics_acc_is_server() THEN RETURN; END IF;
|
|
31932
|
+
IF pg_trigger_depth() > 0 THEN RETURN; END IF;
|
|
31933
|
+
IF NOT public.logistics_acc_direct(p_fn) THEN RETURN; END IF;
|
|
31934
|
+
IF p_level = 'ingelogd' AND auth.uid() IS NOT NULL THEN RETURN; END IF;
|
|
31935
|
+
IF p_level = 'beheer' AND auth.uid() IS NOT NULL AND public.logistics_is_beheer() THEN RETURN; END IF;
|
|
31936
|
+
RAISE EXCEPTION '%', CASE p_level
|
|
31937
|
+
WHEN 'server' THEN 'Geen toegang: ' || p_fn || ' is alleen voor de server.'
|
|
31938
|
+
WHEN 'beheer' THEN 'Geen toegang: ' || p_fn || ' is alleen voor beheer.'
|
|
31939
|
+
ELSE 'Geen toegang: log in om ' || p_fn || ' te gebruiken.' END
|
|
31940
|
+
USING ERRCODE = '42501';
|
|
31941
|
+
END $function$;
|
|
31942
|
+
REVOKE ALL ON FUNCTION public.logistics_acc_guard(text, text) FROM PUBLIC, anon;
|
|
31943
|
+
GRANT EXECUTE ON FUNCTION public.logistics_acc_guard(text, text) TO authenticated, service_role;
|
|
31944
|
+
REVOKE ALL ON FUNCTION public.logistics_acc_direct(text) FROM PUBLIC, anon;
|
|
31945
|
+
GRANT EXECUTE ON FUNCTION public.logistics_acc_direct(text) TO authenticated, service_role;
|
|
31946
|
+
REVOKE ALL ON FUNCTION public.logistics_acc_is_server() FROM PUBLIC, anon;
|
|
31947
|
+
GRANT EXECUTE ON FUNCTION public.logistics_acc_is_server() TO authenticated, service_role;
|
|
31948
|
+
|
|
31949
|
+
CREATE OR REPLACE FUNCTION public.logistics_acc_levels()
|
|
31950
|
+
RETURNS TABLE(functie text, niveau text) LANGUAGE sql IMMUTABLE SET search_path TO 'public'
|
|
31951
|
+
AS $function$
|
|
31952
|
+
SELECT * FROM (
|
|
31953
|
+
SELECT unnest(ARRAY['claim_logistics_tasks','control_get_todays_carts','control_mark_carts_delivered','control_mark_carts_delivered_detail','logistics_allowed_load_carriers','logistics_apply_buffer_decision','logistics_apply_document_layouts','logistics_apply_order_buffer','logistics_approve_delay_reschedule','logistics_archived_orders','logistics_backorder_allowed','logistics_belading_bevestig','logistics_belading_verstuurder','logistics_blocked_orders','logistics_blocked_overview','logistics_buffer_decision','logistics_buffer_detach_late_orders','logistics_buffer_frozen_order','logistics_buffer_handled','logistics_buffer_notify','logistics_buffer_open_key','logistics_buffer_payload','logistics_buffer_simulate','logistics_cancel_order','logistics_cancel_orphan_tasks','logistics_capacity_day_check','logistics_carrier_preview_existing','logistics_carrier_status','logistics_cart_archive','logistics_cart_archive_preview','logistics_cart_checkin_at','logistics_cart_fixed_numbering','logistics_cart_handled','logistics_cart_index','logistics_cart_is_archived','logistics_cart_is_full','logistics_cart_json_fixed','logistics_cart_layout_method','logistics_cart_order_ids','logistics_cart_order_refs','logistics_cart_plan_overview','logistics_cart_plan_status_core','logistics_cart_release_reason','logistics_cart_seq','logistics_cart_unarchive','logistics_cart_units','logistics_cart_wait_until','logistics_check_order_allowed','logistics_check_order_stock','logistics_claim_next_task','logistics_cleanup_duplicate_order_lines','logistics_cleanup_history','logistics_cleanup_tasks','logistics_consistency_check','logistics_control_complete_cart','logistics_control_settings','logistics_cron_health','logistics_day_windows','logistics_delivery_agenda','logistics_departure_preview','logistics_document_layout','logistics_document_layout_v2','logistics_emit_event','logistics_external_fulfillment_key_report','logistics_floriday_cart_plan','logistics_floriday_claim_pushes','logistics_floriday_finish_push','logistics_floriday_finish_push_v2','logistics_floriday_finish_push_v3','logistics_floriday_is_read_only','logistics_floriday_log_refusal','logistics_floriday_log_send','logistics_floriday_order_approved','logistics_floriday_prune_pushes','logistics_floriday_queue_push','logistics_full_cart_min_layers','logistics_full_cart_min_percentage','logistics_install_check','logistics_is_beheer','logistics_item_external_fulfilled','logistics_layout_method_status','logistics_link_order_items','logistics_local_hhmi','logistics_local_today','logistics_merge_decision','logistics_merge_floriday_lines','logistics_merge_lines_enabled','logistics_merge_partial_carts','logistics_opening_timezone','logistics_order_backlog_info','logistics_order_cart_approval','logistics_order_cart_ids','logistics_order_changed','logistics_order_definitively_blocked','logistics_order_departure','logistics_order_departure_list','logistics_order_documents_ready','logistics_order_documents_ready_bool','logistics_order_external_state','logistics_order_finalize_enqueue','logistics_order_finalize_overview','logistics_order_finalize_prune','logistics_order_finalize_reconcile','logistics_order_finalize_retry','logistics_order_finalize_run','logistics_order_frozen','logistics_order_handled','logistics_order_is_archived','logistics_order_is_backlog','logistics_order_is_frozen','logistics_order_line_duplicates','logistics_order_mergeable','logistics_order_overview','logistics_order_plan_coverage','logistics_order_plan_coverage_list','logistics_orphan_carts_list','logistics_orphan_carts_summary','logistics_own_transport_departure','logistics_packing_autofix','logistics_packing_block_reason','logistics_packing_dismiss','logistics_packing_overview','logistics_packing_reconcile','logistics_packing_set_manual','logistics_partial_wait_minutes','logistics_payload_is_floriday','logistics_plan_block','logistics_plan_defer','logistics_plan_enqueue','logistics_plan_finish','logistics_plan_floriday_order','logistics_plan_lock_acquire','logistics_plan_lock_release','logistics_plan_progress','logistics_plan_progress_pct','logistics_plan_queue_list','logistics_plan_reset_queue','logistics_plan_retry','logistics_plan_state_for','logistics_plan_timeout_running','logistics_plan_unarchive','logistics_prune_buffer_member_queue','logistics_queue_capacity_email','logistics_queue_stock_email','logistics_reapply_buffer_decisions','logistics_rebuffer_open_orders','logistics_rebuffer_orders','logistics_rebuffer_pending','logistics_rebuffer_report','logistics_refresh_plan_state','logistics_replan_all','logistics_replan_all_force','logistics_replan_order_journey','logistics_replan_preview','logistics_replan_selected','logistics_report_delay','logistics_reschedule_order','logistics_reschedule_preview','logistics_resolve_carrier','logistics_resolve_carrier_for_location','logistics_resolve_carrier_for_location_many','logistics_resolve_carrier_many','logistics_resolve_settings','logistics_sales_order_external_fulfilled','logistics_schedule_tasks','logistics_set_order_priority','logistics_subtract_working_minutes','logistics_supersede_stale_tasks','logistics_sync_task_carriers','logistics_task_open_counts','logistics_tasks_prune','logistics_tick_health','logistics_tick_ping','logistics_timezone_options','logistics_trace','logistics_trace_all_orders','logistics_trace_archive_order','logistics_trace_batch','logistics_trace_derive','logistics_trace_order_journey_start','logistics_trace_order_origin','logistics_trace_order_overview','logistics_trace_order_state','logistics_trace_order_step','logistics_trace_orders','logistics_trace_progress','logistics_trace_progress_order','logistics_trace_step_once','logistics_trace_stock_check','logistics_trace_timeline','logistics_trace_version_events','logistics_trace_versions','logistics_tz','logistics_unit_order_ids','logistics_upsert_task','logistics_valid_timezone','logistics_write_buffer_layer_positions','logistics_write_cart_layer_positions']), 'ingelogd'
|
|
31954
|
+
UNION ALL
|
|
31955
|
+
SELECT unnest(ARRAY['logistics_active_layout_method','logistics_address_key','logistics_block_reason_code','logistics_buffer_criteria','logistics_buffer_decision_for_settings','logistics_buffer_value','logistics_capacity_plan_day','logistics_carrier_minutes','logistics_delay_customer_email','logistics_document_selection_status','logistics_document_type_map','logistics_floriday_delivery_note_create_enabled','logistics_floriday_gate_status','logistics_floriday_shipping_document','logistics_floriday_status_updates_enabled','logistics_floriday_stock_updates_enabled','logistics_floriday_write_allowed','logistics_is_engine_response','logistics_live_carriers','logistics_live_cart_count','logistics_next_workday_date','logistics_next_workday_not_past','logistics_nl_date','logistics_nl_moment','logistics_not_past','logistics_order_cart_count','logistics_order_is_shipped_status','logistics_order_merge_key','logistics_plan_error_class','logistics_plan_error_text','logistics_resolve_product_id','logistics_resolve_product_match','logistics_retention_days','logistics_rule_bool','logistics_rule_num','logistics_rule_text','logistics_rule_value','logistics_shift_to_workday','logistics_status_after_shipping','logistics_task_owner','logistics_task_retention_days','logistics_trace_node','logistics_trace_redact','logistics_trace_source_node','logistics_tray_plants','logistics_try_uuid']), 'open (rekenhulp/rechten aanroeper)'
|
|
31956
|
+
UNION ALL
|
|
31957
|
+
SELECT unnest(ARRAY['logistics_active_pick_workdays','logistics_auto_send_status','logistics_barcode_lookup','logistics_cancel_stale_cart_pick_rows','logistics_carrier_picks_up_for','logistics_cart_barcode_opschonen','logistics_cart_barcode_value','logistics_cart_has_packing_slip','logistics_cart_pick_starts_at','logistics_cart_plan_status','logistics_cart_released','logistics_cart_scanned','logistics_cart_slip_plan','logistics_cart_slip_queued','logistics_cart_sticker_state','logistics_carts_per_print','logistics_claim_task','logistics_cleanup_orphan_print_jobs','logistics_complete_task','logistics_control_scan_approve','logistics_control_scan_claim','logistics_control_scan_finish','logistics_control_scan_lookup','logistics_control_scan_overview','logistics_control_scan_print_own','logistics_control_scan_record_afmelding','logistics_control_scan_record_afmelding_cart','logistics_control_scan_retry','logistics_document_for_order','logistics_document_station','logistics_enqueue_shipping_note_with_slip','logistics_enqueue_sticker_with_slip','logistics_ensure_cart_barcode','logistics_ensure_pick_data','logistics_ensure_shipping_notes','logistics_fail_task','logistics_fix_wrong_shipping_notes','logistics_fulfill_barcode_requests','logistics_is_group_label','logistics_is_pick_workday','logistics_normalize_product_label','logistics_order_all_carts_scanned','logistics_order_carrier_label','logistics_order_is_topick','logistics_order_pick_day','logistics_order_released','logistics_order_sticker_meldingen','logistics_own_sticker_count','logistics_own_sticker_sync','logistics_own_traysticker_payload','logistics_own_traysticker_sync','logistics_packing_scan','logistics_pakbon_old_order_row','logistics_pakbon_oude_orderregels','logistics_parse_pickup','logistics_pick_agenda','logistics_pick_backlog_max_days','logistics_pick_barcode_enabled','logistics_pick_email_purpose','logistics_pick_mode','logistics_pick_partial_mode','logistics_pick_queue_close','logistics_pick_start_estimate','logistics_pick_units','logistics_pickup_moments_today','logistics_prepare_pick_documents','logistics_print_job_state','logistics_print_via_layout','logistics_prune_handled_pick_queue','logistics_refresh_pick_queue_status','logistics_refresh_pickup_moments','logistics_rescan_orders','logistics_resolve_pick_document','logistics_scan_delays','logistics_scan_order_stock','logistics_scan_resolve','logistics_set_pick_day','logistics_shipping_note_diagnose','logistics_shipping_note_ensure_accepted','logistics_shipping_note_follows_slip','logistics_shipping_note_from_barcode','logistics_shipping_note_job_for_slip','logistics_shipping_note_max_attempts','logistics_shipping_note_release','logistics_shipping_note_status','logistics_shipping_note_wait_reasons','logistics_shipping_note_wake','logistics_shipping_notes_wake_all','logistics_slip_is_floriday','logistics_slip_is_herprint','logistics_slip_note_claim','logistics_slip_note_finish','logistics_slip_note_hold','logistics_slip_note_hold_belading','logistics_slip_note_hold_kenmerk','logistics_slip_note_hold_layout','logistics_slip_note_hold_read_only','logistics_slip_note_keep_waiting','logistics_slip_note_release_layout','logistics_slip_note_retry','logistics_slip_note_skip_herprint','logistics_sticker_blocked_list','logistics_sticker_cart_plek','logistics_sticker_copies','logistics_sticker_distribution','logistics_sticker_etiket_status','logistics_sticker_external_fulfilled','logistics_sticker_follows_slip','logistics_sticker_moment','logistics_sticker_order_counts','logistics_sticker_parse_size','logistics_sticker_sync','logistics_sticker_upsert','logistics_subtract_pick_workdays','logistics_sync_pick_queue','logistics_sync_pick_queue_backlog','logistics_sync_pick_queue_core','logistics_task_pick_minutes','logistics_trace_pick_state','logistics_unit_all_carts_scanned','logistics_working_hours_status','pick_cart_breakdown','pick_enqueue_print_job','pick_queue_cart_plan']), 'wacht op pickschermlijst'
|
|
31958
|
+
UNION ALL
|
|
31959
|
+
SELECT unnest(ARRAY['logistics_afhandeling_fulfillment_order','logistics_allocation_check_changes','logistics_allocation_fp','logistics_allocation_frozen','logistics_apply_cart_swap','logistics_apply_external_fulfillment','logistics_auto_send_claim','logistics_auto_send_enqueue_for_order','logistics_auto_send_finish','logistics_auto_send_route_missing','logistics_auto_send_sent_elsewhere','logistics_auto_send_status_core','logistics_base_url_check_status','logistics_base_url_checks_resolve','logistics_brief_transport','logistics_buffer_closed_for_join','logistics_buffer_frozen','logistics_buffer_target','logistics_carrier_enqueue','logistics_carrier_favorite_id','logistics_carrier_for_location','logistics_carrier_frozen_reason','logistics_carrier_recalc_run','logistics_carrier_result','logistics_carrier_settings_ensure','logistics_carrier_skip_reason','logistics_cart_archive_classify','logistics_cart_coverage_check','logistics_cart_extra_fields','logistics_cart_ids_frozen','logistics_cart_is_frozen','logistics_cart_plan_status_core_v152','logistics_cart_seq_dubbel','logistics_departure_calc','logistics_double_group_lines','logistics_ensure_runtime_defaults','logistics_expand_line','logistics_fill_cart_departure','logistics_floriday_layout_id','logistics_floriday_push_hold_read_only','logistics_floriday_release_read_only','logistics_frozen_allocation_scaled','logistics_key_product','logistics_mark_cart_delivered_core','logistics_order_afgemeld','logistics_order_buffer_excluded','logistics_order_carrier_id','logistics_order_carrier_info','logistics_order_current_warnings','logistics_order_fp','logistics_order_line_allocation','logistics_order_on_frozen_shared_cart','logistics_order_plan_coverage_list_v152','logistics_order_plan_coverage_v165','logistics_plan_all','logistics_plan_buffer_sql','logistics_plan_claim','logistics_plan_close_claim','logistics_plan_coverage_check','logistics_plan_due_count','logistics_plan_ensure_event','logistics_plan_housekeeping','logistics_plan_impact_orders','logistics_plan_kick','logistics_plan_prune','logistics_plan_queue_dubbel','logistics_plan_release_stale','logistics_plan_retry_later','logistics_plan_setting','logistics_plan_wachttijd','logistics_plan_wachttijd_melden','logistics_planner_cart_snapshot','logistics_planner_diff_mode','logistics_planner_diff_prune','logistics_planner_lines','logistics_prune_cron_history','logistics_queue_row_has_open_peer','logistics_rebuffer_candidates','logistics_rebuffer_simulate_open','logistics_recalc_tick_kick','logistics_recompute_reserved_targeted','logistics_reconcile_missing_plan_queue','logistics_register_tick_apikey','logistics_replan_candidates','logistics_replan_clear_foreign_cart_items','logistics_replan_selected_orders','logistics_report_frozen_shortage','logistics_reserved_fast_skip','logistics_reserved_key','logistics_reserved_order_excluded','logistics_reserved_stock_nightly','logistics_resolve_carrier_core','logistics_set_components_scaled','logistics_shared_cart_peers','logistics_shell_base_url','logistics_sync_stock_alert_email_status','logistics_sync_task_status','logistics_tick','logistics_tick_base_url_check','logistics_tick_calls_resolve','logistics_tick_runs_prune','logistics_today_cart_ids','logistics_verkoop_order_link']), 'server'
|
|
31960
|
+
UNION ALL
|
|
31961
|
+
SELECT unnest(ARRAY['logistics_carrier_promote_oud','logistics_carrier_set_backfill']), 'beheer'
|
|
31962
|
+
UNION ALL
|
|
31963
|
+
SELECT unnest(ARRAY['logistics_set_order_carrier']), 'eigen (p_actor)'
|
|
31964
|
+
UNION ALL
|
|
31965
|
+
SELECT unnest(ARRAY['recompute_all_reserved_stock','recompute_reserved_stock']), 'eigenaar Voorraad'
|
|
31966
|
+
) v(functie, niveau)
|
|
31967
|
+
$function$;
|
|
31968
|
+
|
|
31969
|
+
DO $acc$
|
|
31970
|
+
DECLARE r record; v_def text; v_new text; v_pos int; v_fail text[] := '{}'::text[]; n int := 0;
|
|
31971
|
+
BEGIN
|
|
31972
|
+
FOR r IN
|
|
31973
|
+
SELECT p.oid, p.proname, l.lanname, p.prosrc, x.lvl
|
|
31974
|
+
FROM public.logistics_acc_levels() x(fn, lvl)
|
|
31975
|
+
JOIN pg_proc p ON p.proname = x.fn AND p.pronamespace = 'public'::regnamespace
|
|
31976
|
+
JOIN pg_language l ON l.oid = p.prolang
|
|
31977
|
+
WHERE x.lvl IN ('server', 'ingelogd', 'beheer')
|
|
31978
|
+
AND p.prorettype <> 'trigger'::regtype AND coalesce(p.prosrc, '') <> ''
|
|
31979
|
+
AND p.prosrc NOT LIKE '%logistics_acc_guard(%'
|
|
31980
|
+
LOOP
|
|
31981
|
+
BEGIN
|
|
31982
|
+
v_def := pg_get_functiondef(r.oid);
|
|
31983
|
+
IF r.lanname = 'plpgsql' THEN
|
|
31984
|
+
v_pos := regexp_instr(r.prosrc, '\mBEGIN\M', 1, 1, 1, 'i');
|
|
31985
|
+
IF v_pos = 0 THEN RAISE EXCEPTION 'geen BEGIN gevonden'; END IF;
|
|
31986
|
+
v_new := left(r.prosrc, v_pos - 1) || E'\n PERFORM public.logistics_acc_guard(' || quote_literal(r.lvl) || ', '
|
|
31987
|
+
|| quote_literal(r.proname) || ');' || substr(r.prosrc, v_pos);
|
|
31988
|
+
ELSIF r.lanname = 'sql' THEN
|
|
31989
|
+
v_new := E'\n SELECT public.logistics_acc_guard(' || quote_literal(r.lvl) || ', ' || quote_literal(r.proname) || ');' || r.prosrc;
|
|
31990
|
+
ELSE
|
|
31991
|
+
RAISE EXCEPTION 'taal % niet ondersteund', r.lanname;
|
|
31992
|
+
END IF;
|
|
31993
|
+
v_pos := position(r.prosrc IN v_def);
|
|
31994
|
+
IF v_pos = 0 THEN RAISE EXCEPTION 'definitie niet te herschrijven'; END IF;
|
|
31995
|
+
v_def := overlay(v_def placing v_new from v_pos for length(r.prosrc));
|
|
31996
|
+
EXECUTE v_def;
|
|
31997
|
+
n := n + 1;
|
|
31998
|
+
EXCEPTION WHEN OTHERS THEN
|
|
31999
|
+
v_fail := v_fail || (r.proname || ': ' || SQLERRM);
|
|
32000
|
+
END;
|
|
32001
|
+
END LOOP;
|
|
32002
|
+
RAISE NOTICE 'logistiek-engine toegangscontrole: % functies voorzien; mislukt: %', n, array_to_string(v_fail, ' | ');
|
|
32003
|
+
END $acc$;
|
|
32004
|
+
|
|
32005
|
+
CREATE OR REPLACE FUNCTION public.logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid, p_actor uuid)
|
|
32006
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
32007
|
+
AS $function$
|
|
32008
|
+
DECLARE v_uid uuid; o jsonb; v_skip text; r jsonb;
|
|
32009
|
+
BEGIN
|
|
32010
|
+
IF public.logistics_acc_is_server() THEN
|
|
32011
|
+
v_uid := coalesce(p_actor, auth.uid());
|
|
32012
|
+
ELSE
|
|
32013
|
+
v_uid := auth.uid();
|
|
32014
|
+
IF v_uid IS NULL THEN
|
|
32015
|
+
RAISE EXCEPTION 'Geen toegang: log in om een vervoerder te kiezen.' USING ERRCODE = '42501';
|
|
32016
|
+
END IF;
|
|
32017
|
+
END IF;
|
|
32018
|
+
SELECT to_jsonb(x) INTO o FROM public.orders x WHERE x.id = p_order_id AND x.deleted_at IS NULL FOR UPDATE;
|
|
32019
|
+
IF o IS NULL THEN RAISE EXCEPTION 'Order niet gevonden.'; END IF;
|
|
32020
|
+
IF p_carrier_id IS NOT NULL THEN
|
|
32021
|
+
v_skip := public.logistics_carrier_skip_reason(p_carrier_id);
|
|
32022
|
+
IF v_skip IS NOT NULL THEN RAISE EXCEPTION 'Deze vervoerder kan niet gekozen worden: %.', v_skip; END IF;
|
|
32023
|
+
r := public.logistics_carrier_result(p_carrier_id, 'handmatig', 'Handmatig gekozen op de order.', '{}'::text[]);
|
|
32024
|
+
ELSE
|
|
32025
|
+
r := public.logistics_resolve_carrier_core(o, true);
|
|
32026
|
+
END IF;
|
|
32027
|
+
PERFORM set_config('logistics.carrier_writer', 'engine', true);
|
|
32028
|
+
UPDATE public.orders
|
|
32029
|
+
SET carrier_id = public.logistics_try_uuid(r->>'carrier_id'), carrier_source = r->>'bron',
|
|
32030
|
+
carrier_reason = r->>'reden', carrier_resolved_at = now(), carrier_set_by = v_uid, carrier_set_at = now()
|
|
32031
|
+
WHERE id = p_order_id;
|
|
32032
|
+
PERFORM set_config('logistics.carrier_writer', '', true);
|
|
32033
|
+
RETURN r || jsonb_build_object('bevroren', public.logistics_carrier_frozen_reason(p_order_id));
|
|
32034
|
+
END $function$;
|
|
32035
|
+
|
|
32036
|
+
CREATE OR REPLACE FUNCTION public.logistics_set_order_carrier(p_order_id uuid, p_carrier_id uuid)
|
|
32037
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
32038
|
+
AS $function$
|
|
32039
|
+
BEGIN
|
|
32040
|
+
RETURN public.logistics_set_order_carrier(p_order_id, p_carrier_id, NULL::uuid);
|
|
32041
|
+
END $function$;
|
|
32042
|
+
REVOKE ALL ON FUNCTION public.logistics_set_order_carrier(uuid, uuid, uuid) FROM PUBLIC, anon;
|
|
32043
|
+
GRANT EXECUTE ON FUNCTION public.logistics_set_order_carrier(uuid, uuid, uuid) TO authenticated, service_role;
|
|
32044
|
+
REVOKE ALL ON FUNCTION public.logistics_set_order_carrier(uuid, uuid) FROM PUBLIC, anon;
|
|
32045
|
+
GRANT EXECUTE ON FUNCTION public.logistics_set_order_carrier(uuid, uuid) TO authenticated, service_role;
|
|
32046
|
+
|
|
32047
|
+
CREATE OR REPLACE FUNCTION public.logistics_access_check()
|
|
32048
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text)
|
|
32049
|
+
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
32050
|
+
AS $function$
|
|
32051
|
+
DECLARE r record;
|
|
32052
|
+
BEGIN
|
|
32053
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_access_check');
|
|
32054
|
+
FOR r IN
|
|
32055
|
+
SELECT lv.functie, lv.niveau, p.oid, p.prosrc,
|
|
32056
|
+
has_function_privilege('anon', p.oid, 'EXECUTE') AS an,
|
|
32057
|
+
has_function_privilege('authenticated', p.oid, 'EXECUTE') AS au,
|
|
32058
|
+
pg_get_function_identity_arguments(p.oid) AS args
|
|
32059
|
+
FROM public.logistics_acc_levels() lv
|
|
32060
|
+
LEFT JOIN pg_proc p ON p.proname = lv.functie AND p.pronamespace = 'public'::regnamespace
|
|
32061
|
+
ORDER BY lv.functie, args
|
|
32062
|
+
LOOP
|
|
32063
|
+
onderdeel := 'Toegang ' || r.functie || CASE WHEN r.args IS NOT NULL AND r.args <> '' THEN '(' || r.args || ')' ELSE '' END;
|
|
32064
|
+
IF r.oid IS NULL THEN
|
|
32065
|
+
ok := r.niveau IN ('niet van Engine', 'eigenaar Voorraad'); toelichting := r.niveau || '; functie ontbreekt';
|
|
32066
|
+
ELSIF r.niveau IN ('server', 'ingelogd', 'beheer') THEN
|
|
32067
|
+
ok := r.prosrc LIKE '%logistics_acc_guard(%';
|
|
32068
|
+
toelichting := 'niveau ' || r.niveau || '; controle ' || CASE WHEN ok THEN 'aanwezig' ELSE 'ONTBREEKT' END
|
|
32069
|
+
|| '; uitvoerrecht anon ' || CASE WHEN r.an THEN 'ja' ELSE 'nee' END || ', authenticated ' || CASE WHEN r.au THEN 'ja' ELSE 'nee' END;
|
|
32070
|
+
ELSE
|
|
32071
|
+
ok := true;
|
|
32072
|
+
toelichting := CASE r.niveau WHEN 'wacht op pickschermlijst' THEN 'bewust open: wacht op pickschermlijst (pickscherm/scanner zonder inlog)'
|
|
32073
|
+
ELSE r.niveau END
|
|
32074
|
+
|| '; uitvoerrecht anon ' || CASE WHEN r.an THEN 'ja' ELSE 'nee' END || ', authenticated ' || CASE WHEN r.au THEN 'ja' ELSE 'nee' END;
|
|
32075
|
+
END IF;
|
|
32076
|
+
RETURN NEXT;
|
|
32077
|
+
END LOOP;
|
|
32078
|
+
FOR r IN SELECT t.n, t.tbl FROM unnest(ARRAY['logistics_capacity_alert_notify_trg','logistics_formulas_touch','logistics_packing_deviations_touch','logistics_strategies_touch','logistics_strategy_schedules_touch','logistics_variables_touch','set_logistics_delay_alerts_updated_at','set_logistics_stock_alerts_updated_at','touch_capacity_alerts','touch_pickup_moments','touch_staff_planning','trg_cart_items_layer_positions','trg_cart_number_prunes_pick_queue','trg_control_item_prunes_pick_queue','trg_floriday_gate_status_queue','trg_floriday_gate_stock_queue','trg_fust_types_requeue_blocked','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart','trg_guard_archived_cart_row','trg_logistics_auto_send_on_scan','trg_logistics_block_bvo_note_for_floriday','trg_logistics_block_merged_shipping_note','trg_logistics_carriers_enqueue','trg_logistics_cart_barcode_autofill','trg_logistics_clear_layer_positions','trg_logistics_close_pick_rows_on_shipped','trg_logistics_event_buffer','trg_logistics_event_insert','trg_logistics_keep_archived_cart','trg_logistics_locations_enqueue','trg_logistics_order_finalize_queue_updated','trg_logistics_order_item_autolink','trg_logistics_order_items_stock','trg_logistics_order_sticker_warnings_touch','trg_logistics_orders_carrier_changed','trg_logistics_orders_carrier_fill','trg_logistics_pick_queue_enrich','trg_logistics_pick_queue_layout','trg_logistics_pick_queue_sync','trg_logistics_pin_pick_day','trg_logistics_plan_order_items','trg_logistics_plan_orders','trg_logistics_plan_products','trg_logistics_require_cart_on_packing_slip','trg_logistics_require_pakbon_barcode','trg_logistics_reschedules_touch','trg_logistics_rule_config_layout_sync','trg_logistics_rule_config_method_changed','trg_logistics_rule_config_rebuffer','trg_logistics_rule_config_single_active','trg_logistics_rule_config_snapshot','trg_logistics_rule_config_snapshot_write','trg_logistics_schedule_after_event','trg_logistics_shipping_note_after_slip','trg_logistics_shipping_note_follow_printer','trg_logistics_shipping_note_release_on_scan','trg_logistics_slip_note_block_herprint','trg_logistics_sticker_prints_touch','trg_logistics_stock_alert_email','trg_logistics_stock_alert_skip_closed','trg_logistics_task_status_note','trg_logistics_task_status_scan','trg_logistics_time_settings_validate','trg_logistics_trace_pick_queue','trg_orders_guard_buffer_id','trg_pick_queue_cart_breakdown','trg_strategies_requeue_blocked','trg_trace_control_scan','trg_trace_order_cart_items_del','trg_trace_order_cart_items_ins','trg_trace_order_carts','trg_trace_order_carts_del','trg_trace_order_carts_ins','trg_trace_pick_queue_insert','trg_trace_plan_queue','trg_trace_print_jobs','trg_trace_slip_shipping_note','update_logistics_document_prints_updated_at','update_logistics_events_updated_at','update_logistics_floriday_pushes_updated_at','update_logistics_plan_runs_updated_at','update_logistics_recalc_jobs_updated_at','update_logistics_reservation_allocations_updated_at','update_logistics_rule_configs_updated_at','update_logistics_tasks_updated_at'],
|
|
32079
|
+
ARRAY['logistics_capacity_alerts','logistics_formulas','logistics_packing_deviations','logistics_strategies','logistics_strategy_schedules','logistics_variables','logistics_delay_alerts','logistics_stock_alerts','logistics_capacity_alerts','logistics_pickup_moments','logistics_staff_planning','order_cart_items','cart_numbers','cart_control_items','floriday_status_sync_queue','floriday_continuous_stock_queue','fust_types','logistics_cart_barcode','logistics_control_scan','logistics_slip_shipping_note','logistics_sticker_prints','order_cart_items','pakbon_barcode_verzoeken','pick_queue','print_jobs','order_carts','logistics_control_scan','print_jobs','pick_queue','carriers','order_carts','logistics_rule_configs','orders','logistics_events','logistics_events','order_carts','customer_delivery_locations','logistics_order_finalize_queue','order_items','order_items','logistics_order_sticker_warnings','orders','orders','pick_queue','pick_queue','logistics_tasks','pick_queue','order_items','orders','products','print_jobs','print_jobs','logistics_reschedules','logistics_rule_configs','logistics_rule_configs','logistics_rule_configs','logistics_rule_configs','logistics_rule_configs','logistics_rule_configs','logistics_events','print_jobs','print_jobs','logistics_control_scan','logistics_slip_shipping_note','logistics_sticker_prints','logistics_stock_alerts','logistics_stock_alerts','print_jobs','logistics_control_scan','logistics_time_settings','pick_queue','orders','pick_queue','logistics_strategies','logistics_control_scan','order_cart_items','order_cart_items','order_carts','order_carts','order_carts','pick_queue','logistics_plan_queue','print_jobs','logistics_slip_shipping_note','logistics_document_prints','logistics_events','logistics_floriday_pushes','logistics_plan_runs','logistics_recalc_jobs','logistics_reservation_allocations','logistics_rule_configs','logistics_tasks']) t(n, tbl) LOOP
|
|
32080
|
+
onderdeel := 'Trigger ' || r.n || ' op ' || r.tbl;
|
|
32081
|
+
ok := EXISTS (SELECT 1 FROM pg_trigger g WHERE g.tgname = r.n AND g.tgrelid = to_regclass('public.' || r.tbl));
|
|
32082
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt (schemasync controleren)' END; RETURN NEXT;
|
|
32083
|
+
END LOOP;
|
|
32084
|
+
FOR r IN SELECT t.n, t.tbl FROM unnest(ARRAY['Authenticated can read document prints','Beheer leest externe afhandeling','Beheer leest kar-archieflog','Beheer leest minuutronde-log','Beheer leest reserveringstoewijzing','Beheer leest vertrekcontrole','Beheerders lezen verdeel-vingerafdrukken','Eigen vertragingslogboek','Eigen vertragingsmeldingen','Eigen voorraadmeldingen','Ingelogd lezen stickermeldingen','Ingelogd lezen stickerprints','Ingelogd lezen vastgezette orders','Ingelogde gebruikers kunnen herberekeningen bekijken','Ingelogde gebruikers lezen de hartslag','Ingelogde gebruikers lezen de herberekenstatus','Ingelogde gebruikers lezen dekkingspogingen','Ingelogde gebruikers lezen pickdagen','Ingelogde gebruikers lezen planner-vergelijkingen','Ingelogde gebruikers lezen verzendbriefwachtrij','Ingelogde gebruikers zien beladingsafwijkingen','Ingelogde gebruikers zien de pushstatus','Users manage their own logistics events','Users manage their own logistics tasks','Users manage their own plan runs','Users manage their own rule configs','Users manage their own rule versions','beheer leest bevestigingen','finalize_queue_read_authenticated','logistics_carrier_events_read','logistics_carrier_settings_read','logistics_cart_barcode_read','logistics_control_scan_authenticated','logistics_floriday_carrier_map_read','logistics_opening_exceptions_rw','logistics_opening_hours_rw','logistics_order_merge_lines_read','logistics_order_merges_read','logistics_pick_data_requests_rw','logistics_shipping_note_scan_read','logistics_time_settings_rw','naamkoppeling logboek lezen door beheerders','override log readable','own capacity alerts','own capacity events','own capacity settings','own decisions','own formulas','own pickup moments','own schedules','own staff planning','own strategies','own variables','plan queue readable','plan settings readable','plan_locks_read_authenticated','refusals_read_authenticated','reschedules own insert','reschedules own read','service role manages runtime config','status_sends_read_authenticated','trace lezen door ingelogde gebruikers','trace_archive_read_authenticated'],
|
|
32085
|
+
ARRAY['logistics_document_prints','logistics_external_fulfillment','logistics_cart_archive_log','logistics_tick_runs','logistics_reservation_allocations','logistics_departure_check','logistics_allocation_fingerprint','logistics_delay_log','logistics_delay_alerts','logistics_stock_alerts','logistics_order_sticker_warnings','logistics_sticker_prints','logistics_order_plan_exclusion','logistics_recalc_jobs','logistics_tick_heartbeat','logistics_rebuffer_state','logistics_plan_coverage_retries','logistics_order_pick_day','logistics_planner_diff_runs','logistics_slip_shipping_note','logistics_packing_deviations','logistics_floriday_pushes','logistics_events','logistics_tasks','logistics_plan_runs','logistics_rule_configs','logistics_rule_versions','logistics_belading_bevestigingen','logistics_order_finalize_queue','logistics_carrier_events','logistics_carrier_settings','logistics_cart_barcode','logistics_control_scan','logistics_floriday_carrier_map','logistics_opening_exceptions','logistics_opening_hours','logistics_order_merge_lines','logistics_order_merges','logistics_pick_data_requests','logistics_shipping_note_scan','logistics_time_settings','logistics_autolink_audit','logistics_layer_override_log','logistics_capacity_alerts','logistics_capacity_events','logistics_capacity_settings','logistics_decisions','logistics_formulas','logistics_pickup_moments','logistics_strategy_schedules','logistics_staff_planning','logistics_strategies','logistics_variables','logistics_plan_queue','logistics_plan_settings','logistics_plan_locks','logistics_floriday_push_refusals','logistics_reschedules','logistics_reschedules','module_runtime_config','logistics_floriday_status_sends','logistics_trace_events','logistics_trace_events_archive']) t(n, tbl) LOOP
|
|
32086
|
+
onderdeel := 'Policy "' || r.n || '" op ' || r.tbl;
|
|
32087
|
+
ok := EXISTS (SELECT 1 FROM pg_policies x WHERE x.schemaname = 'public' AND x.tablename = r.tbl AND x.policyname = r.n);
|
|
32088
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt (schemasync controleren)' END; RETURN NEXT;
|
|
32089
|
+
END LOOP;
|
|
32090
|
+
END $function$;
|
|
32091
|
+
REVOKE ALL ON FUNCTION public.logistics_access_check() FROM PUBLIC, anon;
|
|
32092
|
+
GRANT EXECUTE ON FUNCTION public.logistics_access_check() TO authenticated, service_role;
|
|
32093
|
+
|
|
32094
|
+
DO $ic$
|
|
32095
|
+
DECLARE v_def text;
|
|
32096
|
+
BEGIN
|
|
32097
|
+
v_def := pg_get_functiondef('public.logistics_install_check()'::regprocedure);
|
|
32098
|
+
IF v_def NOT LIKE '%logistics_access_check()%' THEN
|
|
32099
|
+
v_def := regexp_replace(v_def, 'END \$function\$\s*$', E' RETURN QUERY SELECT * FROM public.logistics_access_check();\nEND $function$');
|
|
32100
|
+
EXECUTE v_def;
|
|
32101
|
+
END IF;
|
|
32102
|
+
END $ic$;
|