@flowselections/floriday-voorraad 1.0.121 → 1.0.125

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 (45) 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.js +1 -1
  14. package/dist-lib/hooks/useLoadCarriers.d.ts +12 -0
  15. package/dist-lib/hooks/useLoadCarriers.d.ts.map +1 -0
  16. package/dist-lib/hooks/useLoadCarriers.js +49 -0
  17. package/dist-lib/hooks/usePublishJob.d.ts +1 -0
  18. package/dist-lib/hooks/usePublishJob.d.ts.map +1 -1
  19. package/dist-lib/hooks/usePublishJob.js +20 -1
  20. package/dist-lib/hooks/useStockSyncHealth.d.ts +3 -1
  21. package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -1
  22. package/dist-lib/hooks/useStockSyncHealth.js +68 -19
  23. package/dist-lib/integrations/supabase/types.d.ts +192 -0
  24. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  25. package/dist-lib/lib/__tests__/erp-test-123.test.d.ts +2 -0
  26. package/dist-lib/lib/__tests__/erp-test-123.test.d.ts.map +1 -0
  27. package/dist-lib/lib/__tests__/erp-test-123.test.js +43 -0
  28. package/dist-lib/lib/__tests__/load-carriers.test.d.ts +2 -0
  29. package/dist-lib/lib/__tests__/load-carriers.test.d.ts.map +1 -0
  30. package/dist-lib/lib/__tests__/load-carriers.test.js +15 -0
  31. package/dist-lib/lib/buyer-organizations.d.ts +26 -0
  32. package/dist-lib/lib/buyer-organizations.d.ts.map +1 -0
  33. package/dist-lib/lib/buyer-organizations.js +41 -0
  34. package/dist-lib/lib/floriday-customer-offer.functions.d.ts +4 -0
  35. package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
  36. package/dist-lib/lib/floriday-customer-offer.functions.js +54 -16
  37. package/dist-lib/lib/floriday-info.d.ts +0 -1
  38. package/dist-lib/lib/floriday-info.d.ts.map +1 -1
  39. package/dist-lib/lib/floriday-info.js +0 -8
  40. package/dist-lib/lib/simple-packing.d.ts +31 -0
  41. package/dist-lib/lib/simple-packing.d.ts.map +1 -0
  42. package/dist-lib/lib/simple-packing.js +62 -0
  43. package/package.json +1 -1
  44. package/sql/AGENTS.md +2 -1
  45. package/sql/floriday-voorraad-schema.sql +328 -5
@@ -1,4 +1,4 @@
1
- -- @flowselections/floriday-voorraad 1.0.120 – volledig schema (idempotent, geen gegevens).
1
+ -- @flowselections/floriday-voorraad 1.0.124 – 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;
@@ -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
@@ -6958,6 +6966,26 @@ END $function$
6958
6966
  REVOKE ALL ON FUNCTION trg_orders_external_fulfilled_fn() FROM PUBLIC;
6959
6967
  REVOKE ALL ON FUNCTION trg_orders_external_fulfilled_fn() FROM anon;
6960
6968
  GRANT EXECUTE ON FUNCTION trg_orders_external_fulfilled_fn() TO service_role;
6969
+ CREATE OR REPLACE FUNCTION public.trg_orders_fusten()
6970
+ RETURNS trigger
6971
+ LANGUAGE plpgsql
6972
+ SECURITY DEFINER
6973
+ SET search_path TO 'public'
6974
+ AS $function$
6975
+ DECLARE v_id uuid;
6976
+ BEGIN
6977
+ IF public.voorraad_order_geannuleerd(OLD.status, OLD.cancelled_at, OLD.deleted_at)
6978
+ IS DISTINCT FROM public.voorraad_order_geannuleerd(NEW.status, NEW.cancelled_at, NEW.deleted_at) THEN
6979
+ FOR v_id IN SELECT id FROM public.order_items WHERE order_id = NEW.id ORDER BY id LOOP
6980
+ PERFORM public.sync_order_item_fusten(v_id);
6981
+ END LOOP;
6982
+ END IF;
6983
+ RETURN NEW;
6984
+ END $function$
6985
+ ;
6986
+ REVOKE ALL ON FUNCTION trg_orders_fusten() FROM PUBLIC;
6987
+ REVOKE ALL ON FUNCTION trg_orders_fusten() FROM anon;
6988
+ GRANT EXECUTE ON FUNCTION trg_orders_fusten() TO service_role;
6961
6989
  CREATE OR REPLACE FUNCTION public.trg_orders_recompute_reserved_fn()
