@flowselections/floriday-voorraad 1.0.122 → 1.0.127

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 (53) hide show
  1. package/dist-lib/components/voorraad/ArtikelWizard.d.ts +14 -1
  2. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
  3. package/dist-lib/components/voorraad/ArtikelWizard.js +88 -26
  4. package/dist-lib/components/voorraad/FloridayInfoCard.d.ts.map +1 -1
  5. package/dist-lib/components/voorraad/FloridayInfoCard.js +4 -2
  6. package/dist-lib/components/voorraad/FloridayLoadCarriers.d.ts.map +1 -1
  7. package/dist-lib/components/voorraad/FloridayLoadCarriers.js +3 -2
  8. package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -1
  9. package/dist-lib/components/voorraad/NieuwArtikelPage.js +72 -6
  10. package/dist-lib/components/voorraad/PublishProgressCard.d.ts +7 -0
  11. package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -1
  12. package/dist-lib/components/voorraad/PublishProgressCard.js +22 -1
  13. package/dist-lib/components/voorraad/StockSyncStatus.d.ts.map +1 -1
  14. package/dist-lib/components/voorraad/StockSyncStatus.js +1 -1
  15. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  16. package/dist-lib/components/voorraad/VoorraadTable.js +1 -1
  17. package/dist-lib/hooks/useLoadCarriers.d.ts +12 -0
  18. package/dist-lib/hooks/useLoadCarriers.d.ts.map +1 -0
  19. package/dist-lib/hooks/useLoadCarriers.js +49 -0
  20. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  21. package/dist-lib/hooks/useLocalTradeItems.js +3 -1
  22. package/dist-lib/hooks/usePublishJob.d.ts +1 -0
  23. package/dist-lib/hooks/usePublishJob.d.ts.map +1 -1
  24. package/dist-lib/hooks/usePublishJob.js +20 -1
  25. package/dist-lib/hooks/useStockSyncHealth.d.ts +8 -1
  26. package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -1
  27. package/dist-lib/hooks/useStockSyncHealth.js +91 -19
  28. package/dist-lib/integrations/supabase/types.d.ts +400 -0
  29. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  30. package/dist-lib/lib/__tests__/erp-test-123.test.d.ts +2 -0
  31. package/dist-lib/lib/__tests__/erp-test-123.test.d.ts.map +1 -0
  32. package/dist-lib/lib/__tests__/erp-test-123.test.js +43 -0
  33. package/dist-lib/lib/__tests__/load-carriers.test.d.ts +2 -0
  34. package/dist-lib/lib/__tests__/load-carriers.test.d.ts.map +1 -0
  35. package/dist-lib/lib/__tests__/load-carriers.test.js +15 -0
  36. package/dist-lib/lib/buyer-organizations.d.ts +26 -0
  37. package/dist-lib/lib/buyer-organizations.d.ts.map +1 -0
  38. package/dist-lib/lib/buyer-organizations.js +41 -0
  39. package/dist-lib/lib/floriday-customer-offer.functions.d.ts +4 -0
  40. package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
  41. package/dist-lib/lib/floriday-customer-offer.functions.js +54 -16
  42. package/dist-lib/lib/floriday-info.d.ts +0 -1
  43. package/dist-lib/lib/floriday-info.d.ts.map +1 -1
  44. package/dist-lib/lib/floriday-info.js +0 -8
  45. package/dist-lib/lib/simple-packing.d.ts +31 -0
  46. package/dist-lib/lib/simple-packing.d.ts.map +1 -0
  47. package/dist-lib/lib/simple-packing.js +62 -0
  48. package/dist-lib/lib/voorraad-page-head.d.ts +19 -0
  49. package/dist-lib/lib/voorraad-page-head.d.ts.map +1 -0
  50. package/dist-lib/lib/voorraad-page-head.js +11 -0
  51. package/package.json +1 -1
  52. package/sql/AGENTS.md +2 -1
  53. package/sql/floriday-voorraad-schema.sql +465 -52
@@ -1,4 +1,4 @@
1
- -- @flowselections/floriday-voorraad 1.0.120 – volledig schema (idempotent, geen gegevens).
1
+ -- @flowselections/floriday-voorraad 1.0.126 – 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.
@@ -527,6 +527,14 @@ ALTER TABLE public.voorraad_custom_fields ADD COLUMN IF NOT EXISTS sort_order in
527
527
  ALTER TABLE public.voorraad_custom_fields ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
528
528
  ALTER TABLE public.voorraad_custom_fields ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
529
529
 
530
+ -- voorraad_load_carrier_types
531
+ CREATE TABLE IF NOT EXISTS public.voorraad_load_carrier_types ();
532
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS code text NOT NULL;
533
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS naam text NOT NULL;
534
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS volgorde integer NOT NULL;
535
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
536
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
537
+
530
538
  -- voorraad_local_context
531
539
  CREATE TABLE IF NOT EXISTS public.voorraad_local_context ();
532
540
  ALTER TABLE public.voorraad_local_context ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
@@ -1137,8 +1145,8 @@ BEGIN
1137
1145
  END;
1138
1146
 
1139
1147
  SELECT COALESCE(
1140
- NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''),
1141
1148
  NULLIF(trim(COALESCE(p.trade_item_key, '')), ''),
1149
+ NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''),
1142
1150
  p.id::text
1143
1151
  )
1144
1152
  INTO v_canonical
@@ -4185,7 +4193,7 @@ BEGIN
4185
4193
  IF auth.uid() IS NULL AND NOT public.voorraad_is_server() THEN RAISE EXCEPTION 'Niet ingelogd' USING ERRCODE = '42501'; END IF;
4186
4194
  SELECT NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''), NULLIF(trim(COALESCE(p.trade_item_key, '')), '')
4187
4195
  INTO v_floriday_key, v_product_key FROM public.products p WHERE p.id = p_product_id;
4188
- v_key := COALESCE(v_floriday_key, v_product_key, 'product:' || p_product_id::text);
4196
+ v_key := COALESCE(v_product_key, v_floriday_key, 'product:' || p_product_id::text);
4189
4197
  SELECT * INTO v_ctx FROM public.get_stock_context();
4190
4198
  v_connection_id := v_ctx.connection_id;
4191
4199
 
@@ -5974,7 +5982,7 @@ BEGIN
5974
5982
  SELECT NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''), NULLIF(trim(COALESCE(p.trade_item_key, '')), '')
5975
5983
  INTO v_floriday_key, v_product_key FROM public.products p WHERE p.id = p_product_id;
5976
5984
  IF NOT FOUND THEN RAISE EXCEPTION 'Product niet gevonden'; END IF;
5977
- v_key := COALESCE(v_floriday_key, v_product_key, 'product:' || p_product_id::text);
5985
+ v_key := COALESCE(v_product_key, v_floriday_key, 'product:' || p_product_id::text);
5978
5986
 
5979
5987
  -- Context: Floriday-koppeling (omgeving, anders de enige actieve) of de lokale context.
5980
5988
  SELECT * INTO v_ctx FROM public.get_stock_context(true);
@@ -6333,7 +6341,7 @@ DECLARE
6333
6341
  v_wanted jsonb := '{}'::jsonb; v_row record; v_user uuid; v_ing jsonb;
6334
6342
  BEGIN
6335
6343
  PERFORM public.voorraad_vereis('ingelogd', 'sync_order_item_fusten');
6336
- SELECT oi.*, o.order_number, x.quantity_crates, x.packing_source, x.vbn_package_code, x.quarantined_at AS q_at INTO v_item
6344
+ SELECT oi.*, o.order_number, x.quantity_crates, x.packing_source, x.vbn_package_code, x.quarantined_at AS q_at, public.voorraad_order_geannuleerd(o.status, o.cancelled_at, o.deleted_at) AS o_geannuleerd INTO v_item
6337
6345
  FROM logistics_active.order_items oi
6338
6346
  LEFT JOIN public.orders o ON o.id = oi.order_id
