@flowselections/floriday-voorraad 1.0.129 → 1.0.133

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.
Files changed (47) hide show
  1. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
  2. package/dist-lib/components/voorraad/ArtikelWizard.js +102 -19
  3. package/dist-lib/components/voorraad/PriceStatusBadge.d.ts.map +1 -1
  4. package/dist-lib/components/voorraad/PriceStatusBadge.js +21 -45
  5. package/dist-lib/components/voorraad/ProductStructureCard.d.ts.map +1 -1
  6. package/dist-lib/components/voorraad/ProductStructureCard.js +6 -2
  7. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  8. package/dist-lib/hooks/useLocalTradeItems.js +4 -0
  9. package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
  10. package/dist-lib/hooks/useVoorraadData.js +2 -1
  11. package/dist-lib/integrations/supabase/types.d.ts +845 -0
  12. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  13. package/dist-lib/lib/__tests__/mirror-products.test.d.ts +2 -0
  14. package/dist-lib/lib/__tests__/mirror-products.test.d.ts.map +1 -0
  15. package/dist-lib/lib/__tests__/mirror-products.test.js +13 -0
  16. package/dist-lib/lib/__tests__/release-130.test.d.ts +2 -0
  17. package/dist-lib/lib/__tests__/release-130.test.d.ts.map +1 -0
  18. package/dist-lib/lib/__tests__/release-130.test.js +103 -0
  19. package/dist-lib/lib/floriday-2026v1.server.d.ts +1 -8
  20. package/dist-lib/lib/floriday-2026v1.server.d.ts.map +1 -1
  21. package/dist-lib/lib/floriday-2026v1.server.js +0 -10
  22. package/dist-lib/lib/floriday-gateway.functions.d.ts +6 -0
  23. package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -1
  24. package/dist-lib/lib/floriday-gateway.functions.js +7 -0
  25. package/dist-lib/lib/floriday-gateway.server.d.ts +17 -4
  26. package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -1
  27. package/dist-lib/lib/floriday-gateway.server.js +80 -2
  28. package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
  29. package/dist-lib/lib/floriday-payload.js +9 -4
  30. package/dist-lib/lib/floriday-read-contract.d.ts +49 -0
  31. package/dist-lib/lib/floriday-read-contract.d.ts.map +1 -0
  32. package/dist-lib/lib/floriday-read-contract.js +92 -0
  33. package/dist-lib/lib/mirror-products.d.ts +12 -0
  34. package/dist-lib/lib/mirror-products.d.ts.map +1 -0
  35. package/dist-lib/lib/mirror-products.js +10 -0
  36. package/dist-lib/lib/price-status.d.ts +14 -0
  37. package/dist-lib/lib/price-status.d.ts.map +1 -0
  38. package/dist-lib/lib/price-status.js +16 -0
  39. package/dist-lib/lib/publish-pipeline.d.ts.map +1 -1
  40. package/dist-lib/lib/publish-pipeline.js +2 -7
  41. package/dist-lib/lib/publish-status.d.ts +26 -0
  42. package/dist-lib/lib/publish-status.d.ts.map +1 -0
  43. package/dist-lib/lib/publish-status.js +30 -0
  44. package/dist-lib/server-hooks/floriday-continuous-stock-pull.d.ts.map +1 -1
  45. package/dist-lib/server-hooks/floriday-continuous-stock-pull.js +37 -50
  46. package/package.json +1 -1
  47. package/sql/floriday-voorraad-schema.sql +232 -53
@@ -1,4 +1,4 @@
1
- -- @flowselections/floriday-voorraad 1.0.128 – volledig schema (idempotent, geen gegevens).
1
+ -- @flowselections/floriday-voorraad 1.0.132 – volledig schema (idempotent, geen gegevens).
2
2
  -- Gegenereerd uit de database met scripts/generate-voorraad-schema.py. Niet met de hand wijzigen.
3
3
  -- Volgorde 20. Ontbrekende tabellen van andere modules worden overgeslagen met een NOTICE; draai opnieuw na die module.
4
4
  -- De statuscontrole van floriday_continuous_stock_queue is van Voorraad en wordt hier opnieuw gemaakt.
@@ -458,6 +458,9 @@ ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS notes text;
458
458
  ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
459
459
  ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
460
460
  ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS change_source text DEFAULT 'MANUAL_STOCK'::text NOT NULL;
461
+ ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS archived_at timestamp with time zone;
462
+ ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS archived_reason text;
463
+ ALTER TABLE public.trade_item_stock ADD COLUMN IF NOT EXISTS archived_into text;
461
464
 
462
465
  -- trade_item_supply_lines
463
466
  CREATE TABLE IF NOT EXISTS public.trade_item_supply_lines ();
@@ -2440,7 +2443,6 @@ CREATE OR REPLACE FUNCTION public.ensure_trade_item_stock_row_key(p_key text)
2440
2443
  AS $function$
2441
2444
  DECLARE
2442
2445
  v_ctx RECORD;
2443
- v_product_id uuid;
2444
2446
  v_canonical_key text;
2445
2447
  BEGIN
2446
2448
  PERFORM public.voorraad_vereis('ingelogd', 'ensure_trade_item_stock_row_key');
@@ -2448,53 +2450,17 @@ BEGIN
2448
2450
  RETURN NULL;
2449
2451
  END IF;
2450
2452
 
2451
- v_canonical_key := btrim(p_key);
2452
-
2453
- IF v_canonical_key LIKE 'product:%' THEN
2454
- BEGIN
2455
- v_product_id := substring(v_canonical_key from 9)::uuid;
2456
- EXCEPTION WHEN others THEN
2457
- v_product_id := NULL;
2458
- END;
2459
- ELSE
2460
- BEGIN
2461
- v_product_id := v_canonical_key::uuid;
2462
- EXCEPTION WHEN others THEN
2463
- v_product_id := NULL;
2464
- END;
2465
- END IF;
2466
-
2467
- IF v_product_id IS NOT NULL THEN
2468
- SELECT COALESCE(
2469
- NULLIF(btrim(COALESCE(p.floriday_trade_item_id, '')), ''),
2470
- NULLIF(btrim(COALESCE(p.trade_item_key, '')), ''),
2471
- p.id::text
2472
- )
2473
- INTO v_canonical_key
2474
- FROM public.products p
2475
- WHERE p.id = v_product_id
2476
- LIMIT 1;
2477
- v_canonical_key := COALESCE(v_canonical_key, btrim(p_key));
2478
- ELSE
2479
- SELECT COALESCE(
2480
- NULLIF(btrim(COALESCE(p.floriday_trade_item_id, '')), ''),
2481
- NULLIF(btrim(COALESCE(p.trade_item_key, '')), ''),
2482
- p.id::text
2483
- )
2484
- INTO v_canonical_key
2485
- FROM public.products p
2486
- WHERE p.floriday_trade_item_id = p_key
2487
- OR p.trade_item_key = p_key
2488
- LIMIT 1;
2489
- v_canonical_key := COALESCE(v_canonical_key, btrim(p_key));
2490
- END IF;
2453
+ BEGIN
2454
+ SELECT c.trade_item_key INTO v_canonical_key FROM public.voorraad_canoniek_artikel(p_key) c;
2455
+ EXCEPTION
2456
+ WHEN SQLSTATE 'VR011' THEN v_canonical_key := btrim(p_key);
2457
+ WHEN SQLSTATE 'VR010' THEN
2458
+ RAISE WARNING 'Voorraad: % — geen voorraadregel gekozen', SQLERRM;
2459
+ RETURN NULL;
2460
+ END;
2461
+ v_canonical_key := COALESCE(v_canonical_key, btrim(p_key));
2491
2462
 