6962
6990
  RETURNS trigger
6963
6991
  LANGUAGE plpgsql
@@ -8369,6 +8397,196 @@ $function$
8369
8397
  REVOKE ALL ON FUNCTION voorraad_correctie_1120(boolean) FROM PUBLIC;
8370
8398
  REVOKE ALL ON FUNCTION voorraad_correctie_1120(boolean) FROM anon;
8371
8399
  GRANT EXECUTE ON FUNCTION voorraad_correctie_1120(boolean) TO service_role;
8400
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1121(p_uitvoeren boolean DEFAULT false)
8401
+ RETURNS jsonb
8402
+ LANGUAGE plpgsql
8403
+ SECURITY DEFINER
8404
+ SET search_path TO 'public'
8405
+ AS $function$
8406
+ DECLARE
8407
+ r record; v_now int; v_delta int; v_status text; v_user uuid; v_note text;
8408
+ v_fust jsonb; v_regels jsonb; v_wie text := COALESCE(auth.uid()::text, session_user::text);
8409
+ BEGIN
8410
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1121');
8411
+ CREATE TEMP TABLE _c1121 ON COMMIT DROP AS SELECT * FROM public.voorraad_correctie_1121_regels();
8412
+ ALTER TABLE _c1121 ADD COLUMN status text, ADD COLUMN geboekt_delta int DEFAULT 0;
8413
+ CREATE INDEX _c1121_idx ON _c1121 (order_item_id, fust_type_id); ANALYZE _c1121;
8414
+ CREATE TEMP TABLE _c1121_voor ON COMMIT DROP AS
8415
+ SELECT ft.id, ft.name, ft.stock FROM public.fust_types ft WHERE ft.id IN (SELECT DISTINCT fust_type_id FROM _c1121);
8416
+
8417
+ FOR r IN SELECT * FROM _c1121 ORDER BY fust_type_id, order_item_id LOOP
8418
+ IF r.fust_type_id IS NULL OR r.order_item_id IS NULL THEN v_status := 'overgeslagen: geen fustsoort of regel';
8419
+ ELSE
8420
+ PERFORM 1 FROM public.order_fust_bookings b
8421
+ WHERE b.order_item_id = r.order_item_id AND public.voorraad_active_fust_id(NULL, b.fust_type_id) = r.fust_type_id
8422
+ ORDER BY b.id FOR UPDATE;
8423
+ SELECT COALESCE(sum(b.quantity), 0)::int INTO v_now FROM public.order_fust_bookings b
8424
+ WHERE b.order_item_id = r.order_item_id AND public.voorraad_active_fust_id(NULL, b.fust_type_id) = r.fust_type_id;
8425
+ IF v_now <> r.netto_geboekt THEN v_status := 'overgeslagen: geboekt veranderd (' || r.netto_geboekt || ' → ' || v_now || ')';
8426
+ ELSIF NOT p_uitvoeren THEN v_status := 'voorstel';
8427
+ ELSE
8428
+ v_delta := r.netto_geboekt - r.juist; -- >0 = fust terug (tegenboeking), <0 = extra afboeken
8429
+ v_note := 'Correctie 1121 · ' || COALESCE('Order ' || r.order_number, 'regel bestaat niet meer') || ' · regel ' || r.order_item_id || ' · ' || r.reden;
8430
+ SELECT user_id INTO v_user FROM public.fust_types WHERE id = r.fust_type_id;
8431
+ INSERT INTO public.fust_stock_mutations (user_id, fust_type_id, delta, reason, note)
8432
+ 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);
8433
+ UPDATE public.order_fust_bookings b SET quantity = 0, updated_at = now()
8434
+ WHERE b.order_item_id = r.order_item_id AND b.fust_type_id <> r.fust_type_id
8435
+ AND public.voorraad_active_fust_id(NULL, b.fust_type_id) = r.fust_type_id AND b.quantity <> 0;
8436
+ INSERT INTO public.order_fust_bookings (order_item_id, fust_type_id, quantity)
8437
+ VALUES (r.order_item_id, r.fust_type_id, r.juist)
8438
+ ON CONFLICT (order_item_id, fust_type_id) DO UPDATE SET quantity = EXCLUDED.quantity, updated_at = now();
8439
+ v_status := CASE WHEN v_delta > 0 THEN 'tegenboeking' ELSE 'aanvullende boeking' END;
8440
+ UPDATE _c1121 SET geboekt_delta = v_delta WHERE order_item_id = r.order_item_id AND fust_type_id = r.fust_type_id;
8441
+ END IF;
8442
+ END IF;
8443
+ UPDATE _c1121 SET status = v_status WHERE order_item_id = r.order_item_id AND fust_type_id = r.fust_type_id;
8444
+ END LOOP;
8445
+
8446
+ SELECT COALESCE(jsonb_agg(jsonb_build_object(
8447
+ 'fust', v.name, 'fust_type_id', v.id, 'voorraad_voor', v.stock, 'voorraad_na', ft.stock,
8448
+ 'voorraad_na_verwacht', v.stock + COALESCE(s.voorstel, 0),
8449
+ 'tegenboekingen', COALESCE(s.teg, 0), 'aanvullende_boekingen', COALESCE(s.aan, 0),
8450
+ 'voorstel_regels', COALESCE(s.vs, 0), 'overgeslagen', COALESCE(s.ovr, 0)) ORDER BY v.name), '[]'::jsonb)
8451
+ INTO v_fust
8452
+ FROM _c1121_voor v JOIN public.fust_types ft ON ft.id = v.id
8453
+ LEFT JOIN (SELECT fust_type_id,
8454
+ count(*) FILTER (WHERE status = 'tegenboeking') teg,
8455
+ count(*) FILTER (WHERE status = 'aanvullende boeking') aan,
8456
+ count(*) FILTER (WHERE status = 'voorstel') vs,
8457
+ count(*) FILTER (WHERE status LIKE 'overgeslagen%') ovr,
8458
+ sum(-verschil) FILTER (WHERE status IN ('voorstel','tegenboeking','aanvullende boeking')) voorstel
8459
+ FROM _c1121 GROUP BY 1) s ON s.fust_type_id = v.id;
8460
+ 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;
8461
+
8462
+ IF p_uitvoeren THEN
8463
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8464
+ VALUES ('voorraad_correctie_1121', v_wie, false, jsonb_build_object('per_fust', v_fust, 'regels', v_regels), NULL);
8465
+ END IF;
8466
+ RETURN jsonb_build_object('ok', true, 'proef', NOT p_uitvoeren, 'regels_met_verschil', (SELECT count(*) FROM _c1121),
8467
+ 'per_fust', v_fust, 'regels', v_regels);
8468
+ END $function$
8469
+ ;
8470
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121(boolean) FROM PUBLIC;
8471
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121(boolean) FROM anon;
8472
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1121(boolean) TO service_role;
8473
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1121_regels()
8474
+ 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)
8475
+ LANGUAGE plpgsql
8476
+ STABLE SECURITY DEFINER
8477
+ SET search_path TO 'public'
8478
+ AS $function$
8479
+ BEGIN
8480
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1121_regels');
8481
+ RETURN QUERY
8482
+ WITH b AS (
8483
+ 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
8484
+ FROM public.order_fust_bookings ob GROUP BY 1, 2
8485
+ ), j AS (
8486
+ SELECT oi.id AS order_item_id, r.fust_type_id AS f, r.aantal AS q, r.bron
8487
+ FROM public.order_items oi CROSS JOIN LATERAL public.voorraad_fust_juist(oi.id) r
8488
+ WHERE r.fust_type_id IS NOT NULL
8489
+ ), c AS (
8490
+ SELECT COALESCE(b.order_item_id, j.order_item_id) AS order_item_id, COALESCE(b.f, j.f) AS f,
8491
+ COALESCE(b.q, 0) AS geboekt, COALESCE(j.q, 0) AS juist, j.bron, COALESCE(b.n, 0) AS n
8492
+ FROM b FULL JOIN j ON j.order_item_id = b.order_item_id AND j.f = b.f
8493
+ )
8494
+ SELECT o.order_number::text, c.order_item_id, (oi.id IS NOT NULL), c.f, ft.name::text, c.n,
8495
+ c.geboekt, c.juist, c.juist - c.geboekt,
8496
+ CASE WHEN oi.id IS NULL THEN 'regel bestaat niet meer (juist 0)'
8497
+ WHEN oi.quarantined_at IS NOT NULL THEN 'regel in quarantaine (juist 0)'
8498
+ WHEN public.voorraad_order_geannuleerd(o.status, o.cancelled_at, o.deleted_at) THEN 'order geannuleerd (juist 0)'
8499
+ WHEN c.bron IS NOT NULL THEN 'juist volgens ' || c.bron
8500
+ ELSE 'geen fust volgens huidige regel (geen fustcode of aantal; juist 0)' END
8501
+ FROM c
8502
+ LEFT JOIN public.order_items oi ON oi.id = c.order_item_id
8503
+ LEFT JOIN public.orders o ON o.id = oi.order_id
8504
+ LEFT JOIN public.fust_types ft ON ft.id = c.f
8505
+ WHERE c.geboekt <> c.juist;
8506
+ END $function$
8507
+ ;
8508
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121_regels() FROM PUBLIC;
8509
+ REVOKE ALL ON FUNCTION voorraad_correctie_1121_regels() FROM anon;
8510
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1121_regels() TO service_role;
8511
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1123(p_uitvoeren boolean DEFAULT false)
8512
+ RETURNS jsonb
8513
+ LANGUAGE plpgsql
8514
+ SECURITY DEFINER
8515
+ SET search_path TO 'public'
8516
+ AS $function$
8517
+ DECLARE
8518
+ c_groep constant uuid := 'e4c0f2cd-d99a-4ef1-b848-ba576b175638';
8519
+ c_product constant uuid := '4e62fc60-e9b7-468f-8cc4-cdf64b938f57';
8520
+ v_g record; v_items int; v_status text;
8521
+ BEGIN
8522
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1123');
8523
+ SELECT * INTO v_g FROM public.product_groups WHERE id = c_groep FOR UPDATE;
8524
+ SELECT count(*) INTO v_items FROM public.product_group_items WHERE product_group_id = c_groep;
8525
+ IF v_g.id IS NULL THEN v_status := 'overgeslagen: groep niet in deze database';
8526
+ ELSIF v_g.head_product_id IS DISTINCT FROM c_product THEN v_status := 'overgeslagen: groep hoort bij een ander artikel';
8527
+ ELSIF NOT v_g.is_active THEN v_status := 'al inactief';
8528
+ ELSIF v_items > 0 THEN v_status := 'overgeslagen: groep heeft ' || v_items || ' artikelen';
8529
+ ELSE v_status := CASE WHEN p_uitvoeren THEN 'uitgevoerd' ELSE 'voorstel' END;
8530
+ END IF;
8531
+ IF v_status = 'uitgevoerd' THEN
8532
+ UPDATE public.product_groups SET is_active = false, updated_at = now() WHERE id = c_groep;
8533
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
8534
+ VALUES ('voorraad_correctie_1123', COALESCE(auth.uid()::text, session_user::text), false,
8535
+ jsonb_build_object('groep', c_groep, 'naam', v_g.name, 'status', v_status), true);
8536
+ END IF;
8537
+ RETURN jsonb_build_object('ok', true, 'proef', NOT p_uitvoeren, 'groep', c_groep, 'naam', v_g.name, 'artikelen', v_items, 'status', v_status);
8538
+ END $function$
8539
+ ;
8540
+ REVOKE ALL ON FUNCTION voorraad_correctie_1123(boolean) FROM PUBLIC;
8541
+ REVOKE ALL ON FUNCTION voorraad_correctie_1123(boolean) FROM anon;
8542
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1123(boolean) TO service_role;
8543
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1124(p_uitvoeren boolean DEFAULT false)
8544
+ RETURNS jsonb
8545
+ LANGUAGE plpgsql
8546
+ SECURITY DEFINER
8547
+ SET search_path TO 'public'
8548
+ 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.');
8585
+ END $function$
8586
+ ;
8587
+ REVOKE ALL ON FUNCTION voorraad_correctie_1124(boolean) FROM PUBLIC;
8588
+ REVOKE ALL ON FUNCTION voorraad_correctie_1124(boolean) FROM anon;
8589
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1124(boolean) TO service_role;
8372
8590
  CREATE OR REPLACE FUNCTION public.voorraad_correctie_status(p_correctie text DEFAULT '1098'::text)