6339
6347
  LEFT JOIN public.order_items x ON x.id = oi.id
@@ -6342,7 +6350,7 @@ BEGIN
6342
6350
  v_order_number := COALESCE(v_item.order_number, 'order');
6343
6351
  v_user := COALESCE(auth.uid(), (SELECT user_id FROM public.fust_types WHERE user_id IS NOT NULL LIMIT 1));
6344
6352
 
6345
- IF v_item.id IS NOT NULL AND v_item.q_at IS NULL AND v_item.product_id IS NOT NULL AND COALESCE(v_item.quantity,0) > 0 THEN
6353
+ IF v_item.id IS NOT NULL AND v_item.q_at IS NULL AND NOT COALESCE(v_item.o_geannuleerd, false) AND v_item.product_id IS NOT NULL AND COALESCE(v_item.quantity,0) > 0 THEN
6346
6354
  -- 1. Orderregel zelf: aantal fust, of (Floriday-order) planten per fust + fustcode van de order.
6347
6355
  IF COALESCE(v_item.quantity_crates, 0) > 0 THEN
6348
6356
  v_needed := v_item.quantity_crates;
@@ -6402,7 +6410,7 @@ BEGIN
6402
6410
  END IF;
6403
6411
 
6404
6412
  -- Floriday-order al afgeboekt bij het binnenhalen: die boeking overnemen (geen tweede mutatie).
6405
- IF v_item.id IS NOT NULL AND v_item.q_at IS NULL AND v_item.source_line_key IS NOT NULL
6413
+ IF v_item.id IS NOT NULL AND v_item.q_at IS NULL AND NOT COALESCE(v_item.o_geannuleerd, false) AND v_item.source_line_key IS NOT NULL
6406
6414
  AND NOT EXISTS (SELECT 1 FROM public.order_fust_bookings b WHERE b.order_item_id = _order_item_id) THEN
6407
6415
  SELECT i.impact INTO v_ing FROM public.floriday_sales_order_ingest i
6408
6416
  WHERE i.sales_order_id = v_item.source_line_key AND (i.impact->>'fustTypeId') IS NOT NULL
@@ -6455,53 +6463,18 @@ CREATE OR REPLACE FUNCTION public.sync_products_quantity_from_stock()
6455
6463
  SECURITY DEFINER
6456
6464
  SET search_path TO 'public'
6457
6465
  AS $function$
6458
- DECLARE
6459
- v_key text;
6460
- v_qty integer;
6461
- v_uuid uuid;
6466
+ DECLARE k text; c uuid;
6462
6467
  BEGIN
6463
- IF TG_OP = 'DELETE' THEN
6464
- v_key := OLD.trade_item_key;
6465
- v_qty := 0;
6466
- ELSE
6467
- v_key := NEW.trade_item_key;
6468
- v_qty := COALESCE(NEW.physical_stock, 0);
6469
- END IF;
6470
-
6471
- IF v_key IS NULL THEN
6472
- RETURN COALESCE(NEW, OLD);
6473
- END IF;
6474
-
6475
- -- Oude vorm `product:<uuid>`
6476
- IF position('product:' in v_key) = 1 THEN
6477
- BEGIN
6478
- v_uuid := substring(v_key from 9)::uuid;
6479
- EXCEPTION WHEN others THEN
6480
- v_uuid := NULL;
6481
- END;
6482
- IF v_uuid IS NOT NULL THEN
6483
- UPDATE public.products SET quantity = v_qty WHERE id = v_uuid;
6484
- END IF;
6485
- RETURN COALESCE(NEW, OLD);
6486
- END IF;
6487
-
6488
- -- Canonieke vorm: eigen sleutel of Floriday-artikel-ID
6489
- UPDATE public.products
6490
- SET quantity = v_qty
6491
- WHERE trade_item_key = v_key
6492
- OR floriday_trade_item_id::text = v_key;
6493
-
6494
- RETURN COALESCE(NEW, OLD);
6495
- END;
6496
- $function$
6468
+ PERFORM public.voorraad_vereis('ingelogd','sync_products_quantity_from_stock');
6469
+ k:=CASE WHEN TG_OP='DELETE' THEN OLD.trade_item_key ELSE NEW.trade_item_key END;
6470
+ c:=CASE WHEN TG_OP='DELETE' THEN OLD.connection_id ELSE NEW.connection_id END;
6471
+ UPDATE public.products p SET quantity=COALESCE((SELECT s.physical_stock FROM public.trade_item_stock s WHERE s.connection_id=c AND s.trade_item_key=COALESCE(NULLIF(btrim(p.trade_item_key),''),NULLIF(btrim(p.floriday_trade_item_id),''),'product:'||p.id::text)),0)
6472
+ WHERE p.trade_item_key=k OR p.floriday_trade_item_id=k OR 'product:'||p.id::text=k;
6473
+ RETURN COALESCE(NEW,OLD);
6474
+ END $function$
6497
6475
  ;
6498
6476
  REVOKE ALL ON FUNCTION sync_products_quantity_from_stock() FROM PUBLIC;
6499
6477
  REVOKE ALL ON FUNCTION sync_products_quantity_from_stock() FROM anon;
6500
- REVOKE EXECUTE ON FUNCTION sync_products_quantity_from_stock() FROM PUBLIC;
6501
- GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO authenticated;
6502
- GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO service_role;
6503
- REVOKE EXECUTE ON FUNCTION sync_products_quantity_from_stock() FROM anon;
6504
- GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO authenticated;
6505
6478
  GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO service_role;
6506
6479
  CREATE OR REPLACE FUNCTION public.touch_fust_types_updated_at()
6507
6480
  RETURNS trigger
@@ -6958,6 +6931,26 @@ END $function$
6958
6931
  REVOKE ALL ON FUNCTION trg_orders_external_fulfilled_fn() FROM PUBLIC;
6959
6932
  REVOKE ALL ON FUNCTION trg_orders_external_fulfilled_fn() FROM anon;
6960
6933
  GRANT EXECUTE ON FUNCTION trg_orders_external_fulfilled_fn() TO service_role;
6934
+ CREATE OR REPLACE FUNCTION public.trg_orders_fusten()
6935
+ RETURNS trigger
6936
+ LANGUAGE plpgsql
6937
+ SECURITY DEFINER
6938
+ SET search_path TO 'public'
6939
+ AS $function$
6940
+ DECLARE v_id uuid;
6941
+ BEGIN
6942
+ IF public.voorraad_order_geannuleerd(OLD.status, OLD.cancelled_at, OLD.deleted_at)
6943
+ IS DISTINCT FROM public.voorraad_order_geannuleerd(NEW.status, NEW.cancelled_at, NEW.deleted_at) THEN
6944
+ FOR v_id IN SELECT id FROM public.order_items WHERE order_id = NEW.id ORDER BY id LOOP
6945
+ PERFORM public.sync_order_item_fusten(v_id);
6946
+ END LOOP;
6947
+ END IF;
6948
+ RETURN NEW;
6949
+ END $function$
6950
+ ;
6951
+ REVOKE ALL ON FUNCTION trg_orders_fusten() FROM PUBLIC;
6952
+ REVOKE ALL ON FUNCTION trg_orders_fusten() FROM anon;
6953
+ GRANT EXECUTE ON FUNCTION trg_orders_fusten() TO service_role;
6961
6954
  CREATE OR REPLACE FUNCTION public.trg_orders_recompute_reserved_fn()
6962
6955
  RETURNS trigger
6963
6956
  LANGUAGE plpgsql
@@ -7695,6 +7688,26 @@ GRANT EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() TO service_role;
7695
7688
  REVOKE EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() FROM anon;
7696
7689
  GRANT EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() TO authenticated;
7697
7690
  GRANT EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() TO service_role;