2492
- -- Eerst opzoeken: bestaat de canonieke rij al, dan de sleutel teruggeven,
2493
- -- ongeacht of er een actieve Floriday-koppeling is.
2494
- IF EXISTS (
2495
- SELECT 1 FROM public.trade_item_stock s
2496
- WHERE s.trade_item_key = v_canonical_key
2497
- ) THEN
2463
+ IF EXISTS (SELECT 1 FROM public.trade_item_stock s WHERE s.trade_item_key = v_canonical_key) THEN
2498
2464
  RETURN v_canonical_key;
2499
2465
  END IF;
2500
2466
 
@@ -4599,11 +4565,11 @@ DECLARE v_key text; v_p numeric; v_r numeric; v_hit boolean := false;
4599
4565
  BEGIN
4600
4566
  PERFORM public.voorraad_vereis('ingelogd', 'product_own_available');
4601
4567
  has_row := false; physical := 0; reserved := 0; available := 0;
4602
- SELECT COALESCE(NULLIF(btrim(COALESCE(p.floriday_trade_item_id,'')),''), NULLIF(btrim(COALESCE(p.trade_item_key,'')),''))
4603
- INTO v_key FROM public.products p WHERE p.id = p_product_id;
4568
+ v_key := public.voorraad_canoniek_sleutel(p_product_id);
4604
4569
  IF v_key IS NULL THEN RETURN; END IF;
4605
4570
  SELECT true, COALESCE(ts.physical_stock,0), COALESCE(ts.reserved_stock,0) INTO v_hit, v_p, v_r
4606
- FROM public.trade_item_stock ts WHERE ts.connection_id = p_connection_id AND ts.trade_item_key = v_key LIMIT 1;
4571
+ FROM public.trade_item_stock ts
4572
+ WHERE ts.connection_id = p_connection_id AND ts.trade_item_key = v_key AND ts.archived_at IS NULL LIMIT 1;
4607
4573
  IF COALESCE(v_hit,false) THEN
4608
4574
  has_row := true; physical := v_p; reserved := v_r;
4609
4575
  available := GREATEST(0, floor(v_p - v_r))::int;
@@ -7887,6 +7853,24 @@ REVOKE ALL ON FUNCTION voorraad_article_vbn(uuid) FROM PUBLIC;
7887
7853
  REVOKE ALL ON FUNCTION voorraad_article_vbn(uuid) FROM anon;
7888
7854
  GRANT EXECUTE ON FUNCTION voorraad_article_vbn(uuid) TO authenticated;
7889
7855
  GRANT EXECUTE ON FUNCTION voorraad_article_vbn(uuid) TO service_role;
7856
+ CREATE OR REPLACE FUNCTION public.voorraad_artikel_prijs(p_id text)
7857
+ RETURNS TABLE(product_id uuid, sale_price numeric, unit text)
7858
+ LANGUAGE plpgsql
7859
+ STABLE SECURITY DEFINER
7860
+ SET search_path TO 'public'
7861
+ AS $function$
7862
+ #variable_conflict use_column
7863
+ DECLARE v_pid uuid;
7864
+ BEGIN
7865
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_artikel_prijs');
7866
+ SELECT c.product_id INTO v_pid FROM public.voorraad_canoniek_artikel(p_id) c;
7867
+ RETURN QUERY SELECT p.id, p.sale_price::numeric, p.unit::text FROM public.products p WHERE p.id = v_pid;
7868
+ END $function$
7869
+ ;
7870
+ REVOKE ALL ON FUNCTION voorraad_artikel_prijs(text) FROM PUBLIC;
7871
+ REVOKE ALL ON FUNCTION voorraad_artikel_prijs(text) FROM anon;
7872
+ GRANT EXECUTE ON FUNCTION voorraad_artikel_prijs(text) TO authenticated;
7873
+ GRANT EXECUTE ON FUNCTION voorraad_artikel_prijs(text) TO service_role;
7890
7874
  CREATE OR REPLACE FUNCTION public.voorraad_can_write()
7891
7875
  RETURNS boolean
7892
7876
  LANGUAGE sql
@@ -7906,6 +7890,81 @@ REVOKE ALL ON FUNCTION voorraad_can_write() FROM PUBLIC;
7906
7890
  REVOKE ALL ON FUNCTION voorraad_can_write() FROM anon;
7907
7891
  GRANT EXECUTE ON FUNCTION voorraad_can_write() TO authenticated;
7908
7892
  GRANT EXECUTE ON FUNCTION voorraad_can_write() TO service_role;
