@flowselections/floriday-voorraad 1.0.125 → 1.0.129

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.
@@ -1,4 +1,4 @@
1
- -- @flowselections/floriday-voorraad 1.0.124 – volledig schema (idempotent, geen gegevens).
1
+ -- @flowselections/floriday-voorraad 1.0.128 – 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.
@@ -574,6 +574,11 @@ ALTER TABLE public.voorraad_media_upload_failures ADD COLUMN IF NOT EXISTS respo
574
574
  ALTER TABLE public.voorraad_media_upload_failures ADD COLUMN IF NOT EXISTS error_message text;
575
575
  ALTER TABLE public.voorraad_media_upload_failures ADD COLUMN IF NOT EXISTS client_user_id uuid;
576
576
 
577
+ -- voorraad_placeholder_codes
578
+ CREATE TABLE IF NOT EXISTS public.voorraad_placeholder_codes ();
579
+ ALTER TABLE public.voorraad_placeholder_codes ADD COLUMN IF NOT EXISTS code text NOT NULL;
580
+ ALTER TABLE public.voorraad_placeholder_codes ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
581
+
577
582
  -- voorraad_publish_attempts
578
583
  CREATE TABLE IF NOT EXISTS public.voorraad_publish_attempts ();
579
584
  ALTER TABLE public.voorraad_publish_attempts ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
@@ -1145,8 +1150,8 @@ BEGIN
1145
1150
  END;
1146
1151
 
1147
1152
  SELECT COALESCE(
1148
- NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''),
1149
1153
  NULLIF(trim(COALESCE(p.trade_item_key, '')), ''),
1154
+ NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''),
1150
1155
  p.id::text
1151
1156
  )
1152
1157
  INTO v_canonical
@@ -4193,7 +4198,7 @@ BEGIN
4193
4198
  IF auth.uid() IS NULL AND NOT public.voorraad_is_server() THEN RAISE EXCEPTION 'Niet ingelogd' USING ERRCODE = '42501'; END IF;
4194
4199
  SELECT NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''), NULLIF(trim(COALESCE(p.trade_item_key, '')), '')
4195
4200
  INTO v_floriday_key, v_product_key FROM public.products p WHERE p.id = p_product_id;
4196
- v_key := COALESCE(v_floriday_key, v_product_key, 'product:' || p_product_id::text);
4201
+ v_key := COALESCE(v_product_key, v_floriday_key, 'product:' || p_product_id::text);
4197
4202
  SELECT * INTO v_ctx FROM public.get_stock_context();
4198
4203
  v_connection_id := v_ctx.connection_id;
4199
4204
 
@@ -5982,7 +5987,7 @@ BEGIN
5982
5987
  SELECT NULLIF(trim(COALESCE(p.floriday_trade_item_id, '')), ''), NULLIF(trim(COALESCE(p.trade_item_key, '')), '')
5983
5988
  INTO v_floriday_key, v_product_key FROM public.products p WHERE p.id = p_product_id;
5984
5989
  IF NOT FOUND THEN RAISE EXCEPTION 'Product niet gevonden'; END IF;
5985
- v_key := COALESCE(v_floriday_key, v_product_key, 'product:' || p_product_id::text);
5990
+ v_key := COALESCE(v_product_key, v_floriday_key, 'product:' || p_product_id::text);
5986
5991
 
5987
5992
  -- Context: Floriday-koppeling (omgeving, anders de enige actieve) of de lokale context.
5988
5993
  SELECT * INTO v_ctx FROM public.get_stock_context(true);
@@ -6463,53 +6468,18 @@ CREATE OR REPLACE FUNCTION public.sync_products_quantity_from_stock()
6463
6468
  SECURITY DEFINER
6464
6469
  SET search_path TO 'public'
6465
6470
  AS $function$
6466
- DECLARE
6467
- v_key text;
6468
- v_qty integer;
6469
- v_uuid uuid;
6471
+ DECLARE k text; c uuid;
6470
6472
  BEGIN