7691
+ CREATE OR REPLACE FUNCTION public.trg_voorraad_link_primary_packing()
7692
+ RETURNS trigger
7693
+ LANGUAGE plpgsql
7694
+ SECURITY DEFINER
7695
+ SET search_path TO 'public'
7696
+ AS $function$
7697
+ BEGIN
7698
+ PERFORM public.voorraad_vereis('ingelogd','trg_voorraad_link_primary_packing');
7699
+ IF NULLIF(btrim(NEW.floriday_trade_item_id),'') IS NOT NULL THEN
7700
+ IF TG_OP='INSERT' OR NEW.floriday_trade_item_id IS DISTINCT FROM OLD.floriday_trade_item_id THEN
7701
+ PERFORM public.voorraad_packing_from_floriday(NEW.id,true);
7702
+ END IF;
7703
+ END IF;
7704
+ RETURN NEW;
7705
+ END $function$
7706
+ ;
7707
+ REVOKE ALL ON FUNCTION trg_voorraad_link_primary_packing() FROM PUBLIC;
7708
+ REVOKE ALL ON FUNCTION trg_voorraad_link_primary_packing() FROM anon;
7709
+ GRANT EXECUTE ON FUNCTION trg_voorraad_link_primary_packing() TO authenticated;
7710
+ GRANT EXECUTE ON FUNCTION trg_voorraad_link_primary_packing() TO service_role;
7698
7711
  CREATE OR REPLACE FUNCTION public.update_updated_at_column()
7699
7712
  RETURNS trigger
7700
7713
  LANGUAGE plpgsql
@@ -8369,6 +8382,237 @@ $function$
8369
8382
  REVOKE ALL ON FUNCTION voorraad_correctie_1120(boolean) FROM PUBLIC;
8370
8383
  REVOKE ALL ON FUNCTION voorraad_correctie_1120(boolean) FROM anon;
8371
8384
  GRANT EXECUTE ON FUNCTION voorraad_correctie_1120(boolean) TO service_role;