8373
8591
  RETURNS jsonb
8374
8592
  LANGUAGE plpgsql
@@ -8495,6 +8713,71 @@ REVOKE ALL ON FUNCTION voorraad_fust_dimensions() FROM PUBLIC;
8495
8713
  REVOKE ALL ON FUNCTION voorraad_fust_dimensions() FROM anon;
8496
8714
  GRANT EXECUTE ON FUNCTION voorraad_fust_dimensions() TO authenticated;
8497
8715
  GRANT EXECUTE ON FUNCTION voorraad_fust_dimensions() TO service_role;
8716
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_juist(p_order_item_id uuid)
8717
+ RETURNS TABLE(fust_type_id uuid, fust_key text, aantal integer, bron text)
8718
+ LANGUAGE plpgsql
8719
+ STABLE SECURITY DEFINER
8720
+ SET search_path TO 'public'
8721
+ AS $function$
8722
+ DECLARE
8723
+ v_item record; v_packs jsonb; v_pack jsonb; v_key text; v_units numeric; v_needed integer; v_bron text;
8724
+ BEGIN
8725
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_fust_juist');
8726
+ 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
8727
+ INTO v_item
8728
+ FROM logistics_active.order_items oi
8729
+ JOIN public.order_items x ON x.id = oi.id
8730
+ LEFT JOIN public.orders o ON o.id = oi.order_id
8731
+ WHERE oi.id = p_order_item_id;
8732
+ IF v_item.id IS NULL OR v_item.product_id IS NULL OR COALESCE(v_item.quantity, 0) <= 0
8733
+ OR public.voorraad_order_geannuleerd(v_item.o_status, v_item.o_cancel, v_item.o_del) THEN
8734
+ RETURN;
8735
+ END IF;
8736
+ IF COALESCE(v_item.quantity_crates, 0) > 0 THEN
8737
+ v_needed := v_item.quantity_crates; v_bron := 'orderregel: ' || v_item.quantity_crates || ' fust';
8738
+ ELSIF COALESCE(v_item.plants_per_crate, 0) > 0 THEN
8739
+ v_needed := ceil(v_item.quantity::numeric / v_item.plants_per_crate)::int;
8740
+ v_bron := 'orderregel: ' || v_item.quantity || ' stuks ÷ ' || v_item.plants_per_crate || ' per fust';
8741
+ END IF;
8742
+ IF COALESCE(v_item.vbn_package_code::text, '') <> '' THEN v_key := 'vbn:' || v_item.vbn_package_code::text; END IF;
8743
+ IF v_needed IS NULL OR v_key IS NULL THEN
8744
+ SELECT COALESCE(p.custom_fields->'floriday_payload'->'packingConfigurations', p.custom_fields->'packingConfigurations')
8745
+ INTO v_packs FROM public.products p WHERE p.id = v_item.product_id;
8746
+ IF v_packs IS NULL THEN
8747
+ SELECT c.data->'packingConfigurations' INTO v_packs FROM public.floriday_trade_items_cache c
8748
+ WHERE c.floriday_id = (SELECT p.trade_item_key FROM public.products p WHERE p.id = v_item.product_id) LIMIT 1;
8749
+ END IF;
8750
+ IF jsonb_typeof(v_packs) = 'array' THEN
8751
+ SELECT e INTO v_pack FROM jsonb_array_elements(v_packs) e WHERE COALESCE((e->>'isPrimary')::boolean, false) LIMIT 1;
8752
+ IF v_pack IS NULL THEN SELECT e INTO v_pack FROM jsonb_array_elements(v_packs) e LIMIT 1; END IF;
8753
+ IF v_pack IS NOT NULL THEN
8754
+ IF v_needed IS NULL THEN
8755
+ v_units := NULLIF((v_pack->>'unitsPerPackage')::numeric, 0);
8756
+ IF v_units IS NOT NULL THEN
8757
+ v_needed := ceil(v_item.quantity::numeric / v_units)::int;
8758
+ v_bron := 'artikel: ' || v_item.quantity || ' stuks ÷ ' || v_units || ' per fust';
8759
+ END IF;
8760
+ END IF;
8761
+ IF v_key IS NULL THEN
8762
+ IF COALESCE(v_pack->>'source','') = 'SUPPLIER' AND COALESCE(v_pack->>'packagingMaterialId','') <> '' THEN
8763
+ v_key := 'custom:' || (v_pack->>'packagingMaterialId');
8764
+ ELSIF COALESCE(v_pack->>'packagingType','') <> '' THEN
8765
+ v_key := 'vbn:' || (v_pack->>'packagingType');
8766
+ END IF;
8767
+ END IF;
8768
+ END IF;
8769
+ END IF;
8770
+ END IF;
8771
+ IF v_key IS NULL OR COALESCE(v_needed, 0) <= 0 THEN RETURN; END IF;
8772
+ fust_type_id := public.voorraad_active_fust_id(v_key, NULL);
8773
+ fust_key := v_key; aantal := v_needed; bron := v_bron;
8774
+ RETURN NEXT;
8775
+ END $function$
8776
+ ;
8777
+ REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM PUBLIC;
8778
+ REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM anon;
8779
+ GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO authenticated;
8780
+ GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO service_role;
8498
8781
  CREATE OR REPLACE FUNCTION public.voorraad_hook_base_url()