7893
+ CREATE OR REPLACE FUNCTION public.voorraad_canoniek_artikel(p_id text)
7894
+ RETURNS TABLE(product_id uuid, trade_item_key text)
7895
+ LANGUAGE plpgsql
7896
+ STABLE SECURITY DEFINER
7897
+ SET search_path TO 'public'
7898
+ AS $function$
7899
+ #variable_conflict use_column
7900
+ DECLARE v_raw text; v_ids uuid[]; v_uuid uuid; v_pid uuid;
7901
+ BEGIN
7902
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_canoniek_artikel');
7903
+ v_raw := btrim(COALESCE(p_id, ''));
7904
+ IF v_raw = '' THEN
7905
+ RAISE EXCEPTION 'Geen artikel opgegeven' USING ERRCODE = 'VR011';
7906
+ END IF;
7907
+ IF v_raw LIKE 'product:%' THEN v_raw := substring(v_raw from 9); END IF;
7908
+
7909
+ -- a. Eigen voorraadartikel met dit Floriday-id wint, ook als products.id = p_id een ander (spiegel)product is.
7910
+ SELECT array_agg(p.id ORDER BY p.id) INTO v_ids FROM public.products p WHERE p.floriday_trade_item_id = v_raw;
7911
+ IF COALESCE(array_length(v_ids, 1), 0) > 1 THEN
7912
+ RAISE EXCEPTION 'Meerdere artikelen hebben Floriday-id %: %. Er wordt niets gekozen; koppel er één los.',
7913
+ v_raw, (SELECT string_agg(COALESCE(p.article_number, '?') || ' (' || p.id || ')', ', ' ORDER BY p.id) FROM public.products p WHERE p.id = ANY(v_ids))
7914
+ USING ERRCODE = 'VR010';
7915
+ END IF;
7916
+ v_pid := v_ids[1];
7917
+
7918
+ -- b. Anders products.id = p_id.
7919
+ IF v_pid IS NULL THEN
7920
+ BEGIN v_uuid := v_raw::uuid; EXCEPTION WHEN others THEN v_uuid := NULL; END;
7921
+ IF v_uuid IS NOT NULL THEN SELECT p.id INTO v_pid FROM public.products p WHERE p.id = v_uuid; END IF;
7922
+ END IF;
7923
+
7924
+ -- Terugval voor vrije sleutels (bijv. 'draft:…'): products.trade_item_key.
7925
+ IF v_pid IS NULL THEN
7926
+ SELECT array_agg(p.id ORDER BY p.id) INTO v_ids FROM public.products p WHERE p.trade_item_key = btrim(p_id);
7927
+ IF COALESCE(array_length(v_ids, 1), 0) > 1 THEN
7928
+ RAISE EXCEPTION 'Meerdere artikelen hebben voorraadsleutel %. Er wordt niets gekozen.', btrim(p_id) USING ERRCODE = 'VR010';
7929
+ END IF;
7930
+ v_pid := v_ids[1];
7931
+ END IF;
7932
+
7933
+ IF v_pid IS NULL THEN
7934
+ RAISE EXCEPTION 'Geen artikel gevonden voor %', btrim(p_id) USING ERRCODE = 'VR011';
7935
+ END IF;
7936
+ RETURN QUERY SELECT v_pid, public.voorraad_canoniek_sleutel(v_pid);
7937
+ END $function$
7938
+ ;
7939
+ REVOKE ALL ON FUNCTION voorraad_canoniek_artikel(text) FROM PUBLIC;
7940
+ REVOKE ALL ON FUNCTION voorraad_canoniek_artikel(text) FROM anon;
7941
+ GRANT EXECUTE ON FUNCTION voorraad_canoniek_artikel(text) TO authenticated;
7942
+ GRANT EXECUTE ON FUNCTION voorraad_canoniek_artikel(text) TO service_role;
7943
+ CREATE OR REPLACE FUNCTION public.voorraad_canoniek_sleutel(p_product_id uuid)
7944
+ RETURNS text
7945
+ LANGUAGE plpgsql
7946
+ STABLE SECURITY DEFINER
7947
+ SET search_path TO 'public'
7948
+ AS $function$
7949
+ DECLARE v_tk text; v_fl text;
7950
+ BEGIN
7951
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_canoniek_sleutel');
7952
+ SELECT NULLIF(btrim(COALESCE(p.trade_item_key,'')),''), NULLIF(btrim(COALESCE(p.floriday_trade_item_id,'')),'')
7953
+ INTO v_tk, v_fl FROM public.products p WHERE p.id = p_product_id;
7954
+ IF NOT FOUND THEN RETURN NULL; END IF;
7955
+ IF v_tk IS NOT NULL AND EXISTS (SELECT 1 FROM public.trade_item_stock s WHERE s.trade_item_key = v_tk AND s.archived_at IS NULL) THEN
7956
+ RETURN v_tk;
7957
+ END IF;
7958
+ IF v_fl IS NOT NULL AND EXISTS (SELECT 1 FROM public.trade_item_stock s WHERE s.trade_item_key = v_fl AND s.archived_at IS NULL) THEN
7959
+ RETURN v_fl;
7960
+ END IF;
7961
+ RETURN COALESCE(v_fl, v_tk, p_product_id::text);
7962
+ END $function$
7963
+ ;
7964
+ REVOKE ALL ON FUNCTION voorraad_canoniek_sleutel(uuid) FROM PUBLIC;
7965
+ REVOKE ALL ON FUNCTION voorraad_canoniek_sleutel(uuid) FROM anon;
7966
+ GRANT EXECUTE ON FUNCTION voorraad_canoniek_sleutel(uuid) TO authenticated;
7967
+ GRANT EXECUTE ON FUNCTION voorraad_canoniek_sleutel(uuid) TO service_role;
7909
7968
  CREATE OR REPLACE FUNCTION public.voorraad_cleanup_old_rows()
7910
7969
  RETURNS jsonb
7911
7970
  LANGUAGE plpgsql
@@ -8639,6 +8698,71 @@ END $function$
8639
8698
  REVOKE ALL ON FUNCTION voorraad_correctie_1127(boolean) FROM PUBLIC;
8640
8699
  REVOKE ALL ON FUNCTION voorraad_correctie_1127(boolean) FROM anon;
8641
8700
  GRANT EXECUTE ON FUNCTION voorraad_correctie_1127(boolean) TO service_role;