8385
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1121(p_uitvoeren boolean DEFAULT false)
8386
+ RETURNS jsonb
8387
+ LANGUAGE plpgsql
8388
+ SECURITY DEFINER
8389
+ SET search_path TO 'public'
8390
+ AS $function$
8391
+ DECLARE
8392
+ r record; v_now int; v_delta int; v_status text; v_user uuid; v_note text;
8393
+ v_fust jsonb; v_regels jsonb; v_wie text := COALESCE(auth.uid()::text, session_user::text);
8394
+ BEGIN
8395
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1121');
8396
+ CREATE TEMP TABLE _c1121 ON COMMIT DROP AS SELECT * FROM public.voorraad_correctie_1121_regels();
8397
+ ALTER TABLE _c1121 ADD COLUMN status text, ADD COLUMN geboekt_delta int DEFAULT 0;
8398
+ CREATE INDEX _c1121_idx ON _c1121 (order_item_id, fust_type_id); ANALYZE _c1121;
8399
+ CREATE TEMP TABLE _c1121_voor ON COMMIT DROP AS
8400
+ SELECT ft.id, ft.name, ft.stock FROM public.fust_types ft WHERE ft.id IN (SELECT DISTINCT fust_type_id FROM _c1121);
8401
+
8402
+ FOR r IN SELECT * FROM _c1121 ORDER BY fust_type_id, order_item_id LOOP
8403
+ IF r.fust_type_id IS NULL OR r.order_item_id IS NULL THEN v_status := 'overgeslagen: geen fustsoort of regel';
8404
+ ELSE
8405
+ PERFORM 1 FROM public.order_fust_bookings b
8406
+ WHERE b.order_item_id = r.order_item_id AND public.voorraad_active_fust_id(NULL, b.fust_type_id) = r.fust_type_id
8407
+ ORDER BY b.id FOR UPDATE;
8408
+ SELECT COALESCE(sum(b.quantity), 0)::int INTO v_now FROM public.order_fust_bookings b
8409
+ WHERE b.order_item_id = r.order_item_id AND public.voorraad_active_fust_id(NULL, b.fust_type_id) = r.fust_type_id;
8410
+ IF v_now <> r.netto_geboekt THEN v_status := 'overgeslagen: geboekt veranderd (' || r.netto_geboekt || ' → ' || v_now || ')';
8411
+ ELSIF NOT p_uitvoeren THEN v_status := 'voorstel';
8412
+ ELSE
8413
+ v_delta := r.netto_geboekt - r.juist; -- >0 = fust terug (tegenboeking), <0 = extra afboeken
8414
+ v_note := 'Correctie 1121 · ' || COALESCE('Order ' || r.order_number, 'regel bestaat niet meer') || ' · regel ' || r.order_item_id || ' · ' || r.reden;
8415
+ SELECT user_id INTO v_user FROM public.fust_types WHERE id = r.fust_type_id;
8416
+ INSERT INTO public.fust_stock_mutations (user_id, fust_type_id, delta, reason, note)
8417
+ VALUES (COALESCE(auth.uid(), v_user), r.fust_type_id, v_delta, CASE WHEN v_delta > 0 THEN 'sale_cancelled' ELSE 'sale' END, v_note);
8418
+ UPDATE public.order_fust_bookings b SET quantity = 0, updated_at = now()
8419
+ WHERE b.order_item_id = r.order_item_id AND b.fust_type_id <> r.fust_type_id
8420
+ AND public.voorraad_active_fust_id(NULL, b.fust_type_id) = r.fust_type_id AND b.quantity <> 0;
8421
+ INSERT INTO public.order_fust_bookings (order_item_id, fust_type_id, quantity)
8422
+ VALUES (r.order_item_id, r.fust_type_id, r.juist)
8423
+ ON CONFLICT (order_item_id, fust_type_id) DO UPDATE SET quantity = EXCLUDED.quantity, updated_at = now();
8424
+ v_status := CASE WHEN v_delta > 0 THEN 'tegenboeking' ELSE 'aanvullende boeking' END;
8425
+ UPDATE _c1121 SET geboekt_delta = v_delta WHERE order_item_id = r.order_item_id AND fust_type_id = r.fust_type_id;
8426
+ END IF;
8427
+ END IF;
8428
+ UPDATE _c1121 SET status = v_status WHERE order_item_id = r.order_item_id AND fust_type_id = r.fust_type_id;
8429
+ END LOOP;
8430
+
8431
+ SELECT COALESCE(jsonb_agg(jsonb_build_object(
8432
+ 'fust', v.name, 'fust_type_id', v.id, 'voorraad_voor', v.stock, 'voorraad_na', ft.stock,
8433
+ 'voorraad_na_verwacht', v.stock + COALESCE(s.voorstel, 0),
8434
+ 'tegenboekingen', COALESCE(s.teg, 0), 'aanvullende_boekingen', COALESCE(s.aan, 0),
8435
+ 'voorstel_regels', COALESCE(s.vs, 0), 'overgeslagen', COALESCE(s.ovr, 0)) ORDER BY v.name), '[]'::jsonb)
8436
+ INTO v_fust
8437
+ FROM _c1121_voor v JOIN public.fust_types ft ON ft.id = v.id
8438
+ LEFT JOIN (SELECT fust_type_id,
8439
+ count(*) FILTER (WHERE status = 'tegenboeking') teg,
8440
+ count(*) FILTER (WHERE status = 'aanvullende boeking') aan,
8441
+ count(*) FILTER (WHERE status = 'voorstel') vs,
8442
+ count(*) FILTER (WHERE status LIKE 'overgeslagen%') ovr,
8443
+ sum(-verschil) FILTER (WHERE status IN ('voorstel','tegenboeking','aanvullende boeking')) voorstel
8444
+ FROM _c1121 GROUP BY 1) s ON s.fust_type_id = v.id;
8445
+ SELECT COALESCE(jsonb_agg(to_jsonb(c) ORDER BY c.fust_naam, c.order_number NULLS LAST, c.order_item_id), '[]'::jsonb) INTO v_regels FROM _c1121 c;
8446
+
8447
+ IF p_uitvoeren THEN
8448
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8449
+ VALUES ('voorraad_correctie_1121', v_wie, false, jsonb_build_object('per_fust', v_fust, 'regels', v_regels), NULL);
8450
+ END IF;
8451
+ RETURN jsonb_build_object('ok', true, 'proef', NOT p_uitvoeren, 'regels_met_verschil', (SELECT count(*) FROM _c1121),
8452
+ 'per_fust', v_fust, 'regels', v_regels);
8453
+ END $function$
8454
+ ;
8455
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121(boolean) FROM PUBLIC;
8456
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121(boolean) FROM anon;
8457
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1121(boolean) TO service_role;
8458
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1121_regels()
8459
+ RETURNS TABLE(order_number text, order_item_id uuid, regel_bestaat boolean, fust_type_id uuid, fust_naam text, aantal_boekingen integer, netto_geboekt integer, juist integer, verschil integer, reden text)
8460
+ LANGUAGE plpgsql
8461
+ STABLE SECURITY DEFINER
8462
+ SET search_path TO 'public'
8463
+ AS $function$
8464
+ BEGIN
8465
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1121_regels');
8466
+ RETURN QUERY
8467
+ WITH b AS (
8468
+ SELECT ob.order_item_id, public.voorraad_active_fust_id(NULL, ob.fust_type_id) AS f, sum(ob.quantity)::int AS q, count(*)::int AS n
8469
+ FROM public.order_fust_bookings ob GROUP BY 1, 2
8470
+ ), j AS (
8471
+ SELECT oi.id AS order_item_id, r.fust_type_id AS f, r.aantal AS q, r.bron
8472
+ FROM public.order_items oi CROSS JOIN LATERAL public.voorraad_fust_juist(oi.id) r
8473
+ WHERE r.fust_type_id IS NOT NULL
8474
+ ), c AS (
8475
+ SELECT COALESCE(b.order_item_id, j.order_item_id) AS order_item_id, COALESCE(b.f, j.f) AS f,
8476
+ COALESCE(b.q, 0) AS geboekt, COALESCE(j.q, 0) AS juist, j.bron, COALESCE(b.n, 0) AS n
8477
+ FROM b FULL JOIN j ON j.order_item_id = b.order_item_id AND j.f = b.f
8478
+ )
8479
+ SELECT o.order_number::text, c.order_item_id, (oi.id IS NOT NULL), c.f, ft.name::text, c.n,
8480
+ c.geboekt, c.juist, c.juist - c.geboekt,
8481
+ CASE WHEN oi.id IS NULL THEN 'regel bestaat niet meer (juist 0)'
8482
+ WHEN oi.quarantined_at IS NOT NULL THEN 'regel in quarantaine (juist 0)'
8483
+ WHEN public.voorraad_order_geannuleerd(o.status, o.cancelled_at, o.deleted_at) THEN 'order geannuleerd (juist 0)'
8484
+ WHEN c.bron IS NOT NULL THEN 'juist volgens ' || c.bron
8485
+ ELSE 'geen fust volgens huidige regel (geen fustcode of aantal; juist 0)' END
8486
+ FROM c
8487
+ LEFT JOIN public.order_items oi ON oi.id = c.order_item_id
8488
+ LEFT JOIN public.orders o ON o.id = oi.order_id
8489
+ LEFT JOIN public.fust_types ft ON ft.id = c.f
8490
+ WHERE c.geboekt <> c.juist;
8491
+ END $function$
8492
+ ;
8493
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121_regels() FROM PUBLIC;
8494
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121_regels() FROM anon;
8495
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1121_regels() TO service_role;
8496
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1123(p_uitvoeren boolean DEFAULT false)
8497
+ RETURNS jsonb
8498
+ LANGUAGE plpgsql
8499
+ SECURITY DEFINER
8500
+ SET search_path TO 'public'
8501
+ AS $function$
8502
+ DECLARE
8503
+ c_groep constant uuid := 'e4c0f2cd-d99a-4ef1-b848-ba576b175638';
8504
+ c_product constant uuid := '4e62fc60-e9b7-468f-8cc4-cdf64b938f57';
8505
+ v_g record; v_items int; v_status text;
8506
+ BEGIN
8507
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1123');
8508
+ SELECT * INTO v_g FROM public.product_groups WHERE id = c_groep FOR UPDATE;
8509
+ SELECT count(*) INTO v_items FROM public.product_group_items WHERE product_group_id = c_groep;
8510
+ IF v_g.id IS NULL THEN v_status := 'overgeslagen: groep niet in deze database';
8511
+ ELSIF v_g.head_product_id IS DISTINCT FROM c_product THEN v_status := 'overgeslagen: groep hoort bij een ander artikel';
8512
+ ELSIF NOT v_g.is_active THEN v_status := 'al inactief';
8513
+ ELSIF v_items > 0 THEN v_status := 'overgeslagen: groep heeft ' || v_items || ' artikelen';
8514
+ ELSE v_status := CASE WHEN p_uitvoeren THEN 'uitgevoerd' ELSE 'voorstel' END;
8515
+ END IF;
8516
+ IF v_status = 'uitgevoerd' THEN
8517
+ UPDATE public.product_groups SET is_active = false, updated_at = now() WHERE id = c_groep;
8518
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8519
+ VALUES ('voorraad_correctie_1123', COALESCE(auth.uid()::text, session_user::text), false,
8520
+ jsonb_build_object('groep', c_groep, 'naam', v_g.name, 'status', v_status), true);
8521
+ END IF;
8522
+ RETURN jsonb_build_object('ok', true, 'proef', NOT p_uitvoeren, 'groep', c_groep, 'naam', v_g.name, 'artikelen', v_items, 'status', v_status);
8523
+ END $function$
8524
+ ;
8525
+ REVOKE ALL ON FUNCTION voorraad_correctie_1123(boolean) FROM PUBLIC;
8526
+ REVOKE ALL ON FUNCTION voorraad_correctie_1123(boolean) FROM anon;
8527
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1123(boolean) TO service_role;
8528
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1124(p_uitvoeren boolean DEFAULT false)
8529
+ RETURNS jsonb
8530
+ LANGUAGE plpgsql
8531
+ SECURITY DEFINER
8532
+ SET search_path TO 'public'
8533
+ AS $function$
8534
+ BEGIN
8535
+ PERFORM public.voorraad_vereis('server','voorraad_correctie_1124');
8536
+ RETURN public.voorraad_correctie_1126(p_uitvoeren);
8537
+ END $function$
8538
+ ;
8539
+ REVOKE ALL ON FUNCTION voorraad_correctie_1124(boolean) FROM PUBLIC;
8540
+ REVOKE ALL ON FUNCTION voorraad_correctie_1124(boolean) FROM anon;
8541
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1124(boolean) TO service_role;
8542
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1126(p_uitvoeren boolean DEFAULT false)
8543
+ RETURNS jsonb
8544
+ LANGUAGE plpgsql
8545
+ SECURITY DEFINER
8546
+ SET search_path TO 'public'
8547
+ AS $function$
8548
+ DECLARE
8549
+ pid constant uuid:='4e62fc60-e9b7-468f-8cc4-cdf64b938f57'; fid constant text:='c3406752-b5e0-438b-b3a9-109b58b9e970';
8550
+ p record; ctx record; ownrow record; fdrow record; before_rows jsonb; after_rows jsonb; ch text; qh text; unchanged boolean; status text; result jsonb; handled text;
8551
+ BEGIN
8552
+ PERFORM public.voorraad_vereis('server','voorraad_correctie_1126');
8553
+ PERFORM pg_advisory_xact_lock(hashtextextended('voorraad_correctie_1126',0));
8554
+ SELECT * INTO p FROM public.products WHERE id=pid FOR UPDATE;
8555
+ SELECT * INTO ctx FROM public.get_stock_context();
8556
+ PERFORM 1 FROM public.trade_item_stock WHERE connection_id=ctx.connection_id AND trade_item_key IN(p.trade_item_key,fid) ORDER BY id FOR UPDATE;
8557
+ SELECT * INTO ownrow FROM public.trade_item_stock WHERE connection_id=ctx.connection_id AND trade_item_key=p.trade_item_key;
8558
+ SELECT * INTO fdrow FROM public.trade_item_stock WHERE connection_id=ctx.connection_id AND trade_item_key=fid;
8559
+ SELECT jsonb_agg(to_jsonb(s) ORDER BY s.id) INTO before_rows FROM public.trade_item_stock s WHERE s.id IN(ownrow.id,fdrow.id);
8560
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO ch FROM public.floriday_trade_items_cache t;
8561
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO qh FROM public.floriday_continuous_stock_queue t;
8562
+ IF p.id IS NULL OR p.article_number IS DISTINCT FROM 'TQA2710G' OR p.floriday_trade_item_id IS DISTINCT FROM fid OR p.trade_item_key IS DISTINCT FROM 'product:'||pid::text THEN status:='overgeslagen: artikel/koppeling/sleutel wijkt af';
8563
+ ELSIF ownrow.id IS NULL OR fdrow.id IS NULL OR ownrow.reserved_stock<>0 OR fdrow.reserved_stock<>0 OR ownrow.incoming_stock<>0 OR fdrow.incoming_stock<>0 THEN status:='overgeslagen: voorraadrij ontbreekt of reservering/inkomend gewijzigd';
8564
+ ELSIF ownrow.physical_stock=500 AND fdrow.physical_stock=0 THEN status:='al uitgevoerd';
8565
+ ELSIF ownrow.physical_stock<>0 OR fdrow.physical_stock<>500 OR p.sale_price<>2.40 THEN status:='overgeslagen: stand of prijs gewijzigd';
8566
+ ELSE status:=CASE WHEN p_uitvoeren THEN 'uitgevoerd' ELSE 'voorstel' END; END IF;
8567
+ IF status='uitgevoerd' THEN
8568
+ handled:=COALESCE(NULLIF(current_setting('stock.log_handled',true),''),';');
8569
+ PERFORM set_config('stock.log_handled',handled||ctx.connection_id||'|'||fid||'|0|0;'||ctx.connection_id||'|'||p.trade_item_key||'|500|0;',true);
8570
+ UPDATE public.trade_item_stock SET physical_stock=0,change_source='FLORIDAY_PUBLICATION',updated_at=now() WHERE id=fdrow.id;
8571
+ UPDATE public.trade_item_stock SET physical_stock=500,change_source='FLORIDAY_PUBLICATION',updated_at=now() WHERE id=ownrow.id;
8572
+ INSERT INTO public.stock_mutation_log(trade_item_key,connection_id,mutation_type,qty_delta,physical_before,physical_after,reserved_before,reserved_after,reason,created_by)
8573
+ VALUES(fid,ctx.connection_id,'manual_correction',-500,500,0,0,0,'[correctie_1126] TQA2710G tegenboeking verkeerde Floriday-sleutel; voorraad naar eigen leessleutel',auth.uid()),
8574
+ (p.trade_item_key,ctx.connection_id,'manual_correction',500,0,500,0,0,'[correctie_1126] TQA2710G 500 op eigen leessleutel; geen dubbele voorraad',auth.uid());
8575
+ PERFORM set_config('stock.log_handled',handled,true);
8576
+ END IF;
8577
+ SELECT jsonb_agg(to_jsonb(s) ORDER BY s.id) INTO after_rows FROM public.trade_item_stock s WHERE s.id IN(ownrow.id,fdrow.id);
8578
+ unchanged:=ch=(SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) FROM public.floriday_trade_items_cache t) AND qh=(SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) FROM public.floriday_continuous_stock_queue t);
8579
+ IF NOT unchanged THEN RAISE EXCEPTION 'Floriday-kopie of wachtrij gewijzigd; correctie teruggedraaid'; END IF;
8580
+ result:=jsonb_build_object('ok',status NOT LIKE 'overgeslagen%','status',status,'voor',before_rows,'na',after_rows,'hash_ok',unchanged,'prijs',p.sale_price,'sleutel',p.trade_item_key);
8581
+ INSERT INTO public.voorraad_correcties(correctie,uitgevoerd_door,proef,aantallen,hash_ok) VALUES('voorraad_correctie_1126',COALESCE(auth.uid()::text,session_user::text),NOT p_uitvoeren,result,unchanged);
8582
+ RETURN result;
8583
+ END $function$
8584
+ ;
8585
+ REVOKE ALL ON FUNCTION voorraad_correctie_1126(boolean) FROM PUBLIC;
8586
+ REVOKE ALL ON FUNCTION voorraad_correctie_1126(boolean) FROM anon;
8587
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1126(boolean) TO service_role;
8588
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1127(p_uitvoeren boolean DEFAULT false)
8589
+ RETURNS jsonb
8590
+ LANGUAGE plpgsql
8591
+ SECURITY DEFINER
8592
+ SET search_path TO 'public'
8593
+ AS $function$
8594
+ DECLARE pid constant uuid:='4e62fc60-e9b7-468f-8cc4-cdf64b938f57'; r jsonb; ch text; qh text; okhash boolean;
8595
+ BEGIN
8596
+ PERFORM public.voorraad_vereis('server','voorraad_correctie_1127');
8597
+ PERFORM 1 FROM public.products WHERE id=pid FOR UPDATE;
8598
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO ch FROM public.floriday_trade_items_cache t;
8599
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO qh FROM public.floriday_continuous_stock_queue t;
8600
+ r:=public.voorraad_packing_from_floriday(pid,false);
8601
+ IF NOT EXISTS(SELECT 1 FROM public.product_packings WHERE product_id=pid AND is_primary) THEN
8602
+ IF NOT COALESCE((r->>'ok')::boolean,false) OR (r#>>'{packing,package,vbnPackageCode}',r#>>'{packing,piecesPerPackage}',r#>>'{packing,packagesPerLayer}',r#>>'{packing,layersPerLoadCarrier}',r#>>'{packing,loadCarrier}') IS DISTINCT FROM ('412','12','5','8','DANISH_TROLLEY') THEN
8603
+ RAISE EXCEPTION 'Floriday-belading wijkt af van het goedgekeurde overzicht; niets overgenomen';
8604
+ END IF;
8605
+ END IF;
8606
+ IF p_uitvoeren THEN r:=public.voorraad_packing_from_floriday(pid,true); END IF;
8607
+ okhash:=ch=(SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) FROM public.floriday_trade_items_cache t) AND qh=(SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) FROM public.floriday_continuous_stock_queue t);
8608
+ IF NOT okhash THEN RAISE EXCEPTION 'Floriday-kopie of wachtrij gewijzigd; correctie teruggedraaid'; END IF;
8609
+ INSERT INTO public.voorraad_correcties(correctie,uitgevoerd_door,proef,aantallen,hash_ok) VALUES('voorraad_correctie_1127',COALESCE(auth.uid()::text,session_user::text),NOT p_uitvoeren,r,okhash);
8610
+ RETURN r||jsonb_build_object('hash_ok',okhash);
8611
+ END $function$
8612
+ ;
8613
+ REVOKE ALL ON FUNCTION voorraad_correctie_1127(boolean) FROM PUBLIC;
8614
+ REVOKE ALL ON FUNCTION voorraad_correctie_1127(boolean) FROM anon;
8615
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1127(boolean) TO service_role;
8372
8616
  CREATE OR REPLACE FUNCTION public.voorraad_correctie_status(p_correctie text DEFAULT '1098'::text)