6471
- IF TG_OP = 'DELETE' THEN
6472
- v_key := OLD.trade_item_key;
6473
- v_qty := 0;
6474
- ELSE
6475
- v_key := NEW.trade_item_key;
6476
- v_qty := COALESCE(NEW.physical_stock, 0);
6477
- END IF;
6478
-
6479
- IF v_key IS NULL THEN
6480
- RETURN COALESCE(NEW, OLD);
6481
- END IF;
6482
-
6483
- -- Oude vorm `product:<uuid>`
6484
- IF position('product:' in v_key) = 1 THEN
6485
- BEGIN
6486
- v_uuid := substring(v_key from 9)::uuid;
6487
- EXCEPTION WHEN others THEN
6488
- v_uuid := NULL;
6489
- END;
6490
- IF v_uuid IS NOT NULL THEN
6491
- UPDATE public.products SET quantity = v_qty WHERE id = v_uuid;
6492
- END IF;
6493
- RETURN COALESCE(NEW, OLD);
6494
- END IF;
6495
-
6496
- -- Canonieke vorm: eigen sleutel of Floriday-artikel-ID
6497
- UPDATE public.products
6498
- SET quantity = v_qty
6499
- WHERE trade_item_key = v_key
6500
- OR floriday_trade_item_id::text = v_key;
6501
-
6502
- RETURN COALESCE(NEW, OLD);
6503
- END;
6504
- $function$
6473
+ PERFORM public.voorraad_vereis('ingelogd','sync_products_quantity_from_stock');
6474
+ k:=CASE WHEN TG_OP='DELETE' THEN OLD.trade_item_key ELSE NEW.trade_item_key END;
6475
+ c:=CASE WHEN TG_OP='DELETE' THEN OLD.connection_id ELSE NEW.connection_id END;
6476
+ 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)
6477
+ WHERE p.trade_item_key=k OR p.floriday_trade_item_id=k OR 'product:'||p.id::text=k;
6478
+ RETURN COALESCE(NEW,OLD);
6479
+ END $function$
6505
6480
  ;
6506
6481
  REVOKE ALL ON FUNCTION sync_products_quantity_from_stock() FROM PUBLIC;
6507
6482
  REVOKE ALL ON FUNCTION sync_products_quantity_from_stock() FROM anon;
6508
- REVOKE EXECUTE ON FUNCTION sync_products_quantity_from_stock() FROM PUBLIC;
6509
- GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO authenticated;
6510
- GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO service_role;
6511
- REVOKE EXECUTE ON FUNCTION sync_products_quantity_from_stock() FROM anon;
6512
- GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO authenticated;
6513
6483
  GRANT EXECUTE ON FUNCTION sync_products_quantity_from_stock() TO service_role;
6514
6484
  CREATE OR REPLACE FUNCTION public.touch_fust_types_updated_at()
6515
6485
  RETURNS trigger
@@ -7171,6 +7141,27 @@ END $function$
7171
7141
  REVOKE ALL ON FUNCTION trg_products_floriday_link_enqueue() FROM PUBLIC;
7172
7142
  REVOKE ALL ON FUNCTION trg_products_floriday_link_enqueue() FROM anon;
7173
7143
  GRANT EXECUTE ON FUNCTION trg_products_floriday_link_enqueue() TO service_role;
7144
+ CREATE OR REPLACE FUNCTION public.trg_products_placeholder_code()
7145
+ RETURNS trigger
7146
+ LANGUAGE plpgsql
7147
+ SECURITY DEFINER
7148
+ SET search_path TO 'public'
7149
+ AS $function$
7150
+ DECLARE v text := lower(btrim(coalesce(NEW.article_number, '')));
7151
+ BEGIN
7152
+ IF TG_OP = 'UPDATE' AND NEW.article_number IS NOT DISTINCT FROM OLD.article_number THEN RETURN NEW; END IF;
7153
+ IF v = '' OR NOT EXISTS (SELECT 1 FROM public.voorraad_placeholder_codes c WHERE c.code = v) THEN RETURN NEW; END IF;
7154
+ IF public.voorraad_is_server() THEN
7155
+ RAISE WARNING 'Artikel %: "%" is een invultekst als artikelcode (gemeld, niet geweigerd).', NEW.id, NEW.article_number;
7156
+ RETURN NEW;
7157
+ END IF;
7158
+ RAISE EXCEPTION '"%" is een invultekst, geen artikelcode. Vul de echte artikelcode in.', btrim(NEW.article_number)
7159
+ USING ERRCODE = 'P0001';
7160
+ END $function$
7161
+ ;
7162
+ REVOKE ALL ON FUNCTION trg_products_placeholder_code() FROM PUBLIC;
7163
+ REVOKE ALL ON FUNCTION trg_products_placeholder_code() FROM anon;
7164
+ GRANT EXECUTE ON FUNCTION trg_products_placeholder_code() TO service_role;
7174
7165
  CREATE OR REPLACE FUNCTION public.trg_products_seed_stock_fn()