8701
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1131(p_uitvoeren boolean DEFAULT false)
8702
+ RETURNS jsonb
8703
+ LANGUAGE plpgsql
8704
+ SECURITY DEFINER
8705
+ SET search_path TO 'public'
8706
+ AS $function$
8707
+ DECLARE v_rows jsonb; v_result jsonb;
8708
+ BEGIN
8709
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1131');
8710
+ IF p_uitvoeren THEN
8711
+ RAISE EXCEPTION 'Correctie 1131 is alleen als overzicht vrijgegeven; uitvoeren wacht op akkoord' USING ERRCODE = 'VR012';
8712
+ END IF;
8713
+ SELECT COALESCE(jsonb_agg(jsonb_build_object(
8714
+ 'artikelnummer', c.article_number,
8715
+ 'voorraadartikel', c.id, 'canonieke_sleutel', public.voorraad_canoniek_sleutel(c.id),
8716
+ 'spiegelproduct', m.id, 'spiegel_bron', m.custom_fields->>'source',
8717
+ 'spiegel_herkend_als_verkoop', (m.custom_fields->>'source') = 'sales-module-floriday-mirror',
8718
+ 'canonieke_regel', (SELECT to_jsonb(s) - 'notes' FROM public.trade_item_stock s
8719
+ WHERE s.trade_item_key = public.voorraad_canoniek_sleutel(c.id) AND s.archived_at IS NULL LIMIT 1),
8720
+ 'spiegelregels', (SELECT jsonb_agg(to_jsonb(s) - 'notes' ORDER BY s.id) FROM public.trade_item_stock s
8721
+ WHERE s.trade_item_key IN (m.id::text, m.trade_item_key, 'product:' || m.id::text)
8722
+ AND s.trade_item_key IS DISTINCT FROM public.voorraad_canoniek_sleutel(c.id)
8723
+ AND s.archived_at IS NULL),
8724
+ 'voorstel', 'reserveringen opnieuw berekenen zodat ze op de canonieke regel landen; spiegelregel archiveren (archived_at, archived_into = canonieke sleutel); fysieke voorraad van de spiegel niet optellen, alleen loggen; spiegelproduct verdwijnt uit voorraadlijst en tellingen; niets verwijderen'
8725
+ ) ORDER BY c.article_number), '[]'::jsonb)
8726
+ INTO v_rows
8727
+ FROM public.products m
8728
+ JOIN public.products c ON c.floriday_trade_item_id = m.id::text AND c.id <> m.id;
8729
+ v_result := jsonb_build_object('ok', true, 'status', 'voorstel', 'artikelen', v_rows);
8730
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8731
+ VALUES ('voorraad_correctie_1131', COALESCE(auth.uid()::text, session_user::text), true, v_result, true);
8732
+ RETURN v_result;
8733
+ END $function$
8734
+ ;
8735
+ REVOKE ALL ON FUNCTION voorraad_correctie_1131(boolean) FROM PUBLIC;
8736
+ REVOKE ALL ON FUNCTION voorraad_correctie_1131(boolean) FROM anon;
8737
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1131(boolean) TO service_role;
8738
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1132(p_uitvoeren boolean DEFAULT false)
8739
+ RETURNS jsonb
8740
+ LANGUAGE plpgsql
8741
+ SECURITY DEFINER
8742
+ SET search_path TO 'public'
8743
+ AS $function$
8744
+ DECLARE pid constant uuid := '27612767-2b14-468c-b169-a8f9a4abe053'; p record; v_status text; v_result jsonb; v_after numeric;
8745
+ BEGIN
8746
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1132');
8747
+ PERFORM pg_advisory_xact_lock(hashtextextended('voorraad_correctie_1132', 0));
8748
+ SELECT * INTO p FROM public.products WHERE id = pid FOR UPDATE;
8749
+ IF p.id IS NULL OR p.article_number IS DISTINCT FROM 'TQA2810A' THEN v_status := 'overgeslagen: artikel wijkt af';
8750
+ ELSIF p.sale_price = 1.40 THEN v_status := 'al uitgevoerd';
8751
+ ELSIF p.sale_price IS DISTINCT FROM 1.25 THEN v_status := 'overgeslagen: prijs gewijzigd';
8752
+ ELSE v_status := CASE WHEN p_uitvoeren THEN 'uitgevoerd' ELSE 'voorstel' END; END IF;
8753
+ IF v_status = 'uitgevoerd' THEN
8754
+ UPDATE public.products SET sale_price = 1.40, updated_at = now() WHERE id = pid;
8755
+ END IF;
8756
+ SELECT sale_price INTO v_after FROM public.products WHERE id = pid;
8757
+ v_result := jsonb_build_object('ok', v_status NOT LIKE 'overgeslagen%', 'status', v_status, 'product', pid, 'voor', p.sale_price, 'na', v_after);
8758
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8759
+ VALUES ('voorraad_correctie_1132', COALESCE(auth.uid()::text, session_user::text), NOT p_uitvoeren, v_result, true);
8760
+ RETURN v_result;
8761
+ END $function$
8762
+ ;
8763
+ REVOKE ALL ON FUNCTION voorraad_correctie_1132(boolean) FROM PUBLIC;
8764
+ REVOKE ALL ON FUNCTION voorraad_correctie_1132(boolean) FROM anon;
8765
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1132(boolean) TO service_role;
8642
8766
  CREATE OR REPLACE FUNCTION public.voorraad_correctie_status(p_correctie text DEFAULT '1098'::text)
8643
8767
  RETURNS jsonb
8644
8768
  LANGUAGE plpgsql
@@ -8662,6 +8786,33 @@ REVOKE ALL ON FUNCTION voorraad_correctie_status(text) FROM PUBLIC;
8662
8786
  REVOKE ALL ON FUNCTION voorraad_correctie_status(text) FROM anon;
8663
8787
  GRANT EXECUTE ON FUNCTION voorraad_correctie_status(text) TO authenticated;
8664
8788
  GRANT EXECUTE ON FUNCTION voorraad_correctie_status(text) TO service_role;
8789
+ CREATE OR REPLACE FUNCTION public.voorraad_dubbele_voorraadregels()
8790
+ RETURNS jsonb
8791
+ LANGUAGE plpgsql
8792
+ STABLE SECURITY DEFINER
8793
+ SET search_path TO 'public'
8794
+ AS $function$
8795
+ DECLARE v jsonb;
8796
+ BEGIN
8797
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_dubbele_voorraadregels');
8798
+ SELECT COALESCE(jsonb_agg(x ORDER BY x->>'floriday_id'), '[]'::jsonb) INTO v FROM (
8799
+ SELECT jsonb_build_object('floriday_id', p.floriday_trade_item_id, 'product_id', p.id, 'artikelnummer', p.article_number,
8800
+ 'waarschuwing', 'meer dan één voorraadregel voor dit Floriday-id',
8801
+ 'regels', jsonb_agg(jsonb_build_object('id', s.id, 'sleutel', s.trade_item_key, 'fysiek', s.physical_stock,
8802
+ 'gereserveerd', s.reserved_stock, 'inkomend', s.incoming_stock) ORDER BY s.id)) x
8803
+ FROM public.products p
8804
+ JOIN public.trade_item_stock s ON s.archived_at IS NULL
8805
+ AND s.trade_item_key IN (p.floriday_trade_item_id, p.trade_item_key, 'product:' || p.id::text, p.id::text)
8806
+ WHERE NULLIF(btrim(COALESCE(p.floriday_trade_item_id,'')),'') IS NOT NULL
8807
+ GROUP BY p.id, p.floriday_trade_item_id, p.article_number, s.connection_id
8808
+ HAVING count(DISTINCT s.trade_item_key) > 1) q;
8809
+ RETURN v;
8810
+ END $function$
8811
+ ;
8812
+ REVOKE ALL ON FUNCTION voorraad_dubbele_voorraadregels() FROM PUBLIC;
8813
+ REVOKE ALL ON FUNCTION voorraad_dubbele_voorraadregels() FROM anon;
8814
+ GRANT EXECUTE ON FUNCTION voorraad_dubbele_voorraadregels() TO authenticated;
8815
+ GRANT EXECUTE ON FUNCTION voorraad_dubbele_voorraadregels() TO service_role;
8665
8816
  CREATE OR REPLACE FUNCTION public.voorraad_external_fulfilled_ids(p_cf jsonb)