8373
8617
  RETURNS jsonb
8374
8618
  LANGUAGE plpgsql
@@ -8495,6 +8739,71 @@ REVOKE ALL ON FUNCTION voorraad_fust_dimensions() FROM PUBLIC;
8495
8739
  REVOKE ALL ON FUNCTION voorraad_fust_dimensions() FROM anon;
8496
8740
  GRANT EXECUTE ON FUNCTION voorraad_fust_dimensions() TO authenticated;
8497
8741
  GRANT EXECUTE ON FUNCTION voorraad_fust_dimensions() TO service_role;
8742
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_juist(p_order_item_id uuid)
8743
+ RETURNS TABLE(fust_type_id uuid, fust_key text, aantal integer, bron text)
8744
+ LANGUAGE plpgsql
8745
+ STABLE SECURITY DEFINER
8746
+ SET search_path TO 'public'
8747
+ AS $function$
8748
+ DECLARE
8749
+ v_item record; v_packs jsonb; v_pack jsonb; v_key text; v_units numeric; v_needed integer; v_bron text;
8750
+ BEGIN
8751
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_fust_juist');
8752
+ SELECT oi.*, x.quantity_crates, x.vbn_package_code, o.status AS o_status, o.cancelled_at AS o_cancel, o.deleted_at AS o_del
8753
+ INTO v_item
8754
+ FROM logistics_active.order_items oi
8755
+ JOIN public.order_items x ON x.id = oi.id
8756
+ LEFT JOIN public.orders o ON o.id = oi.order_id
8757
+ WHERE oi.id = p_order_item_id;
8758
+ IF v_item.id IS NULL OR v_item.product_id IS NULL OR COALESCE(v_item.quantity, 0) <= 0
8759
+ OR public.voorraad_order_geannuleerd(v_item.o_status, v_item.o_cancel, v_item.o_del) THEN
8760
+ RETURN;
8761
+ END IF;
8762
+ IF COALESCE(v_item.quantity_crates, 0) > 0 THEN
8763
+ v_needed := v_item.quantity_crates; v_bron := 'orderregel: ' || v_item.quantity_crates || ' fust';
8764
+ ELSIF COALESCE(v_item.plants_per_crate, 0) > 0 THEN
8765
+ v_needed := ceil(v_item.quantity::numeric / v_item.plants_per_crate)::int;
8766
+ v_bron := 'orderregel: ' || v_item.quantity || ' stuks ÷ ' || v_item.plants_per_crate || ' per fust';
8767
+ END IF;
8768
+ IF COALESCE(v_item.vbn_package_code::text, '') <> '' THEN v_key := 'vbn:' || v_item.vbn_package_code::text; END IF;
8769
+ IF v_needed IS NULL OR v_key IS NULL THEN
8770
+ SELECT COALESCE(p.custom_fields->'floriday_payload'->'packingConfigurations', p.custom_fields->'packingConfigurations')
8771
+ INTO v_packs FROM public.products p WHERE p.id = v_item.product_id;
8772
+ IF v_packs IS NULL THEN
8773
+ SELECT c.data->'packingConfigurations' INTO v_packs FROM public.floriday_trade_items_cache c
8774
+ WHERE c.floriday_id = (SELECT p.trade_item_key FROM public.products p WHERE p.id = v_item.product_id) LIMIT 1;
8775
+ END IF;
8776
+ IF jsonb_typeof(v_packs) = 'array' THEN
8777
+ SELECT e INTO v_pack FROM jsonb_array_elements(v_packs) e WHERE COALESCE((e->>'isPrimary')::boolean, false) LIMIT 1;
8778
+ IF v_pack IS NULL THEN SELECT e INTO v_pack FROM jsonb_array_elements(v_packs) e LIMIT 1; END IF;
8779
+ IF v_pack IS NOT NULL THEN
8780
+ IF v_needed IS NULL THEN
8781
+ v_units := NULLIF((v_pack->>'unitsPerPackage')::numeric, 0);
8782
+ IF v_units IS NOT NULL THEN
8783
+ v_needed := ceil(v_item.quantity::numeric / v_units)::int;
8784
+ v_bron := 'artikel: ' || v_item.quantity || ' stuks ÷ ' || v_units || ' per fust';
8785
+ END IF;
8786
+ END IF;
8787
+ IF v_key IS NULL THEN
8788
+ IF COALESCE(v_pack->>'source','') = 'SUPPLIER' AND COALESCE(v_pack->>'packagingMaterialId','') <> '' THEN
8789
+ v_key := 'custom:' || (v_pack->>'packagingMaterialId');
8790
+ ELSIF COALESCE(v_pack->>'packagingType','') <> '' THEN
8791
+ v_key := 'vbn:' || (v_pack->>'packagingType');
8792
+ END IF;
8793
+ END IF;
8794
+ END IF;
8795
+ END IF;
8796
+ END IF;
8797
+ IF v_key IS NULL OR COALESCE(v_needed, 0) <= 0 THEN RETURN; END IF;
8798
+ fust_type_id := public.voorraad_active_fust_id(v_key, NULL);
8799
+ fust_key := v_key; aantal := v_needed; bron := v_bron;
8800
+ RETURN NEXT;
8801
+ END $function$
8802
+ ;
8803
+ REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM PUBLIC;
8804
+ REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM anon;
8805
+ GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO authenticated;
8806
+ GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO service_role;
8498
8807
  CREATE OR REPLACE FUNCTION public.voorraad_hook_base_url()