7175
7166
  RETURNS trigger
7176
7167
  LANGUAGE plpgsql
@@ -7723,6 +7714,26 @@ GRANT EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() TO service_role;
7723
7714
  REVOKE EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() FROM anon;
7724
7715
  GRANT EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() TO authenticated;
7725
7716
  GRANT EXECUTE ON FUNCTION trg_trade_items_cache_autolink_fn() TO service_role;
7717
+ CREATE OR REPLACE FUNCTION public.trg_voorraad_link_primary_packing()
7718
+ RETURNS trigger
7719
+ LANGUAGE plpgsql
7720
+ SECURITY DEFINER
7721
+ SET search_path TO 'public'
7722
+ AS $function$
7723
+ BEGIN
7724
+ PERFORM public.voorraad_vereis('ingelogd','trg_voorraad_link_primary_packing');
7725
+ IF NULLIF(btrim(NEW.floriday_trade_item_id),'') IS NOT NULL THEN
7726
+ IF TG_OP='INSERT' OR NEW.floriday_trade_item_id IS DISTINCT FROM OLD.floriday_trade_item_id THEN
7727
+ PERFORM public.voorraad_packing_from_floriday(NEW.id,true);
7728
+ END IF;
7729
+ END IF;
7730
+ RETURN NEW;
7731
+ END $function$
7732
+ ;
7733
+ REVOKE ALL ON FUNCTION trg_voorraad_link_primary_packing() FROM PUBLIC;
7734
+ REVOKE ALL ON FUNCTION trg_voorraad_link_primary_packing() FROM anon;
7735
+ GRANT EXECUTE ON FUNCTION trg_voorraad_link_primary_packing() TO authenticated;
7736
+ GRANT EXECUTE ON FUNCTION trg_voorraad_link_primary_packing() TO service_role;
7726
7737
  CREATE OR REPLACE FUNCTION public.update_updated_at_column()
7727
7738
  RETURNS trigger
7728
7739
  LANGUAGE plpgsql