8666
8817
  RETURNS text[]
8667
8818
  LANGUAGE sql
@@ -8830,6 +8981,34 @@ REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM PUBLIC;
8830
8981
  REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM anon;
8831
8982
  GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO authenticated;
8832
8983
  GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO service_role;
8984
+ CREATE OR REPLACE FUNCTION public.voorraad_gateway_routes_check()
8985
+ RETURNS jsonb
8986
+ LANGUAGE plpgsql
8987
+ STABLE SECURITY DEFINER
8988
+ SET search_path TO 'public'
8989
+ AS $function$
8990
+ DECLARE
8991
+ v_req text[] := ARRAY['/api/public/gateway/write','/api/public/gateway/floriday-get'];
8992
+ v_raw text; v_cfg jsonb := '{}'::jsonb; v_out jsonb;
8993
+ BEGIN
8994
+ PERFORM public.voorraad_vereis('server', 'voorraad_gateway_routes_check');
8995
+ SELECT value INTO v_raw FROM public.module_runtime_config WHERE key = 'voorraad_gateway_routes';
8996
+ BEGIN v_cfg := COALESCE(v_raw::jsonb, '{}'::jsonb); EXCEPTION WHEN others THEN v_cfg := '{}'::jsonb; END;
8997
+ SELECT jsonb_agg(jsonb_build_object(
8998
+ 'route', r,
8999
+ 'status', COALESCE(v_cfg->r->>'status', 'niet_gecontroleerd'),
9000
+ 'gecontroleerd_op', v_cfg->r->>'checked_at',
9001
+ 'melding', CASE COALESCE(v_cfg->r->>'status','')
9002
+ WHEN 'aanwezig' THEN NULL
9003
+ WHEN 'ontbreekt' THEN 'Route ontbreekt in de shell: ' || r
9004
+ ELSE 'Nog niet gecontroleerd; draai de routecontrole of wacht op de eerste Floriday-aanroep' END)
9005
+ ORDER BY r) INTO v_out FROM unnest(v_req) r;
9006
+ RETURN v_out;
9007
+ END $function$
9008
+ ;
9009
+ REVOKE ALL ON FUNCTION voorraad_gateway_routes_check() FROM PUBLIC;
9010
+ REVOKE ALL ON FUNCTION voorraad_gateway_routes_check() FROM anon;
9011
+ GRANT EXECUTE ON FUNCTION voorraad_gateway_routes_check() TO service_role;
8833
9012
  CREATE OR REPLACE FUNCTION public.voorraad_hook_base_url()
8834
9013
  RETURNS text
8835
9014
  LANGUAGE plpgsql
@@ -8947,7 +9126,7 @@ CREATE OR REPLACE FUNCTION public.voorraad_install_check()
8947
9126
  STABLE SECURITY DEFINER
8948
9127
  SET search_path TO 'public'
8949
9128
  AS $function$