8499
8782
  RETURNS text
8500
8783
  LANGUAGE plpgsql
@@ -8612,7 +8895,7 @@ CREATE OR REPLACE FUNCTION public.voorraad_install_check()
8612
8895
  STABLE SECURITY DEFINER
8613
8896
  SET search_path TO 'public'
8614
8897
  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'];
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'];
8616
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'];
8617
8900
  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
8901
  v_open text[] := ARRAY['voorraad_is_server','voorraad_vereis'];
@@ -8675,6 +8958,21 @@ GRANT EXECUTE ON FUNCTION voorraad_is_server() TO service_role;
8675
8958
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO anon;
8676
8959
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO authenticated;
8677
8960
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO service_role;
8961
+ CREATE OR REPLACE FUNCTION public.voorraad_load_carriers()
8962
+ RETURNS TABLE(code text, naam text, volgorde integer)
8963
+ LANGUAGE plpgsql
8964
+ STABLE
8965
+ SET search_path TO 'public'
8966
+ AS $function$
8967
+ BEGIN
8968
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_load_carriers');
8969
+ RETURN QUERY SELECT t.code, t.naam, t.volgorde FROM public.voorraad_load_carrier_types t ORDER BY t.volgorde, t.code;
8970
+ END $function$
8971
+ ;
8972
+ REVOKE ALL ON FUNCTION voorraad_load_carriers() FROM PUBLIC;
8973
+ REVOKE ALL ON FUNCTION voorraad_load_carriers() FROM anon;
8974
+ GRANT EXECUTE ON FUNCTION voorraad_load_carriers() TO authenticated;
8975
+ GRANT EXECUTE ON FUNCTION voorraad_load_carriers() TO service_role;
8678
8976
  CREATE OR REPLACE FUNCTION public.voorraad_mark_floriday_sold_before_switch(p_product_id uuid)