8499
8808
  RETURNS text
8500
8809
  LANGUAGE plpgsql
@@ -8612,8 +8921,8 @@ CREATE OR REPLACE FUNCTION public.voorraad_install_check()
8612
8921
  STABLE SECURITY DEFINER
8613
8922
  SET search_path TO 'public'
8614
8923
  AS $function$
8615
- DECLARE v_f text[] := ARRAY['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'];
8616
- v_t text[] := ARRAY['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'];
8924
+ DECLARE v_f text[] := ARRAY['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'];
8925
+ 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'];
8617
8926
  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'];
8618
8927
  v_open text[] := ARRAY['voorraad_is_server','voorraad_vereis'];
8619
8928
  v_func jsonb; v_trig jsonb; v_pol jsonb;
@@ -8675,6 +8984,21 @@ GRANT EXECUTE ON FUNCTION voorraad_is_server() TO service_role;
8675
8984
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO anon;
8676
8985
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO authenticated;
8677
8986
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO service_role;
8987
+ CREATE OR REPLACE FUNCTION public.voorraad_load_carriers()
8988
+ RETURNS TABLE(code text, naam text, volgorde integer)
8989
+ LANGUAGE plpgsql
8990
+ STABLE
8991
+ SET search_path TO 'public'
8992
+ AS $function$
8993
+ BEGIN
8994
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_load_carriers');
8995
+ RETURN QUERY SELECT t.code, t.naam, t.volgorde FROM public.voorraad_load_carrier_types t ORDER BY t.volgorde, t.code;
8996
+ END $function$
8997
+ ;
8998
+ REVOKE ALL ON FUNCTION voorraad_load_carriers() FROM PUBLIC;
8999
+ REVOKE ALL ON FUNCTION voorraad_load_carriers() FROM anon;
9000
+ GRANT EXECUTE ON FUNCTION voorraad_load_carriers() TO authenticated;
9001
+ GRANT EXECUTE ON FUNCTION voorraad_load_carriers() TO service_role;
8678
9002
  CREATE OR REPLACE FUNCTION public.voorraad_mark_floriday_sold_before_switch(p_product_id uuid)
8679
9003
  RETURNS integer
8680
9004
  LANGUAGE plpgsql
@@ -8706,6 +9030,86 @@ END $function$
8706
9030
  REVOKE ALL ON FUNCTION voorraad_mark_floriday_sold_before_switch(uuid) FROM PUBLIC;
8707
9031
  REVOKE ALL ON FUNCTION voorraad_mark_floriday_sold_before_switch(uuid) FROM anon;
8708
9032
  GRANT EXECUTE ON FUNCTION voorraad_mark_floriday_sold_before_switch(uuid) TO service_role;