8950
- DECLARE v_f text[] := ARRAY['voorraad_placeholder_code_reason','trg_products_placeholder_code','voorraad_fust_juist','voorraad_correctie_1121','voorraad_correctie_1121_regels','voorraad_correctie_1123','voorraad_correctie_1124','voorraad_load_carriers','voorraad_packing_from_floriday','voorraad_packing_missing','voorraad_correctie_1126','voorraad_correctie_1127','trg_voorraad_link_primary_packing','voorraad_order_geannuleerd','voorraad_article_vbn','voorraad_correctie_1112','voorraad_reverse_order_mutations','voorraad_withdraw_stock_row','ensure_voorraad_local_context','get_stock_context','voorraad_stock_context_status','voorraad_fcsq_local_guard','_floriday_queue_cleanup_batch','_migrate_rewrite_stock_key','_stock_import_caller','apply_fust_stock_mutation','apply_stock_consumption','apply_stock_reservation','autolink_product_to_floriday','backfill_open_order_reservations','calculate_floriday_desired_stock','calculate_structure_available','canonicalize_trade_item_stock_key','check_product_structure','claim_floriday_base_supply','claim_floriday_stock_queue','cleanup_floriday_stock_queue','cleanup_voorraad_module_history','complete_floriday_base_supply','complete_floriday_stock_queue','complete_floriday_stock_queue_outcome','consume_bom_for_production','consume_order_item','drain_inventory_recompute_queue','enqueue_floriday_continuous_stock','enqueue_floriday_continuous_stock_after_warehouse_preference','enqueue_structure_recompute','ensure_inventory_recompute_drain','ensure_trade_item_stock_row','ensure_trade_item_stock_row_key','fcsq_block_disabled','fcsq_fallback_supersede','fcsq_wake_base_supply','find_trade_item_key','floriday_adopt_connection','floriday_autoheal_connections','floriday_capture_stock_snapshot','floriday_cleanup_stock_queue_v2','floriday_compact_stock_snapshots','floriday_default_owner','floriday_desired_stock_regression_check','floriday_ensure_inventory_settings','floriday_erp_leading_preview','floriday_fill_publish_horizon','floriday_follow_apply','floriday_ingest_sales_orders','floriday_leading_summary','floriday_make_erp_leading','floriday_norm_offer_forms','floriday_orphan_settings_count','floriday_publish_horizon_weeks','floriday_queue_erp_guard','floriday_queue_first_positive','floriday_recompute_inventory','floriday_relink_products','floriday_requeue_dead_letters','floriday_settings_change_recompute','floriday_settings_change_recompute_stmt','floriday_stock_change_recompute','floriday_stock_queue_supersede','floriday_takeover_apply','floriday_takeover_fetch_state','floriday_takeover_store_forms','floriday_takeover_undo','fust_negative_stock_report','fust_types_duplicate_guard','get_active_floriday_context','get_group_allocation_keys','get_group_head_key','get_product_stock','get_product_structure_totals','get_product_structure_totals_batch','inventory_inline_budget_ok','merge_products','normalize_order_source','process_inventory_recompute_queue','produce_designed_product','product_active_group_id','product_id_from_ref','product_is_set','product_label','product_member_group_ids','product_own_available','product_packings_derive','product_packings_replace','product_packings_sync_from_floriday','product_primary_pieces','product_set_depth_above','product_set_depth_below','product_structure_ancestors','product_structure_max_depth','product_structure_path','product_tray_stickers_touch','product_type','promote_trade_item_key','recompute_all_reserved_stock','recompute_order_status','recompute_reserved_for_order','recompute_reserved_stock','requeue_skipped_stock_rows','reset_stalled_floriday_stock_queue','resolve_group_allocation','resolve_group_member_stock_key','resolve_product_id_for_item','resolve_stock_trade_item_key','reverse_production','run_floriday_base_supply_process','run_floriday_continuous_stock_sync','run_floriday_follow','run_floriday_stock_queue_process','run_floriday_stock_reconcile','run_logistics_tasks_dispatch','self_heal_floriday_links','set_module_runtime_config_updated_at','set_product_bom_tenant','set_product_stock','set_updated_at_order_fust_bookings','stock_import_cleanup','stock_import_create','stock_import_process_chunk','stock_import_stop','stock_import_undo_chunk','sync_order_item_fusten','sync_products_quantity_from_stock','touch_fust_types_updated_at','trade_item_drafts_readonly','trade_item_prices_touch_updated_at','trade_item_stock_duplicates','trg_cart_numbers_sync_order_status_fn','trg_cart_session_consume_fn','trg_check_product_structure','trg_floriday_cache_relink_fn','trg_floriday_trade_items_autolink_fn','trg_order_items_autolink_fn','trg_order_items_fusten','trg_order_items_reserve_fn','trg_orders_cancel_release_fn','trg_orders_consume_on_complete_fn','trg_orders_default_phase_fn','trg_orders_external_fulfilled_fn','trg_orders_recompute_reserved_fn','trg_pgi_assign_sort_order','trg_pgi_order_taken_check','trg_process_recompute_on_commit','trg_product_packings_derive_fn','trg_products_autolink_fn','trg_products_floriday_link_enqueue','trg_products_seed_stock_fn','trg_requeue_no_warehouse_cache','trg_requeue_no_warehouse_connection','trg_requeue_no_warehouse_item_pref','trg_requeue_skipped_no_price','trg_stock_structure_recompute_ins','trg_stock_structure_recompute_upd','trg_structure_change_recompute','trg_trade_item_drafts_autolink_fn','trg_trade_item_stock_auto_bom','trg_trade_item_stock_auto_bom_reverse','trg_trade_item_stock_log_change','trg_trade_item_stock_reserve_fn','trg_trade_item_stock_zero_watch','trg_trade_items_cache_autolink_fn','update_updated_at_column','voorraad_alert_floriday_not_updated','voorraad_can_write','voorraad_cleanup_old_rows','voorraad_consume_external_fulfilled','voorraad_correctie_1098','voorraad_correctie_status','voorraad_external_fulfilled_ids','voorraad_floriday_leads_key','voorraad_fust_dimensions','voorraad_hook_base_url','voorraad_hook_on','voorraad_hook_post','voorraad_hook_switch_jobs','voorraad_install_check','voorraad_is_server','voorraad_mark_floriday_sold_before_switch','voorraad_production_enabled','voorraad_schema_ddl','voorraad_touch_updated_at','voorraad_vereis','voorraad_week_is_past'];
9129
+ DECLARE v_f text[] := ARRAY['voorraad_canoniek_artikel','voorraad_canoniek_sleutel','voorraad_artikel_prijs','voorraad_dubbele_voorraadregels','voorraad_correctie_1131','voorraad_correctie_1132','voorraad_gateway_routes_check','voorraad_placeholder_code_reason','trg_products_placeholder_code','voorraad_fust_juist','voorraad_correctie_1121','voorraad_correctie_1121_regels','voorraad_correctie_1123','voorraad_correctie_1124','voorraad_load_carriers','voorraad_packing_from_floriday','voorraad_packing_missing','voorraad_correctie_1126','voorraad_correctie_1127','trg_voorraad_link_primary_packing','voorraad_order_geannuleerd','voorraad_article_vbn','voorraad_correctie_1112','voorraad_reverse_order_mutations','voorraad_withdraw_stock_row','ensure_voorraad_local_context','get_stock_context','voorraad_stock_context_status','voorraad_fcsq_local_guard','_floriday_queue_cleanup_batch','_migrate_rewrite_stock_key','_stock_import_caller','apply_fust_stock_mutation','apply_stock_consumption','apply_stock_reservation','autolink_product_to_floriday','backfill_open_order_reservations','calculate_floriday_desired_stock','calculate_structure_available','canonicalize_trade_item_stock_key','check_product_structure','claim_floriday_base_supply','claim_floriday_stock_queue','cleanup_floriday_stock_queue','cleanup_voorraad_module_history','complete_floriday_base_supply','complete_floriday_stock_queue','complete_floriday_stock_queue_outcome','consume_bom_for_production','consume_order_item','drain_inventory_recompute_queue','enqueue_floriday_continuous_stock','enqueue_floriday_continuous_stock_after_warehouse_preference','enqueue_structure_recompute','ensure_inventory_recompute_drain','ensure_trade_item_stock_row','ensure_trade_item_stock_row_key','fcsq_block_disabled','fcsq_fallback_supersede','fcsq_wake_base_supply','find_trade_item_key','floriday_adopt_connection','floriday_autoheal_connections','floriday_capture_stock_snapshot','floriday_cleanup_stock_queue_v2','floriday_compact_stock_snapshots','floriday_default_owner','floriday_desired_stock_regression_check','floriday_ensure_inventory_settings','floriday_erp_leading_preview','floriday_fill_publish_horizon','floriday_follow_apply','floriday_ingest_sales_orders','floriday_leading_summary','floriday_make_erp_leading','floriday_norm_offer_forms','floriday_orphan_settings_count','floriday_publish_horizon_weeks','floriday_queue_erp_guard','floriday_queue_first_positive','floriday_recompute_inventory','floriday_relink_products','floriday_requeue_dead_letters','floriday_settings_change_recompute','floriday_settings_change_recompute_stmt','floriday_stock_change_recompute','floriday_stock_queue_supersede','floriday_takeover_apply','floriday_takeover_fetch_state','floriday_takeover_store_forms','floriday_takeover_undo','fust_negative_stock_report','fust_types_duplicate_guard','get_active_floriday_context','get_group_allocation_keys','get_group_head_key','get_product_stock','get_product_structure_totals','get_product_structure_totals_batch','inventory_inline_budget_ok','merge_products','normalize_order_source','process_inventory_recompute_queue','produce_designed_product','product_active_group_id','product_id_from_ref','product_is_set','product_label','product_member_group_ids','product_own_available','product_packings_derive','product_packings_replace','product_packings_sync_from_floriday','product_primary_pieces','product_set_depth_above','product_set_depth_below','product_structure_ancestors','product_structure_max_depth','product_structure_path','product_tray_stickers_touch','product_type','promote_trade_item_key','recompute_all_reserved_stock','recompute_order_status','recompute_reserved_for_order','recompute_reserved_stock','requeue_skipped_stock_rows','reset_stalled_floriday_stock_queue','resolve_group_allocation','resolve_group_member_stock_key','resolve_product_id_for_item','resolve_stock_trade_item_key','reverse_production','run_floriday_base_supply_process','run_floriday_continuous_stock_sync','run_floriday_follow','run_floriday_stock_queue_process','run_floriday_stock_reconcile','run_logistics_tasks_dispatch','self_heal_floriday_links','set_module_runtime_config_updated_at','set_product_bom_tenant','set_product_stock','set_updated_at_order_fust_bookings','stock_import_cleanup','stock_import_create','stock_import_process_chunk','stock_import_stop','stock_import_undo_chunk','sync_order_item_fusten','sync_products_quantity_from_stock','touch_fust_types_updated_at','trade_item_drafts_readonly','trade_item_prices_touch_updated_at','trade_item_stock_duplicates','trg_cart_numbers_sync_order_status_fn','trg_cart_session_consume_fn','trg_check_product_structure','trg_floriday_cache_relink_fn','trg_floriday_trade_items_autolink_fn','trg_order_items_autolink_fn','trg_order_items_fusten','trg_order_items_reserve_fn','trg_orders_cancel_release_fn','trg_orders_consume_on_complete_fn','trg_orders_default_phase_fn','trg_orders_external_fulfilled_fn','trg_orders_recompute_reserved_fn','trg_pgi_assign_sort_order','trg_pgi_order_taken_check','trg_process_recompute_on_commit','trg_product_packings_derive_fn','trg_products_autolink_fn','trg_products_floriday_link_enqueue','trg_products_seed_stock_fn','trg_requeue_no_warehouse_cache','trg_requeue_no_warehouse_connection','trg_requeue_no_warehouse_item_pref','trg_requeue_skipped_no_price','trg_stock_structure_recompute_ins','trg_stock_structure_recompute_upd','trg_structure_change_recompute','trg_trade_item_drafts_autolink_fn','trg_trade_item_stock_auto_bom','trg_trade_item_stock_auto_bom_reverse','trg_trade_item_stock_log_change','trg_trade_item_stock_reserve_fn','trg_trade_item_stock_zero_watch','trg_trade_items_cache_autolink_fn','update_updated_at_column','voorraad_alert_floriday_not_updated','voorraad_can_write','voorraad_cleanup_old_rows','voorraad_consume_external_fulfilled','voorraad_correctie_1098','voorraad_correctie_status','voorraad_external_fulfilled_ids','voorraad_floriday_leads_key','voorraad_fust_dimensions','voorraad_hook_base_url','voorraad_hook_on','voorraad_hook_post','voorraad_hook_switch_jobs','voorraad_install_check','voorraad_is_server','voorraad_mark_floriday_sold_before_switch','voorraad_production_enabled','voorraad_schema_ddl','voorraad_touch_updated_at','voorraad_vereis','voorraad_week_is_past'];
8951
9130
  v_t text[] := ARRAY['trg_voorraad_link_primary_packing@products','aa0_fcsq_local_context_guard@floriday_continuous_stock_queue','aa_fcsq_erp_leading_guard@floriday_continuous_stock_queue','aa_fis_norm_offer_forms@floriday_inventory_settings','aa_pgi_assign_sort_order@product_group_items','fcsq_block_disabled@floriday_continuous_stock_queue','fcsq_wake_base_supply_ins@floriday_continuous_stock_queue','fcsq_wake_base_supply_upd@floriday_continuous_stock_queue','fust_stock_mutations_apply@fust_stock_mutations','fust_types_duplicate_guard@fust_types','fust_types_touch@fust_types','product_packings_derive_trg@product_packings','product_packings_updated_at@product_packings','set_product_bom_tenant_trigger@product_bom_items','trade_item_prices_set_updated_at@trade_item_prices','trg_cart_numbers_sync_order_status@cart_numbers','trg_cart_session_consume@cart_control_sessions','trg_check_product_structure@product_bom_items','trg_check_product_structure@product_group_items','trg_check_product_structure@product_groups','trg_fcs_queue_updated_at@floriday_continuous_stock_queue','trg_fcsq_fallback_supersede@floriday_continuous_stock_queue','trg_fcsq_supersede@floriday_continuous_stock_queue','trg_floriday_cache_relink@floriday_trade_items_cache','trg_floriday_ensure_inventory_settings@products','trg_floriday_gate_stock_queue@floriday_continuous_stock_queue','trg_floriday_settings_change_recompute_ins@floriday_inventory_settings','trg_floriday_settings_change_recompute_upd@floriday_inventory_settings','trg_floriday_stock_change_recompute@trade_item_stock','trg_floriday_takeover_runs_updated_at@floriday_takeover_runs','trg_floriday_trade_items_autolink@floriday_trade_items_cache','trg_fust_types_requeue_blocked@fust_types','trg_module_runtime_config_updated_at@module_runtime_config','trg_order_fust_bookings_updated_at@order_fust_bookings','trg_order_items_autolink@order_items','trg_order_items_fusten_aiud@order_items','trg_order_items_reserve@order_items','trg_orders_cancel_release@orders','trg_orders_consume_on_complete@orders','trg_orders_default_phase@orders','trg_orders_external_fulfilled@orders','trg_orders_recompute_reserved@orders','trg_prevent_duplicate_product_draft@trade_item_drafts','trg_product_tray_stickers_touch@product_tray_stickers','trg_products_autolink@products','trg_products_floriday_link_enqueue@products','trg_products_seed_stock@products','trg_requeue_no_warehouse_cache@floriday_trade_items_cache','trg_requeue_no_warehouse_connection@floriday_connections','trg_requeue_no_warehouse_item_pref@trade_item_warehouse_preferences','trg_requeue_skipped_no_price@products','trg_stock_mutation_alert@stock_mutation_log','trg_stock_structure_recompute_ins@trade_item_stock','trg_stock_structure_recompute_upd@trade_item_stock','trg_structure_change_recompute@product_bom_items','trg_structure_change_recompute@product_group_items','trg_structure_change_recompute@product_groups','trg_sync_layer_stock_from_trade_stock@trade_item_stock','trg_sync_products_quantity_from_stock_del@trade_item_stock','trg_sync_products_quantity_from_stock_iu@trade_item_stock','trg_trade_item_drafts_autolink@trade_item_drafts','trg_trade_item_drafts_readonly@trade_item_drafts','trg_trade_item_stock_canonical_key@trade_item_stock','trg_trade_item_stock_publish@trade_item_stock','trg_trade_item_stock_reserve@trade_item_stock','trg_trade_item_stock_updated_at@trade_item_stock','trg_trade_item_stock_zero_watch@trade_item_stock','trg_trade_item_supply_lines_touch@trade_item_supply_lines','trg_trade_item_warehouse_preference_enqueue_stock@trade_item_warehouse_preferences','trg_trade_items_cache_autolink@floriday_trade_items_cache','trg_voorraad_buffer_state_updated_at@voorraad_buffer_state','trg_voorraad_event_log_updated_at@voorraad_logistics_event_log','update_trade_item_drafts_updated_at@trade_item_drafts','update_trade_item_warehouse_preferences_updated_at@trade_item_warehouse_preferences','update_voorraad_custom_fields_updated_at@voorraad_custom_fields','update_voorraad_publish_jobs_updated_at@voorraad_publish_jobs','update_voorraad_publish_learnings_updated_at@voorraad_publish_learnings','update_voorraad_publish_steps_updated_at@voorraad_publish_steps','voorraad_hook_switch_jobs@module_runtime_config','zz_fcsq_first_positive@floriday_continuous_stock_queue'];