8679
8977
  RETURNS integer
8680
8978
  LANGUAGE plpgsql
@@ -8706,6 +9004,23 @@ END $function$
8706
9004
  REVOKE ALL ON FUNCTION voorraad_mark_floriday_sold_before_switch(uuid) FROM PUBLIC;
8707
9005
  REVOKE ALL ON FUNCTION voorraad_mark_floriday_sold_before_switch(uuid) FROM anon;
8708
9006
  GRANT EXECUTE ON FUNCTION voorraad_mark_floriday_sold_before_switch(uuid) TO service_role;
9007
+ 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)
9008
+ RETURNS boolean
9009
+ LANGUAGE sql
9010
+ IMMUTABLE
9011
+ SET search_path TO 'public'
9012
+ AS $function$
9013
+ SELECT lower(btrim(COALESCE(p_status, ''))) IN ('geannuleerd', 'cancelled') OR p_cancelled_at IS NOT NULL OR p_deleted_at IS NOT NULL
9014
+ $function$
9015
+ ;
9016
+ REVOKE ALL ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM PUBLIC;
9017
+ REVOKE ALL ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM anon;
9018
+ REVOKE EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM PUBLIC;
9019
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO authenticated;
9020
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO service_role;
9021
+ REVOKE EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM anon;
9022
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO authenticated;
9023
+ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO service_role;
8709
9024
  CREATE OR REPLACE FUNCTION public.voorraad_production_enabled()