@@ -8546,47 +8557,88 @@ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1124(p_uitvoeren boolean DE
8546
8557
  SECURITY DEFINER
8547
8558
  SET search_path TO 'public'
8548
8559
  AS $function$
8549
- DECLARE
8550
- c_product constant uuid := '4e62fc60-e9b7-468f-8cc4-cdf64b938f57';
8551
- c_fid constant text := 'c3406752-b5e0-438b-b3a9-109b58b9e970';
8552
- c_prijs constant numeric := 2.40;
8553
- v_p record; v_ander int; v_voor jsonb; v_na jsonb; v_status text; v_fid_rows int;
8554
- BEGIN
8555
- PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1124');
8556
- SELECT * INTO v_p FROM public.products WHERE id = c_product FOR UPDATE;
8557
- SELECT count(*) INTO v_ander FROM public.products WHERE id <> c_product AND floriday_trade_item_id = c_fid;
8558
- SELECT count(*) INTO v_fid_rows FROM public.trade_item_stock WHERE trade_item_key = c_fid;
8559
- SELECT COALESCE(jsonb_agg(jsonb_build_object('id', s.id, 'sleutel', s.trade_item_key, 'koppeling', s.connection_id,
8560
- 'fysiek', s.physical_stock, 'gereserveerd', s.reserved_stock, 'inkomend', s.incoming_stock) ORDER BY s.trade_item_key), '[]'::jsonb)
8561
- INTO v_voor FROM public.trade_item_stock s WHERE s.trade_item_key IN (c_fid, 'product:' || c_product::text, c_product::text);
8562
- IF v_p.id IS NULL THEN v_status := 'overgeslagen: artikel niet in deze database';
8563
- ELSIF v_ander > 0 THEN v_status := 'overgeslagen: Floriday-artikel al aan ander artikel gekoppeld';
8564
- ELSIF v_p.floriday_trade_item_id IS NOT NULL AND v_p.floriday_trade_item_id <> c_fid THEN v_status := 'overgeslagen: al aan ander Floriday-artikel gekoppeld';
8565
- ELSIF v_fid_rows <> 1 THEN v_status := 'overgeslagen: verwacht precies één voorraadrij op de Floriday-sleutel, gevonden ' || v_fid_rows;
8566
- ELSIF v_p.floriday_trade_item_id = c_fid AND v_p.sale_price = c_prijs THEN v_status := 'al uitgevoerd';
8567
- ELSE v_status := CASE WHEN p_uitvoeren THEN 'uitgevoerd' ELSE 'voorstel' END;
8568
- END IF;
8569
- IF v_status = 'uitgevoerd' THEN
8570
- UPDATE public.products SET floriday_trade_item_id = COALESCE(floriday_trade_item_id, c_fid), sale_price = c_prijs, updated_at = now()
8571
- WHERE id = c_product;
8572
- SELECT COALESCE(jsonb_agg(jsonb_build_object('id', s.id, 'sleutel', s.trade_item_key, 'koppeling', s.connection_id,
8573
- 'fysiek', s.physical_stock, 'gereserveerd', s.reserved_stock, 'inkomend', s.incoming_stock) ORDER BY s.trade_item_key), '[]'::jsonb)
8574
- INTO v_na FROM public.trade_item_stock s WHERE s.trade_item_key IN (c_fid, 'product:' || c_product::text, c_product::text);
8575
- INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8576
- VALUES ('voorraad_correctie_1124', COALESCE(auth.uid()::text, session_user::text), false,
8577
- jsonb_build_object('artikel', c_product, 'floriday_id', c_fid, 'prijs_voor', v_p.sale_price, 'prijs_na', c_prijs,
8578
- 'voorraad_voor', v_voor, 'voorraad_na', v_na), NULL);
8579
- END IF;
8580
- RETURN jsonb_build_object('ok', true, 'proef', NOT p_uitvoeren, 'status', v_status,
8581
- 'artikel', jsonb_build_object('id', c_product, 'code', v_p.article_number, 'floriday_id_voor', v_p.floriday_trade_item_id,
8582
- 'floriday_id_na', c_fid, 'prijs_voor', v_p.sale_price, 'prijs_na', c_prijs),
8583
- 'voorraad_voor', v_voor, 'voorraad_na', COALESCE(v_na, v_voor),
8584
- 'uitleg', 'Lijst en Floriday-publicatie lezen na koppelen de Floriday-sleutel (500). De rij op de eigen sleutel staat op 0 en telt dus niet dubbel.');
8560
+ BEGIN
8561
+ PERFORM public.voorraad_vereis('server','voorraad_correctie_1124');
8562
+ RETURN public.voorraad_correctie_1126(p_uitvoeren);
8585
8563
  END $function$
8586
8564
  ;
8587
8565
  REVOKE ALL ON FUNCTION voorraad_correctie_1124(boolean) FROM PUBLIC;
8588
8566
  REVOKE ALL ON FUNCTION voorraad_correctie_1124(boolean) FROM anon;
8589
8567
  GRANT EXECUTE ON FUNCTION voorraad_correctie_1124(boolean) TO service_role;
8568
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1126(p_uitvoeren boolean DEFAULT false)
8569
+ RETURNS jsonb
8570
+ LANGUAGE plpgsql
8571
+ SECURITY DEFINER
8572
+ SET search_path TO 'public'
8573
+ AS $function$
8574
+ DECLARE
8575
+ pid constant uuid:='4e62fc60-e9b7-468f-8cc4-cdf64b938f57'; fid constant text:='c3406752-b5e0-438b-b3a9-109b58b9e970';
8576
+ 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;
8577
+ BEGIN
8578
+ PERFORM public.voorraad_vereis('server','voorraad_correctie_1126');
8579
+ PERFORM pg_advisory_xact_lock(hashtextextended('voorraad_correctie_1126',0));
8580
+ SELECT * INTO p FROM public.products WHERE id=pid FOR UPDATE;
8581
+ SELECT * INTO ctx FROM public.get_stock_context();
8582
+ 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;
8583
+ SELECT * INTO ownrow FROM public.trade_item_stock WHERE connection_id=ctx.connection_id AND trade_item_key=p.trade_item_key;
8584
+ SELECT * INTO fdrow FROM public.trade_item_stock WHERE connection_id=ctx.connection_id AND trade_item_key=fid;
8585
+ 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);
8586
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO ch FROM public.floriday_trade_items_cache t;
8587
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO qh FROM public.floriday_continuous_stock_queue t;
8588
+ 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';
8589
+ 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';
8590
+ ELSIF ownrow.physical_stock=500 AND fdrow.physical_stock=0 THEN status:='al uitgevoerd';
8591
+ ELSIF ownrow.physical_stock<>0 OR fdrow.physical_stock<>500 OR p.sale_price<>2.40 THEN status:='overgeslagen: stand of prijs gewijzigd';
8592
+ ELSE status:=CASE WHEN p_uitvoeren THEN 'uitgevoerd' ELSE 'voorstel' END; END IF;
8593
+ IF status='uitgevoerd' THEN
8594
+ handled:=COALESCE(NULLIF(current_setting('stock.log_handled',true),''),';');
8595
+ PERFORM set_config('stock.log_handled',handled||ctx.connection_id||'|'||fid||'|0|0;'||ctx.connection_id||'|'||p.trade_item_key||'|500|0;',true);
8596
+ UPDATE public.trade_item_stock SET physical_stock=0,change_source='FLORIDAY_PUBLICATION',updated_at=now() WHERE id=fdrow.id;
8597
+ UPDATE public.trade_item_stock SET physical_stock=500,change_source='FLORIDAY_PUBLICATION',updated_at=now() WHERE id=ownrow.id;
8598
+ 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)
8599
+ 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()),
8600
+ (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());
8601
+ PERFORM set_config('stock.log_handled',handled,true);
8602
+ END IF;
8603
+ 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);
8604
+ 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);
8605
+ IF NOT unchanged THEN RAISE EXCEPTION 'Floriday-kopie of wachtrij gewijzigd; correctie teruggedraaid'; END IF;
8606
+ 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);
8607
+ 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);
8608
+ RETURN result;
8609
+ END $function$
8610
+ ;
8611
+ REVOKE ALL ON FUNCTION voorraad_correctie_1126(boolean) FROM PUBLIC;
8612
+ REVOKE ALL ON FUNCTION voorraad_correctie_1126(boolean) FROM anon;
8613
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1126(boolean) TO service_role;
8614
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1127(p_uitvoeren boolean DEFAULT false)
8615
+ RETURNS jsonb
8616
+ LANGUAGE plpgsql
8617
+ SECURITY DEFINER
8618
+ SET search_path TO 'public'
8619
+ AS $function$
8620
+ DECLARE pid constant uuid:='4e62fc60-e9b7-468f-8cc4-cdf64b938f57'; r jsonb; ch text; qh text; okhash boolean;
8621
+ BEGIN
8622
+ PERFORM public.voorraad_vereis('server','voorraad_correctie_1127');
8623
+ PERFORM 1 FROM public.products WHERE id=pid FOR UPDATE;
8624
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO ch FROM public.floriday_trade_items_cache t;
8625
+ SELECT md5(COALESCE(string_agg(t::text,'|' ORDER BY t::text),'')) INTO qh FROM public.floriday_continuous_stock_queue t;
8626
+ r:=public.voorraad_packing_from_floriday(pid,false);
8627
+ IF NOT EXISTS(SELECT 1 FROM public.product_packings WHERE product_id=pid AND is_primary) THEN
8628
+ 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
8629
+ RAISE EXCEPTION 'Floriday-belading wijkt af van het goedgekeurde overzicht; niets overgenomen';
8630
+ END IF;
8631
+ END IF;
8632
+ IF p_uitvoeren THEN r:=public.voorraad_packing_from_floriday(pid,true); END IF;
8633
+ 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);
8634
+ IF NOT okhash THEN RAISE EXCEPTION 'Floriday-kopie of wachtrij gewijzigd; correctie teruggedraaid'; END IF;
8635
+ 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);
8636
+ RETURN r||jsonb_build_object('hash_ok',okhash);
8637
+ END $function$
8638
+ ;
8639
+ REVOKE ALL ON FUNCTION voorraad_correctie_1127(boolean) FROM PUBLIC;
8640
+ REVOKE ALL ON FUNCTION voorraad_correctie_1127(boolean) FROM anon;
8641
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1127(boolean) TO service_role;
8590
8642
  CREATE OR REPLACE FUNCTION public.voorraad_correctie_status(p_correctie text DEFAULT '1098'::text)