8952
9131
  v_p text[] := ARRAY['Authenticated can add learnings@voorraad_publish_learnings','Authenticated can delete voorraad custom fields@voorraad_custom_fields','Authenticated can insert vbn required characteristics@floriday_vbn_required_characteristics','Authenticated can insert voorraad custom fields@voorraad_custom_fields','Authenticated can read continuous stock cache@floriday_continuous_stock_cache','Authenticated can read learnings@voorraad_publish_learnings','Authenticated can read vbn required characteristics@floriday_vbn_required_characteristics','Authenticated can read voorraad custom fields@voorraad_custom_fields','Authenticated can update learnings@voorraad_publish_learnings','Authenticated can update vbn required characteristics@floriday_vbn_required_characteristics','Authenticated can update voorraad custom fields@voorraad_custom_fields','Authenticated delete trade_item_warehouse_preferences@trade_item_warehouse_preferences','Authenticated insert trade_item_warehouse_preferences@trade_item_warehouse_preferences','Authenticated select trade_item_warehouse_preferences@trade_item_warehouse_preferences','Authenticated update trade_item_warehouse_preferences@trade_item_warehouse_preferences','Eigen momentopnamen lezen@inventory_stock_snapshots','Eigen voorraadinstellingen beheren@floriday_inventory_settings','Eigenaar leest importporties@stock_import_chunks','Eigenaar leest importregels@stock_import_rows','Fust mutations delete@fust_stock_mutations','Fust mutations insert@fust_stock_mutations','Fust mutations read@fust_stock_mutations','Fust mutations update@fust_stock_mutations','Fust types delete@fust_types','Fust types insert@fust_types','Fust types read@fust_types','Fust types update@fust_types','Ingelogde gebruikers kunnen bufferstatus lezen@voorraad_buffer_state','Ingelogde gebruikers kunnen de eventlog lezen@voorraad_logistics_event_log','Ingelogde gebruikers kunnen fustboekingen lezen@order_fust_bookings','Ingelogde gebruikers lezen drempels@inventory_recompute_limits','Ingelogde gebruikers lezen opruimlogboek@structure_cleanup_log','Ingelogde gebruikers lezen opruimruns@floriday_queue_cleanup_runs','Ingelogden beheren traystickers@product_tray_stickers','Ingelogden lezen herberekenwachtrij@inventory_recompute_queue','Ingelogden lezen voorraadmeldingen@stock_integrity_alerts','Ingelogden markeren voorraadmeldingen als gezien@stock_integrity_alerts','Own queue rows select@floriday_continuous_stock_queue','Owner delete trade_item_drafts@trade_item_drafts','Owner insert trade_item_drafts@trade_item_drafts','Owner select trade_item_drafts@trade_item_drafts','Owner update trade_item_drafts@trade_item_drafts','Signed-in users read reconcile runs@floriday_reconcile_runs','Stock delete@trade_item_stock','Stock insert@trade_item_stock','Stock read@trade_item_stock','Stock update@trade_item_stock','Synchronisatieposities lezen@floriday_sync_cursors','Users can insert own publish attempts@voorraad_publish_attempts','Users can read own publish attempts@voorraad_publish_attempts','Users can read own stock mutations@stock_mutation_log','Users manage own import runs@stock_import_runs','Users manage own supply lines@trade_item_supply_lines','Users manage own trade item prices@trade_item_prices','Users manage their own publish jobs@voorraad_publish_jobs','Users manage their own publish steps@voorraad_publish_steps','Verwerkte orders lezen@floriday_sales_order_ingest','Voorraadschrijvers lezen overnameregels@floriday_takeover_items','Voorraadschrijvers lezen overnames@floriday_takeover_runs','authenticated can insert merge log@product_merge_log','authenticated can read merge log@product_merge_log','service role only@voorraad_media_upload_failures','product_packings_read@product_packings','product_packings_write@product_packings'];
8953
9132
  v_open text[] := ARRAY['voorraad_is_server','voorraad_vereis'];
@@ -8975,7 +9154,7 @@ BEGIN
8975
9154
  SELECT jsonb_agg(jsonb_build_object('policy', split_part(t, '@', 1), 'tabel', split_part(t, '@', 2),
8976
9155
  'aanwezig', EXISTS (SELECT 1 FROM pg_policies x WHERE x.schemaname = 'public' AND x.policyname = split_part(t, '@', 1)
8977
9156
  AND x.tablename = split_part(t, '@', 2))) ORDER BY t) INTO v_pol FROM unnest(v_p) t;
8978
- RETURN jsonb_build_object(
9157
+ RETURN jsonb_build_object('dubbele_voorraadregels', public.voorraad_dubbele_voorraadregels(), 'gateway_routes', public.voorraad_gateway_routes_check(),
8979
9158
  'samenvatting', jsonb_build_object(
8980
9159
  'functies', jsonb_array_length(v_func),
8981
9160
  'functies_ontbrekend', (SELECT count(*) FROM jsonb_array_elements(v_func) e WHERE NOT (e->>'aanwezig')::boolean),