8710
9025
  RETURNS boolean
8711
9026
  LANGUAGE sql
@@ -9098,6 +9413,7 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'trade_i
9098
9413
  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
9414
  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
9415
  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$;
9416
+ 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
9417
  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
9418
  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
9419
  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 +9668,10 @@ ALTER TABLE public.voorraad_custom_fields ENABLE ROW LEVEL SECURITY;
9352
9668
  REVOKE ALL ON public.voorraad_custom_fields FROM anon;
9353
9669
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_custom_fields TO authenticated;
9354
9670
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_custom_fields TO service_role;
9671
+ ALTER TABLE public.voorraad_load_carrier_types ENABLE ROW LEVEL SECURITY;
9672
+ REVOKE ALL ON public.voorraad_load_carrier_types FROM anon;
9673
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_load_carrier_types TO authenticated;
9674
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_load_carrier_types TO service_role;
9355
9675
  ALTER TABLE public.voorraad_local_context ENABLE ROW LEVEL SECURITY;
9356
9676
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_local_context TO authenticated;
9357
9677
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_local_context TO service_role;
@@ -9495,6 +9815,8 @@ DROP POLICY IF EXISTS "Authenticated can read voorraad custom fields" ON public.
9495
9815
  CREATE POLICY "Authenticated can read voorraad custom fields" ON public.voorraad_custom_fields AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9496
9816
  DROP POLICY IF EXISTS "Authenticated can update voorraad custom fields" ON public.voorraad_custom_fields;
9497
9817
  CREATE POLICY "Authenticated can update voorraad custom fields" ON public.voorraad_custom_fields AS PERMISSIVE FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
9818
+ DROP POLICY IF EXISTS "Ingelogd mag ladingdragers lezen" ON public.voorraad_load_carrier_types;
9819
+ CREATE POLICY "Ingelogd mag ladingdragers lezen" ON public.voorraad_load_carrier_types AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9498
9820
  DROP POLICY IF EXISTS "Lokale context lezen" ON public.voorraad_local_context;
9499
9821
  CREATE POLICY "Lokale context lezen" ON public.voorraad_local_context AS PERMISSIVE FOR SELECT TO authenticated USING (true);
9500
9822
  DROP POLICY IF EXISTS "Ingelogde gebruikers kunnen de eventlog lezen" ON public.voorraad_logistics_event_log;
@@ -9573,6 +9895,7 @@ DO $g$ BEGIN IF to_regclass('public.orders') IS NULL THEN RAISE NOTICE 'Voorraad
9573
9895
  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
9896
  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
9897
  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$;
9898
+ 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
9899
  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
9900
  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
9901
  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$;