8591
8643
  RETURNS jsonb
8592
8644
  LANGUAGE plpgsql
@@ -8895,8 +8947,8 @@ CREATE OR REPLACE FUNCTION public.voorraad_install_check()
8895
8947
  STABLE SECURITY DEFINER
8896
8948
  SET search_path TO 'public'
8897
8949
  AS $function$
8898
- 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_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'];
8899
- 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'];
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'];
8951
+ 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'];
8900
8952
  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'];
8901
8953
  v_open text[] := ARRAY['voorraad_is_server','voorraad_vereis'];
8902
8954
  v_func jsonb; v_trig jsonb; v_pol jsonb;
@@ -9021,6 +9073,92 @@ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zo
9021
9073
  REVOKE EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM anon;
9022
9074
  GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO authenticated;
9023
9075
  GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO service_role;
9076
+ CREATE OR REPLACE FUNCTION public.voorraad_packing_from_floriday(p_product_id uuid, p_uitvoeren boolean)
9077
+ RETURNS jsonb
9078
+ LANGUAGE plpgsql
9079
+ SET search_path TO 'public'
9080
+ AS $function$
9081
+ DECLARE p record; ctx record; cfg jsonb; d jsonb; missing text[]:='{}'; n int; f uuid; result jsonb; msg text; copied boolean:=false;
9082
+ BEGIN
9083
+ PERFORM public.voorraad_vereis('ingelogd','voorraad_packing_from_floriday');
9084
+ 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;
9085
+ SELECT * INTO p FROM public.products WHERE id=p_product_id FOR UPDATE;
9086
+ IF NOT FOUND THEN RAISE EXCEPTION 'Artikel niet gevonden' USING ERRCODE='P0001'; END IF;
9087
+ IF EXISTS(SELECT 1 FROM public.product_packings WHERE product_id=p_product_id AND is_primary) THEN
9088
+ RETURN jsonb_build_object('ok',true,'copied',false,'melding','Hoofdverpakking bestaat al; niets overschreven');
9089
+ END IF;
9090
+ SELECT * INTO ctx FROM public.get_stock_context();
9091
+ 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);
9092
+ IF d IS NULL THEN msg:='Hoofdverpakking niet overgenomen: artikel ontbreekt in de Floriday-kopie';
9093
+ ELSE
9094
+ 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;
9095
+ IF n<>1 THEN msg:='Hoofdverpakking niet overgenomen: verwacht één primaire Floriday-verpakking, gevonden '||n;
9096
+ ELSE
9097
+ missing:=public.voorraad_packing_missing(cfg);IF cardinality(missing)>0 THEN msg:='Hoofdverpakking niet overgenomen: ontbrekend of ongeldig: '||array_to_string(missing,', ');
9098
+ ELSE
9099
+ 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;
9100
+ IF p_uitvoeren THEN
9101
+ 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)
9102
+ 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))));
9103
+ copied:=true;
9104
+ END IF;
9105
+ msg:=CASE WHEN p_uitvoeren THEN 'Hoofdverpakking overgenomen uit Floriday' ELSE 'Volledige hoofdverpakking beschikbaar om over te nemen' END;
9106
+ END IF;
9107
+ END IF;
9108
+ END IF;
9109
+ result:=jsonb_build_object('ok',msg NOT LIKE 'Hoofdverpakking niet%','copied',copied,'melding',msg,'missing',to_jsonb(missing),'packing',cfg);
9110
+ 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;
9111
+ RETURN result;
9112
+ END $function$
9113
+ ;
9114
+ REVOKE ALL ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) FROM PUBLIC;
9115
+ REVOKE ALL ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) FROM anon;
9116
+ GRANT EXECUTE ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) TO authenticated;
9117
+ GRANT EXECUTE ON FUNCTION voorraad_packing_from_floriday(uuid,boolean) TO service_role;
9118
+ CREATE OR REPLACE FUNCTION public.voorraad_packing_missing(p_packing jsonb)
9119
+ RETURNS text[]
9120
+ LANGUAGE plpgsql
9121
+ STABLE
9122
+ SET search_path TO 'public'
9123
+ AS $function$
9124
+ DECLARE missing text[]:='{}';
9125
+ BEGIN
9126
+ PERFORM public.voorraad_vereis('ingelogd','voorraad_packing_missing');
9127
+ IF COALESCE(p_packing#>>'{package,vbnPackageCode}','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'fust (vbnPackageCode)'); END IF;
9128
+ IF COALESCE(p_packing->>'piecesPerPackage','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'planten per fust'); END IF;
9129
+ IF COALESCE(p_packing->>'packagesPerLayer','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'fusten per laag'); END IF;
9130
+ IF COALESCE(p_packing->>'layersPerLoadCarrier','') !~ '^[1-9][0-9]{0,8}$' THEN missing:=array_append(missing,'lagen per kar'); END IF;
9131
+ IF NOT EXISTS(SELECT 1 FROM public.voorraad_load_carrier_types WHERE code=p_packing->>'loadCarrier') THEN missing:=array_append(missing,'ladingdrager'); END IF;
9132
+ RETURN missing;
9133
+ END $function$
9134
+ ;
9135
+ REVOKE ALL ON FUNCTION voorraad_packing_missing(jsonb) FROM PUBLIC;
9136
+ REVOKE ALL ON FUNCTION voorraad_packing_missing(jsonb) FROM anon;
9137
+ GRANT EXECUTE ON FUNCTION voorraad_packing_missing(jsonb) TO authenticated;
9138
+ GRANT EXECUTE ON FUNCTION voorraad_packing_missing(jsonb) TO service_role;
9139
+ CREATE OR REPLACE FUNCTION public.voorraad_placeholder_code_reason(p_code text, p_name text)
9140
+ RETURNS text
9141
+ LANGUAGE plpgsql
9142
+ STABLE
9143
+ SET search_path TO 'public'
9144
+ AS $function$
9145
+ DECLARE v text := lower(btrim(coalesce(p_code, '')));
9146
+ BEGIN
9147
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_placeholder_code_reason');
9148
+ IF v = '' THEN RETURN 'De artikelcode is leeg.'; END IF;
9149
+ IF EXISTS (SELECT 1 FROM public.voorraad_placeholder_codes c WHERE c.code = v) THEN
9150
+ RETURN format('"%s" is een invultekst, geen artikelcode.', btrim(p_code));
9151
+ END IF;
9152
+ IF p_name IS NOT NULL AND v = lower(btrim(p_name)) THEN
9153
+ RETURN 'De artikelcode is gelijk aan de artikelnaam.';
9154
+ END IF;
9155
+ RETURN NULL;
9156
+ END $function$
9157
+ ;
9158
+ REVOKE ALL ON FUNCTION voorraad_placeholder_code_reason(text,text) FROM PUBLIC;
9159
+ REVOKE ALL ON FUNCTION voorraad_placeholder_code_reason(text,text) FROM anon;
9160
+ GRANT EXECUTE ON FUNCTION voorraad_placeholder_code_reason(text,text) TO authenticated;
9161
+ GRANT EXECUTE ON FUNCTION voorraad_placeholder_code_reason(text,text) TO service_role;
9024
9162
  CREATE OR REPLACE FUNCTION public.voorraad_production_enabled()
9025
9163
  RETURNS boolean
9026
9164
  LANGUAGE sql
@@ -9417,6 +9555,7 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraa
9417
9555
  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$;
9418
9556
  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$;
9419
9557
  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$;
9558
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_placeholder_codes_pkey' AND conrelid = 'public.voorraad_placeholder_codes'::regclass) THEN ALTER TABLE public.voorraad_placeholder_codes ADD CONSTRAINT voorraad_placeholder_codes_pkey PRIMARY KEY (code); END IF; END $c$;
9420
9559
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_publish_attempts_pkey' AND conrelid = 'public.voorraad_publish_attempts'::regclass) THEN ALTER TABLE public.voorraad_publish_attempts ADD CONSTRAINT voorraad_publish_attempts_pkey PRIMARY KEY (id); END IF; END $c$;
9421
9560
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_publish_jobs_pkey' AND conrelid = 'public.voorraad_publish_jobs'::regclass) THEN ALTER TABLE public.voorraad_publish_jobs ADD CONSTRAINT voorraad_publish_jobs_pkey PRIMARY KEY (id); END IF; END $c$;
9422
9561
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_publish_learnings_pkey' AND conrelid = 'public.voorraad_publish_learnings'::regclass) THEN ALTER TABLE public.voorraad_publish_learnings ADD CONSTRAINT voorraad_publish_learnings_pkey PRIMARY KEY (id); END IF; END $c$;
@@ -9683,6 +9822,10 @@ ALTER TABLE public.voorraad_media_upload_failures ENABLE ROW LEVEL SECURITY;
9683
9822
  REVOKE ALL ON public.voorraad_media_upload_failures FROM anon;
9684
9823
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_media_upload_failures TO authenticated;
9685
9824
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_media_upload_failures TO service_role;
9825
+ ALTER TABLE public.voorraad_placeholder_codes ENABLE ROW LEVEL SECURITY;
9826
+ REVOKE ALL ON public.voorraad_placeholder_codes FROM anon;
9827
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_placeholder_codes TO authenticated;
9828
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_placeholder_codes TO service_role;
9686
9829
  ALTER TABLE public.voorraad_publish_attempts ENABLE ROW LEVEL SECURITY;
9687
9830
  REVOKE ALL ON public.voorraad_publish_attempts FROM anon;
9688
9831
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_publish_attempts TO authenticated;
@@ -9823,6 +9966,8 @@ DROP POLICY IF EXISTS "Ingelogde gebruikers kunnen de eventlog lezen" ON public.
9823
9966
  CREATE POLICY "Ingelogde gebruikers kunnen de eventlog lezen" ON public.voorraad_logistics_event_log AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9824
9967
  DROP POLICY IF EXISTS "service role only" ON public.voorraad_media_upload_failures;
9825
9968
  CREATE POLICY "service role only" ON public.voorraad_media_upload_failures AS PERMISSIVE FOR ALL TO service_role USING (true) WITH CHECK (true);
9969
+ DROP POLICY IF EXISTS "Ingelogd mag invulteksten lezen" ON public.voorraad_placeholder_codes;
9970
+ CREATE POLICY "Ingelogd mag invulteksten lezen" ON public.voorraad_placeholder_codes AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9826
9971
  DROP POLICY IF EXISTS "Users can insert own publish attempts" ON public.voorraad_publish_attempts;
9827
9972
  CREATE POLICY "Users can insert own publish attempts" ON public.voorraad_publish_attempts AS PERMISSIVE FOR INSERT TO authenticated WITH CHECK ((auth.uid() = user_id));
9828
9973
  DROP POLICY IF EXISTS "Users can read own publish attempts" ON public.voorraad_publish_attempts;
@@ -9915,8 +10060,10 @@ CREATE TRIGGER trg_product_tray_stickers_touch BEFORE UPDATE ON public.product_t
9915
10060
  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_floriday_ensure_inventory_settings AFTER INSERT ON public.products FOR EACH ROW EXECUTE FUNCTION floriday_ensure_inventory_settings()$q$; END IF; END $g$;
9916
10061
  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_autolink BEFORE INSERT OR UPDATE OF product, trade_item_key ON public.products FOR EACH ROW EXECUTE FUNCTION trg_products_autolink_fn()$q$; END IF; END $g$;
9917
10062
  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$;
10063
+ 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_placeholder_code BEFORE INSERT OR UPDATE OF article_number ON public.products FOR EACH ROW EXECUTE FUNCTION trg_products_placeholder_code()$q$; END IF; END $g$;
9918
10064
  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$;
9919
10065
  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$;
10066
+ 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$;
9920
10067
  DROP TRIGGER IF EXISTS trg_stock_mutation_alert ON public.stock_mutation_log;
9921
10068
  CREATE TRIGGER trg_stock_mutation_alert AFTER INSERT ON public.stock_mutation_log FOR EACH ROW EXECUTE FUNCTION trg_stock_mutation_alert_fn();
9922
10069
  DROP TRIGGER IF EXISTS trg_prevent_duplicate_product_draft ON public.trade_item_drafts;