@flowselections/logistiek-engine 1.0.236 → 1.0.238
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 +1260 -0
- package/dist-lib/components/StandaardgegevensCard.d.ts.map +1 -1
- package/dist-lib/components/StandaardgegevensCard.js +48 -2
- package/dist-lib/components/rule-engine/RuleFieldInput.d.ts.map +1 -1
- package/dist-lib/components/rule-engine/RuleFieldInput.js +6 -2
- package/dist-lib/hooks/usePickstations.d.ts +3 -0
- package/dist-lib/hooks/usePickstations.d.ts.map +1 -1
- package/dist-lib/hooks/usePickstations.js +19 -3
- package/dist-lib/integrations/supabase/types.d.ts +1519 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/logisticsPlanner.d.ts.map +1 -1
- package/dist-lib/lib/logisticsPlanner.js +1 -11
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +5 -5
- package/package.json +1 -1
|
@@ -39825,3 +39825,1263 @@ RETURNS TABLE(punt text, ok boolean, uitleg text) LANGUAGE sql STABLE SET search
|
|
|
39825
39825
|
$$;
|
|
39826
39826
|
REVOKE ALL ON FUNCTION public.logistics_install_check_231() FROM PUBLIC, anon, authenticated;
|
|
39827
39827
|
GRANT EXECUTE ON FUNCTION public.logistics_install_check_231() TO service_role;
|
|
39828
|
+
|
|
39829
|
+
-- ===== 1.0.232 productiebon uit productieorders =====
|
|
39830
|
+
CREATE TABLE IF NOT EXISTS public.logistics_productiebon_log (
|
|
39831
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
39832
|
+
productie_order_id uuid,
|
|
39833
|
+
actie text NOT NULL,
|
|
39834
|
+
status text NOT NULL,
|
|
39835
|
+
melding text,
|
|
39836
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
39837
|
+
);
|
|
39838
|
+
CREATE INDEX IF NOT EXISTS logistics_productiebon_log_created_idx ON public.logistics_productiebon_log (created_at DESC);
|
|
39839
|
+
GRANT SELECT ON public.logistics_productiebon_log TO authenticated;
|
|
39840
|
+
GRANT ALL ON public.logistics_productiebon_log TO service_role;
|
|
39841
|
+
ALTER TABLE public.logistics_productiebon_log ENABLE ROW LEVEL SECURITY;
|
|
39842
|
+
DO $p$ BEGIN
|
|
39843
|
+
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='logistics_productiebon_log' AND policyname='productiebon_log_lezen') THEN
|
|
39844
|
+
CREATE POLICY productiebon_log_lezen ON public.logistics_productiebon_log FOR SELECT TO authenticated USING (auth.uid() IS NOT NULL);
|
|
39845
|
+
END IF;
|
|
39846
|
+
END $p$;
|
|
39847
|
+
|
|
39848
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_log_schrijf(p_id uuid, p_actie text, p_status text, p_melding text)
|
|
39849
|
+
RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
39850
|
+
AS $function$
|
|
39851
|
+
BEGIN
|
|
39852
|
+
INSERT INTO public.logistics_productiebon_log (productie_order_id, actie, status, melding) VALUES (p_id, p_actie, p_status, p_melding);
|
|
39853
|
+
DELETE FROM public.logistics_productiebon_log WHERE id IN (
|
|
39854
|
+
SELECT id FROM public.logistics_productiebon_log WHERE created_at < now() - interval '90 days' ORDER BY created_at LIMIT 500);
|
|
39855
|
+
END $function$;
|
|
39856
|
+
|
|
39857
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_sync(p_productie_order_id uuid)
|
|
39858
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
39859
|
+
AS $function$
|
|
39860
|
+
DECLARE
|
|
39861
|
+
po record; s jsonb; v_release text; v_approval boolean; v_station uuid; v_screen uuid;
|
|
39862
|
+
v_type uuid; v_queued uuid; v_new uuid; v_cancel uuid; v_done uuid; v_row record; v_lines integer; v_payload jsonb; v_n integer;
|
|
39863
|
+
BEGIN
|
|
39864
|
+
SELECT * INTO po FROM public.productie_orders WHERE id = p_productie_order_id;
|
|
39865
|
+
IF NOT FOUND THEN RETURN jsonb_build_object('actie','geen','reden','productieorder niet gevonden'); END IF;
|
|
39866
|
+
SELECT id INTO v_type FROM public.pick_document_types WHERE code = 'productiebon' LIMIT 1;
|
|
39867
|
+
IF v_type IS NULL THEN
|
|
39868
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'sync', 'fout', 'Documentsoort productiebon ontbreekt in de pickschermen.');
|
|
39869
|
+
RETURN jsonb_build_object('actie','fout','reden','documentsoort productiebon ontbreekt');
|
|
39870
|
+
END IF;
|
|
39871
|
+
SELECT id INTO v_queued FROM public.pick_document_statuses WHERE code = 'queued' LIMIT 1;
|
|
39872
|
+
SELECT id INTO v_new FROM public.pick_document_statuses WHERE code = 'new' LIMIT 1;
|
|
39873
|
+
SELECT id INTO v_cancel FROM public.pick_document_statuses WHERE code = 'cancelled' LIMIT 1;
|
|
39874
|
+
SELECT id INTO v_done FROM public.pick_document_statuses WHERE code = 'done' LIMIT 1;
|
|
39875
|
+
SELECT q.* INTO v_row FROM public.pick_queue q
|
|
39876
|
+
WHERE q.document_type_id = v_type AND q.payload->>'productie_order_id' = po.id::text
|
|
39877
|
+
ORDER BY q.created_at DESC LIMIT 1;
|
|
39878
|
+
|
|
39879
|
+
IF po.status = 'geannuleerd' THEN
|
|
39880
|
+
UPDATE public.pick_queue q SET cancelled_at = now(), status_id = coalesce(v_cancel, q.status_id), updated_at = now(),
|
|
39881
|
+
payload = coalesce(q.payload,'{}'::jsonb) || jsonb_build_object('cancelReason','Productieorder geannuleerd')
|
|
39882
|
+
WHERE q.document_type_id = v_type AND q.payload->>'productie_order_id' = po.id::text
|
|
39883
|
+
AND q.cancelled_at IS NULL AND q.completed_at IS NULL;
|
|
39884
|
+
GET DIAGNOSTICS v_n = ROW_COUNT;
|
|
39885
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'annuleren', 'ok', v_n || ' regel(s) uit de wachtrij');
|
|
39886
|
+
RETURN jsonb_build_object('actie','geannuleerd','regels',v_n);
|
|
39887
|
+
ELSIF po.status = 'verwerkt' THEN
|
|
39888
|
+
UPDATE public.pick_queue q SET completed_at = now(), status_id = coalesce(v_done, q.status_id), updated_at = now()
|
|
39889
|
+
WHERE q.document_type_id = v_type AND q.payload->>'productie_order_id' = po.id::text
|
|
39890
|
+
AND q.cancelled_at IS NULL AND q.completed_at IS NULL;
|
|
39891
|
+
GET DIAGNOSTICS v_n = ROW_COUNT;
|
|
39892
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'afronden', 'ok', v_n || ' regel(s) afgerond');
|
|
39893
|
+
RETURN jsonb_build_object('actie','afgerond','regels',v_n);
|
|
39894
|
+
ELSIF po.status <> 'open' THEN
|
|
39895
|
+
RETURN jsonb_build_object('actie','geen','reden','status ' || coalesce(po.status,'leeg') || ' verandert de wachtrij niet');
|
|
39896
|
+
END IF;
|
|
39897
|
+
|
|
39898
|
+
SELECT settings INTO s FROM public.logistics_rule_configs
|
|
39899
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
39900
|
+
v_release := coalesce(public.logistics_rule_text(s, 'pickstations', 'production_note_release', 'on_stock_upgrade'), 'on_stock_upgrade');
|
|
39901
|
+
v_approval := v_release = 'manual_approval_after_upgrade';
|
|
39902
|
+
v_station := public.logistics_try_uuid(s->'pickstations'->'fields'->>'production_note_station');
|
|
39903
|
+
SELECT count(*)::int INTO v_lines FROM public.productie_order_onderdelen o WHERE o.productie_order_id = po.id;
|
|
39904
|
+
v_payload := jsonb_build_object('source','logistiek-engine','documentType','productiebon',
|
|
39905
|
+
'productie_order_id', po.id, 'productieOrderNummer', po.nummer, 'productId', po.product_id,
|
|
39906
|
+
'tradeItemKey', po.trade_item_key, 'aantal', po.aantal, 'opmerking', po.opmerking,
|
|
39907
|
+
'onderdelen', v_lines);
|
|
39908
|
+
|
|
39909
|
+
IF v_row.id IS NOT NULL THEN
|
|
39910
|
+
IF v_row.cancelled_at IS NULL AND v_row.completed_at IS NULL THEN
|
|
39911
|
+
UPDATE public.pick_queue q SET document_number = po.nummer, line_count = v_lines,
|
|
39912
|
+
payload = coalesce(q.payload,'{}'::jsonb) || v_payload, updated_at = now()
|
|
39913
|
+
WHERE q.id = v_row.id
|
|
39914
|
+
AND (q.document_number, q.line_count, coalesce(q.payload,'{}'::jsonb))
|
|
39915
|
+
IS DISTINCT FROM (po.nummer, v_lines, coalesce(q.payload,'{}'::jsonb) || v_payload);
|
|
39916
|
+
END IF;
|
|
39917
|
+
RETURN jsonb_build_object('actie','bestaat','queueId',v_row.id);
|
|
39918
|
+
END IF;
|
|
39919
|
+
|
|
39920
|
+
IF v_station IS NULL OR NOT EXISTS (SELECT 1 FROM public.pick_stations WHERE id = v_station) THEN
|
|
39921
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'aanmaken', 'overgeslagen',
|
|
39922
|
+
'Geen pickstation ingesteld bij Productiebon (Werkwijze, stap Pickstations).');
|
|
39923
|
+
RETURN jsonb_build_object('actie','overgeslagen','reden','geen pickstation ingesteld');
|
|
39924
|
+
END IF;
|
|
39925
|
+
SELECT sc.id INTO v_screen FROM public.pick_station_screens sc
|
|
39926
|
+
WHERE sc.station_id = v_station
|
|
39927
|
+
ORDER BY (EXISTS (SELECT 1 FROM public.pick_screen_document_types d WHERE d.screen_id = sc.id AND d.document_type_id = v_type)) DESC, sc.created_at
|
|
39928
|
+
LIMIT 1;
|
|
39929
|
+
|
|
39930
|
+
INSERT INTO public.pick_queue (station_id, screen_id, document_type_id, status_id, document_number, order_number, reference,
|
|
39931
|
+
customer_name, line_count, cart_count, priority, is_urgent, announced_at, due_at, payload)
|
|
39932
|
+
VALUES (v_station, v_screen, v_type, CASE WHEN v_approval THEN coalesce(v_new, v_queued) ELSE v_queued END,
|
|
39933
|
+
po.nummer, NULL, po.id::text, NULL, v_lines, 0, 50, false, now(), NULL,
|
|
39934
|
+
v_payload || jsonb_build_object('requiresApproval', v_approval, 'approvedAt', NULL, 'approvedBy', NULL));
|
|
39935
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'aanmaken', 'ok',
|
|
39936
|
+
CASE WHEN v_approval THEN 'In wachtrij, wacht op goedkeuring' ELSE 'In wachtrij' END);
|
|
39937
|
+
RETURN jsonb_build_object('actie','aangemaakt','wachtOpGoedkeuring',v_approval);
|
|
39938
|
+
END $function$;
|
|
39939
|
+
|
|
39940
|
+
CREATE OR REPLACE FUNCTION public.logistics_productie_orders_trg()
|
|
39941
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
39942
|
+
AS $function$
|
|
39943
|
+
BEGIN
|
|
39944
|
+
BEGIN
|
|
39945
|
+
PERFORM public.logistics_productiebon_sync(NEW.id);
|
|
39946
|
+
EXCEPTION WHEN OTHERS THEN
|
|
39947
|
+
BEGIN
|
|
39948
|
+
PERFORM public.logistics_productiebon_log_schrijf(NEW.id, 'trigger', 'fout', SQLSTATE || ': ' || SQLERRM);
|
|
39949
|
+
EXCEPTION WHEN OTHERS THEN
|
|
39950
|
+
RAISE WARNING 'logistiek-engine productiebon: % (log mislukt: %)', NEW.id, SQLERRM;
|
|
39951
|
+
END;
|
|
39952
|
+
END;
|
|
39953
|
+
RETURN NULL;
|
|
39954
|
+
END $function$;
|
|
39955
|
+
|
|
39956
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_goedkeuren(p_queue_id uuid)
|
|
39957
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
39958
|
+
AS $function$
|
|
39959
|
+
DECLARE v_queued uuid; v_po text; v_n integer;
|
|
39960
|
+
BEGIN
|
|
39961
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_goedkeuren');
|
|
39962
|
+
SELECT id INTO v_queued FROM public.pick_document_statuses WHERE code = 'queued' LIMIT 1;
|
|
39963
|
+
UPDATE public.pick_queue q
|
|
39964
|
+
SET status_id = coalesce(v_queued, q.status_id), updated_at = now(),
|
|
39965
|
+
payload = q.payload || jsonb_build_object('approvedAt', now(), 'approvedBy', auth.uid())
|
|
39966
|
+
WHERE q.id = p_queue_id AND q.payload ? 'productie_order_id'
|
|
39967
|
+
AND coalesce((q.payload->>'requiresApproval')::boolean, false)
|
|
39968
|
+
AND q.payload->>'approvedAt' IS NULL AND q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
39969
|
+
RETURNING q.payload->>'productie_order_id' INTO v_po;
|
|
39970
|
+
GET DIAGNOSTICS v_n = ROW_COUNT;
|
|
39971
|
+
IF v_n = 0 THEN
|
|
39972
|
+
RETURN jsonb_build_object('ok', false, 'melding', 'Deze productiebon wacht niet (meer) op goedkeuring.');
|
|
39973
|
+
END IF;
|
|
39974
|
+
PERFORM public.logistics_productiebon_log_schrijf(v_po::uuid, 'goedkeuren', 'ok', 'Goedgekeurd');
|
|
39975
|
+
RETURN jsonb_build_object('ok', true, 'melding', 'Productiebon goedgekeurd.');
|
|
39976
|
+
END $function$;
|
|
39977
|
+
|
|
39978
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_status()
|
|
39979
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
39980
|
+
AS $function$
|
|
39981
|
+
DECLARE v_type uuid; r jsonb;
|
|
39982
|
+
BEGIN
|
|
39983
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_status');
|
|
39984
|
+
IF to_regclass('public.pick_queue') IS NULL OR to_regclass('public.pick_document_types') IS NULL THEN
|
|
39985
|
+
RETURN jsonb_build_object('beschikbaar', false);
|
|
39986
|
+
END IF;
|
|
39987
|
+
SELECT id INTO v_type FROM public.pick_document_types WHERE code = 'productiebon' LIMIT 1;
|
|
39988
|
+
SELECT jsonb_build_object('beschikbaar', true,
|
|
39989
|
+
'inWachtrij', count(*) FILTER (WHERE q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
39990
|
+
AND NOT (coalesce((q.payload->>'requiresApproval')::boolean,false) AND q.payload->>'approvedAt' IS NULL)),
|
|
39991
|
+
'wachtOpGoedkeuring', count(*) FILTER (WHERE q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
39992
|
+
AND coalesce((q.payload->>'requiresApproval')::boolean,false) AND q.payload->>'approvedAt' IS NULL))
|
|
39993
|
+
INTO r FROM public.pick_queue q WHERE q.document_type_id = v_type AND q.payload ? 'productie_order_id';
|
|
39994
|
+
RETURN r || jsonb_build_object('fouten', coalesce((SELECT jsonb_agg(jsonb_build_object('op', l.created_at, 'status', l.status, 'melding', l.melding) ORDER BY l.created_at DESC)
|
|
39995
|
+
FROM (SELECT * FROM public.logistics_productiebon_log WHERE status IN ('fout','overgeslagen') AND created_at > now() - interval '7 days'
|
|
39996
|
+
ORDER BY created_at DESC LIMIT 5) l), '[]'::jsonb));
|
|
39997
|
+
END $function$;
|
|
39998
|
+
|
|
39999
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_productiebon()
|
|
40000
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text) LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
40001
|
+
AS $function$
|
|
40002
|
+
DECLARE f text;
|
|
40003
|
+
BEGIN
|
|
40004
|
+
FOREACH f IN ARRAY ARRAY['logistics_productiebon_sync(uuid)','logistics_productiebon_goedkeuren(uuid)',
|
|
40005
|
+
'logistics_productiebon_status()','logistics_productie_orders_trg()'] LOOP
|
|
40006
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
40007
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; RETURN NEXT;
|
|
40008
|
+
END LOOP;
|
|
40009
|
+
onderdeel := 'tabel logistics_productiebon_log'; ok := to_regclass('public.logistics_productiebon_log') IS NOT NULL;
|
|
40010
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt' END; RETURN NEXT;
|
|
40011
|
+
onderdeel := 'trigger trg_logistics_productie_orders_productiebon';
|
|
40012
|
+
IF to_regclass('public.productie_orders') IS NULL THEN ok := true; toelichting := 'niet nodig: Voorraad-productieorders ontbreken';
|
|
40013
|
+
ELSE ok := EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_logistics_productie_orders_productiebon' AND tgrelid = 'public.productie_orders'::regclass);
|
|
40014
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; END IF;
|
|
40015
|
+
RETURN NEXT;
|
|
40016
|
+
END $function$;
|
|
40017
|
+
|
|
40018
|
+
CREATE OR REPLACE FUNCTION public.logistics_pick_queue_close(p_ids uuid[], p_mode text, p_reason text)
|
|
40019
|
+
RETURNS integer
|
|
40020
|
+
LANGUAGE plpgsql
|
|
40021
|
+
SECURITY DEFINER
|
|
40022
|
+
SET search_path TO 'public'
|
|
40023
|
+
AS $function$
|
|
40024
|
+
DECLARE v_n integer := 0; r record;
|
|
40025
|
+
BEGIN
|
|
40026
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_pick_queue_close');
|
|
40027
|
+
IF p_ids IS NULL OR cardinality(p_ids) = 0 THEN RETURN 0; END IF;
|
|
40028
|
+
FOR r IN
|
|
40029
|
+
UPDATE public.pick_queue q
|
|
40030
|
+
SET cancelled_at = CASE WHEN p_mode = 'cancel' THEN now() ELSE q.cancelled_at END,
|
|
40031
|
+
completed_at = CASE WHEN p_mode = 'complete' THEN now() ELSE q.completed_at END,
|
|
40032
|
+
updated_at = now()
|
|
40033
|
+
WHERE q.id = ANY(p_ids) AND q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
40034
|
+
-- Productiebonnen volgen alleen hun productieorder, niet de order-opruiming.
|
|
40035
|
+
AND NOT (coalesce(q.payload, '{}'::jsonb) ? 'productie_order_id')
|
|
40036
|
+
RETURNING q.id, q.order_number, q.document_number, coalesce(q.payload->>'cartId', CASE WHEN q.payload ? 'cartRowFor' THEN q.reference END) AS cart_id
|
|
40037
|
+
LOOP
|
|
40038
|
+
v_n := v_n + 1;
|
|
40039
|
+
BEGIN
|
|
40040
|
+
INSERT INTO public.logistics_trace_events(order_ref, cart_ref, slip_ref, phase, step, status, actor, reason, db_table, db_record, db_action)
|
|
40041
|
+
VALUES (r.order_number, r.cart_id, r.document_number, 'pick', 'pickregel_afgesloten', 'ok', 'logistiek-engine',
|
|
40042
|
+
p_reason, 'pick_queue', r.id::text, CASE WHEN p_mode = 'cancel' THEN 'cancelled_at' ELSE 'completed_at' END);
|
|
40043
|
+
EXCEPTION WHEN OTHERS THEN NULL; -- tijdlijn mag het afsluiten nooit blokkeren
|
|
40044
|
+
END;
|
|
40045
|
+
END LOOP;
|
|
40046
|
+
RETURN v_n;
|
|
40047
|
+
END $function$;
|
|
40048
|
+
|
|
40049
|
+
REVOKE ALL ON FUNCTION public.logistics_productiebon_log_schrijf(uuid,text,text,text) FROM PUBLIC, anon, authenticated;
|
|
40050
|
+
REVOKE ALL ON FUNCTION public.logistics_productiebon_sync(uuid) FROM PUBLIC, anon, authenticated;
|
|
40051
|
+
REVOKE ALL ON FUNCTION public.logistics_productie_orders_trg() FROM PUBLIC, anon, authenticated;
|
|
40052
|
+
REVOKE ALL ON FUNCTION public.logistics_productiebon_goedkeuren(uuid) FROM PUBLIC, anon;
|
|
40053
|
+
REVOKE ALL ON FUNCTION public.logistics_productiebon_status() FROM PUBLIC, anon;
|
|
40054
|
+
REVOKE ALL ON FUNCTION public.logistics_install_check_productiebon() FROM PUBLIC, anon;
|
|
40055
|
+
GRANT EXECUTE ON FUNCTION public.logistics_productiebon_log_schrijf(uuid,text,text,text) TO service_role;
|
|
40056
|
+
GRANT EXECUTE ON FUNCTION public.logistics_productiebon_sync(uuid) TO service_role;
|
|
40057
|
+
GRANT EXECUTE ON FUNCTION public.logistics_productiebon_goedkeuren(uuid) TO authenticated, service_role;
|
|
40058
|
+
GRANT EXECUTE ON FUNCTION public.logistics_productiebon_status() TO authenticated, service_role;
|
|
40059
|
+
GRANT EXECUTE ON FUNCTION public.logistics_install_check_productiebon() TO authenticated, service_role;
|
|
40060
|
+
|
|
40061
|
+
-- Voorwaardelijke stap: alleen als Voorraad-productieorders bestaan.
|
|
40062
|
+
DO $t$ BEGIN
|
|
40063
|
+
IF to_regclass('public.productie_orders') IS NOT NULL
|
|
40064
|
+
AND NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_logistics_productie_orders_productiebon' AND tgrelid = 'public.productie_orders'::regclass) THEN
|
|
40065
|
+
CREATE TRIGGER trg_logistics_productie_orders_productiebon
|
|
40066
|
+
AFTER INSERT OR UPDATE OF status ON public.productie_orders
|
|
40067
|
+
FOR EACH ROW EXECUTE FUNCTION public.logistics_productie_orders_trg();
|
|
40068
|
+
END IF;
|
|
40069
|
+
EXCEPTION WHEN OTHERS THEN
|
|
40070
|
+
RAISE NOTICE 'logistiek-engine: trigger productiebon niet aangemaakt: %', SQLERRM;
|
|
40071
|
+
END $t$;
|
|
40072
|
+
|
|
40073
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check()
|
|
40074
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text)
|
|
40075
|
+
LANGUAGE plpgsql
|
|
40076
|
+
SECURITY DEFINER
|
|
40077
|
+
SET search_path TO 'public'
|
|
40078
|
+
AS $function$
|
|
40079
|
+
DECLARE c text; f text; t text; v_fav text; n bigint; s record;
|
|
40080
|
+
BEGIN
|
|
40081
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_install_check');
|
|
40082
|
+
-- Alleen bestaan controleren: herberekenen nooit tijdens installatie uitvoeren.
|
|
40083
|
+
FOREACH f IN ARRAY ARRAY['logistics_pickup_at(text,date)',
|
|
40084
|
+
'logistics_pickup_ts(text,date)', 'logistics_pickup_herbereken()'] LOOP
|
|
40085
|
+
onderdeel := 'functie ' || f;
|
|
40086
|
+
ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
40087
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END;
|
|
40088
|
+
RETURN NEXT;
|
|
40089
|
+
END LOOP;
|
|
40090
|
+
FOREACH f IN ARRAY ARRAY[
|
|
40091
|
+
'f:logistics_try_uuid','f:logistics_tz','f:logistics_is_beheer','f:logistics_buffer_payload','f:logistics_apply_order_buffer',
|
|
40092
|
+
'f:logistics_apply_buffer_decision','f:logistics_rebuffer_pending','f:logistics_departure_calc','f:logistics_own_transport_departure',
|
|
40093
|
+
'f:logistics_order_departure','f:logistics_brief_transport','f:logistics_order_frozen','f:logistics_order_is_frozen',
|
|
40094
|
+
'f:logistics_order_finalize_run','f:run_logistics_tasks_dispatch','f:enqueue_cart_replan_if_unlocked','f:logistics_tick',
|
|
40095
|
+
't:logistics_tick_runs',
|
|
40096
|
+
'f:logistics_belading_bevestig','f:logistics_cart_seq_dubbel','f:logistics_plan_retry_later','f:logistics_own_traysticker_sync',
|
|
40097
|
+
't:logistics_belading_bevestigingen',
|
|
40098
|
+
'f:logistics_sticker_copies','f:logistics_sticker_etiket_status','f:logistics_sticker_order_counts','f:logistics_sticker_sync',
|
|
40099
|
+
'c:logistics_sticker_prints.kopieen_bron',
|
|
40100
|
+
'f:logistics_carrier_settings_ensure','t:logistics_carrier_settings','t:logistics_carrier_recalc_queue','t:logistics_carrier_events',
|
|
40101
|
+
'f:logistics_carrier_status','f:logistics_carrier_set_backfill','f:logistics_carrier_preview_existing','c:control_get_todays_carts.carrier_name',
|
|
40102
|
+
'f:logistics_plan_fail_log'] LOOP
|
|
40103
|
+
onderdeel := 'Engine: ' || substr(f, 3);
|
|
40104
|
+
ok := CASE left(f, 1)
|
|
40105
|
+
WHEN 'f' THEN EXISTS (SELECT 1 FROM pg_proc p WHERE p.pronamespace = 'public'::regnamespace AND p.proname = substr(f, 3))
|
|
40106
|
+
WHEN 't' THEN to_regclass('public.' || substr(f, 3)) IS NOT NULL
|
|
40107
|
+
ELSE CASE WHEN split_part(substr(f, 3), '.', 1) = 'control_get_todays_carts'
|
|
40108
|
+
THEN coalesce(pg_get_function_result(to_regprocedure('public.control_get_todays_carts()')), '') LIKE '%carrier_name%'
|
|
40109
|
+
ELSE EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public'
|
|
40110
|
+
AND table_name = split_part(substr(f, 3), '.', 1) AND column_name = split_part(substr(f, 3), '.', 2)) END
|
|
40111
|
+
END;
|
|
40112
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie (1.0.182 t/m 1.0.188) in dev uitvoeren en via schemasync verspreiden' END;
|
|
40113
|
+
RETURN NEXT;
|
|
40114
|
+
END LOOP;
|
|
40115
|
+
FOREACH c IN ARRAY ARRAY['carrier_id','carrier_source','carrier_reason','carrier_resolved_at','carrier_set_by','carrier_set_at'] LOOP
|
|
40116
|
+
onderdeel := 'orders.' || c;
|
|
40117
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='orders' AND column_name=c);
|
|
40118
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
40119
|
+
END LOOP;
|
|
40120
|
+
FOREACH f IN ARRAY ARRAY['logistics_resolve_carrier(uuid)','logistics_resolve_carrier_many(uuid[])',
|
|
40121
|
+
'logistics_resolve_carrier_for_location(uuid,uuid)','logistics_resolve_carrier_for_location_many(uuid[],uuid)',
|
|
40122
|
+
'logistics_resolve_carrier_for_location_many(jsonb)',
|
|
40123
|
+
'logistics_set_order_carrier(uuid,uuid)','logistics_carrier_recalc_run(integer)'] LOOP
|
|
40124
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
40125
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
40126
|
+
END LOOP;
|
|
40127
|
+
FOREACH t IN ARRAY ARRAY['orders:trg_logistics_orders_carrier_fill','orders:trg_logistics_orders_carrier_changed',
|
|
40128
|
+
'carriers:trg_logistics_carriers_enqueue','customer_delivery_locations:trg_logistics_locations_enqueue'] LOOP
|
|
40129
|
+
onderdeel := 'trigger ' || split_part(t, ':', 2);
|
|
40130
|
+
ok := EXISTS (SELECT 1 FROM pg_trigger g WHERE g.tgname = split_part(t, ':', 2)
|
|
40131
|
+
AND g.tgrelid = to_regclass('public.' || split_part(t, ':', 1)));
|
|
40132
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Engine-migratie' END; RETURN NEXT;
|
|
40133
|
+
END LOOP;
|
|
40134
|
+
onderdeel := 'minuutronde rekent vervoerders';
|
|
40135
|
+
ok := EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'logistics_tick' AND prosrc LIKE '%logistics_carrier_recalc_run%');
|
|
40136
|
+
toelichting := CASE WHEN ok THEN 'ja' ELSE 'nee' END; RETURN NEXT;
|
|
40137
|
+
FOREACH c IN ARRAY ARRAY['carrier_kind','is_favorite','archived_at','delivery_location_glns'] LOOP
|
|
40138
|
+
onderdeel := 'Afhandeling: carriers.' || c;
|
|
40139
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='carriers' AND column_name=c);
|
|
40140
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Afhandeling' END; RETURN NEXT;
|
|
40141
|
+
END LOOP;
|
|
40142
|
+
FOREACH f IN ARRAY ARRAY['afh_favorite_carrier','afh_city_code','afh_normalize_country','afh_normalize_nl_province'] LOOP
|
|
40143
|
+
onderdeel := 'Afhandeling: ' || f || '()';
|
|
40144
|
+
ok := EXISTS (SELECT 1 FROM pg_proc p WHERE p.pronamespace = 'public'::regnamespace AND p.proname = f);
|
|
40145
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Afhandeling' END; RETURN NEXT;
|
|
40146
|
+
END LOOP;
|
|
40147
|
+
onderdeel := 'Favoriete vervoerder ingesteld en bruikbaar';
|
|
40148
|
+
IF to_regprocedure('public.afh_favorite_carrier()') IS NULL THEN ok := false; toelichting := 'functie ontbreekt';
|
|
40149
|
+
ELSE
|
|
40150
|
+
BEGIN v_fav := public.logistics_carrier_favorite_id()::text; EXCEPTION WHEN OTHERS THEN v_fav := NULL; END;
|
|
40151
|
+
ok := public.logistics_try_uuid(v_fav) IS NOT NULL AND public.logistics_carrier_skip_reason(public.logistics_try_uuid(v_fav)) IS NULL;
|
|
40152
|
+
toelichting := CASE WHEN ok THEN 'ja' WHEN v_fav IS NULL THEN 'geen favoriet ingesteld (Afhandeling → Vervoerders)'
|
|
40153
|
+
ELSE public.logistics_carrier_skip_reason(public.logistics_try_uuid(v_fav)) END;
|
|
40154
|
+
END IF;
|
|
40155
|
+
RETURN NEXT;
|
|
40156
|
+
onderdeel := 'Klanten: customers.default_carrier_id';
|
|
40157
|
+
ok := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='customers' AND column_name='default_carrier_id');
|
|
40158
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: Klanten' END; RETURN NEXT;
|
|
40159
|
+
IF to_regclass('public.logistics_carrier_settings') IS NOT NULL AND to_regclass('public.orders') IS NOT NULL
|
|
40160
|
+
AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='public' AND table_name='orders' AND column_name='carrier_source') THEN
|
|
40161
|
+
SELECT * INTO s FROM public.logistics_carrier_settings_ensure();
|
|
40162
|
+
EXECUTE $q$SELECT count(*) FROM public.orders o
|
|
40163
|
+
WHERE o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
40164
|
+
AND coalesce(o.delivery_date, '') ~ '^\d{4}-\d{2}-\d{2}' AND left(o.delivery_date, 10)::date >= current_date
|
|
40165
|
+
AND (o.carrier_source = 'geen' OR (o.carrier_source IS NULL AND o.created_at >= $1))$q$ INTO n USING s.installed_at;
|
|
40166
|
+
onderdeel := 'Open orders zonder vervoerder'; ok := n = 0; toelichting := n || ' order(s)'; RETURN NEXT;
|
|
40167
|
+
onderdeel := 'Schakelaar bestaande orders'; ok := true;
|
|
40168
|
+
toelichting := CASE WHEN coalesce(s.backfill_existing, false) THEN 'aan' ELSE 'uit (bestaande orders wachten op akkoord)' END; RETURN NEXT;
|
|
40169
|
+
END IF;
|
|
40170
|
+
SELECT count(*) INTO n FROM public.logistics_trace_events e
|
|
40171
|
+
WHERE e.actor IN ('trg_logistics_plan_order_items', 'trg_logistics_plan_orders')
|
|
40172
|
+
AND e.status = 'mislukt' AND e.created_at > now() - interval '24 hours';
|
|
40173
|
+
onderdeel := 'Mislukte herplanning (laatste 24 uur)'; ok := n = 0;
|
|
40174
|
+
toelichting := CASE WHEN n = 0 THEN 'geen' ELSE n || ' keer; laatste: ' || coalesce((SELECT coalesce(e.order_ref, '?') || ': ' || coalesce(e.error, '') FROM public.logistics_trace_events e
|
|
40175
|
+
WHERE e.actor IN ('trg_logistics_plan_order_items', 'trg_logistics_plan_orders') AND e.status = 'mislukt'
|
|
40176
|
+
ORDER BY e.created_at DESC LIMIT 1), '') END;
|
|
40177
|
+
RETURN NEXT;
|
|
40178
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_194();
|
|
40179
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_196();
|
|
40180
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_197();
|
|
40181
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_198();
|
|
40182
|
+
RETURN QUERY SELECT * FROM public.logistics_access_check();
|
|
40183
|
+
RETURN QUERY SELECT * FROM public.logistics_overload_check();
|
|
40184
|
+
RETURN QUERY SELECT * FROM public.logistics_check_190();
|
|
40185
|
+
RETURN QUERY SELECT * FROM public.logistics_install_check_productiebon();
|
|
40186
|
+
END $function$;
|
|
40187
|
+
-- Productiebon goedkeuren vanaf pickstation (v2)
|
|
40188
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_goedkeuren_v2(p_queue_id uuid, p_bron jsonb DEFAULT NULL)
|
|
40189
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
40190
|
+
AS $function$
|
|
40191
|
+
DECLARE v_queued uuid; v_po text; v_n integer; v_station uuid; v_via jsonb; v_uid uuid := auth.uid();
|
|
40192
|
+
BEGIN
|
|
40193
|
+
-- Direct via de API: alleen ingelogd. Geneste aanroep (bv. pickstation-wrapper na pick_device_check) mag.
|
|
40194
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_goedkeuren_v2');
|
|
40195
|
+
v_station := public.logistics_try_uuid(p_bron->>'stationId');
|
|
40196
|
+
IF v_uid IS NULL AND v_station IS NULL THEN
|
|
40197
|
+
RETURN jsonb_build_object('ok', false, 'melding', 'Goedkeuren kan alleen door een ingelogde gebruiker of een gekoppeld pickstation.');
|
|
40198
|
+
END IF;
|
|
40199
|
+
v_via := jsonb_build_object(
|
|
40200
|
+
'soort', CASE WHEN v_station IS NOT NULL THEN 'pickstation' ELSE 'gebruiker' END,
|
|
40201
|
+
'stationId', v_station, 'stationSlug', p_bron->>'stationSlug', 'deviceId', p_bron->>'deviceId');
|
|
40202
|
+
SELECT id INTO v_queued FROM public.pick_document_statuses WHERE code = 'queued' LIMIT 1;
|
|
40203
|
+
UPDATE public.pick_queue q
|
|
40204
|
+
SET status_id = coalesce(v_queued, q.status_id), updated_at = now(),
|
|
40205
|
+
payload = q.payload || jsonb_build_object('approvedAt', now(), 'approvedBy', v_uid, 'approvedVia', v_via)
|
|
40206
|
+
WHERE q.id = p_queue_id AND q.payload ? 'productie_order_id'
|
|
40207
|
+
AND (v_station IS NULL OR q.station_id = v_station)
|
|
40208
|
+
AND coalesce((q.payload->>'requiresApproval')::boolean, false)
|
|
40209
|
+
AND q.payload->>'approvedAt' IS NULL AND q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
40210
|
+
RETURNING q.payload->>'productie_order_id' INTO v_po;
|
|
40211
|
+
GET DIAGNOSTICS v_n = ROW_COUNT;
|
|
40212
|
+
IF v_n = 0 THEN
|
|
40213
|
+
RETURN jsonb_build_object('ok', false, 'melding', 'Deze productiebon wacht niet (meer) op goedkeuring op dit station.');
|
|
40214
|
+
END IF;
|
|
40215
|
+
PERFORM public.logistics_productiebon_log_schrijf(v_po::uuid, 'goedkeuren', 'ok',
|
|
40216
|
+
'Goedgekeurd via ' || (v_via->>'soort') || coalesce(' ' || (p_bron->>'stationSlug'), '') || coalesce(' apparaat ' || (p_bron->>'deviceId'), ''));
|
|
40217
|
+
RETURN jsonb_build_object('ok', true, 'melding', 'Productiebon goedgekeurd.');
|
|
40218
|
+
END $function$;
|
|
40219
|
+
REVOKE ALL ON FUNCTION public.logistics_productiebon_goedkeuren_v2(uuid, jsonb) FROM PUBLIC, anon;
|
|
40220
|
+
GRANT EXECUTE ON FUNCTION public.logistics_productiebon_goedkeuren_v2(uuid, jsonb) TO authenticated, service_role;
|
|
40221
|
+
|
|
40222
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_goedkeuren(p_queue_id uuid)
|
|
40223
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
40224
|
+
AS $function$
|
|
40225
|
+
BEGIN
|
|
40226
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_goedkeuren');
|
|
40227
|
+
RETURN public.logistics_productiebon_goedkeuren_v2(p_queue_id, NULL);
|
|
40228
|
+
END $function$;
|
|
40229
|
+
|
|
40230
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_productiebon()
|
|
40231
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text) LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public'
|
|
40232
|
+
AS $function$
|
|
40233
|
+
DECLARE f text;
|
|
40234
|
+
BEGIN
|
|
40235
|
+
FOREACH f IN ARRAY ARRAY['logistics_productiebon_sync(uuid)','logistics_productiebon_goedkeuren(uuid)',
|
|
40236
|
+
'logistics_productiebon_goedkeuren_v2(uuid,jsonb)',
|
|
40237
|
+
'logistics_productiebon_status()','logistics_productie_orders_trg()'] LOOP
|
|
40238
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
40239
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; RETURN NEXT;
|
|
40240
|
+
END LOOP;
|
|
40241
|
+
onderdeel := 'tabel logistics_productiebon_log'; ok := to_regclass('public.logistics_productiebon_log') IS NOT NULL;
|
|
40242
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt' END; RETURN NEXT;
|
|
40243
|
+
onderdeel := 'trigger trg_logistics_productie_orders_productiebon';
|
|
40244
|
+
IF to_regclass('public.productie_orders') IS NULL THEN ok := true; toelichting := 'niet nodig: Voorraad-productieorders ontbreken';
|
|
40245
|
+
ELSE ok := EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_logistics_productie_orders_productiebon' AND tgrelid = 'public.productie_orders'::regclass);
|
|
40246
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; END IF;
|
|
40247
|
+
RETURN NEXT;
|
|
40248
|
+
END $function$;
|
|
40249
|
+
-- Productiebon-station leesfunctie (20261109101920.sql)
|
|
40250
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_station()
|
|
40251
|
+
RETURNS jsonb
|
|
40252
|
+
LANGUAGE plpgsql
|
|
40253
|
+
STABLE SECURITY DEFINER
|
|
40254
|
+
SET search_path TO 'public'
|
|
40255
|
+
AS $function$
|
|
40256
|
+
DECLARE v_station uuid; v_slug text;
|
|
40257
|
+
BEGIN
|
|
40258
|
+
-- Direct via de API: alleen ingelogd. Geneste aanroep (pickstation-wrapper) mag, net als _v2.
|
|
40259
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_station');
|
|
40260
|
+
IF to_regclass('public.pick_stations') IS NULL THEN RETURN '{}'::jsonb; END IF;
|
|
40261
|
+
SELECT public.logistics_try_uuid(settings->'pickstations'->'fields'->>'production_note_station') INTO v_station
|
|
40262
|
+
FROM public.logistics_rule_configs
|
|
40263
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
40264
|
+
IF v_station IS NULL THEN RETURN '{}'::jsonb; END IF;
|
|
40265
|
+
SELECT s.slug INTO v_slug FROM public.pick_stations s WHERE s.id = v_station;
|
|
40266
|
+
IF NOT FOUND THEN RETURN '{}'::jsonb; END IF;
|
|
40267
|
+
RETURN jsonb_build_object('station_id', v_station, 'station_slug', v_slug);
|
|
40268
|
+
END $function$;
|
|
40269
|
+
|
|
40270
|
+
REVOKE ALL ON FUNCTION public.logistics_productiebon_station() FROM PUBLIC, anon;
|
|
40271
|
+
GRANT EXECUTE ON FUNCTION public.logistics_productiebon_station() TO authenticated, service_role;
|
|
40272
|
+
|
|
40273
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_status()
|
|
40274
|
+
RETURNS jsonb
|
|
40275
|
+
LANGUAGE plpgsql
|
|
40276
|
+
STABLE SECURITY DEFINER
|
|
40277
|
+
SET search_path TO 'public'
|
|
40278
|
+
AS $function$
|
|
40279
|
+
DECLARE v_type uuid; r jsonb; v_station jsonb;
|
|
40280
|
+
BEGIN
|
|
40281
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_status');
|
|
40282
|
+
IF to_regclass('public.pick_queue') IS NULL OR to_regclass('public.pick_document_types') IS NULL THEN
|
|
40283
|
+
RETURN jsonb_build_object('beschikbaar', false);
|
|
40284
|
+
END IF;
|
|
40285
|
+
v_station := public.logistics_productiebon_station();
|
|
40286
|
+
SELECT id INTO v_type FROM public.pick_document_types WHERE code = 'productiebon' LIMIT 1;
|
|
40287
|
+
SELECT jsonb_build_object('beschikbaar', true,
|
|
40288
|
+
'stationIngesteld', v_station ? 'station_id',
|
|
40289
|
+
'stationMelding', CASE WHEN v_station ? 'station_id' THEN NULL ELSE 'Kies een pickstation voor productiebonnen' END,
|
|
40290
|
+
'inWachtrij', count(*) FILTER (WHERE q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
40291
|
+
AND NOT (coalesce((q.payload->>'requiresApproval')::boolean,false) AND q.payload->>'approvedAt' IS NULL)),
|
|
40292
|
+
'wachtOpGoedkeuring', count(*) FILTER (WHERE q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
40293
|
+
AND coalesce((q.payload->>'requiresApproval')::boolean,false) AND q.payload->>'approvedAt' IS NULL))
|
|
40294
|
+
INTO r FROM public.pick_queue q WHERE q.document_type_id = v_type AND q.payload ? 'productie_order_id';
|
|
40295
|
+
RETURN r || jsonb_build_object('fouten', coalesce((SELECT jsonb_agg(jsonb_build_object('op', l.created_at, 'status', l.status, 'melding', l.melding) ORDER BY l.created_at DESC)
|
|
40296
|
+
FROM (SELECT * FROM public.logistics_productiebon_log WHERE status IN ('fout','overgeslagen') AND created_at > now() - interval '7 days'
|
|
40297
|
+
ORDER BY created_at DESC LIMIT 5) l), '[]'::jsonb));
|
|
40298
|
+
END $function$;
|
|
40299
|
+
|
|
40300
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_productiebon()
|
|
40301
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text)
|
|
40302
|
+
LANGUAGE plpgsql
|
|
40303
|
+
STABLE SECURITY DEFINER
|
|
40304
|
+
SET search_path TO 'public'
|
|
40305
|
+
AS $function$
|
|
40306
|
+
DECLARE f text;
|
|
40307
|
+
BEGIN
|
|
40308
|
+
FOREACH f IN ARRAY ARRAY['logistics_productiebon_sync(uuid)','logistics_productiebon_goedkeuren(uuid)',
|
|
40309
|
+
'logistics_productiebon_goedkeuren_v2(uuid,jsonb)','logistics_productiebon_station()',
|
|
40310
|
+
'logistics_productiebon_status()','logistics_productie_orders_trg()'] LOOP
|
|
40311
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
40312
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; RETURN NEXT;
|
|
40313
|
+
END LOOP;
|
|
40314
|
+
onderdeel := 'tabel logistics_productiebon_log'; ok := to_regclass('public.logistics_productiebon_log') IS NOT NULL;
|
|
40315
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt' END; RETURN NEXT;
|
|
40316
|
+
onderdeel := 'trigger trg_logistics_productie_orders_productiebon';
|
|
40317
|
+
IF to_regclass('public.productie_orders') IS NULL THEN ok := true; toelichting := 'niet nodig: Voorraad-productieorders ontbreken';
|
|
40318
|
+
ELSE ok := EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_logistics_productie_orders_productiebon' AND tgrelid = 'public.productie_orders'::regclass);
|
|
40319
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; END IF;
|
|
40320
|
+
RETURN NEXT;
|
|
40321
|
+
END $function$;
|
|
40322
|
+
|
|
40323
|
+
-- Standaardstations voor documenten (system_code)
|
|
40324
|
+
CREATE OR REPLACE FUNCTION public.logistics_station_voor_document(p_document text)
|
|
40325
|
+
RETURNS jsonb
|
|
40326
|
+
LANGUAGE plpgsql
|
|
40327
|
+
STABLE SECURITY DEFINER
|
|
40328
|
+
SET search_path TO 'public'
|
|
40329
|
+
AS $function$
|
|
40330
|
+
DECLARE
|
|
40331
|
+
v_doc text := lower(btrim(coalesce(p_document, '')));
|
|
40332
|
+
v_key text; v_code text; v_label text;
|
|
40333
|
+
v_gekozen uuid; v_weg boolean := false; r record; v_heeft_code boolean;
|
|
40334
|
+
BEGIN
|
|
40335
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_station_voor_document');
|
|
40336
|
+
SELECT t.k, t.c, t.l INTO v_key, v_code, v_label FROM (VALUES
|
|
40337
|
+
('pakbon','packing_slip_station','orders','pakbonnen'),
|
|
40338
|
+
('pakbonnen','packing_slip_station','orders','pakbonnen'),
|
|
40339
|
+
('sticker','sticker_station','orders','stickers'),
|
|
40340
|
+
('stickers','sticker_station','orders','stickers'),
|
|
40341
|
+
('verzendbrief','shipping_note_station','orders','verzendbrieven'),
|
|
40342
|
+
('verzendbrieven','shipping_note_station','orders','verzendbrieven'),
|
|
40343
|
+
('veilingbrief','shipping_note_station','orders','verzendbrieven'),
|
|
40344
|
+
('transportbrief','shipping_note_station','orders','verzendbrieven'),
|
|
40345
|
+
('productiebon','production_note_station','productie','productiebonnen'),
|
|
40346
|
+
('productiebonnen','production_note_station','productie','productiebonnen'),
|
|
40347
|
+
('productielijst','production_note_station','productie','productiebonnen')
|
|
40348
|
+
) AS t(d, k, c, l) WHERE t.d = v_doc;
|
|
40349
|
+
IF v_key IS NULL THEN
|
|
40350
|
+
RETURN jsonb_build_object('bron','geen','melding','Onbekend document: ' || coalesce(p_document,''));
|
|
40351
|
+
END IF;
|
|
40352
|
+
IF to_regclass('public.pick_stations') IS NULL THEN
|
|
40353
|
+
RETURN jsonb_build_object('document', v_label, 'bron','geen','melding','Kies een pickstation voor ' || v_label);
|
|
40354
|
+
END IF;
|
|
40355
|
+
|
|
40356
|
+
SELECT public.logistics_try_uuid(settings->'pickstations'->'fields'->>v_key) INTO v_gekozen
|
|
40357
|
+
FROM public.logistics_rule_configs
|
|
40358
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
40359
|
+
|
|
40360
|
+
IF v_gekozen IS NOT NULL THEN
|
|
40361
|
+
SELECT s.id, s.slug, s.name, s.active INTO r FROM public.pick_stations s WHERE s.id = v_gekozen;
|
|
40362
|
+
IF FOUND THEN
|
|
40363
|
+
RETURN jsonb_build_object('document', v_label, 'bron','gekozen', 'station_id', r.id,
|
|
40364
|
+
'station_slug', r.slug, 'station_naam', r.name, 'actief', coalesce(r.active, true));
|
|
40365
|
+
END IF;
|
|
40366
|
+
v_weg := true;
|
|
40367
|
+
END IF;
|
|
40368
|
+
|
|
40369
|
+
v_heeft_code := EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = 'public.pick_stations'::regclass
|
|
40370
|
+
AND attname = 'system_code' AND NOT attisdropped);
|
|
40371
|
+
IF v_heeft_code THEN
|
|
40372
|
+
EXECUTE 'SELECT s.id, s.slug, s.name, s.active FROM public.pick_stations s WHERE s.system_code = $1 LIMIT 1'
|
|
40373
|
+
INTO r USING v_code;
|
|
40374
|
+
IF r.id IS NOT NULL THEN
|
|
40375
|
+
RETURN jsonb_build_object('document', v_label, 'bron','standaard', 'system_code', v_code,
|
|
40376
|
+
'station_id', r.id, 'station_slug', r.slug, 'station_naam', r.name, 'actief', coalesce(r.active, true),
|
|
40377
|
+
'gekozenBestaatNiet', v_weg);
|
|
40378
|
+
END IF;
|
|
40379
|
+
END IF;
|
|
40380
|
+
RETURN jsonb_build_object('document', v_label, 'bron','geen', 'system_code', v_code,
|
|
40381
|
+
'gekozenBestaatNiet', v_weg, 'melding', 'Kies een pickstation voor ' || v_label);
|
|
40382
|
+
END $function$;
|
|
40383
|
+
|
|
40384
|
+
REVOKE ALL ON FUNCTION public.logistics_station_voor_document(text) FROM PUBLIC, anon;
|
|
40385
|
+
GRANT EXECUTE ON FUNCTION public.logistics_station_voor_document(text) TO authenticated, service_role;
|
|
40386
|
+
|
|
40387
|
+
CREATE OR REPLACE FUNCTION public.logistics_station_in_gebruik(p_station_id uuid)
|
|
40388
|
+
RETURNS jsonb
|
|
40389
|
+
LANGUAGE plpgsql
|
|
40390
|
+
STABLE SECURITY DEFINER
|
|
40391
|
+
SET search_path TO 'public'
|
|
40392
|
+
AS $function$
|
|
40393
|
+
DECLARE d text; v jsonb; res jsonb := '[]'::jsonb;
|
|
40394
|
+
BEGIN
|
|
40395
|
+
-- Direct via de API: alleen beheer. Geneste aanroep (trigger/wrapper van Pickschermen) mag.
|
|
40396
|
+
PERFORM public.logistics_acc_guard('beheer', 'logistics_station_in_gebruik');
|
|
40397
|
+
IF p_station_id IS NULL THEN RETURN res; END IF;
|
|
40398
|
+
FOREACH d IN ARRAY ARRAY['productiebon','pakbon','stickers','verzendbrief'] LOOP
|
|
40399
|
+
v := public.logistics_station_voor_document(d);
|
|
40400
|
+
IF v->>'station_id' = p_station_id::text THEN res := res || to_jsonb(v->>'document'); END IF;
|
|
40401
|
+
END LOOP;
|
|
40402
|
+
RETURN res;
|
|
40403
|
+
END $function$;
|
|
40404
|
+
|
|
40405
|
+
REVOKE ALL ON FUNCTION public.logistics_station_in_gebruik(uuid) FROM PUBLIC, anon;
|
|
40406
|
+
GRANT EXECUTE ON FUNCTION public.logistics_station_in_gebruik(uuid) TO authenticated, service_role;
|
|
40407
|
+
|
|
40408
|
+
CREATE OR REPLACE FUNCTION public.logistics_station_meldingen()
|
|
40409
|
+
RETURNS jsonb
|
|
40410
|
+
LANGUAGE plpgsql
|
|
40411
|
+
STABLE SECURITY DEFINER
|
|
40412
|
+
SET search_path TO 'public'
|
|
40413
|
+
AS $function$
|
|
40414
|
+
DECLARE d text; v jsonb; res jsonb := '[]'::jsonb;
|
|
40415
|
+
BEGIN
|
|
40416
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_station_meldingen');
|
|
40417
|
+
FOREACH d IN ARRAY ARRAY['productiebon','pakbon','stickers','verzendbrief'] LOOP
|
|
40418
|
+
v := public.logistics_station_voor_document(d);
|
|
40419
|
+
IF coalesce((v->>'gekozenBestaatNiet')::boolean, false) THEN
|
|
40420
|
+
res := res || to_jsonb('Het gekozen station voor ' || (v->>'document') || ' bestaat niet meer; het standaardstation wordt gebruikt.');
|
|
40421
|
+
END IF;
|
|
40422
|
+
IF v->>'bron' = 'geen' THEN
|
|
40423
|
+
res := res || to_jsonb(v->>'melding');
|
|
40424
|
+
ELSIF NOT coalesce((v->>'actief')::boolean, true) THEN
|
|
40425
|
+
res := res || to_jsonb('Het station ' || coalesce(v->>'station_naam','') || ' staat uit, maar krijgt nog ' || (v->>'document') || '.');
|
|
40426
|
+
END IF;
|
|
40427
|
+
END LOOP;
|
|
40428
|
+
RETURN res;
|
|
40429
|
+
END $function$;
|
|
40430
|
+
|
|
40431
|
+
REVOKE ALL ON FUNCTION public.logistics_station_meldingen() FROM PUBLIC, anon;
|
|
40432
|
+
GRANT EXECUTE ON FUNCTION public.logistics_station_meldingen() TO authenticated, service_role;
|
|
40433
|
+
|
|
40434
|
+
CREATE OR REPLACE FUNCTION public.logistics_document_station(_document_code text)
|
|
40435
|
+
RETURNS uuid
|
|
40436
|
+
LANGUAGE plpgsql
|
|
40437
|
+
STABLE SECURITY DEFINER
|
|
40438
|
+
SET search_path TO 'public'
|
|
40439
|
+
AS $function$
|
|
40440
|
+
BEGIN
|
|
40441
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_document_station');
|
|
40442
|
+
RETURN public.logistics_try_uuid(public.logistics_station_voor_document(_document_code)->>'station_id');
|
|
40443
|
+
EXCEPTION WHEN others THEN
|
|
40444
|
+
RETURN NULL;
|
|
40445
|
+
END;
|
|
40446
|
+
$function$;
|
|
40447
|
+
|
|
40448
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_station()
|
|
40449
|
+
RETURNS jsonb
|
|
40450
|
+
LANGUAGE plpgsql
|
|
40451
|
+
STABLE SECURITY DEFINER
|
|
40452
|
+
SET search_path TO 'public'
|
|
40453
|
+
AS $function$
|
|
40454
|
+
DECLARE v jsonb;
|
|
40455
|
+
BEGIN
|
|
40456
|
+
-- Direct via de API: alleen ingelogd. Geneste aanroep (pickstation-wrapper) mag, net als _v2.
|
|
40457
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_station');
|
|
40458
|
+
v := public.logistics_station_voor_document('productiebon');
|
|
40459
|
+
IF NOT (v ? 'station_id') THEN RETURN '{}'::jsonb; END IF;
|
|
40460
|
+
RETURN jsonb_build_object('station_id', (v->>'station_id')::uuid, 'station_slug', v->>'station_slug');
|
|
40461
|
+
END $function$;
|
|
40462
|
+
|
|
40463
|
+
-- Stickers en traystickers: lege of verdwenen stationkeuze -> standaardstation 'orders' (pakbon en stickers delen die standaard).
|
|
40464
|
+
CREATE OR REPLACE FUNCTION public.logistics_sticker_cart_plek(_cart uuid, _fallback text)
|
|
40465
|
+
RETURNS text
|
|
40466
|
+
LANGUAGE sql
|
|
40467
|
+
STABLE SECURITY DEFINER
|
|
40468
|
+
SET search_path TO 'public'
|
|
40469
|
+
AS $function$
|
|
40470
|
+
SELECT public.logistics_acc_guard('ingelogd', 'logistics_sticker_cart_plek');
|
|
40471
|
+
SELECT coalesce(
|
|
40472
|
+
(SELECT nullif(btrim(pj.payload->>'print_plek_id'),'') FROM public.print_jobs pj
|
|
40473
|
+
WHERE pj.payload->>'cart_id' = _cart::text AND pj.documenttype = 'pakbon'
|
|
40474
|
+
AND coalesce(pj.is_herprint,false) = false
|
|
40475
|
+
ORDER BY pj.created_at DESC LIMIT 1),
|
|
40476
|
+
(SELECT s.id::text FROM public.pick_stations s WHERE s.id = public.logistics_try_uuid(_fallback)),
|
|
40477
|
+
nullif(public.logistics_station_voor_document('stickers')->>'station_id', ''));
|
|
40478
|
+
$function$;
|
|
40479
|
+
|
|
40480
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_sync(p_productie_order_id uuid)
|
|
40481
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
|
|
40482
|
+
AS $function$
|
|
40483
|
+
DECLARE
|
|
40484
|
+
po record; s jsonb; v_release text; v_approval boolean; v_station uuid; v_screen uuid;
|
|
40485
|
+
v_type uuid; v_queued uuid; v_new uuid; v_cancel uuid; v_done uuid; v_row record; v_lines integer; v_payload jsonb; v_n integer;
|
|
40486
|
+
BEGIN
|
|
40487
|
+
SELECT * INTO po FROM public.productie_orders WHERE id = p_productie_order_id;
|
|
40488
|
+
IF NOT FOUND THEN RETURN jsonb_build_object('actie','geen','reden','productieorder niet gevonden'); END IF;
|
|
40489
|
+
SELECT id INTO v_type FROM public.pick_document_types WHERE code = 'productiebon' LIMIT 1;
|
|
40490
|
+
IF v_type IS NULL THEN
|
|
40491
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'sync', 'fout', 'Documentsoort productiebon ontbreekt in de pickschermen.');
|
|
40492
|
+
RETURN jsonb_build_object('actie','fout','reden','documentsoort productiebon ontbreekt');
|
|
40493
|
+
END IF;
|
|
40494
|
+
SELECT id INTO v_queued FROM public.pick_document_statuses WHERE code = 'queued' LIMIT 1;
|
|
40495
|
+
SELECT id INTO v_new FROM public.pick_document_statuses WHERE code = 'new' LIMIT 1;
|
|
40496
|
+
SELECT id INTO v_cancel FROM public.pick_document_statuses WHERE code = 'cancelled' LIMIT 1;
|
|
40497
|
+
SELECT id INTO v_done FROM public.pick_document_statuses WHERE code = 'done' LIMIT 1;
|
|
40498
|
+
SELECT q.* INTO v_row FROM public.pick_queue q
|
|
40499
|
+
WHERE q.document_type_id = v_type AND q.payload->>'productie_order_id' = po.id::text
|
|
40500
|
+
ORDER BY q.created_at DESC LIMIT 1;
|
|
40501
|
+
|
|
40502
|
+
IF po.status = 'geannuleerd' THEN
|
|
40503
|
+
UPDATE public.pick_queue q SET cancelled_at = now(), status_id = coalesce(v_cancel, q.status_id), updated_at = now(),
|
|
40504
|
+
payload = coalesce(q.payload,'{}'::jsonb) || jsonb_build_object('cancelReason','Productieorder geannuleerd')
|
|
40505
|
+
WHERE q.document_type_id = v_type AND q.payload->>'productie_order_id' = po.id::text
|
|
40506
|
+
AND q.cancelled_at IS NULL AND q.completed_at IS NULL;
|
|
40507
|
+
GET DIAGNOSTICS v_n = ROW_COUNT;
|
|
40508
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'annuleren', 'ok', v_n || ' regel(s) uit de wachtrij');
|
|
40509
|
+
RETURN jsonb_build_object('actie','geannuleerd','regels',v_n);
|
|
40510
|
+
ELSIF po.status = 'verwerkt' THEN
|
|
40511
|
+
UPDATE public.pick_queue q SET completed_at = now(), status_id = coalesce(v_done, q.status_id), updated_at = now()
|
|
40512
|
+
WHERE q.document_type_id = v_type AND q.payload->>'productie_order_id' = po.id::text
|
|
40513
|
+
AND q.cancelled_at IS NULL AND q.completed_at IS NULL;
|
|
40514
|
+
GET DIAGNOSTICS v_n = ROW_COUNT;
|
|
40515
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'afronden', 'ok', v_n || ' regel(s) afgerond');
|
|
40516
|
+
RETURN jsonb_build_object('actie','afgerond','regels',v_n);
|
|
40517
|
+
ELSIF po.status <> 'open' THEN
|
|
40518
|
+
RETURN jsonb_build_object('actie','geen','reden','status ' || coalesce(po.status,'leeg') || ' verandert de wachtrij niet');
|
|
40519
|
+
END IF;
|
|
40520
|
+
|
|
40521
|
+
SELECT settings INTO s FROM public.logistics_rule_configs
|
|
40522
|
+
ORDER BY is_active DESC, (status = 'actief') DESC, updated_at DESC LIMIT 1;
|
|
40523
|
+
v_release := coalesce(public.logistics_rule_text(s, 'pickstations', 'production_note_release', 'on_stock_upgrade'), 'on_stock_upgrade');
|
|
40524
|
+
v_approval := v_release = 'manual_approval_after_upgrade';
|
|
40525
|
+
v_station := public.logistics_try_uuid(public.logistics_station_voor_document('productiebon')->>'station_id');
|
|
40526
|
+
SELECT count(*)::int INTO v_lines FROM public.productie_order_onderdelen o WHERE o.productie_order_id = po.id;
|
|
40527
|
+
v_payload := jsonb_build_object('source','logistiek-engine','documentType','productiebon',
|
|
40528
|
+
'productie_order_id', po.id, 'productieOrderNummer', po.nummer, 'productId', po.product_id,
|
|
40529
|
+
'tradeItemKey', po.trade_item_key, 'aantal', po.aantal, 'opmerking', po.opmerking,
|
|
40530
|
+
'onderdelen', v_lines);
|
|
40531
|
+
|
|
40532
|
+
IF v_row.id IS NOT NULL THEN
|
|
40533
|
+
IF v_row.cancelled_at IS NULL AND v_row.completed_at IS NULL THEN
|
|
40534
|
+
UPDATE public.pick_queue q SET document_number = po.nummer, line_count = v_lines,
|
|
40535
|
+
payload = coalesce(q.payload,'{}'::jsonb) || v_payload, updated_at = now()
|
|
40536
|
+
WHERE q.id = v_row.id
|
|
40537
|
+
AND (q.document_number, q.line_count, coalesce(q.payload,'{}'::jsonb))
|
|
40538
|
+
IS DISTINCT FROM (po.nummer, v_lines, coalesce(q.payload,'{}'::jsonb) || v_payload);
|
|
40539
|
+
END IF;
|
|
40540
|
+
RETURN jsonb_build_object('actie','bestaat','queueId',v_row.id);
|
|
40541
|
+
END IF;
|
|
40542
|
+
|
|
40543
|
+
IF v_station IS NULL OR NOT EXISTS (SELECT 1 FROM public.pick_stations WHERE id = v_station) THEN
|
|
40544
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'aanmaken', 'overgeslagen',
|
|
40545
|
+
'Kies een pickstation voor productiebonnen (Werkwijze, stap Pickstations).');
|
|
40546
|
+
RETURN jsonb_build_object('actie','overgeslagen','reden','geen pickstation ingesteld');
|
|
40547
|
+
END IF;
|
|
40548
|
+
SELECT sc.id INTO v_screen FROM public.pick_station_screens sc
|
|
40549
|
+
WHERE sc.station_id = v_station
|
|
40550
|
+
ORDER BY (EXISTS (SELECT 1 FROM public.pick_screen_document_types d WHERE d.screen_id = sc.id AND d.document_type_id = v_type)) DESC, sc.created_at
|
|
40551
|
+
LIMIT 1;
|
|
40552
|
+
|
|
40553
|
+
INSERT INTO public.pick_queue (station_id, screen_id, document_type_id, status_id, document_number, order_number, reference,
|
|
40554
|
+
customer_name, line_count, cart_count, priority, is_urgent, announced_at, due_at, payload)
|
|
40555
|
+
VALUES (v_station, v_screen, v_type, CASE WHEN v_approval THEN coalesce(v_new, v_queued) ELSE v_queued END,
|
|
40556
|
+
po.nummer, NULL, po.id::text, NULL, v_lines, 0, 50, false, now(), NULL,
|
|
40557
|
+
v_payload || jsonb_build_object('requiresApproval', v_approval, 'approvedAt', NULL, 'approvedBy', NULL));
|
|
40558
|
+
PERFORM public.logistics_productiebon_log_schrijf(po.id, 'aanmaken', 'ok',
|
|
40559
|
+
CASE WHEN v_approval THEN 'In wachtrij, wacht op goedkeuring' ELSE 'In wachtrij' END);
|
|
40560
|
+
RETURN jsonb_build_object('actie','aangemaakt','wachtOpGoedkeuring',v_approval);
|
|
40561
|
+
END $function$;
|
|
40562
|
+
|
|
40563
|
+
CREATE OR REPLACE FUNCTION public.logistics_productiebon_status()
|
|
40564
|
+
RETURNS jsonb
|
|
40565
|
+
LANGUAGE plpgsql
|
|
40566
|
+
STABLE SECURITY DEFINER
|
|
40567
|
+
SET search_path TO 'public'
|
|
40568
|
+
AS $function$
|
|
40569
|
+
DECLARE v_type uuid; r jsonb; v_station jsonb;
|
|
40570
|
+
BEGIN
|
|
40571
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_productiebon_status');
|
|
40572
|
+
IF to_regclass('public.pick_queue') IS NULL OR to_regclass('public.pick_document_types') IS NULL THEN
|
|
40573
|
+
RETURN jsonb_build_object('beschikbaar', false);
|
|
40574
|
+
END IF;
|
|
40575
|
+
v_station := public.logistics_productiebon_station();
|
|
40576
|
+
SELECT id INTO v_type FROM public.pick_document_types WHERE code = 'productiebon' LIMIT 1;
|
|
40577
|
+
SELECT jsonb_build_object('beschikbaar', true,
|
|
40578
|
+
'stationIngesteld', v_station ? 'station_id',
|
|
40579
|
+
'stationMelding', CASE WHEN v_station ? 'station_id' THEN NULL ELSE 'Kies een pickstation voor productiebonnen' END,
|
|
40580
|
+
'inWachtrij', count(*) FILTER (WHERE q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
40581
|
+
AND NOT (coalesce((q.payload->>'requiresApproval')::boolean,false) AND q.payload->>'approvedAt' IS NULL)),
|
|
40582
|
+
'wachtOpGoedkeuring', count(*) FILTER (WHERE q.cancelled_at IS NULL AND q.completed_at IS NULL
|
|
40583
|
+
AND coalesce((q.payload->>'requiresApproval')::boolean,false) AND q.payload->>'approvedAt' IS NULL))
|
|
40584
|
+
INTO r FROM public.pick_queue q WHERE q.document_type_id = v_type AND q.payload ? 'productie_order_id';
|
|
40585
|
+
RETURN r || jsonb_build_object('stationMeldingen', public.logistics_station_meldingen(),
|
|
40586
|
+
'fouten', coalesce((SELECT jsonb_agg(jsonb_build_object('op', l.created_at, 'status', l.status, 'melding', l.melding) ORDER BY l.created_at DESC)
|
|
40587
|
+
FROM (SELECT * FROM public.logistics_productiebon_log WHERE status IN ('fout','overgeslagen') AND created_at > now() - interval '7 days'
|
|
40588
|
+
ORDER BY created_at DESC LIMIT 5) l), '[]'::jsonb));
|
|
40589
|
+
END $function$;
|
|
40590
|
+
|
|
40591
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_productiebon()
|
|
40592
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text)
|
|
40593
|
+
LANGUAGE plpgsql
|
|
40594
|
+
STABLE SECURITY DEFINER
|
|
40595
|
+
SET search_path TO 'public'
|
|
40596
|
+
AS $function$
|
|
40597
|
+
DECLARE f text;
|
|
40598
|
+
BEGIN
|
|
40599
|
+
FOREACH f IN ARRAY ARRAY['logistics_productiebon_sync(uuid)','logistics_productiebon_goedkeuren(uuid)',
|
|
40600
|
+
'logistics_productiebon_goedkeuren_v2(uuid,jsonb)','logistics_productiebon_station()',
|
|
40601
|
+
'logistics_productiebon_status()','logistics_productie_orders_trg()',
|
|
40602
|
+
'logistics_station_voor_document(text)','logistics_station_in_gebruik(uuid)','logistics_station_meldingen()'] LOOP
|
|
40603
|
+
onderdeel := 'functie ' || f; ok := to_regprocedure('public.' || f) IS NOT NULL;
|
|
40604
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; RETURN NEXT;
|
|
40605
|
+
END LOOP;
|
|
40606
|
+
onderdeel := 'tabel logistics_productiebon_log'; ok := to_regclass('public.logistics_productiebon_log') IS NOT NULL;
|
|
40607
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt' END; RETURN NEXT;
|
|
40608
|
+
onderdeel := 'trigger trg_logistics_productie_orders_productiebon';
|
|
40609
|
+
IF to_regclass('public.productie_orders') IS NULL THEN ok := true; toelichting := 'niet nodig: Voorraad-productieorders ontbreken';
|
|
40610
|
+
ELSE ok := EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_logistics_productie_orders_productiebon' AND tgrelid = 'public.productie_orders'::regclass);
|
|
40611
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END; END IF;
|
|
40612
|
+
RETURN NEXT;
|
|
40613
|
+
onderdeel := 'kolom pick_stations.system_code';
|
|
40614
|
+
IF to_regclass('public.pick_stations') IS NULL THEN ok := true; toelichting := 'niet nodig: Pickschermen ontbreekt';
|
|
40615
|
+
ELSE ok := EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = 'public.pick_stations'::regclass AND attname = 'system_code' AND NOT attisdropped);
|
|
40616
|
+
toelichting := CASE WHEN ok THEN 'aanwezig' ELSE 'ontbreekt: werk Pickschermen bij; tot dan geen standaardstations' END; END IF;
|
|
40617
|
+
RETURN NEXT;
|
|
40618
|
+
END $function$;-- Samenvoeggroepen (orderbuffers): geannuleerde/verwijderde orders nooit (meer) in een groep.
|
|
40619
|
+
|
|
40620
|
+
CREATE OR REPLACE FUNCTION public.logistics_order_vervallen(p_order_id uuid)
|
|
40621
|
+
RETURNS boolean LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40622
|
+
DECLARE v boolean := false;
|
|
40623
|
+
BEGIN
|
|
40624
|
+
SELECT (o.deleted_at IS NOT NULL OR o.cancelled_at IS NOT NULL
|
|
40625
|
+
OR lower(btrim(coalesce(o.status, ''))) IN ('geannuleerd', 'cancelled'))
|
|
40626
|
+
INTO v FROM public.orders o WHERE o.id = p_order_id;
|
|
40627
|
+
IF coalesce(v, false) THEN RETURN true; END IF;
|
|
40628
|
+
IF to_regclass('public.voorraad_order_terugdraaiing') IS NOT NULL THEN
|
|
40629
|
+
EXECUTE 'SELECT EXISTS (SELECT 1 FROM public.voorraad_order_terugdraaiing t WHERE t.order_id = $1)'
|
|
40630
|
+
INTO v USING p_order_id;
|
|
40631
|
+
END IF;
|
|
40632
|
+
RETURN coalesce(v, false);
|
|
40633
|
+
END $$;
|
|
40634
|
+
REVOKE ALL ON FUNCTION public.logistics_order_vervallen(uuid) FROM PUBLIC, anon;
|
|
40635
|
+
GRANT EXECUTE ON FUNCTION public.logistics_order_vervallen(uuid) TO authenticated, service_role;
|
|
40636
|
+
|
|
40637
|
+
CREATE OR REPLACE FUNCTION public.logistics_order_buffer_excluded(p_order_id uuid)
|
|
40638
|
+
RETURNS boolean
|
|
40639
|
+
LANGUAGE sql
|
|
40640
|
+
STABLE SECURITY DEFINER
|
|
40641
|
+
SET search_path TO 'public'
|
|
40642
|
+
AS $function$
|
|
40643
|
+
SELECT public.logistics_acc_guard('server', 'logistics_order_buffer_excluded');
|
|
40644
|
+
SELECT EXISTS (SELECT 1 FROM public.logistics_order_plan_exclusion x WHERE x.order_id = p_order_id)
|
|
40645
|
+
OR public.logistics_order_afgemeld(p_order_id)
|
|
40646
|
+
OR public.logistics_order_vervallen(p_order_id)
|
|
40647
|
+
$function$;
|
|
40648
|
+
|
|
40649
|
+
CREATE OR REPLACE FUNCTION public._logistics_buffers_vervallen_herstel(p_order_id uuid)
|
|
40650
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40651
|
+
DECLARE r record; v_groepen uuid[] := '{}'; v_orders int := 0; v_oud text; v_stand jsonb;
|
|
40652
|
+
BEGIN
|
|
40653
|
+
v_oud := current_setting('logistics.buffer_writer', true);
|
|
40654
|
+
FOR r IN
|
|
40655
|
+
SELECT o.id, o.order_number, o.buffer_id,
|
|
40656
|
+
CASE WHEN o.deleted_at IS NOT NULL THEN 'verwijderd' ELSE 'geannuleerd' END AS reden
|
|
40657
|
+
FROM public.orders o
|
|
40658
|
+
WHERE o.buffer_id IS NOT NULL AND (p_order_id IS NULL OR o.id = p_order_id)
|
|
40659
|
+
AND public.logistics_order_vervallen(o.id)
|
|
40660
|
+
ORDER BY o.order_number
|
|
40661
|
+
FOR UPDATE OF o
|
|
40662
|
+
LOOP
|
|
40663
|
+
PERFORM set_config('logistics.buffer_writer', 'engine', true);
|
|
40664
|
+
UPDATE public.orders SET buffer_id = NULL WHERE id = r.id AND buffer_id = r.buffer_id;
|
|
40665
|
+
INSERT INTO public.logistics_correctie_log (correctie, object_id, omschrijving, oud, nieuw)
|
|
40666
|
+
VALUES ('buffers_geannuleerd', r.id, coalesce(r.order_number, r.id::text) || ' (' || r.reden || ') losgemaakt uit samenvoeggroep',
|
|
40667
|
+
jsonb_build_object('buffer_id', r.buffer_id), jsonb_build_object('buffer_id', NULL));
|
|
40668
|
+
v_orders := v_orders + 1;
|
|
40669
|
+
IF NOT r.buffer_id = ANY (v_groepen) THEN v_groepen := v_groepen || r.buffer_id; END IF;
|
|
40670
|
+
END LOOP;
|
|
40671
|
+
PERFORM set_config('logistics.buffer_writer', coalesce(v_oud, ''), true);
|
|
40672
|
+
|
|
40673
|
+
IF cardinality(v_groepen) > 0 THEN
|
|
40674
|
+
FOR r IN SELECT x.id, x.order_number FROM public.orders x
|
|
40675
|
+
WHERE x.buffer_id = ANY (v_groepen) AND x.deleted_at IS NULL AND x.cancelled_at IS NULL LOOP
|
|
40676
|
+
BEGIN
|
|
40677
|
+
PERFORM public.logistics_plan_enqueue(r.id, 'correctie_buffers_geannuleerd');
|
|
40678
|
+
EXCEPTION WHEN others THEN
|
|
40679
|
+
INSERT INTO public.logistics_correctie_log (correctie, object_id, omschrijving)
|
|
40680
|
+
VALUES ('buffers_geannuleerd_fout', r.id, 'Opnieuw plannen van ' || coalesce(r.order_number, r.id::text) || ' mislukt: ' || SQLERRM);
|
|
40681
|
+
END;
|
|
40682
|
+
END LOOP;
|
|
40683
|
+
SELECT value::jsonb INTO v_stand FROM public.logistics_plan_settings WHERE key = 'buffers_geannuleerd_herstel';
|
|
40684
|
+
v_stand := jsonb_build_object(
|
|
40685
|
+
'totaalGroepen', coalesce((v_stand->>'totaalGroepen')::int, 0) + cardinality(v_groepen),
|
|
40686
|
+
'totaalOrders', coalesce((v_stand->>'totaalOrders')::int, 0) + v_orders,
|
|
40687
|
+
'laatsteGroepen', cardinality(v_groepen), 'laatsteOrders', v_orders, 'laatsteOp', now());
|
|
40688
|
+
INSERT INTO public.logistics_plan_settings (key, value) VALUES ('buffers_geannuleerd_herstel', v_stand::text)
|
|
40689
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now();
|
|
40690
|
+
END IF;
|
|
40691
|
+
RETURN jsonb_build_object('groepen', cardinality(v_groepen), 'orders', v_orders);
|
|
40692
|
+
END $$;
|
|
40693
|
+
REVOKE ALL ON FUNCTION public._logistics_buffers_vervallen_herstel(uuid) FROM PUBLIC, anon, authenticated;
|
|
40694
|
+
GRANT EXECUTE ON FUNCTION public._logistics_buffers_vervallen_herstel(uuid) TO service_role;
|
|
40695
|
+
|
|
40696
|
+
CREATE OR REPLACE FUNCTION public.logistics_correctie_buffers_geannuleerd(p_uitvoeren boolean DEFAULT false)
|
|
40697
|
+
RETURNS TABLE(order_id uuid, order_number text, reden text, buffer_id uuid, actieve_karren integer,
|
|
40698
|
+
andere_open_orders text, uitgevoerd boolean)
|
|
40699
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40700
|
+
#variable_conflict use_column
|
|
40701
|
+
DECLARE r record;
|
|
40702
|
+
BEGIN
|
|
40703
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_correctie_buffers_geannuleerd');
|
|
40704
|
+
FOR r IN
|
|
40705
|
+
SELECT o.id, o.order_number, o.buffer_id,
|
|
40706
|
+
CASE WHEN o.deleted_at IS NOT NULL THEN 'verwijderd' ELSE 'geannuleerd' END AS reden,
|
|
40707
|
+
(SELECT count(*)::int FROM public.order_carts c WHERE c.order_id = o.id AND c.archived_at IS NULL) AS karren,
|
|
40708
|
+
(SELECT string_agg(x.order_number, ' ' ORDER BY x.order_number) FROM public.orders x
|
|
40709
|
+
WHERE x.buffer_id = o.buffer_id AND x.id <> o.id AND x.deleted_at IS NULL AND x.cancelled_at IS NULL) AS anderen
|
|
40710
|
+
FROM public.orders o
|
|
40711
|
+
WHERE o.buffer_id IS NOT NULL AND public.logistics_order_vervallen(o.id)
|
|
40712
|
+
ORDER BY o.order_number
|
|
40713
|
+
LOOP
|
|
40714
|
+
order_id := r.id; order_number := r.order_number; reden := r.reden; buffer_id := r.buffer_id;
|
|
40715
|
+
actieve_karren := r.karren; andere_open_orders := r.anderen; uitgevoerd := p_uitvoeren;
|
|
40716
|
+
RETURN NEXT;
|
|
40717
|
+
END LOOP;
|
|
40718
|
+
IF p_uitvoeren THEN PERFORM public._logistics_buffers_vervallen_herstel(NULL); END IF;
|
|
40719
|
+
END $$;
|
|
40720
|
+
REVOKE ALL ON FUNCTION public.logistics_correctie_buffers_geannuleerd(boolean) FROM PUBLIC, anon, authenticated;
|
|
40721
|
+
GRANT EXECUTE ON FUNCTION public.logistics_correctie_buffers_geannuleerd(boolean) TO service_role;
|
|
40722
|
+
|
|
40723
|
+
CREATE OR REPLACE FUNCTION public.logistics_orders_vervallen_buffer_trg()
|
|
40724
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40725
|
+
BEGIN
|
|
40726
|
+
BEGIN
|
|
40727
|
+
PERFORM public._logistics_buffers_vervallen_herstel(NEW.id);
|
|
40728
|
+
EXCEPTION WHEN others THEN
|
|
40729
|
+
BEGIN
|
|
40730
|
+
INSERT INTO public.logistics_correctie_log (correctie, object_id, omschrijving)
|
|
40731
|
+
VALUES ('buffers_geannuleerd_fout', NEW.id, 'Losmaken uit samenvoeggroep mislukt: ' || SQLERRM);
|
|
40732
|
+
EXCEPTION WHEN others THEN RAISE WARNING 'logistics_orders_vervallen_buffer_trg: %', SQLERRM;
|
|
40733
|
+
END;
|
|
40734
|
+
END;
|
|
40735
|
+
RETURN NULL;
|
|
40736
|
+
END $$;
|
|
40737
|
+
REVOKE ALL ON FUNCTION public.logistics_orders_vervallen_buffer_trg() FROM PUBLIC, anon, authenticated;
|
|
40738
|
+
|
|
40739
|
+
DROP TRIGGER IF EXISTS trg_logistics_orders_vervallen_buffer ON public.orders;
|
|
40740
|
+
CREATE TRIGGER trg_logistics_orders_vervallen_buffer
|
|
40741
|
+
AFTER UPDATE OF cancelled_at, deleted_at, status, buffer_id ON public.orders
|
|
40742
|
+
FOR EACH ROW
|
|
40743
|
+
WHEN (NEW.buffer_id IS NOT NULL AND (NEW.cancelled_at IS NOT NULL OR NEW.deleted_at IS NOT NULL
|
|
40744
|
+
OR lower(btrim(coalesce(NEW.status, ''))) IN ('geannuleerd', 'cancelled')))
|
|
40745
|
+
EXECUTE FUNCTION public.logistics_orders_vervallen_buffer_trg();
|
|
40746
|
+
|
|
40747
|
+
CREATE OR REPLACE FUNCTION public.logistics_terugdraaiing_buffer_trg()
|
|
40748
|
+
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40749
|
+
BEGIN
|
|
40750
|
+
BEGIN
|
|
40751
|
+
PERFORM public._logistics_buffers_vervallen_herstel(NEW.order_id);
|
|
40752
|
+
EXCEPTION WHEN others THEN
|
|
40753
|
+
BEGIN
|
|
40754
|
+
INSERT INTO public.logistics_correctie_log (correctie, object_id, omschrijving)
|
|
40755
|
+
VALUES ('buffers_geannuleerd_fout', NEW.order_id, 'Losmaken uit samenvoeggroep na terugdraaien mislukt: ' || SQLERRM);
|
|
40756
|
+
EXCEPTION WHEN others THEN RAISE WARNING 'logistics_terugdraaiing_buffer_trg: %', SQLERRM;
|
|
40757
|
+
END;
|
|
40758
|
+
END;
|
|
40759
|
+
RETURN NULL;
|
|
40760
|
+
END $$;
|
|
40761
|
+
REVOKE ALL ON FUNCTION public.logistics_terugdraaiing_buffer_trg() FROM PUBLIC, anon, authenticated;
|
|
40762
|
+
|
|
40763
|
+
DO $do$ BEGIN
|
|
40764
|
+
IF to_regclass('public.voorraad_order_terugdraaiing') IS NOT NULL THEN
|
|
40765
|
+
DROP TRIGGER IF EXISTS trg_logistics_terugdraaiing_buffer ON public.voorraad_order_terugdraaiing;
|
|
40766
|
+
CREATE TRIGGER trg_logistics_terugdraaiing_buffer AFTER INSERT ON public.voorraad_order_terugdraaiing
|
|
40767
|
+
FOR EACH ROW EXECUTE FUNCTION public.logistics_terugdraaiing_buffer_trg();
|
|
40768
|
+
END IF;
|
|
40769
|
+
END $do$;
|
|
40770
|
+
|
|
40771
|
+
CREATE OR REPLACE FUNCTION public.logistics_buffers_herstel_status()
|
|
40772
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40773
|
+
BEGIN
|
|
40774
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_buffers_herstel_status');
|
|
40775
|
+
RETURN jsonb_build_object(
|
|
40776
|
+
'stand', (SELECT value::jsonb FROM public.logistics_plan_settings WHERE key = 'buffers_geannuleerd_herstel'),
|
|
40777
|
+
'nogInGroep', (SELECT count(*) FROM public.orders o WHERE o.buffer_id IS NOT NULL
|
|
40778
|
+
AND (o.deleted_at IS NOT NULL OR o.cancelled_at IS NOT NULL)),
|
|
40779
|
+
'fouten', coalesce((SELECT jsonb_agg(jsonb_build_object('op', l.created_at, 'melding', l.omschrijving) ORDER BY l.created_at DESC)
|
|
40780
|
+
FROM (SELECT * FROM public.logistics_correctie_log WHERE correctie = 'buffers_geannuleerd_fout'
|
|
40781
|
+
AND created_at > now() - interval '7 days' ORDER BY created_at DESC LIMIT 5) l), '[]'::jsonb));
|
|
40782
|
+
END $$;
|
|
40783
|
+
REVOKE ALL ON FUNCTION public.logistics_buffers_herstel_status() FROM PUBLIC, anon;
|
|
40784
|
+
GRANT EXECUTE ON FUNCTION public.logistics_buffers_herstel_status() TO authenticated, service_role;
|
|
40785
|
+
|
|
40786
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_buffers_vervallen()
|
|
40787
|
+
RETURNS TABLE(onderdeel text, ok boolean, toelichting text) LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
40788
|
+
SELECT 'functie ' || f, to_regprocedure('public.' || f) IS NOT NULL,
|
|
40789
|
+
CASE WHEN to_regprocedure('public.' || f) IS NOT NULL THEN 'aanwezig' ELSE 'ontbreekt: werk de Engine bij via Supabase bijwerken' END
|
|
40790
|
+
FROM unnest(ARRAY['logistics_order_vervallen(uuid)', '_logistics_buffers_vervallen_herstel(uuid)',
|
|
40791
|
+
'logistics_buffers_herstel_status()', 'logistics_orders_vervallen_buffer_trg()']) f
|
|
40792
|
+
UNION ALL
|
|
40793
|
+
SELECT 'trigger trg_logistics_orders_vervallen_buffer',
|
|
40794
|
+
EXISTS (SELECT 1 FROM pg_trigger g WHERE g.tgname = 'trg_logistics_orders_vervallen_buffer' AND g.tgrelid = 'public.orders'::regclass),
|
|
40795
|
+
'Maakt geannuleerde orders los uit hun samenvoeggroep'
|
|
40796
|
+
$$;
|
|
40797
|
+
REVOKE ALL ON FUNCTION public.logistics_install_check_buffers_vervallen() FROM PUBLIC, anon;
|
|
40798
|
+
GRANT EXECUTE ON FUNCTION public.logistics_install_check_buffers_vervallen() TO authenticated, service_role;
|
|
40799
|
+
|
|
40800
|
+
CREATE OR REPLACE FUNCTION public.logistics_buffer_frozen(p_buffer uuid)
|
|
40801
|
+
RETURNS boolean
|
|
40802
|
+
LANGUAGE sql
|
|
40803
|
+
STABLE SECURITY DEFINER
|
|
40804
|
+
SET search_path TO 'public'
|
|
40805
|
+
AS $function$
|
|
40806
|
+
SELECT public.logistics_acc_guard('server', 'logistics_buffer_frozen');
|
|
40807
|
+
SELECT p_buffer IS NOT NULL AND (
|
|
40808
|
+
EXISTS (SELECT 1 FROM logistics_active.order_carts oc
|
|
40809
|
+
WHERE oc.buffer_id = p_buffer
|
|
40810
|
+
AND (public.logistics_cart_is_frozen(oc.id)
|
|
40811
|
+
OR EXISTS (SELECT 1 FROM public.logistics_control_scan s WHERE s.cart_id = oc.id AND s.status <> 'geannuleerd')
|
|
40812
|
+
OR EXISTS (SELECT 1 FROM public.logistics_slip_shipping_note n
|
|
40813
|
+
WHERE n.cart_id = oc.id AND (n.status IN ('in_printwachtrij','geprint') OR n.fulfillment_order_id IS NOT NULL))))
|
|
40814
|
+
OR EXISTS (SELECT 1 FROM public.orders x
|
|
40815
|
+
WHERE x.buffer_id = p_buffer AND x.deleted_at IS NULL AND x.cancelled_at IS NULL
|
|
40816
|
+
AND (EXISTS (SELECT 1 FROM public.logistics_control_scan s WHERE s.order_id = x.id AND s.status <> 'geannuleerd')
|
|
40817
|
+
OR EXISTS (SELECT 1 FROM public.logistics_slip_shipping_note n
|
|
40818
|
+
WHERE n.order_id = x.id AND (n.status IN ('in_printwachtrij','geprint') OR n.fulfillment_order_id IS NOT NULL))
|
|
40819
|
+
OR EXISTS (SELECT 1 FROM public.floriday_status_sync_queue q WHERE q.order_id = x.id AND q.state = 'done')))
|
|
40820
|
+
)
|
|
40821
|
+
$function$;
|
|
40822
|
+
|
|
40823
|
+
CREATE OR REPLACE FUNCTION public.logistics_buffer_handled(p_buffer uuid)
|
|
40824
|
+
RETURNS boolean
|
|
40825
|
+
LANGUAGE sql
|
|
40826
|
+
STABLE SECURITY DEFINER
|
|
40827
|
+
SET search_path TO 'public'
|
|
40828
|
+
AS $function$
|
|
40829
|
+
SELECT public.logistics_acc_guard('ingelogd', 'logistics_buffer_handled');
|
|
40830
|
+
WITH karren AS (
|
|
40831
|
+
SELECT oc.id, oc.cart_number, oc.order_id
|
|
40832
|
+
FROM logistics_active.order_carts oc
|
|
40833
|
+
WHERE oc.buffer_id = p_buffer
|
|
40834
|
+
), leden AS (
|
|
40835
|
+
SELECT COALESCE(o.order_number, o.id::text) AS ref, o.id
|
|
40836
|
+
FROM public.orders o
|
|
40837
|
+
WHERE o.buffer_id = p_buffer
|
|
40838
|
+
AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
40839
|
+
), op_kar AS (
|
|
40840
|
+
SELECT DISTINCT k.id AS cart_id, COALESCE(o.order_number, o.id::text) AS ref
|
|
40841
|
+
FROM karren k
|
|
40842
|
+
JOIN logistics_active.order_cart_items ci ON ci.cart_id = k.id
|
|
40843
|
+
JOIN public.order_items oi ON oi.id = ci.order_item_id
|
|
40844
|
+
JOIN public.orders o ON o.id = oi.order_id AND o.deleted_at IS NULL AND o.cancelled_at IS NULL
|
|
40845
|
+
WHERE k.order_id IS NULL
|
|
40846
|
+
)
|
|
40847
|
+
SELECT EXISTS (SELECT 1 FROM karren)
|
|
40848
|
+
AND NOT EXISTS (
|
|
40849
|
+
SELECT 1 FROM karren k
|
|
40850
|
+
WHERE k.order_id IS NOT NULL
|
|
40851
|
+
AND NOT EXISTS (
|
|
40852
|
+
SELECT 1 FROM leden l
|
|
40853
|
+
WHERE l.id = k.order_id
|
|
40854
|
+
AND public.logistics_cart_handled(l.ref, k.cart_number))
|
|
40855
|
+
)
|
|
40856
|
+
AND NOT EXISTS (
|
|
40857
|
+
SELECT 1 FROM karren k
|
|
40858
|
+
WHERE k.order_id IS NULL
|
|
40859
|
+
AND (
|
|
40860
|
+
NOT EXISTS (SELECT 1 FROM op_kar ok WHERE ok.cart_id = k.id)
|
|
40861
|
+
OR EXISTS (
|
|
40862
|
+
SELECT 1 FROM op_kar ok
|
|
40863
|
+
WHERE ok.cart_id = k.id
|
|
40864
|
+
AND NOT public.logistics_cart_handled(ok.ref, k.cart_number))
|
|
40865
|
+
)
|
|
40866
|
+
);
|
|
40867
|
+
$function$;
|
|
40868
|
+
|
|
40869
|
+
CREATE OR REPLACE FUNCTION public.logistics_buffer_open_key(p_base_key text)
|
|
40870
|
+
RETURNS text
|
|
40871
|
+
LANGUAGE plpgsql
|
|
40872
|
+
SECURITY DEFINER
|
|
40873
|
+
SET search_path TO 'public'
|
|
40874
|
+
AS $function$
|
|
40875
|
+
DECLARE
|
|
40876
|
+
v_try int := 0;
|
|
40877
|
+
v_key text;
|
|
40878
|
+
v_id uuid;
|
|
40879
|
+
v_closed boolean;
|
|
40880
|
+
BEGIN
|
|
40881
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_buffer_open_key');
|
|
40882
|
+
IF p_base_key IS NULL OR btrim(p_base_key) = '' THEN
|
|
40883
|
+
RETURN p_base_key;
|
|
40884
|
+
END IF;
|
|
40885
|
+
|
|
40886
|
+
LOOP
|
|
40887
|
+
v_key := CASE WHEN v_try = 0 THEN p_base_key ELSE p_base_key || '#' || v_try END;
|
|
40888
|
+
SELECT id INTO v_id FROM public.order_buffers WHERE buffer_key = v_key;
|
|
40889
|
+
IF v_id IS NULL THEN
|
|
40890
|
+
RETURN v_key;
|
|
40891
|
+
END IF;
|
|
40892
|
+
|
|
40893
|
+
SELECT b.closed_at IS NOT NULL
|
|
40894
|
+
OR (b.close_at IS NOT NULL AND b.close_at <= now())
|
|
40895
|
+
OR public.logistics_buffer_handled(b.id)
|
|
40896
|
+
OR EXISTS (SELECT 1 FROM public.orders x WHERE x.buffer_id = b.id AND x.plan_locked_at IS NOT NULL)
|
|
40897
|
+
OR EXISTS (SELECT 1 FROM public.orders x WHERE x.buffer_id = b.id AND public.logistics_order_vervallen(x.id))
|
|
40898
|
+
OR EXISTS (SELECT 1 FROM logistics_active.order_carts oc
|
|
40899
|
+
WHERE oc.buffer_id = b.id AND (oc.pickup_locked IS TRUE OR oc.is_complete IS TRUE))
|
|
40900
|
+
INTO v_closed
|
|
40901
|
+
FROM public.order_buffers b WHERE b.id = v_id;
|
|
40902
|
+
|
|
40903
|
+
IF NOT COALESCE(v_closed, false) THEN
|
|
40904
|
+
RETURN v_key;
|
|
40905
|
+
END IF;
|
|
40906
|
+
|
|
40907
|
+
UPDATE public.order_buffers
|
|
40908
|
+
SET closed_at = COALESCE(closed_at, now()), updated_at = now()
|
|
40909
|
+
WHERE id = v_id;
|
|
40910
|
+
|
|
40911
|
+
v_try := v_try + 1;
|
|
40912
|
+
IF v_try > 200 THEN
|
|
40913
|
+
RAISE EXCEPTION 'Geen open orderbuffer beschikbaar voor sleutel %', p_base_key;
|
|
40914
|
+
END IF;
|
|
40915
|
+
END LOOP;
|
|
40916
|
+
END;
|
|
40917
|
+
$function$;
|
|
40918
|
+
|
|
40919
|
+
CREATE OR REPLACE FUNCTION public.logistics_ensure_defaults()
|
|
40920
|
+
RETURNS jsonb
|
|
40921
|
+
LANGUAGE plpgsql
|
|
40922
|
+
SECURITY DEFINER
|
|
40923
|
+
SET search_path TO 'public'
|
|
40924
|
+
AS $function$
|
|
40925
|
+
DECLARE
|
|
40926
|
+
v_ladingdragers text[] := '{}';
|
|
40927
|
+
v_ladingdrager_velden text[] := '{}';
|
|
40928
|
+
v_vertalingen text[] := '{}';
|
|
40929
|
+
v_instellingen text[] := '{}';
|
|
40930
|
+
v_tijd text := NULL;
|
|
40931
|
+
v_strategie boolean := false;
|
|
40932
|
+
v_meldingen text[] := '{}';
|
|
40933
|
+
v_gewijzigd boolean;
|
|
40934
|
+
v_res jsonb;
|
|
40935
|
+
v_heeft_orders boolean;
|
|
40936
|
+
v_herstel jsonb := NULL;
|
|
40937
|
+
BEGIN
|
|
40938
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_ensure_defaults');
|
|
40939
|
+
PERFORM pg_advisory_xact_lock(hashtext('logistics_ensure_defaults'));
|
|
40940
|
+
|
|
40941
|
+
WITH std(code, name, capacity_model, layers, len, wid, max_crates, max_boxes, max_kg, max_cm, mix, sort_order) AS (VALUES
|
|
40942
|
+
('trolley','Stapelwagen','layered',5,135,56,NULL::int,NULL::int,500::numeric,190,true,10),
|
|
40943
|
+
('danish_container','Deense container','layered',5,135,56,NULL,NULL,500,190,true,20),
|
|
40944
|
+
('euro_rolcontainer','Euro-rolcontainer','layered',6,120,80,NULL,NULL,600,200,true,30),
|
|
40945
|
+
('pallet','Pallet','stacked',4,120,80,NULL,40,800,180,true,40),
|
|
40946
|
+
('euro_pallet','Euro-pallet','single',1,60,40,1,1,20,40,false,50),
|
|
40947
|
+
('loose','Geen ladingdrager','none',1,0,0,NULL,NULL,NULL,NULL,false,60)
|
|
40948
|
+
), ins AS (
|
|
40949
|
+
INSERT INTO public.load_carrier_types (code, name, capacity_model, layers_per_carrier, layer_length_cm, layer_width_cm,
|
|
40950
|
+
max_crates_per_layer, max_boxes, max_weight_kg, max_height_cm, allow_mixing, is_active, is_default, sort_order)
|
|
40951
|
+
SELECT s.code, s.name, s.capacity_model, s.layers, s.len, s.wid, s.max_crates, s.max_boxes, s.max_kg, s.max_cm, s.mix, true,
|
|
40952
|
+
(s.code = 'trolley' AND NOT EXISTS (SELECT 1 FROM public.load_carrier_types d WHERE d.is_default)), s.sort_order
|
|
40953
|
+
FROM std s
|
|
40954
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.load_carrier_types l WHERE l.code = s.code)
|
|
40955
|
+
ON CONFLICT (code) DO NOTHING
|
|
40956
|
+
RETURNING code
|
|
40957
|
+
)
|
|
40958
|
+
SELECT coalesce(array_agg(code ORDER BY code), '{}') INTO v_ladingdragers FROM ins;
|
|
40959
|
+
|
|
40960
|
+
WITH std(code, name, capacity_model, layers, len, wid, max_crates, max_boxes, max_kg, max_cm) AS (VALUES
|
|
40961
|
+
('trolley','Stapelwagen','layered',5,135,56,NULL::int,NULL::int,500::numeric,190),
|
|
40962
|
+
('danish_container','Deense container','layered',5,135,56,NULL,NULL,500,190),
|
|
40963
|
+
('euro_rolcontainer','Euro-rolcontainer','layered',6,120,80,NULL,NULL,600,200),
|
|
40964
|
+
('pallet','Pallet','stacked',4,120,80,NULL,40,800,180),
|
|
40965
|
+
('euro_pallet','Euro-pallet','single',1,60,40,1,1,20,40),
|
|
40966
|
+
('loose','Geen ladingdrager','none',1,0,0,NULL,NULL,NULL,NULL)
|
|
40967
|
+
), upd AS (
|
|
40968
|
+
UPDATE public.load_carrier_types l SET
|
|
40969
|
+
name = coalesce(nullif(btrim(l.name),''), s.name),
|
|
40970
|
+
capacity_model = coalesce(l.capacity_model, s.capacity_model),
|
|
40971
|
+
layers_per_carrier = coalesce(l.layers_per_carrier, s.layers),
|
|
40972
|
+
layer_length_cm = coalesce(l.layer_length_cm, s.len),
|
|
40973
|
+
layer_width_cm = coalesce(l.layer_width_cm, s.wid),
|
|
40974
|
+
max_crates_per_layer = coalesce(l.max_crates_per_layer, s.max_crates),
|
|
40975
|
+
max_boxes = coalesce(l.max_boxes, s.max_boxes),
|
|
40976
|
+
max_weight_kg = coalesce(l.max_weight_kg, s.max_kg),
|
|
40977
|
+
max_height_cm = coalesce(l.max_height_cm, s.max_cm),
|
|
40978
|
+
updated_at = now()
|
|
40979
|
+
FROM std s
|
|
40980
|
+
WHERE l.code = s.code AND NOT (l.code = ANY(v_ladingdragers))
|
|
40981
|
+
AND ( nullif(btrim(l.name),'') IS NULL
|
|
40982
|
+
OR l.capacity_model IS NULL OR l.layers_per_carrier IS NULL OR l.layer_length_cm IS NULL OR l.layer_width_cm IS NULL
|
|
40983
|
+
OR (l.max_crates_per_layer IS NULL AND s.max_crates IS NOT NULL)
|
|
40984
|
+
OR (l.max_boxes IS NULL AND s.max_boxes IS NOT NULL)
|
|
40985
|
+
OR (l.max_weight_kg IS NULL AND s.max_kg IS NOT NULL)
|
|
40986
|
+
OR (l.max_height_cm IS NULL AND s.max_cm IS NOT NULL))
|
|
40987
|
+
RETURNING l.code
|
|
40988
|
+
)
|
|
40989
|
+
SELECT coalesce(array_agg(code ORDER BY code), '{}') INTO v_ladingdrager_velden FROM upd;
|
|
40990
|
+
|
|
40991
|
+
IF to_regclass('public.logistics_floriday_carrier_map') IS NOT NULL THEN
|
|
40992
|
+
WITH v(f, c) AS (VALUES
|
|
40993
|
+
('DANISH_TROLLEY','danish_container'), ('DANISH_TROLLEY_NON_CC_RFID','danish_container'),
|
|
40994
|
+
('DANISH_TROLLEY_WATER_TRAY','danish_container'), ('ONE_THIRD_DANISH_TROLLEY','danish_container'),
|
|
40995
|
+
('AUCTION_TROLLEY','trolley'),
|
|
40996
|
+
('EURO_TROLLEY','euro_rolcontainer'), ('WATERING_CONTAINER','euro_rolcontainer'),
|
|
40997
|
+
('EURO_PALLET','euro_pallet'), ('HT_EURO_PALLET','euro_pallet'),
|
|
40998
|
+
('PALLET','pallet'), ('BLOCK_PALLET','pallet'), ('IFCO_PALLET','pallet'),
|
|
40999
|
+
('CHEP_PALLET_BLUE','pallet'), ('CHEP_PALLET_RED','pallet'),
|
|
41000
|
+
('NONE','loose')
|
|
41001
|
+
), ins AS (
|
|
41002
|
+
INSERT INTO public.logistics_floriday_carrier_map (floriday_code, carrier_code)
|
|
41003
|
+
SELECT v.f, v.c FROM v
|
|
41004
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.logistics_floriday_carrier_map m WHERE upper(m.floriday_code) = v.f)
|
|
41005
|
+
ON CONFLICT DO NOTHING
|
|
41006
|
+
RETURNING floriday_code
|
|
41007
|
+
)
|
|
41008
|
+
SELECT coalesce(array_agg(floriday_code ORDER BY floriday_code), '{}') INTO v_vertalingen FROM ins;
|
|
41009
|
+
END IF;
|
|
41010
|
+
|
|
41011
|
+
WITH v(k, w) AS (VALUES ('batch_size','10'), ('retention_days','7'), ('kick_debounce_seconds','5')),
|
|
41012
|
+
ins AS (
|
|
41013
|
+
INSERT INTO public.logistics_plan_settings (key, value)
|
|
41014
|
+
SELECT v.k, v.w FROM v WHERE NOT EXISTS (SELECT 1 FROM public.logistics_plan_settings p WHERE p.key = v.k)
|
|
41015
|
+
ON CONFLICT (key) DO NOTHING
|
|
41016
|
+
RETURNING key
|
|
41017
|
+
)
|
|
41018
|
+
SELECT coalesce(array_agg(key ORDER BY key), '{}') INTO v_instellingen FROM ins;
|
|
41019
|
+
|
|
41020
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_time_settings) THEN
|
|
41021
|
+
v_heeft_orders := EXISTS (SELECT 1 FROM public.orders);
|
|
41022
|
+
IF v_heeft_orders THEN
|
|
41023
|
+
INSERT INTO public.logistics_time_settings (id, timezone, departure_rule_since, rule_160_since)
|
|
41024
|
+
VALUES (true, 'Europe/Amsterdam', NULL, NULL) ON CONFLICT DO NOTHING;
|
|
41025
|
+
v_tijd := 'aangemaakt zonder ingangsdata (er zijn al orders)';
|
|
41026
|
+
ELSE
|
|
41027
|
+
INSERT INTO public.logistics_time_settings (id, timezone, departure_rule_since, rule_160_since)
|
|
41028
|
+
VALUES (true, 'Europe/Amsterdam', now(), now()) ON CONFLICT DO NOTHING;
|
|
41029
|
+
v_tijd := 'aangemaakt met ingangsdata nu (lege shell)';
|
|
41030
|
+
END IF;
|
|
41031
|
+
END IF;
|
|
41032
|
+
|
|
41033
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_strategies) THEN
|
|
41034
|
+
IF auth.uid() IS NULL THEN
|
|
41035
|
+
v_meldingen := array_append(v_meldingen, 'Basisstrategie wordt aangemaakt bij het openen van de Engine door een gebruiker'::text);
|
|
41036
|
+
ELSE
|
|
41037
|
+
WITH s AS (
|
|
41038
|
+
INSERT INTO public.logistics_strategies (name, is_active, user_id)
|
|
41039
|
+
VALUES ('Basisstrategie', true, auth.uid()) RETURNING id
|
|
41040
|
+
)
|
|
41041
|
+
INSERT INTO public.logistics_rule_configs (name, status, is_active, settings, strategy_id, user_id)
|
|
41042
|
+
SELECT 'Werkwijze Basisstrategie', 'actief',
|
|
41043
|
+
NOT EXISTS (SELECT 1 FROM public.logistics_rule_configs r WHERE r.is_active),
|
|
41044
|
+
'{}'::jsonb, s.id, auth.uid() FROM s;
|
|
41045
|
+
v_strategie := true;
|
|
41046
|
+
END IF;
|
|
41047
|
+
END IF;
|
|
41048
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_strategies WHERE is_active) THEN
|
|
41049
|
+
v_meldingen := array_append(v_meldingen, 'Geen actieve strategie'::text);
|
|
41050
|
+
END IF;
|
|
41051
|
+
|
|
41052
|
+
IF to_regclass('public.pick_station_types') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.pick_station_types) THEN
|
|
41053
|
+
v_meldingen := array_append(v_meldingen, 'Pickstation-soorten leeg (Pickmodule)'::text);
|
|
41054
|
+
END IF;
|
|
41055
|
+
IF to_regclass('public.pick_screen_document_types') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.pick_screen_document_types) THEN
|
|
41056
|
+
v_meldingen := array_append(v_meldingen, 'Pickscherm-documentsoorten leeg (Pickmodule)'::text);
|
|
41057
|
+
END IF;
|
|
41058
|
+
IF to_regclass('public.cart_planning_settings') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.cart_planning_settings) THEN
|
|
41059
|
+
v_meldingen := array_append(v_meldingen, 'Karplanning-instellingen leeg (Verkoop)'::text);
|
|
41060
|
+
END IF;
|
|
41061
|
+
|
|
41062
|
+
-- Samenvoeggroepen: geannuleerde/verwijderde orders losmaken (herhaalbaar; tweede keer zonder effect).
|
|
41063
|
+
BEGIN
|
|
41064
|
+
v_herstel := public._logistics_buffers_vervallen_herstel(NULL);
|
|
41065
|
+
EXCEPTION WHEN others THEN
|
|
41066
|
+
v_meldingen := array_append(v_meldingen, ('Herstel samenvoeggroepen mislukt: ' || SQLERRM)::text);
|
|
41067
|
+
END;
|
|
41068
|
+
|
|
41069
|
+
v_gewijzigd := cardinality(v_ladingdragers) + cardinality(v_ladingdrager_velden) + cardinality(v_vertalingen)
|
|
41070
|
+
+ cardinality(v_instellingen) > 0 OR v_tijd IS NOT NULL OR v_strategie;
|
|
41071
|
+
v_res := jsonb_build_object(
|
|
41072
|
+
'gewijzigd', v_gewijzigd, 'op', now(),
|
|
41073
|
+
'ladingdragers', to_jsonb(v_ladingdragers),
|
|
41074
|
+
'ladingdrager_velden', to_jsonb(v_ladingdrager_velden),
|
|
41075
|
+
'floriday_vertalingen', to_jsonb(v_vertalingen),
|
|
41076
|
+
'plan_instellingen', to_jsonb(v_instellingen),
|
|
41077
|
+
'tijdinstellingen', v_tijd,
|
|
41078
|
+
'basisstrategie', v_strategie,
|
|
41079
|
+
'meldingen', to_jsonb(v_meldingen),
|
|
41080
|
+
'samenvoeggroepen_hersteld', coalesce((v_herstel->>'groepen')::int, 0));
|
|
41081
|
+
|
|
41082
|
+
IF v_gewijzigd THEN
|
|
41083
|
+
INSERT INTO public.logistics_plan_settings (key, value) VALUES ('defaults_last_result', v_res::text)
|
|
41084
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now();
|
|
41085
|
+
END IF;
|
|
41086
|
+
RETURN v_res;
|
|
41087
|
+
END $function$;
|