9033
+ CREATE OR REPLACE FUNCTION public.voorraad_order_geannuleerd(p_status text, p_cancelled_at timestamp with time zone, p_deleted_at timestamp with time zone)
9034
+ RETURNS boolean
9035
+ LANGUAGE sql
9036
+ IMMUTABLE
9037
+ SET search_path TO 'public'
9038
+ AS $function$
9039
+ SELECT lower(btrim(COALESCE(p_status, ''))) IN ('geannuleerd', 'cancelled') OR p_cancelled_at IS NOT NULL OR p_deleted_at IS NOT NULL
9040
+ $function$
9041
+ ;
9042
+ REVOKE ALL ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM PUBLIC;
9043
+ REVOKE ALL ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM anon;
9044
+ REVOKE EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM PUBLIC;
9045
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO authenticated;
9046
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO service_role;
9047
+ REVOKE EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM anon;
9048
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO authenticated;
9049
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO service_role;
9050
+ CREATE OR REPLACE FUNCTION public.voorraad_packing_from_floriday(p_product_id uuid, p_uitvoeren boolean)
9051
+ RETURNS jsonb
9052
+ LANGUAGE plpgsql
9053
+ SET search_path TO 'public'
9054
+ AS $function$
9055
+ DECLARE p record; ctx record; cfg jsonb; d jsonb; missing text[]:='{}'; n int; f uuid; result jsonb; msg text; copied boolean:=false;
9056
+ BEGIN
9057
+ PERFORM public.voorraad_vereis('ingelogd','voorraad_packing_from_floriday');
9058
+ IF NOT public.voorraad_can_write() AND NOT public.voorraad_is_server() THEN RAISE EXCEPTION 'Geen toestemming om belading op te slaan' USING ERRCODE='42501'; END IF;
9059
+ SELECT * INTO p FROM public.products WHERE id=p_product_id FOR UPDATE;
9060
+ IF NOT FOUND THEN RAISE EXCEPTION 'Artikel niet gevonden' USING ERRCODE='P0001'; END IF;
9061
+ IF EXISTS(SELECT 1 FROM public.product_packings WHERE product_id=p_product_id AND is_primary) THEN
9062
+ RETURN jsonb_build_object('ok',true,'copied',false,'melding','Hoofdverpakking bestaat al; niets overschreven');
9063
+ END IF;
9064
+ SELECT * INTO ctx FROM public.get_stock_context();
9065
+ SELECT c.data INTO d FROM public.floriday_trade_items_cache c WHERE c.connection_id=ctx.connection_id AND c.floriday_id=p.floriday_trade_item_id AND NOT COALESCE(c.is_deleted,false);
9066
+ IF d IS NULL THEN msg:='Hoofdverpakking niet overgenomen: artikel ontbreekt in de Floriday-kopie';
9067
+ ELSE
9068
+ SELECT count(*),jsonb_agg(e)->0 INTO n,cfg FROM jsonb_array_elements(CASE WHEN jsonb_typeof(d->'packingConfigurations')='array' THEN d->'packingConfigurations' ELSE '[]'::jsonb END) e WHERE e->'primary'='true'::jsonb;
9069
+ IF n<>1 THEN msg:='Hoofdverpakking niet overgenomen: verwacht één primaire Floriday-verpakking, gevonden '||n;
9070
+ ELSE
9071
+ missing:=public.voorraad_packing_missing(cfg);IF cardinality(missing)>0 THEN msg:='Hoofdverpakking niet overgenomen: ontbrekend of ongeldig: '||array_to_string(missing,', ');
9072
+ ELSE
9073
+ SELECT public.voorraad_active_fust_id(NULL,ft.id) INTO f FROM public.fust_types ft WHERE ft.vbn_code::text=cfg#>>'{package,vbnPackageCode}' AND ft.merged_into IS NULL ORDER BY ft.id LIMIT 1;
9074
+ IF p_uitvoeren THEN
9075
+ INSERT INTO public.product_packings(product_id,source,floriday_packing_id,vbn_package_code,fust_type_id,load_carrier,pieces_per_package,packages_per_layer,layers_per_load_carrier,is_primary,customer_organization_ids)
9076
+ VALUES(p_product_id,'floriday',COALESCE(cfg->>'packingConfigurationId',cfg->>'id'),(cfg#>>'{package,vbnPackageCode}')::int,f,cfg->>'loadCarrier',(cfg->>'piecesPerPackage')::int,(cfg->>'packagesPerLayer')::int,(cfg->>'layersPerLoadCarrier')::int,true,ARRAY(SELECT jsonb_array_elements_text(COALESCE(cfg->'allowedCustomerOrganizationIds','[]'::jsonb))));
9077
+ copied:=true;
9078
+ END IF;
9079
+ msg:=CASE WHEN p_uitvoeren THEN 'Hoofdverpakking overgenomen uit Floriday' ELSE 'Volledige hoofdverpakking beschikbaar om over te nemen' END;
9080
+ END IF;
9081
+ END IF;
9082
+ END IF;
9083
+ result:=jsonb_build_object('ok',msg NOT LIKE 'Hoofdverpakking niet%','copied',copied,'melding',msg,'missing',to_jsonb(missing),'packing',cfg);
9084
+ IF p_uitvoeren THEN UPDATE public.products SET custom_fields=jsonb_set(COALESCE(custom_fields,'{}'::jsonb),'{voorraad_packing_link}',result,true) WHERE id=p_product_id; END IF;
9085
+ RETURN result;
9086
+ END $function$
9087
+ ;
9088
+ REVOKE ALL ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) FROM PUBLIC;
9089
+ REVOKE ALL ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) FROM anon;
9090
+ GRANT EXECUTE ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) TO authenticated;
9091
+ GRANT EXECUTE ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) TO service_role;
9092
+ CREATE OR REPLACE FUNCTION public.voorraad_packing_missing(p_packing jsonb)
9093
+ RETURNS text[]
9094
+ LANGUAGE plpgsql
9095
+ STABLE
9096
+ SET search_path TO 'public'
9097
+ AS $function$
9098
+ DECLARE missing text[]:='{}';
9099
+ BEGIN
9100
+ PERFORM public.voorraad_vereis('ingelogd','voorraad_packing_missing');
9101
+ IF COALESCE(p_packing#>>'{package,vbnPackageCode}','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'fust (vbnPackageCode)'); END IF;
9102
+ IF COALESCE(p_packing->>'piecesPerPackage','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'planten per fust'); END IF;
9103
+ IF COALESCE(p_packing->>'packagesPerLayer','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'fusten per laag'); END IF;
9104
+ IF COALESCE(p_packing->>'layersPerLoadCarrier','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'lagen per kar'); END IF;
9105
+ IF NOT EXISTS(SELECT 1 FROM public.voorraad_load_carrier_types WHERE code=p_packing->>'loadCarrier') THEN missing:=array_append(missing,'ladingdrager'); END IF;
9106
+ RETURN missing;
9107
+ END $function$
9108
+ ;
9109
+ REVOKE ALL ON FUNCTION voorraad_packing_missing(jsonb) FROM PUBLIC;
9110
+ REVOKE ALL ON FUNCTION voorraad_packing_missing(jsonb) FROM anon;
9111
+ GRANT EXECUTE ON FUNCTION voorraad_packing_missing(jsonb) TO authenticated;
9112
+ GRANT EXECUTE ON FUNCTION voorraad_packing_missing(jsonb) TO service_role;
8709
9113
  CREATE OR REPLACE FUNCTION public.voorraad_production_enabled()
8710
9114
  RETURNS boolean
8711
9115
  LANGUAGE sql
@@ -9098,6 +9502,7 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'trade_i
9098
9502
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_buffer_state_pkey' AND conrelid = 'public.voorraad_buffer_state'::regclass) THEN ALTER TABLE public.voorraad_buffer_state ADD CONSTRAINT voorraad_buffer_state_pkey PRIMARY KEY (buffer_id); END IF; END $c$;
9099
9503
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_correcties_pkey' AND conrelid = 'public.voorraad_correcties'::regclass) THEN ALTER TABLE public.voorraad_correcties ADD CONSTRAINT voorraad_correcties_pkey PRIMARY KEY (id); END IF; END $c$;
9100
9504
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_custom_fields_pkey' AND conrelid = 'public.voorraad_custom_fields'::regclass) THEN ALTER TABLE public.voorraad_custom_fields ADD CONSTRAINT voorraad_custom_fields_pkey PRIMARY KEY (id); END IF; END $c$;
9505
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_load_carrier_types_pkey' AND conrelid = 'public.voorraad_load_carrier_types'::regclass) THEN ALTER TABLE public.voorraad_load_carrier_types ADD CONSTRAINT voorraad_load_carrier_types_pkey PRIMARY KEY (code); END IF; END $c$;
9101
9506
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_local_context_pkey' AND conrelid = 'public.voorraad_local_context'::regclass) THEN ALTER TABLE public.voorraad_local_context ADD CONSTRAINT voorraad_local_context_pkey PRIMARY KEY (id); END IF; END $c$;
9102
9507
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_logistics_event_log_pkey' AND conrelid = 'public.voorraad_logistics_event_log'::regclass) THEN ALTER TABLE public.voorraad_logistics_event_log ADD CONSTRAINT voorraad_logistics_event_log_pkey PRIMARY KEY (event_id); END IF; END $c$;
9103
9508
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_media_upload_failures_pkey' AND conrelid = 'public.voorraad_media_upload_failures'::regclass) THEN ALTER TABLE public.voorraad_media_upload_failures ADD CONSTRAINT voorraad_media_upload_failures_pkey PRIMARY KEY (id); END IF; END $c$;
@@ -9352,6 +9757,10 @@ ALTER TABLE public.voorraad_custom_fields ENABLE ROW LEVEL SECURITY;
9352
9757
  REVOKE ALL ON public.voorraad_custom_fields FROM anon;
9353
9758
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_custom_fields TO authenticated;
9354
9759
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_custom_fields TO service_role;
9760
+ ALTER TABLE public.voorraad_load_carrier_types ENABLE ROW LEVEL SECURITY;
9761
+ REVOKE ALL ON public.voorraad_load_carrier_types FROM anon;
9762
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_load_carrier_types TO authenticated;
9763
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_load_carrier_types TO service_role;
9355
9764
  ALTER TABLE public.voorraad_local_context ENABLE ROW LEVEL SECURITY;
9356
9765
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_local_context TO authenticated;
9357
9766
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_local_context TO service_role;
@@ -9495,6 +9904,8 @@ DROP POLICY IF EXISTS "Authenticated can read voorraad custom fields" ON public.
9495
9904
  CREATE POLICY "Authenticated can read voorraad custom fields" ON public.voorraad_custom_fields AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9496
9905
  DROP POLICY IF EXISTS "Authenticated can update voorraad custom fields" ON public.voorraad_custom_fields;
9497
9906
  CREATE POLICY "Authenticated can update voorraad custom fields" ON public.voorraad_custom_fields AS PERMISSIVE FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
9907
+ DROP POLICY IF EXISTS "Ingelogd mag ladingdragers lezen" ON public.voorraad_load_carrier_types;
9908
+ CREATE POLICY "Ingelogd mag ladingdragers lezen" ON public.voorraad_load_carrier_types AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9498
9909
  DROP POLICY IF EXISTS "Lokale context lezen" ON public.voorraad_local_context;
9499
9910
  CREATE POLICY "Lokale context lezen" ON public.voorraad_local_context AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9500
9911
  DROP POLICY IF EXISTS "Ingelogde gebruikers kunnen de eventlog lezen" ON public.voorraad_logistics_event_log;
@@ -9573,6 +9984,7 @@ DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad
9573
9984
  DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad: orders (Verkoop) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_orders_consume_on_complete AFTER UPDATE OF status ON public.orders FOR EACH ROW EXECUTE FUNCTION trg_orders_consume_on_complete_fn()$q$; END IF; END $g$;
9574
9985
  DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad: orders (Verkoop) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_orders_default_phase BEFORE INSERT ON public.orders FOR EACH ROW EXECUTE FUNCTION trg_orders_default_phase_fn()$q$; END IF; END $g$;
9575
9986
  DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad: orders (Verkoop) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_orders_external_fulfilled AFTER UPDATE OF custom_fields ON public.orders FOR EACH ROW EXECUTE FUNCTION trg_orders_external_fulfilled_fn()$q$; END IF; END $g$;
9987
+ DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad: orders (Verkoop) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_orders_fusten_au AFTER UPDATE OF status, cancelled_at, deleted_at ON public.orders FOR EACH ROW WHEN (((old.status IS DISTINCT FROM new.status) OR (old.cancelled_at IS DISTINCT FROM new.cancelled_at) OR (old.deleted_at IS DISTINCT FROM new.deleted_at))) EXECUTE FUNCTION trg_orders_fusten()$q$; END IF; END $g$;
9576
9988
  DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad: orders (Verkoop) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_orders_recompute_reserved AFTER DELETE OR UPDATE ON public.orders FOR EACH ROW EXECUTE FUNCTION trg_orders_recompute_reserved_fn()$q$; END IF; END $g$;
9577
9989
  DO $g$ BEGIN IF to_regclass('public.product_bom_items') IS NULL THEN RAISE NOTICE 'Voorraad: product_bom_items (core) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER set_product_bom_tenant_trigger BEFORE INSERT ON public.product_bom_items FOR EACH ROW EXECUTE FUNCTION set_product_bom_tenant()$q$; END IF; END $g$;
9578
9990
  DO $g$ BEGIN IF to_regclass('public.product_bom_items') IS NULL THEN RAISE NOTICE 'Voorraad: product_bom_items (core) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_check_product_structure BEFORE INSERT OR UPDATE ON public.product_bom_items FOR EACH ROW EXECUTE FUNCTION trg_check_product_structure()$q$; END IF; END $g$;
@@ -9594,6 +10006,7 @@ DO $g$ BEGIN IF to_regclass('public.products') IS NULL THEN RAISE NOTICE 'Voorra
9594
10006
  DO $g$ BEGIN IF to_regclass('public.products') IS NULL THEN RAISE NOTICE 'Voorraad: products (core) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_products_floriday_link_enqueue AFTER UPDATE ON public.products REFERENCING OLD TABLE AS old_rows NEW TABLE AS new_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_products_floriday_link_enqueue()$q$; END IF; END $g$;
9595
10007
  DO $g$ BEGIN IF to_regclass('public.products') IS NULL THEN RAISE NOTICE 'Voorraad: products (core) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_products_seed_stock AFTER INSERT OR UPDATE OF trade_item_key ON public.products FOR EACH ROW EXECUTE FUNCTION trg_products_seed_stock_fn()$q$; END IF; END $g$;
9596
10008
  DO $g$ BEGIN IF to_regclass('public.products') IS NULL THEN RAISE NOTICE 'Voorraad: products (core) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_requeue_skipped_no_price AFTER UPDATE OF sale_price, unit ON public.products FOR EACH ROW EXECUTE FUNCTION trg_requeue_skipped_no_price()$q$; END IF; END $g$;
10009
+ DO $g$ BEGIN IF to_regclass('public.products') IS NULL THEN RAISE NOTICE 'Voorraad: products (core) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_voorraad_link_primary_packing AFTER INSERT OR UPDATE OF floriday_trade_item_id ON public.products FOR EACH ROW EXECUTE FUNCTION trg_voorraad_link_primary_packing()$q$; END IF; END $g$;
9597
10010
  DROP TRIGGER IF EXISTS trg_stock_mutation_alert ON public.stock_mutation_log;
9598
10011
  CREATE TRIGGER trg_stock_mutation_alert AFTER INSERT ON public.stock_mutation_log FOR EACH ROW EXECUTE FUNCTION trg_stock_mutation_alert_fn();
9599
10012
  DROP TRIGGER IF EXISTS trg_prevent_duplicate_product_draft ON public.trade_item_drafts;