@flowselections/floriday-voorraad 1.0.141 → 1.0.145

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 (37) hide show
  1. package/dist-lib/components/voorraad/ArtikelWizard.js +1 -1
  2. package/dist-lib/components/voorraad/FustAdministratie.d.ts +12 -0
  3. package/dist-lib/components/voorraad/FustAdministratie.d.ts.map +1 -0
  4. package/dist-lib/components/voorraad/FustAdministratie.js +69 -0
  5. package/dist-lib/components/voorraad/FustenPage.d.ts.map +1 -1
  6. package/dist-lib/components/voorraad/FustenPage.js +9 -14
  7. package/dist-lib/components/voorraad/KoppelingStatusPanel.d.ts +6 -0
  8. package/dist-lib/components/voorraad/KoppelingStatusPanel.d.ts.map +1 -0
  9. package/dist-lib/components/voorraad/KoppelingStatusPanel.js +47 -0
  10. package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -1
  11. package/dist-lib/components/voorraad/NieuwArtikelPage.js +24 -5
  12. package/dist-lib/components/voorraad/TelmomentButton.d.ts +8 -0
  13. package/dist-lib/components/voorraad/TelmomentButton.d.ts.map +1 -0
  14. package/dist-lib/components/voorraad/TelmomentButton.js +65 -0
  15. package/dist-lib/components/voorraad/ValidationPage.d.ts.map +1 -1
  16. package/dist-lib/components/voorraad/ValidationPage.js +2 -1
  17. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  18. package/dist-lib/components/voorraad/VoorraadPage.js +4 -1
  19. package/dist-lib/hooks/useEnsureVoorraadDefaults.d.ts +7 -0
  20. package/dist-lib/hooks/useEnsureVoorraadDefaults.d.ts.map +1 -0
  21. package/dist-lib/hooks/useEnsureVoorraadDefaults.js +25 -0
  22. package/dist-lib/integrations/supabase/types.d.ts +890 -0
  23. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  24. package/dist-lib/lib/engine-carrier.d.ts +15 -0
  25. package/dist-lib/lib/engine-carrier.d.ts.map +1 -0
  26. package/dist-lib/lib/engine-carrier.js +27 -0
  27. package/dist-lib/lib/fust-administratie.d.ts +29 -0
  28. package/dist-lib/lib/fust-administratie.d.ts.map +1 -0
  29. package/dist-lib/lib/fust-administratie.js +63 -0
  30. package/dist-lib/lib/fusten.d.ts +4 -0
  31. package/dist-lib/lib/fusten.d.ts.map +1 -1
  32. package/dist-lib/lib/simple-packing.d.ts +2 -4
  33. package/dist-lib/lib/simple-packing.d.ts.map +1 -1
  34. package/dist-lib/lib/simple-packing.js +5 -12
  35. package/package.json +2 -2
  36. package/sql/AGENTS.md +6 -1
  37. package/sql/floriday-voorraad-schema.sql +1038 -51
@@ -1,4 +1,5 @@
1
- -- @flowselections/floriday-voorraad 1.0.141 – volledig schema (idempotent, geen gegevens).
1
+ -- @flowselections/floriday-voorraad 1.0.144 – volledig schema (idempotent, geen gegevens).
2
+ -- Laatste migratie: 20261102161116_305f3804-253b-46f3-b4e7-2b25fa06c211.sql
2
3
  -- Gegenereerd uit de database met scripts/generate-voorraad-schema.py. Niet met de hand wijzigen.
3
4
  -- Volgorde 20. Ontbrekende tabellen van andere modules worden overgeslagen met een NOTICE; draai opnieuw na die module.
4
5
  -- De statuscontrole van floriday_continuous_stock_queue is van Voorraad en wordt hier opnieuw gemaakt.
@@ -177,6 +178,30 @@ ALTER TABLE public.floriday_vbn_required_characteristics ADD COLUMN IF NOT EXIST
177
178
  ALTER TABLE public.floriday_vbn_required_characteristics ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
178
179
  ALTER TABLE public.floriday_vbn_required_characteristics ADD COLUMN IF NOT EXISTS updated_by uuid;
179
180
 
181
+ -- fust_startmoment
182
+ CREATE TABLE IF NOT EXISTS public.fust_startmoment ();
183
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
184
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS fust_type_id uuid;
185
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS moment timestamp with time zone NOT NULL;
186
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS beginstand integer NOT NULL;
187
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS automatisch boolean DEFAULT false NOT NULL;
188
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS door uuid DEFAULT auth.uid();
189
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
190
+ ALTER TABLE public.fust_startmoment ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
191
+
192
+ -- fust_startmoment_log
193
+ CREATE TABLE IF NOT EXISTS public.fust_startmoment_log ();
194
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
195
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS fust_type_id uuid;
196
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS moment timestamp with time zone NOT NULL;
197
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS beginstand integer NOT NULL;
198
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS saldo_voor integer;
199
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS saldo_na integer;
200
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS automatisch boolean DEFAULT false NOT NULL;
201
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS notitie text;
202
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS door uuid DEFAULT auth.uid();
203
+ ALTER TABLE public.fust_startmoment_log ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
204
+
180
205
  -- fust_stock_mutations
181
206
  CREATE TABLE IF NOT EXISTS public.fust_stock_mutations ();
182
207
  ALTER TABLE public.fust_stock_mutations ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
@@ -210,6 +235,8 @@ ALTER TABLE public.fust_types ADD COLUMN IF NOT EXISTS width_mm integer;
210
235
  ALTER TABLE public.fust_types ADD COLUMN IF NOT EXISTS height_mm integer;
211
236
  ALTER TABLE public.fust_types ADD COLUMN IF NOT EXISTS capacity_units integer;
212
237
  ALTER TABLE public.fust_types ADD COLUMN IF NOT EXISTS merged_into uuid;
238
+ ALTER TABLE public.fust_types ADD COLUMN IF NOT EXISTS saldo_bijhouden boolean;
239
+ ALTER TABLE public.fust_types ADD COLUMN IF NOT EXISTS eigen_naam text;
213
240
 
214
241
  -- inventory_recompute_limits
215
242
  CREATE TABLE IF NOT EXISTS public.inventory_recompute_limits ();
@@ -530,6 +557,50 @@ ALTER TABLE public.voorraad_custom_fields ADD COLUMN IF NOT EXISTS sort_order in
530
557
  ALTER TABLE public.voorraad_custom_fields ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
531
558
  ALTER TABLE public.voorraad_custom_fields ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
532
559
 
560
+ -- voorraad_defaults_state
561
+ CREATE TABLE IF NOT EXISTS public.voorraad_defaults_state ();
562
+ ALTER TABLE public.voorraad_defaults_state ADD COLUMN IF NOT EXISTS id boolean DEFAULT true NOT NULL;
563
+ ALTER TABLE public.voorraad_defaults_state ADD COLUMN IF NOT EXISTS versie integer NOT NULL;
564
+ ALTER TABLE public.voorraad_defaults_state ADD COLUMN IF NOT EXISTS toegepast_at timestamp with time zone DEFAULT now() NOT NULL;
565
+ ALTER TABLE public.voorraad_defaults_state ADD COLUMN IF NOT EXISTS resultaat jsonb DEFAULT '{}'::jsonb NOT NULL;
566
+
567
+ -- voorraad_floriday_artikel_wachtrij
568
+ CREATE TABLE IF NOT EXISTS public.voorraad_floriday_artikel_wachtrij ();
569
+ ALTER TABLE public.voorraad_floriday_artikel_wachtrij ADD COLUMN IF NOT EXISTS floriday_id text NOT NULL;
570
+ ALTER TABLE public.voorraad_floriday_artikel_wachtrij ADD COLUMN IF NOT EXISTS connection_id uuid;
571
+ ALTER TABLE public.voorraad_floriday_artikel_wachtrij ADD COLUMN IF NOT EXISTS aangemeld_at timestamp with time zone DEFAULT now() NOT NULL;
572
+
573
+ -- voorraad_instellingen
574
+ CREATE TABLE IF NOT EXISTS public.voorraad_instellingen ();
575
+ ALTER TABLE public.voorraad_instellingen ADD COLUMN IF NOT EXISTS id boolean DEFAULT true NOT NULL;
576
+ ALTER TABLE public.voorraad_instellingen ADD COLUMN IF NOT EXISTS standaard_sturing_nieuwe_floriday text DEFAULT 'lokaal'::text NOT NULL;
577
+ ALTER TABLE public.voorraad_instellingen ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
578
+ ALTER TABLE public.voorraad_instellingen ADD COLUMN IF NOT EXISTS updated_by uuid;
579
+
580
+ -- voorraad_koppel_log
581
+ CREATE TABLE IF NOT EXISTS public.voorraad_koppel_log ();
582
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
583
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS run_id uuid;
584
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS soort text NOT NULL;
585
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS floriday_id text;
586
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS product_id uuid;
587
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS order_item_id uuid;
588
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS oud jsonb;
589
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS nieuw jsonb;
590
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS door uuid DEFAULT auth.uid();
591
+ ALTER TABLE public.voorraad_koppel_log ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
592
+
593
+ -- voorraad_koppel_twijfel
594
+ CREATE TABLE IF NOT EXISTS public.voorraad_koppel_twijfel ();
595
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS floriday_id text NOT NULL;
596
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS connection_id uuid;
597
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS naam text;
598
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS reden text NOT NULL;
599
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS kandidaten jsonb;
600
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS eerst_gezien timestamp with time zone DEFAULT now() NOT NULL;
601
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS laatst_gezien timestamp with time zone DEFAULT now() NOT NULL;
602
+ ALTER TABLE public.voorraad_koppel_twijfel ADD COLUMN IF NOT EXISTS opgelost_at timestamp with time zone;
603
+
533
604
  -- voorraad_load_carrier_types
534
605
  CREATE TABLE IF NOT EXISTS public.voorraad_load_carrier_types ();
535
606
  ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS code text NOT NULL;
@@ -537,6 +608,8 @@ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS naam tex
537
608
  ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS volgorde integer NOT NULL;
538
609
  ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
539
610
  ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
611
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS actief boolean DEFAULT true NOT NULL;
612
+ ALTER TABLE public.voorraad_load_carrier_types ADD COLUMN IF NOT EXISTS naam_aangepast boolean DEFAULT false NOT NULL;
540
613
 
541
614
  -- voorraad_local_context
542
615
  CREATE TABLE IF NOT EXISTS public.voorraad_local_context ();
@@ -647,6 +720,23 @@ ALTER TABLE public.voorraad_publish_steps ADD COLUMN IF NOT EXISTS finished_at t
647
720
  ALTER TABLE public.voorraad_publish_steps ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
648
721
  ALTER TABLE public.voorraad_publish_steps ADD COLUMN IF NOT EXISTS updated_at timestamp with time zone DEFAULT now() NOT NULL;
649
722
 
723
+ -- voorraad_telmoment
724
+ CREATE TABLE IF NOT EXISTS public.voorraad_telmoment ();
725
+ ALTER TABLE public.voorraad_telmoment ADD COLUMN IF NOT EXISTS id uuid DEFAULT gen_random_uuid() NOT NULL;
726
+ ALTER TABLE public.voorraad_telmoment ADD COLUMN IF NOT EXISTS telmoment timestamp with time zone NOT NULL;
727
+ ALTER TABLE public.voorraad_telmoment ADD COLUMN IF NOT EXISTS trade_item_keys text[];
728
+ ALTER TABLE public.voorraad_telmoment ADD COLUMN IF NOT EXISTS notitie text;
729
+ ALTER TABLE public.voorraad_telmoment ADD COLUMN IF NOT EXISTS door uuid DEFAULT auth.uid();
730
+ ALTER TABLE public.voorraad_telmoment ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
731
+
732
+ -- voorraad_telmoment_regels
733
+ CREATE TABLE IF NOT EXISTS public.voorraad_telmoment_regels ();
734
+ ALTER TABLE public.voorraad_telmoment_regels ADD COLUMN IF NOT EXISTS order_item_id uuid NOT NULL;
735
+ ALTER TABLE public.voorraad_telmoment_regels ADD COLUMN IF NOT EXISTS telmoment_id uuid NOT NULL;
736
+ ALTER TABLE public.voorraad_telmoment_regels ADD COLUMN IF NOT EXISTS reden text NOT NULL;
737
+ ALTER TABLE public.voorraad_telmoment_regels ADD COLUMN IF NOT EXISTS door uuid DEFAULT auth.uid();
738
+ ALTER TABLE public.voorraad_telmoment_regels ADD COLUMN IF NOT EXISTS created_at timestamp with time zone DEFAULT now() NOT NULL;
739
+
650
740
  -- functies
651
741
  CREATE OR REPLACE FUNCTION public._floriday_queue_cleanup_batch(p_statuses text[], p_days integer, p_keep_latest boolean, p_limit integer)
652
742
  RETURNS integer
@@ -2258,6 +2348,7 @@ AS $function$
2258
2348
  DECLARE n integer := 0; v_batch int;
2259
2349
  BEGIN
2260
2350
  PERFORM public.voorraad_vereis('server', 'drain_inventory_recompute_queue');
2351
+ BEGIN PERFORM public.voorraad_ensure_defaults(); EXCEPTION WHEN others THEN NULL; END;
2261
2352
  SELECT drain_batch INTO v_batch FROM public.inventory_recompute_limits WHERE id;
2262
2353
  PERFORM set_config('inventory.inline_overflow', '0', true);
2263
2354
  n := public.process_inventory_recompute_queue(COALESCE(v_batch, 500));
@@ -3155,6 +3246,7 @@ DECLARE
3155
3246
  v_owner uuid;
3156
3247
  BEGIN
3157
3248
  PERFORM public.voorraad_vereis('ingelogd', 'floriday_ingest_sales_orders');
3249
+ PERFORM public.voorraad_fust_startmoment_auto();
3158
3250
  FOR r IN
3159
3251
  SELECT c.connection_id,
3160
3252
  c.floriday_id,
@@ -3163,7 +3255,8 @@ BEGIN
3163
3255
  c.is_deleted,
3164
3256
  c.data->>'tradeItemId' AS trade_item_id,
3165
3257
  COALESCE((c.data->>'numberOfPieces')::int, 0) AS pieces,
3166
- c.data->'packingConfiguration' AS order_packing
3258
+ c.data->'packingConfiguration' AS order_packing,
3259
+ c.data->'delivery'->>'latestDeliveryDateTime' AS lever_at
3167
3260
  FROM public.floriday_salesorders_cache c
3168
3261
  WHERE NOT EXISTS (
3169
3262
  SELECT 1 FROM public.floriday_sales_order_ingest i
@@ -3276,7 +3369,9 @@ BEGIN
3276
3369
  END IF;
3277
3370
  END IF;
3278
3371
 
3279
- IF v_fust_id IS NOT NULL THEN
3372
+ IF v_fust_id IS NOT NULL AND public.voorraad_fust_voor_startmoment(v_fust_id, public.voorraad_lever_datum(r.lever_at)) THEN
3373
+ v_packages := 0; -- leverdatum vóór het fust-startmoment: geen fustboeking
3374
+ ELSIF v_fust_id IS NOT NULL THEN
3280
3375
  -- Eerder geboekt aantal voor deze order (vorige versie) terugdraaien.
3281
3376
  SELECT COALESCE(MAX((i.impact->>'fustPackages')::int), 0)
3282
3377
  INTO v_prev_packages
@@ -3314,7 +3409,8 @@ BEGIN
3314
3409
  'reservedDelta', v_delta,
3315
3410
  'fustTypeId', v_fust_id,
3316
3411
  'fustKey', v_fust_key,
3317
- 'fustPackages', v_packages
3412
+ 'fustPackages', v_packages,
3413
+ 'voorStartmoment', public.voorraad_fust_voor_startmoment(v_fust_id, public.voorraad_lever_datum(r.lever_at))
3318
3414
  )
3319
3415
  )
3320
3416
  ON CONFLICT (connection_id, sales_order_id, order_version) DO NOTHING;
@@ -4924,6 +5020,7 @@ DECLARE
4924
5020
  v_frozen_ids uuid[];
4925
5021
  BEGIN
4926
5022
  PERFORM public.voorraad_vereis('ingelogd', 'recompute_all_reserved_stock');
5023
+ BEGIN PERFORM public.voorraad_ensure_defaults(); EXCEPTION WHEN others THEN NULL; END;
4927
5024
  IF current_setting('app.recomputing_reserved', true) = 'on' THEN RETURN; END IF;
4928
5025
  PERFORM set_config('app.recomputing_reserved', 'on', true);
4929
5026
 
@@ -6059,7 +6156,7 @@ BEGIN
6059
6156
  v_user := COALESCE(v_uid, v_ctx.user_id);
6060
6157
  SELECT import_chunk_size, import_new_chunk_size, import_max_rows, import_max_bytes INTO l FROM public.inventory_recompute_limits WHERE id;
6061
6158
  v_cs := GREATEST(COALESCE(l.import_chunk_size, 200), 1);
6062
- v_ncs := LEAST(GREATEST(COALESCE(l.import_new_chunk_size, 40), 1), v_cs);
6159
+ v_ncs := LEAST(GREATEST(COALESCE(l.import_new_chunk_size, 20), 1), v_cs);
6063
6160
  IF p_rows IS NULL OR jsonb_typeof(p_rows) <> 'array' OR jsonb_array_length(p_rows) = 0 THEN
6064
6161
  RETURN jsonb_build_object('ok', false, 'code', 'IMPORT_EMPTY', 'message', 'Het bestand bevat geen rijen.');
6065
6162
  END IF;
@@ -6319,10 +6416,10 @@ AS $function$
6319
6416
  DECLARE
6320
6417
  v_item record; v_order_number text; v_packs jsonb; v_pack jsonb; v_key text;
6321
6418
  v_units numeric; v_needed integer; v_fust_id uuid; v_prev integer; v_delta integer;
6322
- v_wanted jsonb := '{}'::jsonb; v_row record; v_user uuid; v_ing jsonb;
6419
+ v_wanted jsonb := '{}'::jsonb; v_row record; v_user uuid; v_ing jsonb; v_voor boolean := false;
6323
6420
  BEGIN
6324
6421
  PERFORM public.voorraad_vereis('ingelogd', 'sync_order_item_fusten');
6325
- 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
6422
+ 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, o.delivery_date AS o_lever INTO v_item
6326
6423
  FROM logistics_active.order_items oi
6327
6424
  LEFT JOIN public.orders o ON o.id = oi.order_id
6328
6425
  LEFT JOIN public.order_items x ON x.id = oi.id
@@ -6384,7 +6481,9 @@ BEGIN
6384
6481
  ON CONFLICT DO NOTHING;
6385
6482
  v_fust_id := public.voorraad_active_fust_id(v_key, NULL);
6386
6483
  END IF;
6387
- IF v_fust_id IS NOT NULL THEN
6484
+ IF v_fust_id IS NOT NULL AND public.voorraad_fust_voor_startmoment(v_fust_id, public.voorraad_lever_datum(v_item.o_lever)) THEN
6485
+ v_voor := true; -- leverdatum vóór het fust-startmoment: niets boeken
6486
+ ELSIF v_fust_id IS NOT NULL THEN
6388
6487
  v_wanted := jsonb_build_object(v_fust_id::text, v_needed);
6389
6488
  END IF;
6390
6489
  END IF;
@@ -6392,7 +6491,7 @@ BEGIN
6392
6491
 
6393
6492
  -- Floriday-order al afgeboekt bij het binnenhalen: die boeking overnemen (geen tweede mutatie).
6394
6493
  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
6395
- AND NOT EXISTS (SELECT 1 FROM public.order_fust_bookings b WHERE b.order_item_id = _order_item_id) THEN
6494
+ AND NOT EXISTS (SELECT 1 FROM public.order_fust_bookings b WHERE b.order_item_id = _order_item_id) AND NOT v_voor THEN
6396
6495
  SELECT i.impact INTO v_ing FROM public.floriday_sales_order_ingest i
6397
6496
  WHERE i.sales_order_id = v_item.source_line_key AND (i.impact->>'fustTypeId') IS NOT NULL
6398
6497
  ORDER BY i.order_version DESC LIMIT 1;
@@ -6405,6 +6504,7 @@ BEGIN
6405
6504
 
6406
6505
  FOR v_row IN SELECT b.fust_type_id, b.quantity FROM public.order_fust_bookings b WHERE b.order_item_id = _order_item_id
6407
6506
  LOOP
6507
+ IF public.voorraad_fust_voor_startmoment(v_row.fust_type_id, public.voorraad_lever_datum(v_item.o_lever)) THEN CONTINUE; END IF;
6408
6508
  v_prev := v_row.quantity;
6409
6509
  v_needed := COALESCE((v_wanted->>v_row.fust_type_id::text)::int, 0);
6410
6510
  v_delta := v_prev - v_needed;
@@ -6682,24 +6782,17 @@ CREATE OR REPLACE FUNCTION public.trg_floriday_trade_items_autolink_fn()
6682
6782
  SECURITY DEFINER
6683
6783
  SET search_path TO 'public'
6684
6784
  AS $function$
6685
- DECLARE r RECORD; v_name text; v_gtin text; v_article text;
6686
6785
  BEGIN
6687
- IF NEW.is_deleted THEN RETURN NEW; END IF;
6688
- v_name := COALESCE(NEW.data->>'tradeItemName', NEW.data->'tradeItemName'->>'nl', NEW.data->'tradeItemName'->>'en');
6689
- v_gtin := NEW.data->>'gtin';
6690
- v_article := NEW.data->>'articleCode';
6691
-
6692
- FOR r IN
6693
- SELECT id FROM public.products
6694
- WHERE (trade_item_key IS NULL OR trade_item_key LIKE 'product:%' OR trade_item_key LIKE 'draft:%')
6695
- AND (
6696
- (v_name IS NOT NULL AND lower(btrim(product)) = lower(btrim(v_name)))
6697
- OR (v_gtin IS NOT NULL AND btrim(barcode) = btrim(v_gtin))
6698
- OR (v_article IS NOT NULL AND btrim(barcode) = btrim(v_article))
6699
- )
6700
- LOOP
6701
- PERFORM public.autolink_product_to_floriday(r.id);
6702
- END LOOP;
6786
+ BEGIN
6787
+ INSERT INTO public.voorraad_floriday_artikel_wachtrij(floriday_id, connection_id, aangemeld_at)
6788
+ VALUES (NEW.floriday_id, NEW.connection_id, now())
6789
+ ON CONFLICT (floriday_id) DO UPDATE SET aangemeld_at = now(), connection_id = EXCLUDED.connection_id;
6790
+ IF NOT EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'voorraad-floriday-artikelen-drain') THEN
6791
+ PERFORM cron.schedule('voorraad-floriday-artikelen-drain', '* * * * *', 'SELECT public.voorraad_floriday_artikelen_vangnet()');
6792
+ END IF;
6793
+ EXCEPTION WHEN others THEN
6794
+ RAISE WARNING '[voorraad] Floriday-artikel niet aangemeld: %', SQLERRM;
6795
+ END;
6703
6796
  RETURN NEW;
6704
6797
  END $function$
6705
6798
  ;
@@ -6717,8 +6810,28 @@ CREATE OR REPLACE FUNCTION public.trg_order_items_autolink_fn()
6717
6810
  SECURITY DEFINER
6718
6811
  SET search_path TO 'public'
6719
6812
  AS $function$
6720
- DECLARE v_resolved uuid;
6813
+ DECLARE v_resolved uuid; v_m jsonb;
6721
6814
  BEGIN
6815
+ -- Floriday-orderregel: koppelen op het Floriday-artikel (eenduidig), nooit op naam.
6816
+ IF NEW.source_line_key IS NOT NULL AND btrim(NEW.source_line_key) <> '' THEN
6817
+ BEGIN
6818
+ v_m := public.voorraad_orderregel_trade_item_bron(NEW.order_id, NEW.source_line_key);
6819
+ EXCEPTION WHEN others THEN v_m := NULL;
6820
+ END;
6821
+ IF v_m->>'status' = 'eenduidig' THEN
6822
+ IF NEW.product_id IS DISTINCT FROM (v_m->>'product_id')::uuid THEN
6823
+ BEGIN
6824
+ INSERT INTO public.voorraad_koppel_log(soort, floriday_id, product_id, order_item_id, oud, nieuw)
6825
+ VALUES ('orderregel_op_floriday_artikel', v_m->>'trade_item_id', (v_m->>'product_id')::uuid, NEW.id,
6826
+ jsonb_build_object('product_id', NEW.product_id), jsonb_build_object('product_id', v_m->>'product_id'));
6827
+ EXCEPTION WHEN others THEN NULL;
6828
+ END;
6829
+ NEW.product_id := (v_m->>'product_id')::uuid;
6830
+ END IF;
6831
+ END IF;
6832
+ RETURN NEW;
6833
+ END IF;
6834
+ -- Mailbox- en handmatige orders: naam als terugval.
6722
6835
  IF NEW.product_id IS NULL AND NEW.product_name IS NOT NULL THEN
6723
6836
  v_resolved := public.resolve_product_id_for_item(NEW.product_name);
6724
6837
  IF v_resolved IS NOT NULL THEN NEW.product_id := v_resolved; END IF;
@@ -7119,6 +7232,28 @@ END $function$
7119
7232
  REVOKE ALL ON FUNCTION trg_products_floriday_link_enqueue() FROM PUBLIC;
7120
7233
  REVOKE ALL ON FUNCTION trg_products_floriday_link_enqueue() FROM anon;
7121
7234
  GRANT EXECUTE ON FUNCTION trg_products_floriday_link_enqueue() TO service_role;
7235
+ CREATE OR REPLACE FUNCTION public.trg_products_floriday_velden_aangepast()
7236
+ RETURNS trigger
7237
+ LANGUAGE plpgsql
7238
+ SECURITY DEFINER
7239
+ SET search_path TO 'public'
7240
+ AS $function$
7241
+ DECLARE v text[];
7242
+ BEGIN
7243
+ IF COALESCE(current_setting('voorraad.floriday_sync', true), '') = 'on' THEN RETURN NEW; END IF;
7244
+ IF COALESCE(NEW.custom_fields->>'voorraad_auto_aangemaakt', '') <> 'true' THEN RETURN NEW; END IF;
7245
+ v := COALESCE(NEW.floriday_velden_aangepast, ARRAY[]::text[]);
7246
+ IF NEW.product IS DISTINCT FROM OLD.product AND NOT ('product' = ANY(v)) THEN v := v || 'product'; END IF;
7247
+ IF NEW.image_url IS DISTINCT FROM OLD.image_url AND NOT ('image_url' = ANY(v)) THEN v := v || 'image_url'; END IF;
7248
+ IF NEW.barcode IS DISTINCT FROM OLD.barcode AND NOT ('barcode' = ANY(v)) THEN v := v || 'barcode'; END IF;
7249
+ NEW.floriday_velden_aangepast := NULLIF(v, ARRAY[]::text[]);
7250
+ RETURN NEW;
7251
+ END $function$
7252
+ ;
7253
+ REVOKE ALL ON FUNCTION trg_products_floriday_velden_aangepast() FROM PUBLIC;
7254
+ REVOKE ALL ON FUNCTION trg_products_floriday_velden_aangepast() FROM anon;
7255
+ GRANT EXECUTE ON FUNCTION trg_products_floriday_velden_aangepast() TO authenticated;
7256
+ GRANT EXECUTE ON FUNCTION trg_products_floriday_velden_aangepast() TO service_role;
7122
7257
  CREATE OR REPLACE FUNCTION public.trg_products_placeholder_code()
7123
7258
  RETURNS trigger
7124
7259
  LANGUAGE plpgsql
@@ -7653,24 +7788,8 @@ CREATE OR REPLACE FUNCTION public.trg_trade_items_cache_autolink_fn()
7653
7788
  SECURITY DEFINER
7654
7789
  SET search_path TO 'public'
7655
7790
  AS $function$
7656
- DECLARE p RECORD; v_new text;
7657
7791
  BEGIN
7658
- IF NEW.is_deleted THEN RETURN NEW; END IF;
7659
- v_new := NEW.floriday_id;
7660
- FOR p IN
7661
- SELECT id, trade_item_key FROM public.products WHERE
7662
- (NEW.data->>'gtin' IS NOT NULL AND barcode = NEW.data->>'gtin')
7663
- OR (NEW.data->>'articleCode' IS NOT NULL AND barcode = NEW.data->>'articleCode')
7664
- OR (NEW.data->>'tradeItemName' IS NOT NULL
7665
- AND lower(btrim(product)) = lower(btrim(NEW.data->>'tradeItemName')))
7666
- LOOP
7667
- IF p.trade_item_key IS DISTINCT FROM v_new THEN
7668
- IF p.trade_item_key IS NOT NULL AND p.trade_item_key LIKE 'product:%' THEN
7669
- PERFORM public.promote_trade_item_key(p.trade_item_key, v_new);
7670
- END IF;
7671
- UPDATE public.products SET trade_item_key = v_new WHERE id = p.id;
7672
- END IF;
7673
- END LOOP;
7792
+ -- Koppelen gebeurt eenduidig in voorraad_floriday_artikelen_aanmaken (via trg_floriday_trade_items_autolink_fn).
7674
7793
  RETURN NEW;
7675
7794
  END $function$
7676
7795
  ;
@@ -8913,6 +9032,77 @@ END $function$
8913
9032
  REVOKE ALL ON FUNCTION voorraad_correctie_1140(boolean) FROM PUBLIC;
8914
9033
  REVOKE ALL ON FUNCTION voorraad_correctie_1140(boolean) FROM anon;
8915
9034
  GRANT EXECUTE ON FUNCTION voorraad_correctie_1140(boolean) TO service_role;
9035
+ CREATE OR REPLACE FUNCTION public.voorraad_correctie_1144(p_uitvoeren boolean DEFAULT false, p_limiet integer DEFAULT 200, p_max_seconden integer DEFAULT 20)
9036
+ RETURNS jsonb
9037
+ LANGUAGE plpgsql
9038
+ SECURITY DEFINER
9039
+ SET search_path TO 'public'
9040
+ AS $function$
9041
+ DECLARE r record; v_m jsonb; v_cat text; v_start timestamptz := clock_timestamp(); v_run uuid := gen_random_uuid();
9042
+ v_tel jsonb := '{}'::jsonb; v_status jsonb := '{}'::jsonb; v_orders uuid[] := ARRAY[]::uuid[]; n_ing int := 0; n_voor_fust int := 0;
9043
+ n_gedaan int := 0; n_rest int := 0; v_res jsonb; v_vb jsonb := '[]'::jsonb;
9044
+ BEGIN
9045
+ PERFORM public.voorraad_vereis('server', 'voorraad_correctie_1144');
9046
+ IF p_uitvoeren AND NOT pg_try_advisory_xact_lock(hashtext('voorraad_correctie_1144')) THEN
9047
+ RETURN jsonb_build_object('ok', false, 'melding', 'Er loopt al een ronde');
9048
+ END IF;
9049
+ FOR r IN
9050
+ SELECT oi.id, oi.order_id, oi.source_line_key, oi.quarantined_at, o.order_number, o.status, o.cancelled_at, o.deleted_at, o.delivery_date
9051
+ FROM public.order_items oi JOIN public.orders o ON o.id = oi.order_id
9052
+ WHERE oi.product_id IS NULL AND NULLIF(btrim(COALESCE(oi.source_line_key,'')),'') IS NOT NULL
9053
+ ORDER BY o.delivery_date NULLS LAST, oi.id
9054
+ LOOP
9055
+ v_m := public.voorraad_orderregel_trade_item_bron(r.order_id, r.source_line_key);
9056
+ v_cat := CASE
9057
+ WHEN v_m->>'status' <> 'eenduidig' THEN 'niet_gekoppeld_' || (v_m->>'status')
9058
+ WHEN r.quarantined_at IS NOT NULL OR public.voorraad_order_geannuleerd(r.status, r.cancelled_at, r.deleted_at) THEN 'overgeslagen_geannuleerd'
9059
+ WHEN lower(COALESCE(r.status,'')) IN ('verzonden','shipped','geleverd','delivered') THEN 'overgeslagen_verzonden'
9060
+ WHEN EXISTS (SELECT 1 FROM public.voorraad_telmoment_regels t WHERE t.order_item_id = r.id)
9061
+ OR EXISTS (SELECT 1 FROM public.stock_mutation_log m WHERE m.order_item_id = r.id AND m.mutation_type = 'consumption') THEN 'overgeslagen_verwerkt_voor_telling'
9062
+ ELSE 'invullen' END;
9063
+ v_tel := jsonb_set(v_tel, ARRAY[v_cat], to_jsonb(COALESCE((v_tel->>v_cat)::int, 0) + 1));
9064
+ IF v_cat = 'invullen' THEN
9065
+ IF NOT (r.order_id = ANY(v_orders)) THEN
9066
+ v_orders := v_orders || r.order_id;
9067
+ v_status := jsonb_set(v_status, ARRAY[COALESCE(r.status,'(leeg)')], to_jsonb(COALESCE((v_status->>COALESCE(r.status,'(leeg)'))::int, 0) + 1));
9068
+ END IF;
9069
+ IF EXISTS (SELECT 1 FROM public.floriday_sales_order_ingest i WHERE i.sales_order_id = r.source_line_key AND COALESCE((i.impact->>'fustPackages')::int,0) > 0) THEN
9070
+ n_ing := n_ing + 1;
9071
+ END IF;
9072
+ IF EXISTS (SELECT 1 FROM public.fust_startmoment) AND public.voorraad_lever_datum(r.delivery_date) <
9073
+ (SELECT (min(s.moment) AT TIME ZONE 'Europe/Amsterdam')::date FROM public.fust_startmoment s) THEN
9074
+ n_voor_fust := n_voor_fust + 1;
9075
+ END IF;
9076
+ IF jsonb_array_length(v_vb) < 20 THEN
9077
+ v_vb := v_vb || jsonb_build_object('order', r.order_number, 'order_item_id', r.id, 'status', r.status, 'leverdatum', r.delivery_date,
9078
+ 'trade_item_id', v_m->>'trade_item_id', 'product_id', v_m->>'product_id');
9079
+ END IF;
9080
+ IF p_uitvoeren THEN
9081
+ IF n_gedaan >= GREATEST(p_limiet, 1) OR clock_timestamp() - v_start > make_interval(secs => GREATEST(p_max_seconden, 1)) THEN
9082
+ n_rest := n_rest + 1;
9083
+ ELSE
9084
+ UPDATE public.order_items SET product_id = (v_m->>'product_id')::uuid WHERE id = r.id AND product_id IS NULL;
9085
+ IF FOUND THEN
9086
+ INSERT INTO public.voorraad_koppel_log(run_id, soort, floriday_id, product_id, order_item_id, oud, nieuw)
9087
+ VALUES (v_run, 'correctie_1144', v_m->>'trade_item_id', (v_m->>'product_id')::uuid, r.id,
9088
+ jsonb_build_object('product_id', NULL), jsonb_build_object('product_id', v_m->>'product_id'));
9089
+ n_gedaan := n_gedaan + 1;
9090
+ END IF;
9091
+ END IF;
9092
+ END IF;
9093
+ END IF;
9094
+ END LOOP;
9095
+ v_res := jsonb_build_object('per_categorie', v_tel, 'orders_per_status_invullen', v_status, 'orders_invullen', COALESCE(array_length(v_orders,1),0),
9096
+ 'regels_met_fustboeking_bij_binnenhalen', n_ing, 'regels_voor_fust_startmoment', n_voor_fust,
9097
+ 'ingevuld', n_gedaan, 'resterend', n_rest, 'run_id', CASE WHEN p_uitvoeren THEN v_run END);
9098
+ INSERT INTO public.voorraad_correcties(correctie, uitgevoerd_door, proef, aantallen, hash_ok)
9099
+ VALUES ('1144', COALESCE(auth.uid()::text, session_user::text), NOT p_uitvoeren, v_res, true);
9100
+ RETURN jsonb_build_object('ok', true, 'uitgevoerd', p_uitvoeren, 'voorbeelden', v_vb) || v_res;
9101
+ END $function$
9102
+ ;
9103
+ REVOKE ALL ON FUNCTION voorraad_correctie_1144(boolean,integer,integer) FROM PUBLIC;
9104
+ REVOKE ALL ON FUNCTION voorraad_correctie_1144(boolean,integer,integer) FROM anon;
9105
+ GRANT EXECUTE ON FUNCTION voorraad_correctie_1144(boolean,integer,integer) TO service_role;
8916
9106
  CREATE OR REPLACE FUNCTION public.voorraad_correctie_status(p_correctie text DEFAULT '1098'::text)
8917
9107
  RETURNS jsonb
8918
9108
  LANGUAGE plpgsql
@@ -8936,6 +9126,56 @@ REVOKE ALL ON FUNCTION voorraad_correctie_status(text) FROM PUBLIC;
8936
9126
  REVOKE ALL ON FUNCTION voorraad_correctie_status(text) FROM anon;
8937
9127
  GRANT EXECUTE ON FUNCTION voorraad_correctie_status(text) TO authenticated;
8938
9128
  GRANT EXECUTE ON FUNCTION voorraad_correctie_status(text) TO service_role;
9129
+ CREATE OR REPLACE FUNCTION public.voorraad_defaults_check()
9130
+ RETURNS jsonb
9131
+ LANGUAGE plpgsql
9132
+ STABLE SECURITY DEFINER
9133
+ SET search_path TO 'public'
9134
+ AS $function$
9135
+ DECLARE v_vert jsonb := '[]'::jsonb; r record; v_res jsonb; v_engine boolean;
9136
+ BEGIN
9137
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_defaults_check');
9138
+ v_engine := to_regprocedure('public.logistics_ladingdrager_resolve(text)') IS NOT NULL;
9139
+ IF v_engine THEN
9140
+ FOR r IN SELECT code FROM public.voorraad_load_carrier_types WHERE actief ORDER BY volgorde, code LOOP
9141
+ BEGIN
9142
+ EXECUTE 'SELECT public.logistics_ladingdrager_resolve($1)' INTO v_res USING r.code;
9143
+ EXCEPTION WHEN others THEN v_res := jsonb_build_object('code', NULL, 'fout', SQLERRM);
9144
+ END;
9145
+ IF v_res->>'code' IS NULL THEN
9146
+ v_vert := v_vert || jsonb_build_object('code', r.code, 'reden', COALESCE(v_res->>'fout', 'onbekend'));
9147
+ END IF;
9148
+ END LOOP;
9149
+ END IF;
9150
+ RETURN jsonb_build_object(
9151
+ 'versie_code', public.voorraad_defaults_versie(),
9152
+ 'versie_toegepast', (SELECT versie FROM public.voorraad_defaults_state WHERE id),
9153
+ 'plaatshoudercodes', (SELECT count(*) FROM public.voorraad_placeholder_codes),
9154
+ 'ladingdragers_actief', (SELECT count(*) FROM public.voorraad_load_carrier_types WHERE actief),
9155
+ 'herberekenlimieten_aanwezig', EXISTS (SELECT 1 FROM public.inventory_recompute_limits WHERE id),
9156
+ 'engine_vertaling_aanwezig', v_engine,
9157
+ 'ladingdragers_niet_vertaalbaar', CASE WHEN v_engine THEN v_vert ELSE NULL END);
9158
+ END $function$
9159
+ ;
9160
+ REVOKE ALL ON FUNCTION voorraad_defaults_check() FROM PUBLIC;
9161
+ REVOKE ALL ON FUNCTION voorraad_defaults_check() FROM anon;
9162
+ GRANT EXECUTE ON FUNCTION voorraad_defaults_check() TO authenticated;
9163
+ GRANT EXECUTE ON FUNCTION voorraad_defaults_check() TO service_role;
9164
+ CREATE OR REPLACE FUNCTION public.voorraad_defaults_versie()
9165
+ RETURNS integer
9166
+ LANGUAGE sql
9167
+ IMMUTABLE
9168
+ SET search_path TO 'public'
9169
+ AS $function$ SELECT 2 $function$
9170
+ ;
9171
+ REVOKE ALL ON FUNCTION voorraad_defaults_versie() FROM PUBLIC;
9172
+ REVOKE ALL ON FUNCTION voorraad_defaults_versie() FROM anon;
9173
+ REVOKE EXECUTE ON FUNCTION voorraad_defaults_versie() FROM PUBLIC;
9174
+ GRANT EXECUTE ON FUNCTION voorraad_defaults_versie() TO authenticated;
9175
+ GRANT EXECUTE ON FUNCTION voorraad_defaults_versie() TO service_role;
9176
+ REVOKE EXECUTE ON FUNCTION voorraad_defaults_versie() FROM anon;
9177
+ GRANT EXECUTE ON FUNCTION voorraad_defaults_versie() TO authenticated;
9178
+ GRANT EXECUTE ON FUNCTION voorraad_defaults_versie() TO service_role;
8939
9179
  CREATE OR REPLACE FUNCTION public.voorraad_dubbele_voorraadregels()
8940
9180
  RETURNS jsonb
8941
9181
  LANGUAGE plpgsql
@@ -8963,6 +9203,97 @@ REVOKE ALL ON FUNCTION voorraad_dubbele_voorraadregels() FROM PUBLIC;
8963
9203
  REVOKE ALL ON FUNCTION voorraad_dubbele_voorraadregels() FROM anon;
8964
9204
  GRANT EXECUTE ON FUNCTION voorraad_dubbele_voorraadregels() TO authenticated;
8965
9205
  GRANT EXECUTE ON FUNCTION voorraad_dubbele_voorraadregels() TO service_role;
9206
+ CREATE OR REPLACE FUNCTION public.voorraad_ensure_defaults()
9207
+ RETURNS jsonb
9208
+ LANGUAGE plpgsql
9209
+ SECURITY DEFINER
9210
+ SET search_path TO 'public'
9211
+ AS $function$
9212
+ DECLARE
9213
+ v_versie int := public.voorraad_defaults_versie();
9214
+ -- Systeemgegevens (standaardlijst). Wijzig je deze lijst: verhoog voorraad_defaults_versie().
9215
+ v_ph text[] := ARRAY['artikelcode','artikelnummer','naam','name','code','article code','articlecode','test','-','x','nvt','n.v.t.','tbd','todo'];
9216
+ v_lc jsonb := '[{"code":"AUCTION_TROLLEY","naam":"Stapelwagen","volgorde":1},{"code":"DANISH_TROLLEY","naam":"Deense container","volgorde":2},{"code":"EURO_TROLLEY","naam":"Euro-rolcontainer","volgorde":3},{"code":"PALLET","naam":"Pallet","volgorde":4},{"code":"EURO_PALLET","naam":"Euro-pallet","volgorde":5},{"code":"NONE","naam":"Geen ladingdrager","volgorde":6}]';
9217
+ v_vervallen text[] := ARRAY[]::text[];
9218
+ n_ph int := 0; n_lc_nieuw int := 0; n_lc_bij int := 0; n_lc_uit int := 0; n_lim int := 0; n_inst int := 0; n_fust int := 0;
9219
+ v_idx text := 'bestaat'; v_job text := 'bestaat'; v_res jsonb; v_job_ok boolean;
9220
+ BEGIN
9221
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_ensure_defaults');
9222
+ BEGIN
9223
+ BEGIN v_job_ok := EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'voorraad-floriday-artikelen-uurlijks'); EXCEPTION WHEN others THEN v_job_ok := true; END;
9224
+ IF EXISTS (SELECT 1 FROM public.voorraad_defaults_state s WHERE s.id AND s.versie = v_versie)
9225
+ AND EXISTS (SELECT 1 FROM public.inventory_recompute_limits l WHERE l.id)
9226
+ AND EXISTS (SELECT 1 FROM public.voorraad_placeholder_codes)
9227
+ AND EXISTS (SELECT 1 FROM public.voorraad_load_carrier_types)
9228
+ AND EXISTS (SELECT 1 FROM public.voorraad_instellingen WHERE id)
9229
+ AND NOT EXISTS (SELECT 1 FROM public.fust_types WHERE saldo_bijhouden IS NULL)
9230
+ AND v_job_ok THEN
9231
+ RETURN jsonb_build_object('ok', true, 'versie', v_versie, 'overgeslagen', true);
9232
+ END IF;
9233
+ PERFORM pg_advisory_xact_lock(hashtext('voorraad_ensure_defaults'));
9234
+
9235
+ INSERT INTO public.voorraad_placeholder_codes(code) SELECT c FROM unnest(v_ph) c ON CONFLICT (code) DO NOTHING;
9236
+ GET DIAGNOSTICS n_ph = ROW_COUNT;
9237
+ INSERT INTO public.voorraad_load_carrier_types(code, naam, volgorde)
9238
+ SELECT e->>'code', e->>'naam', (e->>'volgorde')::int FROM jsonb_array_elements(v_lc) e
9239
+ ON CONFLICT (code) DO NOTHING;
9240
+ GET DIAGNOSTICS n_lc_nieuw = ROW_COUNT;
9241
+ UPDATE public.voorraad_load_carrier_types t
9242
+ SET volgorde = (e->>'volgorde')::int,
9243
+ naam = CASE WHEN t.naam_aangepast THEN t.naam ELSE e->>'naam' END,
9244
+ updated_at = now()
9245
+ FROM jsonb_array_elements(v_lc) e
9246
+ WHERE t.code = e->>'code'
9247
+ AND (t.volgorde IS DISTINCT FROM (e->>'volgorde')::int OR (NOT t.naam_aangepast AND t.naam IS DISTINCT FROM e->>'naam'));
9248
+ GET DIAGNOSTICS n_lc_bij = ROW_COUNT;
9249
+ UPDATE public.voorraad_load_carrier_types t SET actief = false, updated_at = now() WHERE t.code = ANY(v_vervallen) AND t.actief;
9250
+ GET DIAGNOSTICS n_lc_uit = ROW_COUNT;
9251
+
9252
+ -- Klantinstellingen: alleen aanmaken als ze ontbreken, met de kolomstandaarden.
9253
+ INSERT INTO public.inventory_recompute_limits DEFAULT VALUES ON CONFLICT (id) DO NOTHING;
9254
+ GET DIAGNOSTICS n_lim = ROW_COUNT;
9255
+ INSERT INTO public.voorraad_instellingen DEFAULT VALUES ON CONFLICT (id) DO NOTHING;
9256
+ GET DIAGNOSTICS n_inst = ROW_COUNT;
9257
+ -- Saldo bijhouden: alleen invullen waar nog leeg (eenmalige verpakking 999 en 800 uit).
9258
+ UPDATE public.fust_types SET saldo_bijhouden = NOT COALESCE(vbn_code IN (999, 800), false) WHERE saldo_bijhouden IS NULL;
9259
+ GET DIAGNOSTICS n_fust = ROW_COUNT;
9260
+
9261
+ -- Unieke index op het Floriday-id; overslaan (en melden in de installatiecontrole) bij dubbelen.
9262
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE schemaname = 'public' AND indexname = 'products_floriday_trade_item_id_uniek') THEN
9263
+ IF jsonb_array_length(public.voorraad_floriday_dubbele_ids()) = 0 THEN
9264
+ BEGIN
9265
+ EXECUTE 'CREATE UNIQUE INDEX IF NOT EXISTS products_floriday_trade_item_id_uniek ON public.products (lower(btrim(floriday_trade_item_id))) WHERE NULLIF(btrim(COALESCE(floriday_trade_item_id, '''')), '''') IS NOT NULL';
9266
+ v_idx := 'aangemaakt';
9267
+ EXCEPTION WHEN others THEN v_idx := 'mislukt: ' || left(SQLERRM, 200);
9268
+ END;
9269
+ ELSE v_idx := 'overgeslagen: dubbele Floriday-id''s';
9270
+ END IF;
9271
+ END IF;
9272
+
9273
+ -- Uurlijkse controle van Floriday-artikelen (herhaalbaar, nooit dubbel).
9274
+ IF NOT v_job_ok THEN
9275
+ BEGIN
9276
+ PERFORM cron.schedule('voorraad-floriday-artikelen-uurlijks', '41 * * * *', 'SELECT public.voorraad_floriday_artikelen_vangnet()');
9277
+ v_job := 'ingepland';
9278
+ EXCEPTION WHEN others THEN v_job := 'mislukt: ' || left(SQLERRM, 200);
9279
+ END;
9280
+ END IF;
9281
+
9282
+ v_res := jsonb_build_object('plaatshoudercodes_toegevoegd', n_ph, 'ladingdragers_toegevoegd', n_lc_nieuw,
9283
+ 'ladingdragers_bijgewerkt', n_lc_bij, 'ladingdragers_niet_actief', n_lc_uit, 'herberekenlimieten_aangemaakt', n_lim,
9284
+ 'instellingen_aangemaakt', n_inst, 'fustsoorten_saldo_ingevuld', n_fust, 'unieke_index', v_idx, 'uurlijkse_controle', v_job);
9285
+ INSERT INTO public.voorraad_defaults_state(id, versie, toegepast_at, resultaat) VALUES (true, v_versie, now(), v_res)
9286
+ ON CONFLICT (id) DO UPDATE SET versie = EXCLUDED.versie, toegepast_at = EXCLUDED.toegepast_at, resultaat = EXCLUDED.resultaat;
9287
+ RETURN jsonb_build_object('ok', true, 'versie', v_versie, 'overgeslagen', false) || v_res;
9288
+ EXCEPTION WHEN others THEN
9289
+ RETURN jsonb_build_object('ok', false, 'versie', v_versie, 'melding', 'Standaardgegevens konden niet worden aangevuld', 'detail', SQLERRM);
9290
+ END;
9291
+ END $function$
9292
+ ;
9293
+ REVOKE ALL ON FUNCTION voorraad_ensure_defaults() FROM PUBLIC;
9294
+ REVOKE ALL ON FUNCTION voorraad_ensure_defaults() FROM anon;
9295
+ GRANT EXECUTE ON FUNCTION voorraad_ensure_defaults() TO authenticated;
9296
+ GRANT EXECUTE ON FUNCTION voorraad_ensure_defaults() TO service_role;
8966
9297
  CREATE OR REPLACE FUNCTION public.voorraad_external_fulfilled_ids(p_cf jsonb)
8967
9298
  RETURNS text[]
8968
9299
  LANGUAGE sql
@@ -9000,6 +9331,234 @@ REVOKE ALL ON FUNCTION voorraad_fcsq_local_guard() FROM PUBLIC;
9000
9331
  REVOKE ALL ON FUNCTION voorraad_fcsq_local_guard() FROM anon;
9001
9332
  GRANT EXECUTE ON FUNCTION voorraad_fcsq_local_guard() TO authenticated;
9002
9333
  GRANT EXECUTE ON FUNCTION voorraad_fcsq_local_guard() TO service_role;
9334
+ CREATE OR REPLACE FUNCTION public.voorraad_floriday_artikelen_aanmaken(p_connection_id uuid DEFAULT NULL::uuid, p_limiet integer DEFAULT 200, p_uitvoeren boolean DEFAULT false, p_max_seconden integer DEFAULT 20)
9335
+ RETURNS jsonb
9336
+ LANGUAGE plpgsql
9337
+ SECURITY DEFINER
9338
+ SET search_path TO 'public'
9339
+ AS $function$
9340
+ DECLARE
9341
+ v_conn uuid; v_start timestamptz := clock_timestamp(); v_run uuid := gen_random_uuid(); v_dups jsonb;
9342
+ c record; v_name text; v_gtin text; v_code text; v_photo text; v_ver text; v_del boolean;
9343
+ v_p record; v_c uuid[]; v_tier text; v_new uuid; v_sturing text; v_own_key text;
9344
+ n_aan int := 0; n_kop int := 0; n_twijfel int := 0; n_uit int := 0; n_bij int := 0; n_fout int := 0; n_rest int := 0;
9345
+ v_vb jsonb := '[]'::jsonb; v_aangepast text[];
9346
+ BEGIN
9347
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_floriday_artikelen_aanmaken');
9348
+ v_dups := public.voorraad_floriday_dubbele_ids();
9349
+ IF jsonb_array_length(v_dups) > 0 THEN
9350
+ RETURN jsonb_build_object('ok', false, 'melding', 'Er zijn artikelen met hetzelfde Floriday-id. Los die eerst op; er is niets aangemaakt.', 'dubbelen', v_dups);
9351
+ END IF;
9352
+ v_conn := COALESCE(p_connection_id, (SELECT x.connection_id FROM public.get_active_floriday_context() x LIMIT 1));
9353
+ IF v_conn IS NULL THEN RETURN jsonb_build_object('ok', true, 'melding', 'Geen actieve Floriday-koppeling'); END IF;
9354
+ IF p_uitvoeren AND NOT pg_try_advisory_xact_lock(hashtext('voorraad_floriday_artikelen_aanmaken')) THEN
9355
+ RETURN jsonb_build_object('ok', false, 'melding', 'Er loopt al een ronde');
9356
+ END IF;
9357
+ SELECT COALESCE(standaard_sturing_nieuwe_floriday, 'lokaal') INTO v_sturing FROM public.voorraad_instellingen WHERE id;
9358
+ v_sturing := COALESCE(v_sturing, 'lokaal');
9359
+ IF p_uitvoeren THEN PERFORM set_config('voorraad.floriday_sync', 'on', true); END IF;
9360
+
9361
+ FOR c IN
9362
+ SELECT t.floriday_id, t.data, (COALESCE(t.is_deleted,false) OR COALESCE((t.data->>'isDeleted')::boolean,false)) AS del
9363
+ FROM public.floriday_trade_items_cache t
9364
+ WHERE t.connection_id = v_conn
9365
+ AND (
9366
+ (NOT (COALESCE(t.is_deleted,false) OR COALESCE((t.data->>'isDeleted')::boolean,false))
9367
+ AND NOT EXISTS (SELECT 1 FROM public.products p WHERE lower(btrim(p.floriday_trade_item_id)) = lower(t.floriday_id))
9368
+ AND NOT EXISTS (SELECT 1 FROM public.voorraad_koppel_twijfel w WHERE w.floriday_id = t.floriday_id AND w.opgelost_at IS NULL AND w.laatst_gezien > now() - interval '1 hour' AND p_uitvoeren))
9369
+ OR ((COALESCE(t.is_deleted,false) OR COALESCE((t.data->>'isDeleted')::boolean,false))
9370
+ AND EXISTS (SELECT 1 FROM public.products p WHERE lower(btrim(p.floriday_trade_item_id)) = lower(t.floriday_id) AND p.floriday_verwijderd_at IS NULL))
9371
+ OR (NOT (COALESCE(t.is_deleted,false) OR COALESCE((t.data->>'isDeleted')::boolean,false))
9372
+ AND EXISTS (SELECT 1 FROM public.products p WHERE lower(btrim(p.floriday_trade_item_id)) = lower(t.floriday_id)
9373
+ AND (p.floriday_verwijderd_at IS NOT NULL
9374
+ OR (p.custom_fields->>'voorraad_auto_aangemaakt' = 'true'
9375
+ AND p.custom_fields->>'voorraad_floriday_versie' IS DISTINCT FROM t.data->>'tradeItemVersion'))))
9376
+ )
9377
+ ORDER BY t.floriday_id
9378
+ LOOP
9379
+ IF n_aan + n_kop + n_twijfel + n_uit + n_bij + n_fout >= GREATEST(p_limiet, 1)
9380
+ OR clock_timestamp() - v_start > make_interval(secs => GREATEST(p_max_seconden, 1)) THEN
9381
+ n_rest := n_rest + 1; CONTINUE;
9382
+ END IF;
9383
+ v_name := NULLIF(btrim(COALESCE(CASE WHEN jsonb_typeof(c.data->'tradeItemName') = 'string' THEN c.data->>'tradeItemName' END,
9384
+ c.data->'tradeItemName'->>'nl', c.data->'tradeItemName'->>'en')), '');
9385
+ v_gtin := NULLIF(btrim(COALESCE(c.data->>'articleGtin', c.data->>'gtin')), '');
9386
+ v_code := NULLIF(btrim(COALESCE(c.data->>'supplierArticleCode', c.data->>'articleCode')), '');
9387
+ SELECT e->>'url' INTO v_photo FROM jsonb_array_elements(CASE WHEN jsonb_typeof(c.data->'photos') = 'array' THEN c.data->'photos' ELSE '[]'::jsonb END) e
9388
+ ORDER BY COALESCE((e->>'primary')::boolean, false) DESC LIMIT 1;
9389
+ v_ver := c.data->>'tradeItemVersion';
9390
+ SELECT p.* INTO v_p FROM public.products p WHERE lower(btrim(p.floriday_trade_item_id)) = lower(c.floriday_id) LIMIT 1;
9391
+
9392
+ BEGIN
9393
+ IF c.del THEN
9394
+ -- Verwijderd in Floriday: eigen artikel op niet actief, nooit verwijderen.
9395
+ IF p_uitvoeren THEN
9396
+ UPDATE public.products SET floriday_verwijderd_at = now(), updated_at = now() WHERE id = v_p.id;
9397
+ INSERT INTO public.voorraad_koppel_log(run_id, soort, floriday_id, product_id, oud, nieuw)
9398
+ VALUES (v_run, 'niet_actief', c.floriday_id, v_p.id, jsonb_build_object('floriday_verwijderd_at', NULL), jsonb_build_object('floriday_verwijderd_at', now()));
9399
+ END IF;
9400
+ n_uit := n_uit + 1;
9401
+ ELSIF v_p.id IS NOT NULL THEN
9402
+ -- Bestaand artikel bijwerken uit Floriday, alleen velden die de klant niet zelf aanpaste.
9403
+ v_aangepast := COALESCE(v_p.floriday_velden_aangepast, ARRAY[]::text[]);
9404
+ IF p_uitvoeren THEN
9405
+ UPDATE public.products SET
9406
+ floriday_verwijderd_at = NULL,
9407
+ product = CASE WHEN v_p.custom_fields->>'voorraad_auto_aangemaakt' = 'true' AND NOT ('product' = ANY(v_aangepast)) AND v_name IS NOT NULL THEN v_name ELSE product END,
9408
+ image_url = CASE WHEN v_p.custom_fields->>'voorraad_auto_aangemaakt' = 'true' AND NOT ('image_url' = ANY(v_aangepast)) AND v_photo IS NOT NULL THEN v_photo ELSE image_url END,
9409
+ barcode = CASE WHEN v_p.custom_fields->>'voorraad_auto_aangemaakt' = 'true' AND NOT ('barcode' = ANY(v_aangepast)) AND v_gtin IS NOT NULL THEN v_gtin ELSE barcode END,
9410
+ custom_fields = CASE WHEN v_p.custom_fields->>'voorraad_auto_aangemaakt' = 'true'
9411
+ THEN COALESCE(custom_fields, '{}'::jsonb) || jsonb_build_object('voorraad_floriday_versie', v_ver) ELSE custom_fields END,
9412
+ updated_at = now()
9413
+ WHERE id = v_p.id;
9414
+ INSERT INTO public.voorraad_koppel_log(run_id, soort, floriday_id, product_id, oud, nieuw)
9415
+ VALUES (v_run, 'bijgewerkt', c.floriday_id, v_p.id,
9416
+ jsonb_build_object('product', v_p.product, 'image_url', v_p.image_url, 'barcode', v_p.barcode, 'floriday_verwijderd_at', v_p.floriday_verwijderd_at),
9417
+ jsonb_build_object('naam', v_name, 'foto', v_photo, 'gtin', v_gtin, 'versie', v_ver, 'aangepast_door_klant', to_jsonb(v_aangepast)));
9418
+ END IF;
9419
+ n_bij := n_bij + 1;
9420
+ ELSE
9421
+ -- Zoeken: eerst GTIN, dan artikelcode, dan naam. Eerste niveau met treffers telt.
9422
+ v_c := NULL; v_tier := NULL;
9423
+ IF v_gtin IS NOT NULL THEN
9424
+ SELECT array_agg(p.id ORDER BY p.id) INTO v_c FROM public.products p
9425
+ WHERE NULLIF(btrim(COALESCE(p.floriday_trade_item_id,'')),'') IS NULL AND p.floriday_verwijderd_at IS NULL
9426
+ AND COALESCE(p.custom_fields->>'source','') <> 'sales-module-floriday-mirror' AND btrim(COALESCE(p.barcode,'')) = v_gtin;
9427
+ IF v_c IS NOT NULL THEN v_tier := 'GTIN'; END IF;
9428
+ END IF;
9429
+ IF v_c IS NULL AND v_code IS NOT NULL THEN
9430
+ SELECT array_agg(p.id ORDER BY p.id) INTO v_c FROM public.products p
9431
+ WHERE NULLIF(btrim(COALESCE(p.floriday_trade_item_id,'')),'') IS NULL AND p.floriday_verwijderd_at IS NULL
9432
+ AND COALESCE(p.custom_fields->>'source','') <> 'sales-module-floriday-mirror'
9433
+ AND (lower(btrim(COALESCE(p.article_number,''))) = lower(v_code) OR btrim(COALESCE(p.barcode,'')) = v_code);
9434
+ IF v_c IS NOT NULL THEN v_tier := 'artikelcode'; END IF;
9435
+ END IF;
9436
+ IF v_c IS NULL AND v_name IS NOT NULL THEN
9437
+ SELECT array_agg(p.id ORDER BY p.id) INTO v_c FROM public.products p
9438
+ WHERE NULLIF(btrim(COALESCE(p.floriday_trade_item_id,'')),'') IS NULL AND p.floriday_verwijderd_at IS NULL
9439
+ AND COALESCE(p.custom_fields->>'source','') <> 'sales-module-floriday-mirror' AND lower(btrim(COALESCE(p.product,''))) = lower(v_name);
9440
+ IF v_c IS NOT NULL THEN v_tier := 'naam'; END IF;
9441
+ END IF;
9442
+
9443
+ IF v_c IS NOT NULL AND array_length(v_c, 1) > 1 THEN
9444
+ IF p_uitvoeren THEN
9445
+ INSERT INTO public.voorraad_koppel_twijfel(floriday_id, connection_id, naam, reden, kandidaten)
9446
+ VALUES (c.floriday_id, v_conn, v_name, 'Meerdere eigen artikelen met dezelfde ' || v_tier, to_jsonb(v_c))
9447
+ ON CONFLICT (floriday_id) DO UPDATE SET reden = EXCLUDED.reden, kandidaten = EXCLUDED.kandidaten, naam = EXCLUDED.naam, laatst_gezien = now(), opgelost_at = NULL;
9448
+ END IF;
9449
+ n_twijfel := n_twijfel + 1;
9450
+ v_vb := v_vb || jsonb_build_object('floriday_id', c.floriday_id, 'naam', v_name, 'uitkomst', 'twijfel', 'reden', 'meerdere op ' || v_tier);
9451
+ ELSIF v_c IS NOT NULL THEN
9452
+ v_own_key := public.voorraad_canoniek_sleutel(v_c[1]);
9453
+ IF lower(v_own_key) <> lower(c.floriday_id)
9454
+ AND EXISTS (SELECT 1 FROM public.trade_item_stock s WHERE s.trade_item_key = v_own_key AND s.archived_at IS NULL)
9455
+ AND EXISTS (SELECT 1 FROM public.trade_item_stock s WHERE lower(s.trade_item_key) = lower(c.floriday_id) AND s.archived_at IS NULL) THEN
9456
+ IF p_uitvoeren THEN
9457
+ INSERT INTO public.voorraad_koppel_twijfel(floriday_id, connection_id, naam, reden, kandidaten)
9458
+ VALUES (c.floriday_id, v_conn, v_name, 'Eigen artikel en Floriday-product hebben elk een eigen voorraadregel; eerst samenvoegen', to_jsonb(v_c))
9459
+ ON CONFLICT (floriday_id) DO UPDATE SET reden = EXCLUDED.reden, kandidaten = EXCLUDED.kandidaten, naam = EXCLUDED.naam, laatst_gezien = now(), opgelost_at = NULL;
9460
+ END IF;
9461
+ n_twijfel := n_twijfel + 1;
9462
+ v_vb := v_vb || jsonb_build_object('floriday_id', c.floriday_id, 'naam', v_name, 'uitkomst', 'twijfel', 'reden', 'twee voorraadregels');
9463
+ ELSE
9464
+ IF p_uitvoeren THEN
9465
+ UPDATE public.products SET floriday_trade_item_id = c.floriday_id, updated_at = now() WHERE id = v_c[1];
9466
+ INSERT INTO public.voorraad_koppel_log(run_id, soort, floriday_id, product_id, oud, nieuw)
9467
+ VALUES (v_run, 'gekoppeld', c.floriday_id, v_c[1], jsonb_build_object('floriday_trade_item_id', NULL), jsonb_build_object('floriday_trade_item_id', c.floriday_id, 'op', v_tier));
9468
+ UPDATE public.voorraad_koppel_twijfel SET opgelost_at = now() WHERE floriday_id = c.floriday_id AND opgelost_at IS NULL;
9469
+ END IF;
9470
+ n_kop := n_kop + 1;
9471
+ v_vb := v_vb || jsonb_build_object('floriday_id', c.floriday_id, 'naam', v_name, 'uitkomst', 'gekoppeld', 'op', v_tier);
9472
+ END IF;
9473
+ ELSE
9474
+ -- Geen match: eigen artikel aanmaken op dezelfde voorraadsleutel als het Floriday-product.
9475
+ IF v_name IS NULL THEN
9476
+ IF p_uitvoeren THEN
9477
+ INSERT INTO public.voorraad_koppel_twijfel(floriday_id, connection_id, naam, reden)
9478
+ VALUES (c.floriday_id, v_conn, NULL, 'Floriday-product heeft geen naam')
9479
+ ON CONFLICT (floriday_id) DO UPDATE SET reden = EXCLUDED.reden, laatst_gezien = now(), opgelost_at = NULL;
9480
+ END IF;
9481
+ n_twijfel := n_twijfel + 1;
9482
+ ELSE
9483
+ IF p_uitvoeren THEN
9484
+ INSERT INTO public.products(product, batch, location, barcode, article_number, image_url, floriday_trade_item_id, trade_item_key, custom_fields)
9485
+ VALUES (v_name, '', '', v_gtin, v_code, v_photo, c.floriday_id,
9486
+ COALESCE((SELECT s.trade_item_key FROM public.trade_item_stock s WHERE lower(s.trade_item_key) = lower(c.floriday_id) AND s.archived_at IS NULL ORDER BY s.created_at LIMIT 1), c.floriday_id),
9487
+ jsonb_build_object('voorraad_auto_aangemaakt', true, 'voorraad_floriday_versie', v_ver, 'voorraad_auto_aangemaakt_at', now()))
9488
+ RETURNING id INTO v_new;
9489
+ IF v_sturing = 'lokaal' THEN
9490
+ -- Lokaal: eigen voorraad leidt, Floriday volgt niet (geen ERP-leidend, sturing uit).
9491
+ UPDATE public.floriday_inventory_settings SET erp_leading = NULL, stock_mode = 'DISABLED', updated_at = now()
9492
+ WHERE product_id = v_new;
9493
+ END IF;
9494
+ INSERT INTO public.voorraad_koppel_log(run_id, soort, floriday_id, product_id, oud, nieuw)
9495
+ VALUES (v_run, 'aangemaakt', c.floriday_id, v_new, NULL,
9496
+ jsonb_build_object('naam', v_name, 'gtin', v_gtin, 'artikelcode', v_code, 'sturing', v_sturing));
9497
+ UPDATE public.voorraad_koppel_twijfel SET opgelost_at = now() WHERE floriday_id = c.floriday_id AND opgelost_at IS NULL;
9498
+ END IF;
9499
+ n_aan := n_aan + 1;
9500
+ END IF;
9501
+ END IF;
9502
+ END IF;
9503
+ EXCEPTION WHEN others THEN
9504
+ n_fout := n_fout + 1;
9505
+ BEGIN
9506
+ INSERT INTO public.voorraad_koppel_twijfel(floriday_id, connection_id, naam, reden)
9507
+ VALUES (c.floriday_id, v_conn, v_name, 'Aanmaken of koppelen mislukt: ' || left(SQLERRM, 300))
9508
+ ON CONFLICT (floriday_id) DO UPDATE SET reden = EXCLUDED.reden, laatst_gezien = now(), opgelost_at = NULL;
9509
+ EXCEPTION WHEN others THEN NULL;
9510
+ END;
9511
+ END;
9512
+ END LOOP;
9513
+
9514
+ RETURN jsonb_build_object('ok', true, 'uitgevoerd', p_uitvoeren, 'run_id', CASE WHEN p_uitvoeren THEN v_run END,
9515
+ 'aangemaakt', n_aan, 'gekoppeld', n_kop, 'twijfel', n_twijfel, 'niet_actief', n_uit, 'bijgewerkt', n_bij,
9516
+ 'fouten', n_fout, 'resterend', n_rest, 'sturing', v_sturing,
9517
+ 'voorbeelden', (SELECT COALESCE(jsonb_agg(e), '[]'::jsonb) FROM (SELECT e FROM jsonb_array_elements(v_vb) e LIMIT 25) z));
9518
+ END $function$
9519
+ ;
9520
+ REVOKE ALL ON FUNCTION voorraad_floriday_artikelen_aanmaken(uuid,integer,boolean,integer) FROM PUBLIC;
9521
+ REVOKE ALL ON FUNCTION voorraad_floriday_artikelen_aanmaken(uuid,integer,boolean,integer) FROM anon;
9522
+ GRANT EXECUTE ON FUNCTION voorraad_floriday_artikelen_aanmaken(uuid,integer,boolean,integer) TO authenticated;
9523
+ GRANT EXECUTE ON FUNCTION voorraad_floriday_artikelen_aanmaken(uuid,integer,boolean,integer) TO service_role;
9524
+ CREATE OR REPLACE FUNCTION public.voorraad_floriday_artikelen_vangnet()
9525
+ RETURNS jsonb
9526
+ LANGUAGE plpgsql
9527
+ SECURITY DEFINER
9528
+ SET search_path TO 'public'
9529
+ AS $function$
9530
+ DECLARE v jsonb; v_t timestamptz := now();
9531
+ BEGIN
9532
+ PERFORM public.voorraad_vereis('server', 'voorraad_floriday_artikelen_vangnet');
9533
+ v := public.voorraad_floriday_artikelen_aanmaken(NULL, 500, true, 45);
9534
+ IF COALESCE((v->>'resterend')::int, 0) = 0 THEN
9535
+ DELETE FROM public.voorraad_floriday_artikel_wachtrij WHERE aangemeld_at <= v_t;
9536
+ END IF;
9537
+ IF NOT EXISTS (SELECT 1 FROM public.voorraad_floriday_artikel_wachtrij) THEN
9538
+ BEGIN PERFORM cron.unschedule('voorraad-floriday-artikelen-drain'); EXCEPTION WHEN others THEN NULL; END;
9539
+ END IF;
9540
+ RETURN v;
9541
+ END $function$
9542
+ ;
9543
+ REVOKE ALL ON FUNCTION voorraad_floriday_artikelen_vangnet() FROM PUBLIC;
9544
+ REVOKE ALL ON FUNCTION voorraad_floriday_artikelen_vangnet() FROM anon;
9545
+ GRANT EXECUTE ON FUNCTION voorraad_floriday_artikelen_vangnet() TO service_role;
9546
+ CREATE OR REPLACE FUNCTION public.voorraad_floriday_dubbele_ids()
9547
+ RETURNS jsonb
9548
+ LANGUAGE sql
9549
+ STABLE SECURITY DEFINER
9550
+ SET search_path TO 'public'
9551
+ AS $function$
9552
+ SELECT COALESCE(jsonb_agg(jsonb_build_object('floriday_id', k, 'artikelen', ids) ORDER BY k), '[]'::jsonb)
9553
+ FROM (SELECT lower(btrim(floriday_trade_item_id)) k, jsonb_agg(id ORDER BY id) ids
9554
+ FROM public.products WHERE NULLIF(btrim(COALESCE(floriday_trade_item_id,'')),'') IS NOT NULL
9555
+ GROUP BY 1 HAVING count(*) > 1) d
9556
+ $function$
9557
+ ;
9558
+ REVOKE ALL ON FUNCTION voorraad_floriday_dubbele_ids() FROM PUBLIC;
9559
+ REVOKE ALL ON FUNCTION voorraad_floriday_dubbele_ids() FROM anon;
9560
+ GRANT EXECUTE ON FUNCTION voorraad_floriday_dubbele_ids() TO authenticated;
9561
+ GRANT EXECUTE ON FUNCTION voorraad_floriday_dubbele_ids() TO service_role;
9003
9562
  CREATE OR REPLACE FUNCTION public.voorraad_floriday_klaarzetten_toegestaan()
9004
9563
  RETURNS boolean
9005
9564
  LANGUAGE plpgsql
@@ -9043,6 +9602,20 @@ $function$
9043
9602
  REVOKE ALL ON FUNCTION voorraad_floriday_leads_key(text) FROM PUBLIC;
9044
9603
  REVOKE ALL ON FUNCTION voorraad_floriday_leads_key(text) FROM anon;
9045
9604
  GRANT EXECUTE ON FUNCTION voorraad_floriday_leads_key(text) TO service_role;
9605
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_bijhouden(p_fust_type_id uuid)
9606
+ RETURNS boolean
9607
+ LANGUAGE sql
9608
+ STABLE SECURITY DEFINER
9609
+ SET search_path TO 'public'
9610
+ AS $function$
9611
+ SELECT COALESCE(f.saldo_bijhouden, NOT COALESCE(f.vbn_code IN (999, 800), false))
9612
+ FROM public.fust_types f WHERE f.id = p_fust_type_id
9613
+ $function$
9614
+ ;
9615
+ REVOKE ALL ON FUNCTION voorraad_fust_bijhouden(uuid) FROM PUBLIC;
9616
+ REVOKE ALL ON FUNCTION voorraad_fust_bijhouden(uuid) FROM anon;
9617
+ GRANT EXECUTE ON FUNCTION voorraad_fust_bijhouden(uuid) TO authenticated;
9618
+ GRANT EXECUTE ON FUNCTION voorraad_fust_bijhouden(uuid) TO service_role;
9046
9619
  CREATE OR REPLACE FUNCTION public.voorraad_fust_dimensions()
9047
9620
  RETURNS TABLE(fust_type_id uuid, fust_key text, vbn_code integer, name text, floricode_name text, length_mm numeric, width_mm numeric, height_mm numeric, dimension_source text)
9048
9621
  LANGUAGE plpgsql
@@ -9091,6 +9664,25 @@ REVOKE ALL ON FUNCTION voorraad_fust_dimensions() FROM PUBLIC;
9091
9664
  REVOKE ALL ON FUNCTION voorraad_fust_dimensions() FROM anon;
9092
9665
  GRANT EXECUTE ON FUNCTION voorraad_fust_dimensions() TO authenticated;
9093
9666
  GRANT EXECUTE ON FUNCTION voorraad_fust_dimensions() TO service_role;
9667
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_instellingen_opslaan(p_fust_type_id uuid, p_saldo_bijhouden boolean, p_eigen_naam text)
9668
+ RETURNS jsonb
9669
+ LANGUAGE plpgsql
9670
+ SECURITY DEFINER
9671
+ SET search_path TO 'public'
9672
+ AS $function$
9673
+ BEGIN
9674
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_fust_instellingen_opslaan');
9675
+ UPDATE public.fust_types SET saldo_bijhouden = COALESCE(p_saldo_bijhouden, saldo_bijhouden),
9676
+ eigen_naam = NULLIF(btrim(COALESCE(p_eigen_naam, '')), ''), updated_at = now()
9677
+ WHERE id = p_fust_type_id;
9678
+ IF NOT FOUND THEN RETURN jsonb_build_object('ok', false, 'melding', 'Fustsoort niet gevonden'); END IF;
9679
+ RETURN jsonb_build_object('ok', true);
9680
+ END $function$
9681
+ ;
9682
+ REVOKE ALL ON FUNCTION voorraad_fust_instellingen_opslaan(uuid,boolean,text) FROM PUBLIC;
9683
+ REVOKE ALL ON FUNCTION voorraad_fust_instellingen_opslaan(uuid,boolean,text) FROM anon;
9684
+ GRANT EXECUTE ON FUNCTION voorraad_fust_instellingen_opslaan(uuid,boolean,text) TO authenticated;
9685
+ GRANT EXECUTE ON FUNCTION voorraad_fust_instellingen_opslaan(uuid,boolean,text) TO service_role;
9094
9686
  CREATE OR REPLACE FUNCTION public.voorraad_fust_juist(p_order_item_id uuid)
9095
9687
  RETURNS TABLE(fust_type_id uuid, fust_key text, aantal integer, bron text)
9096
9688
  LANGUAGE plpgsql
@@ -9098,10 +9690,10 @@ CREATE OR REPLACE FUNCTION public.voorraad_fust_juist(p_order_item_id uuid)
9098
9690
  SET search_path TO 'public'
9099
9691
  AS $function$
9100
9692
  DECLARE
9101
- v_item record; v_packs jsonb; v_pack jsonb; v_key text; v_units numeric; v_needed integer; v_bron text;
9693
+ v_item record; v_packs jsonb; v_pack jsonb; v_key text; v_units numeric; v_needed integer; v_bron text; v_ft uuid;
9102
9694
  BEGIN
9103
9695
  PERFORM public.voorraad_vereis('ingelogd', 'voorraad_fust_juist');
9104
- 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
9696
+ 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, o.delivery_date AS o_lever
9105
9697
  INTO v_item
9106
9698
  FROM logistics_active.order_items oi
9107
9699
  JOIN public.order_items x ON x.id = oi.id
@@ -9149,6 +9741,12 @@ BEGIN
9149
9741
  IF v_key IS NULL OR COALESCE(v_needed, 0) <= 0 THEN RETURN; END IF;
9150
9742
  fust_type_id := public.voorraad_active_fust_id(v_key, NULL);
9151
9743
  fust_key := v_key; aantal := v_needed; bron := v_bron;
9744
+ v_ft := fust_type_id;
9745
+ IF public.voorraad_fust_voor_startmoment(v_ft, public.voorraad_lever_datum(v_item.o_lever)) THEN
9746
+ -- Vóór het fust-startmoment: geen herberekening, het geboekte aantal blijft juist.
9747
+ aantal := COALESCE((SELECT sum(b.quantity)::int FROM public.order_fust_bookings b WHERE b.order_item_id = p_order_item_id AND b.fust_type_id = v_ft), 0);
9748
+ bron := 'vóór fust-startmoment: niet herberekend';
9749
+ END IF;
9152
9750
  RETURN NEXT;
9153
9751
  END $function$
9154
9752
  ;
@@ -9156,6 +9754,96 @@ REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM PUBLIC;
9156
9754
  REVOKE ALL ON FUNCTION voorraad_fust_juist(uuid) FROM anon;
9157
9755
  GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO authenticated;
9158
9756
  GRANT EXECUTE ON FUNCTION voorraad_fust_juist(uuid) TO service_role;
9757
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_startmoment_auto()
9758
+ RETURNS boolean
9759
+ LANGUAGE plpgsql
9760
+ SECURITY DEFINER
9761
+ SET search_path TO 'public'
9762
+ AS $function$
9763
+ BEGIN
9764
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_fust_startmoment_auto');
9765
+ IF EXISTS (SELECT 1 FROM public.fust_startmoment) OR EXISTS (SELECT 1 FROM public.fust_stock_mutations) THEN RETURN false; END IF;
9766
+ PERFORM pg_advisory_xact_lock(hashtext('voorraad_fust_startmoment'));
9767
+ IF EXISTS (SELECT 1 FROM public.fust_startmoment) OR EXISTS (SELECT 1 FROM public.fust_stock_mutations) THEN RETURN false; END IF;
9768
+ INSERT INTO public.fust_startmoment(fust_type_id, moment, beginstand, automatisch, door) VALUES (NULL, now(), 0, true, NULL);
9769
+ INSERT INTO public.fust_startmoment_log(fust_type_id, moment, beginstand, saldo_voor, saldo_na, automatisch, notitie, door)
9770
+ VALUES (NULL, now(), 0, 0, 0, true, 'Automatisch bij de eerste Floriday-ordersynchronisatie; vul de beginstand in', NULL);
9771
+ RETURN true;
9772
+ END $function$
9773
+ ;
9774
+ REVOKE ALL ON FUNCTION voorraad_fust_startmoment_auto() FROM PUBLIC;
9775
+ REVOKE ALL ON FUNCTION voorraad_fust_startmoment_auto() FROM anon;
9776
+ GRANT EXECUTE ON FUNCTION voorraad_fust_startmoment_auto() TO authenticated;
9777
+ GRANT EXECUTE ON FUNCTION voorraad_fust_startmoment_auto() TO service_role;
9778
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_startmoment_opslaan(p_fust_type_id uuid, p_moment timestamp with time zone, p_beginstand integer, p_beginstanden jsonb DEFAULT NULL::jsonb, p_notitie text DEFAULT NULL::text)
9779
+ RETURNS jsonb
9780
+ LANGUAGE plpgsql
9781
+ SECURITY DEFINER
9782
+ SET search_path TO 'public'
9783
+ AS $function$
9784
+ DECLARE f record; v_begin int; v_na_start int; v_doel int; n int := 0;
9785
+ BEGIN
9786
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_fust_startmoment_opslaan');
9787
+ IF p_moment IS NULL OR p_beginstand IS NULL THEN RETURN jsonb_build_object('ok', false, 'melding', 'Vul een startmoment en een beginstand in'); END IF;
9788
+ PERFORM pg_advisory_xact_lock(hashtext('voorraad_fust_startmoment'));
9789
+ INSERT INTO public.fust_startmoment(fust_type_id, moment, beginstand, automatisch, door)
9790
+ VALUES (p_fust_type_id, p_moment, p_beginstand, false, auth.uid())
9791
+ ON CONFLICT ((COALESCE(fust_type_id, '00000000-0000-0000-0000-000000000000'::uuid)))
9792
+ DO UPDATE SET moment = EXCLUDED.moment, beginstand = EXCLUDED.beginstand, automatisch = false, door = auth.uid(), updated_at = now();
9793
+ FOR f IN SELECT t.id, t.stock FROM public.fust_types t
9794
+ WHERE t.merged_into IS NULL AND (t.id = p_fust_type_id OR (p_fust_type_id IS NULL AND NOT EXISTS (SELECT 1 FROM public.fust_startmoment s WHERE s.fust_type_id = t.id)))
9795
+ ORDER BY t.id FOR UPDATE
9796
+ LOOP
9797
+ v_begin := COALESCE(NULLIF(p_beginstanden->>f.id::text, '')::int, p_beginstand);
9798
+ SELECT COALESCE(sum(m.delta), 0)::int INTO v_na_start FROM public.fust_stock_mutations m
9799
+ WHERE m.fust_type_id = f.id AND m.created_at >= p_moment AND m.reason <> 'startmoment';
9800
+ v_doel := v_begin + v_na_start;
9801
+ IF v_doel <> f.stock THEN
9802
+ INSERT INTO public.fust_stock_mutations(user_id, fust_type_id, delta, reason, note)
9803
+ VALUES (COALESCE(auth.uid(), (SELECT user_id FROM public.fust_types WHERE id = f.id)), f.id, v_doel - f.stock, 'startmoment',
9804
+ 'Startmoment ' || to_char(p_moment AT TIME ZONE 'Europe/Amsterdam', 'DD-MM-YYYY HH24:MI') || ', beginstand ' || v_begin
9805
+ || COALESCE(' — ' || NULLIF(btrim(COALESCE(p_notitie,'')),''), ''));
9806
+ END IF;
9807
+ INSERT INTO public.fust_startmoment_log(fust_type_id, moment, beginstand, saldo_voor, saldo_na, automatisch, notitie)
9808
+ VALUES (f.id, p_moment, v_begin, f.stock, v_doel, false, NULLIF(btrim(COALESCE(p_notitie,'')),''));
9809
+ n := n + 1;
9810
+ END LOOP;
9811
+ RETURN jsonb_build_object('ok', true, 'fustsoorten', n);
9812
+ END $function$
9813
+ ;
9814
+ REVOKE ALL ON FUNCTION voorraad_fust_startmoment_opslaan(uuid,timestamp with time zone,integer,jsonb,text) FROM PUBLIC;
9815
+ REVOKE ALL ON FUNCTION voorraad_fust_startmoment_opslaan(uuid,timestamp with time zone,integer,jsonb,text) FROM anon;
9816
+ GRANT EXECUTE ON FUNCTION voorraad_fust_startmoment_opslaan(uuid,timestamp with time zone,integer,jsonb,text) TO authenticated;
9817
+ GRANT EXECUTE ON FUNCTION voorraad_fust_startmoment_opslaan(uuid,timestamp with time zone,integer,jsonb,text) TO service_role;
9818
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_startmoment_van(p_fust_type_id uuid)
9819
+ RETURNS timestamp with time zone
9820
+ LANGUAGE sql
9821
+ STABLE SECURITY DEFINER
9822
+ SET search_path TO 'public'
9823
+ AS $function$
9824
+ SELECT COALESCE(
9825
+ (SELECT s.moment FROM public.fust_startmoment s WHERE s.fust_type_id = public.voorraad_active_fust_id(NULL, p_fust_type_id)),
9826
+ (SELECT s.moment FROM public.fust_startmoment s WHERE s.fust_type_id IS NULL))
9827
+ $function$
9828
+ ;
9829
+ REVOKE ALL ON FUNCTION voorraad_fust_startmoment_van(uuid) FROM PUBLIC;
9830
+ REVOKE ALL ON FUNCTION voorraad_fust_startmoment_van(uuid) FROM anon;
9831
+ GRANT EXECUTE ON FUNCTION voorraad_fust_startmoment_van(uuid) TO authenticated;
9832
+ GRANT EXECUTE ON FUNCTION voorraad_fust_startmoment_van(uuid) TO service_role;
9833
+ CREATE OR REPLACE FUNCTION public.voorraad_fust_voor_startmoment(p_fust_type_id uuid, p_lever date)
9834
+ RETURNS boolean
9835
+ LANGUAGE sql
9836
+ STABLE SECURITY DEFINER
9837
+ SET search_path TO 'public'
9838
+ AS $function$
9839
+ SELECT p_fust_type_id IS NOT NULL AND p_lever IS NOT NULL
9840
+ AND COALESCE(p_lever < (public.voorraad_fust_startmoment_van(p_fust_type_id) AT TIME ZONE 'Europe/Amsterdam')::date, false)
9841
+ $function$
9842
+ ;
9843
+ REVOKE ALL ON FUNCTION voorraad_fust_voor_startmoment(uuid,date) FROM PUBLIC;
9844
+ REVOKE ALL ON FUNCTION voorraad_fust_voor_startmoment(uuid,date) FROM anon;
9845
+ GRANT EXECUTE ON FUNCTION voorraad_fust_voor_startmoment(uuid,date) TO authenticated;
9846
+ GRANT EXECUTE ON FUNCTION voorraad_fust_voor_startmoment(uuid,date) TO service_role;
9159
9847
  CREATE OR REPLACE FUNCTION public.voorraad_gateway_routes_check()
9160
9848
  RETURNS jsonb
9161
9849
  LANGUAGE plpgsql
@@ -9301,9 +9989,9 @@ CREATE OR REPLACE FUNCTION public.voorraad_install_check()
9301
9989
  STABLE SECURITY DEFINER
9302
9990
  SET search_path TO 'public'
9303
9991
  AS $function$
9304
- DECLARE v_f text[] := ARRAY['voorraad_canoniek_artikel','voorraad_canoniek_sleutel','voorraad_artikel_prijs','voorraad_dubbele_voorraadregels','voorraad_correctie_1131','voorraad_correctie_1132','voorraad_gateway_routes_check','voorraad_placeholder_code_reason','trg_products_placeholder_code','voorraad_fust_juist','voorraad_correctie_1121','voorraad_correctie_1121_regels','voorraad_correctie_1123','voorraad_correctie_1124','voorraad_load_carriers','voorraad_packing_from_floriday','voorraad_packing_missing','voorraad_correctie_1126','voorraad_correctie_1127','trg_voorraad_link_primary_packing','voorraad_order_geannuleerd','voorraad_article_vbn','voorraad_correctie_1112','voorraad_reverse_order_mutations','voorraad_withdraw_stock_row','voorraad_floriday_klaarzetten_toegestaan','voorraad_afboeken','voorraad_voorraad_opslaan','voorraad_correctie_1140','voorraad_overzicht_orderregel_koppeling','voorraad_orderregel_sleutel','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'];
9992
+ DECLARE v_f text[] := ARRAY['voorraad_floriday_artikelen_aanmaken','voorraad_floriday_artikelen_vangnet','voorraad_orderregel_trade_item','voorraad_orderregel_trade_item_bron','voorraad_correctie_1144','voorraad_telmoment_lijst','voorraad_telmoment_opslaan','voorraad_order_vertrokken_voor','voorraad_fust_startmoment_opslaan','voorraad_fust_startmoment_auto','voorraad_fust_instellingen_opslaan','voorraad_koppeling_check','voorraad_instellingen_opslaan','voorraad_ensure_defaults','voorraad_defaults_check','voorraad_defaults_versie','voorraad_canoniek_artikel','voorraad_canoniek_sleutel','voorraad_artikel_prijs','voorraad_dubbele_voorraadregels','voorraad_correctie_1131','voorraad_correctie_1132','voorraad_gateway_routes_check','voorraad_placeholder_code_reason','trg_products_placeholder_code','voorraad_fust_juist','voorraad_correctie_1121','voorraad_correctie_1121_regels','voorraad_correctie_1123','voorraad_correctie_1124','voorraad_load_carriers','voorraad_packing_from_floriday','voorraad_packing_missing','voorraad_correctie_1126','voorraad_correctie_1127','trg_voorraad_link_primary_packing','voorraad_order_geannuleerd','voorraad_article_vbn','voorraad_correctie_1112','voorraad_reverse_order_mutations','voorraad_withdraw_stock_row','voorraad_floriday_klaarzetten_toegestaan','voorraad_afboeken','voorraad_voorraad_opslaan','voorraad_correctie_1140','voorraad_overzicht_orderregel_koppeling','voorraad_orderregel_sleutel','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'];
9305
9993
  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'];
9306
- 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'];
9994
+ 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','Ingelogd mag standaardstatus lezen@voorraad_defaults_state','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'];
9307
9995
  v_open text[] := ARRAY['voorraad_is_server','voorraad_vereis'];
9308
9996
  v_func jsonb; v_trig jsonb; v_pol jsonb;
9309
9997
  BEGIN
@@ -9329,7 +10017,7 @@ BEGIN
9329
10017
  SELECT jsonb_agg(jsonb_build_object('policy', split_part(t, '@', 1), 'tabel', split_part(t, '@', 2),
9330
10018
  'aanwezig', EXISTS (SELECT 1 FROM pg_policies x WHERE x.schemaname = 'public' AND x.policyname = split_part(t, '@', 1)
9331
10019
  AND x.tablename = split_part(t, '@', 2))) ORDER BY t) INTO v_pol FROM unnest(v_p) t;
9332
- RETURN jsonb_build_object('dubbele_voorraadregels', public.voorraad_dubbele_voorraadregels(), 'gateway_routes', public.voorraad_gateway_routes_check(),
10020
+ RETURN jsonb_build_object('koppeling', public.voorraad_koppeling_check(), 'standaardgegevens', public.voorraad_defaults_check(), 'dubbele_voorraadregels', public.voorraad_dubbele_voorraadregels(), 'gateway_routes', public.voorraad_gateway_routes_check(),
9333
10021
  'samenvatting', jsonb_build_object(
9334
10022
  'functies', jsonb_array_length(v_func),
9335
10023
  'functies_ontbrekend', (SELECT count(*) FROM jsonb_array_elements(v_func) e WHERE NOT (e->>'aanwezig')::boolean),
@@ -9346,6 +10034,27 @@ REVOKE ALL ON FUNCTION voorraad_install_check() FROM PUBLIC;
9346
10034
  REVOKE ALL ON FUNCTION voorraad_install_check() FROM anon;
9347
10035
  GRANT EXECUTE ON FUNCTION voorraad_install_check() TO authenticated;
9348
10036
  GRANT EXECUTE ON FUNCTION voorraad_install_check() TO service_role;
10037
+ CREATE OR REPLACE FUNCTION public.voorraad_instellingen_opslaan(p_standaard_sturing text)
10038
+ RETURNS jsonb
10039
+ LANGUAGE plpgsql
10040
+ SECURITY DEFINER
10041
+ SET search_path TO 'public'
10042
+ AS $function$
10043
+ BEGIN
10044
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_instellingen_opslaan');
10045
+ IF p_standaard_sturing NOT IN ('lokaal', 'floriday') THEN
10046
+ RETURN jsonb_build_object('ok', false, 'melding', 'Kies lokaal of Floriday');
10047
+ END IF;
10048
+ INSERT INTO public.voorraad_instellingen(id, standaard_sturing_nieuwe_floriday, updated_at, updated_by)
10049
+ VALUES (true, p_standaard_sturing, now(), auth.uid())
10050
+ ON CONFLICT (id) DO UPDATE SET standaard_sturing_nieuwe_floriday = EXCLUDED.standaard_sturing_nieuwe_floriday, updated_at = now(), updated_by = auth.uid();
10051
+ RETURN jsonb_build_object('ok', true, 'standaard_sturing', p_standaard_sturing);
10052
+ END $function$
10053
+ ;
10054
+ REVOKE ALL ON FUNCTION voorraad_instellingen_opslaan(text) FROM PUBLIC;
10055
+ REVOKE ALL ON FUNCTION voorraad_instellingen_opslaan(text) FROM anon;
10056
+ GRANT EXECUTE ON FUNCTION voorraad_instellingen_opslaan(text) TO authenticated;
10057
+ GRANT EXECUTE ON FUNCTION voorraad_instellingen_opslaan(text) TO service_role;
9349
10058
  CREATE OR REPLACE FUNCTION public.voorraad_is_server()
9350
10059
  RETURNS boolean
9351
10060
  LANGUAGE sql
@@ -9364,15 +10073,62 @@ GRANT EXECUTE ON FUNCTION voorraad_is_server() TO service_role;
9364
10073
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO anon;
9365
10074
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO authenticated;
9366
10075
  GRANT EXECUTE ON FUNCTION voorraad_is_server() TO service_role;
10076
+ CREATE OR REPLACE FUNCTION public.voorraad_koppeling_check()
10077
+ RETURNS jsonb
10078
+ LANGUAGE plpgsql
10079
+ STABLE SECURITY DEFINER
10080
+ SET search_path TO 'public'
10081
+ AS $function$
10082
+ DECLARE v_dups jsonb := public.voorraad_floriday_dubbele_ids(); v_idx boolean; v_job boolean; v_zonder int; v_twijfel int; v_start boolean; v_f jsonb := '[]'::jsonb;
10083
+ BEGIN
10084
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_koppeling_check');
10085
+ v_idx := EXISTS (SELECT 1 FROM pg_indexes WHERE schemaname = 'public' AND indexname = 'products_floriday_trade_item_id_uniek');
10086
+ BEGIN v_job := EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'voorraad-floriday-artikelen-uurlijks'); EXCEPTION WHEN others THEN v_job := false; END;
10087
+ SELECT count(*) INTO v_zonder FROM public.floriday_trade_items_cache t
10088
+ WHERE NOT (COALESCE(t.is_deleted,false) OR COALESCE((t.data->>'isDeleted')::boolean,false))
10089
+ AND t.connection_id = (SELECT x.connection_id FROM public.get_active_floriday_context() x LIMIT 1)
10090
+ AND NOT EXISTS (SELECT 1 FROM public.products p WHERE lower(btrim(p.floriday_trade_item_id)) = lower(t.floriday_id));
10091
+ SELECT count(*) INTO v_twijfel FROM public.voorraad_koppel_twijfel WHERE opgelost_at IS NULL;
10092
+ v_start := EXISTS (SELECT 1 FROM public.fust_startmoment);
10093
+ IF jsonb_array_length(v_dups) > 0 THEN v_f := v_f || to_jsonb('Er zijn artikelen met hetzelfde Floriday-id; automatisch aanmaken staat stil'::text); END IF;
10094
+ IF NOT v_idx THEN v_f := v_f || to_jsonb('Unieke index op het Floriday-id ontbreekt'::text); END IF;
10095
+ IF NOT v_job THEN v_f := v_f || to_jsonb('Uurlijkse controle van Floriday-artikelen is niet ingepland'::text); END IF;
10096
+ RETURN jsonb_build_object('fouten', v_f, 'dubbele_floriday_ids', v_dups, 'unieke_index_aanwezig', v_idx, 'vangnet_job_aanwezig', v_job,
10097
+ 'floriday_zonder_eigen_artikel', v_zonder, 'twijfel_open', v_twijfel, 'fust_startmoment_ingesteld', v_start,
10098
+ 'melding_fust', CASE WHEN NOT v_start THEN 'Stel een startmoment en beginstand in' END);
10099
+ END $function$
10100
+ ;
10101
+ REVOKE ALL ON FUNCTION voorraad_koppeling_check() FROM PUBLIC;
10102
+ REVOKE ALL ON FUNCTION voorraad_koppeling_check() FROM anon;
10103
+ GRANT EXECUTE ON FUNCTION voorraad_koppeling_check() TO authenticated;
10104
+ GRANT EXECUTE ON FUNCTION voorraad_koppeling_check() TO service_role;
10105
+ CREATE OR REPLACE FUNCTION public.voorraad_lever_datum(p text)
10106
+ RETURNS date
10107
+ LANGUAGE plpgsql
10108
+ IMMUTABLE
10109
+ SET search_path TO 'public'
10110
+ AS $function$
10111
+ BEGIN
10112
+ IF p IS NULL OR btrim(p) = '' THEN RETURN NULL; END IF;
10113
+ IF p ~ '^\d{4}-\d{2}-\d{2}$' THEN RETURN p::date; END IF;
10114
+ IF p ~ '^\d{4}-\d{2}-\d{2}T' THEN RETURN (p::timestamptz AT TIME ZONE 'Europe/Amsterdam')::date; END IF;
10115
+ RETURN NULL;
10116
+ EXCEPTION WHEN others THEN RETURN NULL;
10117
+ END $function$
10118
+ ;
10119
+ REVOKE ALL ON FUNCTION voorraad_lever_datum(text) FROM PUBLIC;
10120
+ REVOKE ALL ON FUNCTION voorraad_lever_datum(text) FROM anon;
10121
+ GRANT EXECUTE ON FUNCTION voorraad_lever_datum(text) TO authenticated;
10122
+ GRANT EXECUTE ON FUNCTION voorraad_lever_datum(text) TO service_role;
9367
10123
  CREATE OR REPLACE FUNCTION public.voorraad_load_carriers()
9368
10124
  RETURNS TABLE(code text, naam text, volgorde integer)
9369
10125
  LANGUAGE plpgsql
9370
- STABLE
10126
+ STABLE SECURITY DEFINER
9371
10127
  SET search_path TO 'public'
9372
10128
  AS $function$
9373
10129
  BEGIN
9374
10130
  PERFORM public.voorraad_vereis('ingelogd', 'voorraad_load_carriers');
9375
- RETURN QUERY SELECT t.code, t.naam, t.volgorde FROM public.voorraad_load_carrier_types t ORDER BY t.volgorde, t.code;
10131
+ RETURN QUERY SELECT t.code, t.naam, t.volgorde FROM public.voorraad_load_carrier_types t WHERE t.actief ORDER BY t.volgorde, t.code;
9376
10132
  END $function$
9377
10133
  ;
9378
10134
  REVOKE ALL ON FUNCTION voorraad_load_carriers() FROM PUBLIC;
@@ -9427,6 +10183,33 @@ GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zo
9427
10183
  REVOKE EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) FROM anon;
9428
10184
  GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO authenticated;
9429
10185
  GRANT EXECUTE ON FUNCTION voorraad_order_geannuleerd(text,timestamp with time zone,timestamp with time zone) TO service_role;
10186
+ CREATE OR REPLACE FUNCTION public.voorraad_order_vertrokken_voor(p_order_id uuid, p_moment timestamp with time zone)
10187
+ RETURNS boolean
10188
+ LANGUAGE plpgsql
10189
+ STABLE SECURITY DEFINER
10190
+ SET search_path TO 'public'
10191
+ AS $function$
10192
+ DECLARE v_status text; v_changed timestamptz; v_carts int; v_done int; v_last timestamptz; v_unc int;
10193
+ BEGIN
10194
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_order_vertrokken_voor');
10195
+ SELECT lower(COALESCE(o.status,'')), o.status_changed_at INTO v_status, v_changed FROM public.orders o WHERE o.id = p_order_id;
10196
+ IF v_status IN ('verzonden','shipped','geleverd','delivered') AND v_changed IS NOT NULL AND v_changed <= p_moment THEN RETURN true; END IF;
10197
+ SELECT count(*), count(*) FILTER (WHERE lower(COALESCE(status,'')) IN ('shipped','delivered','verzonden','geleverd') AND delivered_at IS NOT NULL AND delivered_at <= p_moment)
10198
+ INTO v_carts, v_done FROM public.cart_numbers WHERE order_id = p_order_id::text;
10199
+ IF v_carts > 0 AND v_done = v_carts THEN RETURN true; END IF;
10200
+ IF EXISTS (SELECT 1 FROM public.order_shipments s WHERE s.order_id = p_order_id AND s.status = 'shipped' AND s.shipped_at <= p_moment) THEN
10201
+ SELECT count(*) INTO v_unc FROM logistics_active.order_items oi
10202
+ WHERE oi.order_id = p_order_id AND oi.quantity > COALESCE((SELECT sum(si.quantity) FROM public.order_shipment_items si
10203
+ JOIN public.order_shipments s ON s.id = si.shipment_id WHERE si.order_item_id = oi.id AND s.status = 'shipped' AND s.shipped_at <= p_moment), 0);
10204
+ IF v_unc = 0 THEN RETURN true; END IF;
10205
+ END IF;
10206
+ RETURN false;
10207
+ END $function$
10208
+ ;
10209
+ REVOKE ALL ON FUNCTION voorraad_order_vertrokken_voor(uuid,timestamp with time zone) FROM PUBLIC;
10210
+ REVOKE ALL ON FUNCTION voorraad_order_vertrokken_voor(uuid,timestamp with time zone) FROM anon;
10211
+ GRANT EXECUTE ON FUNCTION voorraad_order_vertrokken_voor(uuid,timestamp with time zone) TO authenticated;
10212
+ GRANT EXECUTE ON FUNCTION voorraad_order_vertrokken_voor(uuid,timestamp with time zone) TO service_role;
9430
10213
  CREATE OR REPLACE FUNCTION public.voorraad_orderregel_sleutel(p_ref text)
9431
10214
  RETURNS text
9432
10215
  LANGUAGE plpgsql
@@ -9449,6 +10232,57 @@ REVOKE ALL ON FUNCTION voorraad_orderregel_sleutel(text) FROM PUBLIC;
9449
10232
  REVOKE ALL ON FUNCTION voorraad_orderregel_sleutel(text) FROM anon;
9450
10233
  GRANT EXECUTE ON FUNCTION voorraad_orderregel_sleutel(text) TO authenticated;
9451
10234
  GRANT EXECUTE ON FUNCTION voorraad_orderregel_sleutel(text) TO service_role;
10235
+ CREATE OR REPLACE FUNCTION public.voorraad_orderregel_trade_item(p_order_item_id uuid)
10236
+ RETURNS jsonb
10237
+ LANGUAGE plpgsql
10238
+ STABLE SECURITY DEFINER
10239
+ SET search_path TO 'public'
10240
+ AS $function$
10241
+ DECLARE v_o uuid; v_s text;
10242
+ BEGIN
10243
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_orderregel_trade_item');
10244
+ SELECT oi.order_id, oi.source_line_key INTO v_o, v_s FROM public.order_items oi WHERE oi.id = p_order_item_id;
10245
+ IF NOT FOUND THEN RETURN jsonb_build_object('status', 'onbekende_orderregel'); END IF;
10246
+ RETURN public.voorraad_orderregel_trade_item_bron(v_o, v_s);
10247
+ END $function$
10248
+ ;
10249
+ REVOKE ALL ON FUNCTION voorraad_orderregel_trade_item(uuid) FROM PUBLIC;
10250
+ REVOKE ALL ON FUNCTION voorraad_orderregel_trade_item(uuid) FROM anon;
10251
+ GRANT EXECUTE ON FUNCTION voorraad_orderregel_trade_item(uuid) TO authenticated;
10252
+ GRANT EXECUTE ON FUNCTION voorraad_orderregel_trade_item(uuid) TO service_role;
10253
+ CREATE OR REPLACE FUNCTION public.voorraad_orderregel_trade_item_bron(p_order_id uuid, p_source_line_key text)
10254
+ RETURNS jsonb
10255
+ LANGUAGE plpgsql
10256
+ STABLE SECURITY DEFINER
10257
+ SET search_path TO 'public'
10258
+ AS $function$
10259
+ DECLARE v_cf jsonb; v_k text[]; v_p uuid[];
10260
+ BEGIN
10261
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_orderregel_trade_item_bron');
10262
+ IF p_source_line_key IS NULL OR btrim(p_source_line_key) = '' THEN
10263
+ RETURN jsonb_build_object('status', 'geen_source_line_key');
10264
+ END IF;
10265
+ SELECT o.custom_fields INTO v_cf FROM public.orders o WHERE o.id = p_order_id;
10266
+ SELECT array_agg(DISTINCT k) INTO v_k FROM (
10267
+ SELECT lower(btrim(l->>'trade_item_id')) k
10268
+ FROM jsonb_array_elements(CASE WHEN jsonb_typeof(v_cf->'floriday_lines') = 'array' THEN v_cf->'floriday_lines' ELSE '[]'::jsonb END) l
10269
+ WHERE l->>'sales_order_id' = p_source_line_key AND COALESCE(l->>'trade_item_id','') <> ''
10270
+ UNION
10271
+ SELECT lower(btrim(c.data->>'tradeItemId')) FROM public.floriday_salesorders_cache c
10272
+ WHERE c.floriday_id = p_source_line_key AND COALESCE(c.data->>'tradeItemId','') <> ''
10273
+ ) x;
10274
+ IF v_k IS NULL THEN RETURN jsonb_build_object('status', 'geen_match'); END IF;
10275
+ IF array_length(v_k, 1) > 1 THEN RETURN jsonb_build_object('status', 'meerdere_kandidaten', 'kandidaten', to_jsonb(v_k)); END IF;
10276
+ SELECT array_agg(p.id) INTO v_p FROM public.products p WHERE lower(btrim(p.floriday_trade_item_id)) = v_k[1];
10277
+ IF v_p IS NULL THEN RETURN jsonb_build_object('status', 'geen_eigen_artikel', 'trade_item_id', v_k[1]); END IF;
10278
+ IF array_length(v_p, 1) > 1 THEN RETURN jsonb_build_object('status', 'meerdere_artikelen', 'trade_item_id', v_k[1], 'artikelen', to_jsonb(v_p)); END IF;
10279
+ RETURN jsonb_build_object('status', 'eenduidig', 'trade_item_id', v_k[1], 'product_id', v_p[1]);
10280
+ END $function$
10281
+ ;
10282
+ REVOKE ALL ON FUNCTION voorraad_orderregel_trade_item_bron(uuid,text) FROM PUBLIC;
10283
+ REVOKE ALL ON FUNCTION voorraad_orderregel_trade_item_bron(uuid,text) FROM anon;
10284
+ GRANT EXECUTE ON FUNCTION voorraad_orderregel_trade_item_bron(uuid,text) TO authenticated;
10285
+ GRANT EXECUTE ON FUNCTION voorraad_orderregel_trade_item_bron(uuid,text) TO service_role;
9452
10286
  CREATE OR REPLACE FUNCTION public.voorraad_overzicht_orderregel_koppeling(p_voorbeelden integer DEFAULT 5)
9453
10287
  RETURNS jsonb
9454
10288
  LANGUAGE plpgsql
@@ -9836,6 +10670,81 @@ REVOKE ALL ON FUNCTION voorraad_stock_context_status() FROM PUBLIC;
9836
10670
  REVOKE ALL ON FUNCTION voorraad_stock_context_status() FROM anon;
9837
10671
  GRANT EXECUTE ON FUNCTION voorraad_stock_context_status() TO authenticated;
9838
10672
  GRANT EXECUTE ON FUNCTION voorraad_stock_context_status() TO service_role;
10673
+ CREATE OR REPLACE FUNCTION public.voorraad_telmoment_lijst(p_telmoment timestamp with time zone, p_keys text[] DEFAULT NULL::text[])
10674
+ RETURNS jsonb
10675
+ LANGUAGE plpgsql
10676
+ STABLE SECURITY DEFINER
10677
+ SET search_path TO 'public'
10678
+ AS $function$
10679
+ DECLARE v_dag date := (p_telmoment AT TIME ZONE 'Europe/Amsterdam')::date; v jsonb;
10680
+ BEGIN
10681
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_telmoment_lijst');
10682
+ WITH r AS (
10683
+ SELECT oi.id, o.id AS order_id, o.order_number, o.customer_name, public.voorraad_lever_datum(o.delivery_date) AS lever,
10684
+ oi.quantity, oi.product_name, public.voorraad_orderregel_sleutel(oi.product_id::text) AS sleutel
10685
+ FROM logistics_active.order_items oi JOIN public.orders o ON o.id = oi.order_id
10686
+ WHERE oi.product_id IS NOT NULL
10687
+ AND NOT public.voorraad_order_geannuleerd(o.status, o.cancelled_at, o.deleted_at)
10688
+ AND NOT EXISTS (SELECT 1 FROM public.stock_mutation_log m WHERE m.order_item_id = oi.id AND m.mutation_type = 'consumption')
10689
+ AND NOT EXISTS (SELECT 1 FROM public.voorraad_telmoment_regels t WHERE t.order_item_id = oi.id)
10690
+ ), k AS (
10691
+ SELECT r.*, CASE WHEN r.lever < v_dag THEN 'voor_teldag'
10692
+ WHEN public.voorraad_order_vertrokken_voor(r.order_id, p_telmoment) THEN 'vertrokken'
10693
+ ELSE 'teldag_open' END AS categorie
10694
+ FROM r WHERE r.lever IS NOT NULL AND r.lever <= v_dag AND (p_keys IS NULL OR r.sleutel = ANY(p_keys))
10695
+ )
10696
+ SELECT jsonb_build_object('teldag', v_dag,
10697
+ 'buiten_telling', (SELECT count(*) FROM k WHERE categorie IN ('voor_teldag','vertrokken')),
10698
+ 'regels', COALESCE((SELECT jsonb_agg(jsonb_build_object('order_item_id', id, 'order_number', order_number, 'klant', customer_name,
10699
+ 'leverdatum', lever, 'aantal', quantity, 'artikel', product_name, 'categorie', categorie) ORDER BY lever, order_number) FROM k), '[]'::jsonb))
10700
+ INTO v;
10701
+ RETURN v;
10702
+ END $function$
10703
+ ;
10704
+ REVOKE ALL ON FUNCTION voorraad_telmoment_lijst(timestamp with time zone,text[]) FROM PUBLIC;
10705
+ REVOKE ALL ON FUNCTION voorraad_telmoment_lijst(timestamp with time zone,text[]) FROM anon;
10706
+ GRANT EXECUTE ON FUNCTION voorraad_telmoment_lijst(timestamp with time zone,text[]) TO authenticated;
10707
+ GRANT EXECUTE ON FUNCTION voorraad_telmoment_lijst(timestamp with time zone,text[]) TO service_role;
10708
+ CREATE OR REPLACE FUNCTION public.voorraad_telmoment_opslaan(p_telmoment timestamp with time zone, p_keys text[] DEFAULT NULL::text[], p_al_weg uuid[] DEFAULT NULL::uuid[], p_notitie text DEFAULT NULL::text)
10709
+ RETURNS jsonb
10710
+ LANGUAGE plpgsql
10711
+ SECURITY DEFINER
10712
+ SET search_path TO 'public'
10713
+ AS $function$
10714
+ DECLARE v_id uuid; v_lijst jsonb; e jsonb; v_reden text; n int := 0; v_keys text[] := ARRAY[]::text[]; v_key text; v_oid uuid;
10715
+ BEGIN
10716
+ PERFORM public.voorraad_vereis('ingelogd', 'voorraad_telmoment_opslaan');
10717
+ IF p_telmoment IS NULL THEN RETURN jsonb_build_object('ok', false, 'melding', 'Kies een telmoment'); END IF;
10718
+ v_lijst := public.voorraad_telmoment_lijst(p_telmoment, p_keys);
10719
+ INSERT INTO public.voorraad_telmoment(telmoment, trade_item_keys, notitie) VALUES (p_telmoment, p_keys, NULLIF(btrim(COALESCE(p_notitie,'')),'')) RETURNING id INTO v_id;
10720
+ FOR e IN SELECT * FROM jsonb_array_elements(v_lijst->'regels') LOOP
10721
+ v_reden := CASE e->>'categorie' WHEN 'voor_teldag' THEN 'leverdatum_voor_teldag' WHEN 'vertrokken' THEN 'vertrokken_voor_telmoment'
10722
+ ELSE CASE WHEN (e->>'order_item_id')::uuid = ANY(COALESCE(p_al_weg, ARRAY[]::uuid[])) THEN 'is_al_weg' END END;
10723
+ CONTINUE WHEN v_reden IS NULL;
10724
+ INSERT INTO public.voorraad_telmoment_regels(order_item_id, telmoment_id, reden) VALUES ((e->>'order_item_id')::uuid, v_id, v_reden)
10725
+ ON CONFLICT (order_item_id) DO NOTHING;
10726
+ IF FOUND THEN
10727
+ SELECT oi.order_id, public.voorraad_orderregel_sleutel(oi.product_id::text) INTO v_oid, v_key FROM public.order_items oi WHERE oi.id = (e->>'order_item_id')::uuid;
10728
+ INSERT INTO public.stock_mutation_log(order_id, order_item_id, mutation_type, qty_delta, reason, created_by)
10729
+ VALUES (v_oid, (e->>'order_item_id')::uuid, 'consumption_done', 0, 'Verwerkt vóór telling', auth.uid())
10730
+ ON CONFLICT (order_item_id) WHERE mutation_type = 'consumption_done' AND order_item_id IS NOT NULL DO NOTHING;
10731
+ INSERT INTO public.stock_mutation_log(trade_item_key, order_id, order_item_id, mutation_type, qty_delta, reason, created_by)
10732
+ VALUES (v_key, v_oid, (e->>'order_item_id')::uuid, 'consumption', 0,
10733
+ 'Verwerkt vóór telling (telmoment ' || to_char(p_telmoment AT TIME ZONE 'Europe/Amsterdam', 'DD-MM-YYYY HH24:MI') || '): niet afgeboekt', auth.uid());
10734
+ IF v_key IS NOT NULL AND NOT (v_key = ANY(v_keys)) THEN v_keys := v_keys || v_key; END IF;
10735
+ n := n + 1;
10736
+ END IF;
10737
+ END LOOP;
10738
+ FOREACH v_key IN ARRAY v_keys LOOP
10739
+ BEGIN PERFORM public.recompute_reserved_stock(v_key); EXCEPTION WHEN others THEN NULL; END;
10740
+ END LOOP;
10741
+ RETURN jsonb_build_object('ok', true, 'telmoment_id', v_id, 'buiten_telling', n, 'artikelen_herberekend', array_length(v_keys, 1));
10742
+ END $function$
10743
+ ;
10744
+ REVOKE ALL ON FUNCTION voorraad_telmoment_opslaan(timestamp with time zone,text[],uuid[],text) FROM PUBLIC;
10745
+ REVOKE ALL ON FUNCTION voorraad_telmoment_opslaan(timestamp with time zone,text[],uuid[],text) FROM anon;
10746
+ GRANT EXECUTE ON FUNCTION voorraad_telmoment_opslaan(timestamp with time zone,text[],uuid[],text) TO authenticated;
10747
+ GRANT EXECUTE ON FUNCTION voorraad_telmoment_opslaan(timestamp with time zone,text[],uuid[],text) TO service_role;
9839
10748
  CREATE OR REPLACE FUNCTION public.voorraad_touch_updated_at()
9840
10749
  RETURNS trigger
9841
10750
  LANGUAGE plpgsql
@@ -10012,6 +10921,8 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'florida
10012
10921
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_takeover_items_pkey' AND conrelid = 'public.floriday_takeover_items'::regclass) THEN ALTER TABLE public.floriday_takeover_items ADD CONSTRAINT floriday_takeover_items_pkey PRIMARY KEY (id); END IF; END $c$;
10013
10922
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_takeover_runs_pkey' AND conrelid = 'public.floriday_takeover_runs'::regclass) THEN ALTER TABLE public.floriday_takeover_runs ADD CONSTRAINT floriday_takeover_runs_pkey PRIMARY KEY (id); END IF; END $c$;
10014
10923
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_vbn_required_characteristics_pkey' AND conrelid = 'public.floriday_vbn_required_characteristics'::regclass) THEN ALTER TABLE public.floriday_vbn_required_characteristics ADD CONSTRAINT floriday_vbn_required_characteristics_pkey PRIMARY KEY (vbn_code); END IF; END $c$;
10924
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fust_startmoment_pkey' AND conrelid = 'public.fust_startmoment'::regclass) THEN ALTER TABLE public.fust_startmoment ADD CONSTRAINT fust_startmoment_pkey PRIMARY KEY (id); END IF; END $c$;
10925
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fust_startmoment_log_pkey' AND conrelid = 'public.fust_startmoment_log'::regclass) THEN ALTER TABLE public.fust_startmoment_log ADD CONSTRAINT fust_startmoment_log_pkey PRIMARY KEY (id); END IF; END $c$;
10015
10926
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fust_stock_mutations_pkey' AND conrelid = 'public.fust_stock_mutations'::regclass) THEN ALTER TABLE public.fust_stock_mutations ADD CONSTRAINT fust_stock_mutations_pkey PRIMARY KEY (id); END IF; END $c$;
10016
10927
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fust_types_pkey' AND conrelid = 'public.fust_types'::regclass) THEN ALTER TABLE public.fust_types ADD CONSTRAINT fust_types_pkey PRIMARY KEY (id); END IF; END $c$;
10017
10928
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'inventory_recompute_limits_pkey' AND conrelid = 'public.inventory_recompute_limits'::regclass) THEN ALTER TABLE public.inventory_recompute_limits ADD CONSTRAINT inventory_recompute_limits_pkey PRIMARY KEY (id); END IF; END $c$;
@@ -10035,6 +10946,11 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'trade_i
10035
10946
  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$;
10036
10947
  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$;
10037
10948
  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$;
10949
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_defaults_state_pkey' AND conrelid = 'public.voorraad_defaults_state'::regclass) THEN ALTER TABLE public.voorraad_defaults_state ADD CONSTRAINT voorraad_defaults_state_pkey PRIMARY KEY (id); END IF; END $c$;
10950
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_floriday_artikel_wachtrij_pkey' AND conrelid = 'public.voorraad_floriday_artikel_wachtrij'::regclass) THEN ALTER TABLE public.voorraad_floriday_artikel_wachtrij ADD CONSTRAINT voorraad_floriday_artikel_wachtrij_pkey PRIMARY KEY (floriday_id); END IF; END $c$;
10951
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_instellingen_pkey' AND conrelid = 'public.voorraad_instellingen'::regclass) THEN ALTER TABLE public.voorraad_instellingen ADD CONSTRAINT voorraad_instellingen_pkey PRIMARY KEY (id); END IF; END $c$;
10952
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_koppel_log_pkey' AND conrelid = 'public.voorraad_koppel_log'::regclass) THEN ALTER TABLE public.voorraad_koppel_log ADD CONSTRAINT voorraad_koppel_log_pkey PRIMARY KEY (id); END IF; END $c$;
10953
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_koppel_twijfel_pkey' AND conrelid = 'public.voorraad_koppel_twijfel'::regclass) THEN ALTER TABLE public.voorraad_koppel_twijfel ADD CONSTRAINT voorraad_koppel_twijfel_pkey PRIMARY KEY (floriday_id); END IF; END $c$;
10038
10954
  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$;
10039
10955
  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$;
10040
10956
  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$;
@@ -10044,6 +10960,8 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraa
10044
10960
  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$;
10045
10961
  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$;
10046
10962
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_publish_steps_pkey' AND conrelid = 'public.voorraad_publish_steps'::regclass) THEN ALTER TABLE public.voorraad_publish_steps ADD CONSTRAINT voorraad_publish_steps_pkey PRIMARY KEY (id); END IF; END $c$;
10963
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_telmoment_pkey' AND conrelid = 'public.voorraad_telmoment'::regclass) THEN ALTER TABLE public.voorraad_telmoment ADD CONSTRAINT voorraad_telmoment_pkey PRIMARY KEY (id); END IF; END $c$;
10964
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_telmoment_regels_pkey' AND conrelid = 'public.voorraad_telmoment_regels'::regclass) THEN ALTER TABLE public.voorraad_telmoment_regels ADD CONSTRAINT voorraad_telmoment_regels_pkey PRIMARY KEY (order_item_id); END IF; END $c$;
10047
10965
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_inventory_settings_unique' AND conrelid = 'public.floriday_inventory_settings'::regclass) THEN ALTER TABLE public.floriday_inventory_settings ADD CONSTRAINT floriday_inventory_settings_unique UNIQUE (connection_id, product_id); END IF; END $c$;
10048
10966
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_sales_order_ingest_unique' AND conrelid = 'public.floriday_sales_order_ingest'::regclass) THEN ALTER TABLE public.floriday_sales_order_ingest ADD CONSTRAINT floriday_sales_order_ingest_unique UNIQUE (connection_id, sales_order_id, order_version); END IF; END $c$;
10049
10967
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_sync_cursors_unique' AND conrelid = 'public.floriday_sync_cursors'::regclass) THEN ALTER TABLE public.floriday_sync_cursors ADD CONSTRAINT floriday_sync_cursors_unique UNIQUE (connection_id, resource_type); END IF; END $c$;
@@ -10101,8 +11019,16 @@ ALTER TABLE public.stock_mutation_log DROP CONSTRAINT IF EXISTS stock_mutation_l
10101
11019
  ALTER TABLE public.stock_mutation_log ADD CONSTRAINT stock_mutation_log_mutation_type_check CHECK ((mutation_type = ANY (ARRAY['reservation'::text, 'reservation_release'::text, 'consumption'::text, 'stock_check'::text, 'reservation_skipped'::text, 'consumption_skipped'::text, 'consumption_blocked'::text, 'production_consume'::text, 'production_output'::text, 'production_reverse'::text, 'manual_correction'::text, 'order_sync'::text, 'import'::text, 'production'::text, 'stock_update'::text, 'reservation_recompute'::text, 'unknown'::text, 'consumption_done'::text, 'new_article'::text, 'manual_writeoff'::text])));
10102
11020
  ALTER TABLE public.trade_item_drafts DROP CONSTRAINT IF EXISTS trade_item_drafts_link_status_chk;
10103
11021
  ALTER TABLE public.trade_item_drafts ADD CONSTRAINT trade_item_drafts_link_status_chk CHECK ((floriday_link_status = ANY (ARRAY['unlinked'::text, 'linked'::text, 'waiting_for_data'::text, 'ready_to_publish'::text, 'publish_failed'::text, 'ambiguous_match'::text, 'published'::text])));
11022
+ ALTER TABLE public.voorraad_defaults_state DROP CONSTRAINT IF EXISTS voorraad_defaults_state_id_check;
11023
+ ALTER TABLE public.voorraad_defaults_state ADD CONSTRAINT voorraad_defaults_state_id_check CHECK (id);
11024
+ ALTER TABLE public.voorraad_instellingen DROP CONSTRAINT IF EXISTS voorraad_instellingen_id_check;
11025
+ ALTER TABLE public.voorraad_instellingen ADD CONSTRAINT voorraad_instellingen_id_check CHECK (id);
11026
+ ALTER TABLE public.voorraad_instellingen DROP CONSTRAINT IF EXISTS voorraad_instellingen_standaard_sturing_nieuwe_floriday_check;
11027
+ ALTER TABLE public.voorraad_instellingen ADD CONSTRAINT voorraad_instellingen_standaard_sturing_nieuwe_floriday_check CHECK ((standaard_sturing_nieuwe_floriday = ANY (ARRAY['lokaal'::text, 'floriday'::text])));
10104
11028
  ALTER TABLE public.voorraad_local_context DROP CONSTRAINT IF EXISTS voorraad_local_context_singleton_check;
10105
11029
  ALTER TABLE public.voorraad_local_context ADD CONSTRAINT voorraad_local_context_singleton_check CHECK (singleton);
11030
+ ALTER TABLE public.voorraad_telmoment_regels DROP CONSTRAINT IF EXISTS voorraad_telmoment_regels_reden_check;
11031
+ ALTER TABLE public.voorraad_telmoment_regels ADD CONSTRAINT voorraad_telmoment_regels_reden_check CHECK ((reden = ANY (ARRAY['leverdatum_voor_teldag'::text, 'vertrokken_voor_telmoment'::text, 'is_al_weg'::text])));
10106
11032
  DO $g$ BEGIN IF to_regclass('public.products') IS NULL THEN RAISE NOTICE 'Voorraad: products (core) ontbreekt, controles overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_inventory_settings_product_id_fkey' AND conrelid = 'public.floriday_inventory_settings'::regclass) THEN ALTER TABLE public.floriday_inventory_settings ADD CONSTRAINT floriday_inventory_settings_product_id_fkey FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE; END IF; END $c$$q$; END IF; END $g$;
10107
11033
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_takeover_items_run_id_fkey' AND conrelid = 'public.floriday_takeover_items'::regclass) THEN ALTER TABLE public.floriday_takeover_items ADD CONSTRAINT floriday_takeover_items_run_id_fkey FOREIGN KEY (run_id) REFERENCES floriday_takeover_runs(id) ON DELETE CASCADE; END IF; END $c$;
10108
11034
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'floriday_vbn_required_characteristics_updated_by_fkey' AND conrelid = 'public.floriday_vbn_required_characteristics'::regclass) THEN ALTER TABLE public.floriday_vbn_required_characteristics ADD CONSTRAINT floriday_vbn_required_characteristics_updated_by_fkey FOREIGN KEY (updated_by) REFERENCES auth.users(id) ON DELETE SET NULL; END IF; END $c$;
@@ -10117,6 +11043,7 @@ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'stock_i
10117
11043
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'stock_import_runs_user_id_fkey' AND conrelid = 'public.stock_import_runs'::regclass) THEN ALTER TABLE public.stock_import_runs ADD CONSTRAINT stock_import_runs_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE; END IF; END $c$;
10118
11044
  DO $g$ BEGIN IF to_regclass('public.floriday_connections') IS NULL THEN RAISE NOTICE 'Voorraad: floriday_connections (Floriday-auth) ontbreekt, controles overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'trade_item_warehouse_preferences_connection_id_fkey' AND conrelid = 'public.trade_item_warehouse_preferences'::regclass) THEN ALTER TABLE public.trade_item_warehouse_preferences ADD CONSTRAINT trade_item_warehouse_preferences_connection_id_fkey FOREIGN KEY (connection_id) REFERENCES floriday_connections(id) ON DELETE RESTRICT; END IF; END $c$$q$; END IF; END $g$;
10119
11045
  DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_publish_steps_job_id_fkey' AND conrelid = 'public.voorraad_publish_steps'::regclass) THEN ALTER TABLE public.voorraad_publish_steps ADD CONSTRAINT voorraad_publish_steps_job_id_fkey FOREIGN KEY (job_id) REFERENCES voorraad_publish_jobs(id) ON DELETE CASCADE; END IF; END $c$;
11046
+ DO $c$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'voorraad_telmoment_regels_telmoment_id_fkey' AND conrelid = 'public.voorraad_telmoment_regels'::regclass) THEN ALTER TABLE public.voorraad_telmoment_regels ADD CONSTRAINT voorraad_telmoment_regels_telmoment_id_fkey FOREIGN KEY (telmoment_id) REFERENCES voorraad_telmoment(id); END IF; END $c$;
10120
11047
 
10121
11048
  -- indexen
10122
11049
  CREATE INDEX IF NOT EXISTS floriday_continuous_stock_cache_fetched_at_idx ON public.floriday_continuous_stock_cache USING btree (fetched_at);
@@ -10150,7 +11077,10 @@ CREATE INDEX IF NOT EXISTS stock_import_runs_user_created_idx ON public.stock_im
10150
11077
  CREATE INDEX IF NOT EXISTS stock_integrity_alerts_open_idx ON public.stock_integrity_alerts USING btree (created_at DESC) WHERE (acknowledged_at IS NULL);
10151
11078
  CREATE INDEX IF NOT EXISTS trade_item_prices_lookup ON public.trade_item_prices USING btree (trade_item_key, price_group_id);
10152
11079
  CREATE INDEX IF NOT EXISTS trade_item_stock_trade_item_key_idx ON public.trade_item_stock USING btree (trade_item_key);
11080
+ CREATE INDEX IF NOT EXISTS voorraad_koppel_log_item_idx ON public.voorraad_koppel_log USING btree (order_item_id);
11081
+ CREATE INDEX IF NOT EXISTS voorraad_koppel_log_run_idx ON public.voorraad_koppel_log USING btree (run_id);
10153
11082
  CREATE UNIQUE INDEX IF NOT EXISTS fcsq_one_open_per_week ON public.floriday_continuous_stock_queue USING btree (connection_id, trade_item_id, COALESCE(target_year, '-1'::integer), COALESCE(target_week, '-1'::integer)) WHERE (status = ANY (ARRAY['pending'::text, 'needs_base_supply'::text, 'skipped_no_price'::text, 'failed'::text]));
11083
+ CREATE UNIQUE INDEX IF NOT EXISTS fust_startmoment_uniek ON public.fust_startmoment USING btree (COALESCE(fust_type_id, '00000000-0000-0000-0000-000000000000'::uuid));
10154
11084
  CREATE UNIQUE INDEX IF NOT EXISTS fust_types_fust_key_active_uidx ON public.fust_types USING btree (fust_key) WHERE ((connection_id IS NULL) AND (merged_into IS NULL));
10155
11085
  CREATE UNIQUE INDEX IF NOT EXISTS fust_types_user_key_global_idx ON public.fust_types USING btree (user_id, fust_key) WHERE (connection_id IS NULL);
10156
11086
  CREATE UNIQUE INDEX IF NOT EXISTS product_packings_one_primary ON public.product_packings USING btree (product_id) WHERE is_primary;
@@ -10201,6 +11131,14 @@ ALTER TABLE public.floriday_vbn_required_characteristics ENABLE ROW LEVEL SECURI
10201
11131
  REVOKE ALL ON public.floriday_vbn_required_characteristics FROM anon;
10202
11132
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.floriday_vbn_required_characteristics TO authenticated;
10203
11133
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.floriday_vbn_required_characteristics TO service_role;
11134
+ ALTER TABLE public.fust_startmoment ENABLE ROW LEVEL SECURITY;
11135
+ REVOKE ALL ON public.fust_startmoment FROM anon;
11136
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.fust_startmoment TO authenticated;
11137
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.fust_startmoment TO service_role;
11138
+ ALTER TABLE public.fust_startmoment_log ENABLE ROW LEVEL SECURITY;
11139
+ REVOKE ALL ON public.fust_startmoment_log FROM anon;
11140
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.fust_startmoment_log TO authenticated;
11141
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.fust_startmoment_log TO service_role;
10204
11142
  ALTER TABLE public.fust_stock_mutations ENABLE ROW LEVEL SECURITY;
10205
11143
  REVOKE ALL ON public.fust_stock_mutations FROM anon;
10206
11144
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.fust_stock_mutations TO authenticated;
@@ -10291,6 +11229,26 @@ ALTER TABLE public.voorraad_custom_fields ENABLE ROW LEVEL SECURITY;
10291
11229
  REVOKE ALL ON public.voorraad_custom_fields FROM anon;
10292
11230
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_custom_fields TO authenticated;
10293
11231
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_custom_fields TO service_role;
11232
+ ALTER TABLE public.voorraad_defaults_state ENABLE ROW LEVEL SECURITY;
11233
+ REVOKE ALL ON public.voorraad_defaults_state FROM anon;
11234
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_defaults_state TO authenticated;
11235
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_defaults_state TO service_role;
11236
+ ALTER TABLE public.voorraad_floriday_artikel_wachtrij ENABLE ROW LEVEL SECURITY;
11237
+ REVOKE ALL ON public.voorraad_floriday_artikel_wachtrij FROM anon;
11238
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_floriday_artikel_wachtrij TO authenticated;
11239
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_floriday_artikel_wachtrij TO service_role;
11240
+ ALTER TABLE public.voorraad_instellingen ENABLE ROW LEVEL SECURITY;
11241
+ REVOKE ALL ON public.voorraad_instellingen FROM anon;
11242
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_instellingen TO authenticated;
11243
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_instellingen TO service_role;
11244
+ ALTER TABLE public.voorraad_koppel_log ENABLE ROW LEVEL SECURITY;
11245
+ REVOKE ALL ON public.voorraad_koppel_log FROM anon;
11246
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_koppel_log TO authenticated;
11247
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_koppel_log TO service_role;
11248
+ ALTER TABLE public.voorraad_koppel_twijfel ENABLE ROW LEVEL SECURITY;
11249
+ REVOKE ALL ON public.voorraad_koppel_twijfel FROM anon;
11250
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_koppel_twijfel TO authenticated;
11251
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_koppel_twijfel TO service_role;
10294
11252
  ALTER TABLE public.voorraad_load_carrier_types ENABLE ROW LEVEL SECURITY;
10295
11253
  REVOKE ALL ON public.voorraad_load_carrier_types FROM anon;
10296
11254
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_load_carrier_types TO authenticated;
@@ -10326,6 +11284,14 @@ ALTER TABLE public.voorraad_publish_steps ENABLE ROW LEVEL SECURITY;
10326
11284
  REVOKE ALL ON public.voorraad_publish_steps FROM anon;
10327
11285
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_publish_steps TO authenticated;
10328
11286
  GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_publish_steps TO service_role;
11287
+ ALTER TABLE public.voorraad_telmoment ENABLE ROW LEVEL SECURITY;
11288
+ REVOKE ALL ON public.voorraad_telmoment FROM anon;
11289
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_telmoment TO authenticated;
11290
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_telmoment TO service_role;
11291
+ ALTER TABLE public.voorraad_telmoment_regels ENABLE ROW LEVEL SECURITY;
11292
+ REVOKE ALL ON public.voorraad_telmoment_regels FROM anon;
11293
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_telmoment_regels TO authenticated;
11294
+ GRANT DELETE, INSERT, REFERENCES, SELECT, TRIGGER, TRUNCATE, UPDATE ON public.voorraad_telmoment_regels TO service_role;
10329
11295
  DROP POLICY IF EXISTS "Authenticated can read continuous stock cache" ON public.floriday_continuous_stock_cache;
10330
11296
  CREATE POLICY "Authenticated can read continuous stock cache" ON public.floriday_continuous_stock_cache AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10331
11297
  DROP POLICY IF EXISTS "Own queue rows select" ON public.floriday_continuous_stock_queue;
@@ -10350,6 +11316,10 @@ DROP POLICY IF EXISTS "Authenticated can read vbn required characteristics" ON p
10350
11316
  CREATE POLICY "Authenticated can read vbn required characteristics" ON public.floriday_vbn_required_characteristics AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10351
11317
  DROP POLICY IF EXISTS "Authenticated can update vbn required characteristics" ON public.floriday_vbn_required_characteristics;
10352
11318
  CREATE POLICY "Authenticated can update vbn required characteristics" ON public.floriday_vbn_required_characteristics AS PERMISSIVE FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
11319
+ DROP POLICY IF EXISTS fust_startmoment_lezen ON public.fust_startmoment;
11320
+ CREATE POLICY fust_startmoment_lezen ON public.fust_startmoment AS PERMISSIVE FOR SELECT TO authenticated USING (true);
11321
+ DROP POLICY IF EXISTS fust_startmoment_log_lezen ON public.fust_startmoment_log;
11322
+ CREATE POLICY fust_startmoment_log_lezen ON public.fust_startmoment_log AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10353
11323
  DROP POLICY IF EXISTS "Fust mutations delete" ON public.fust_stock_mutations;
10354
11324
  CREATE POLICY "Fust mutations delete" ON public.fust_stock_mutations AS PERMISSIVE FOR DELETE TO authenticated USING (voorraad_can_write());
10355
11325
  DROP POLICY IF EXISTS "Fust mutations insert" ON public.fust_stock_mutations;
@@ -10442,6 +11412,16 @@ DROP POLICY IF EXISTS "Authenticated can read voorraad custom fields" ON public.
10442
11412
  CREATE POLICY "Authenticated can read voorraad custom fields" ON public.voorraad_custom_fields AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10443
11413
  DROP POLICY IF EXISTS "Authenticated can update voorraad custom fields" ON public.voorraad_custom_fields;
10444
11414
  CREATE POLICY "Authenticated can update voorraad custom fields" ON public.voorraad_custom_fields AS PERMISSIVE FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
11415
+ DROP POLICY IF EXISTS "Ingelogd mag standaardstatus lezen" ON public.voorraad_defaults_state;
11416
+ CREATE POLICY "Ingelogd mag standaardstatus lezen" ON public.voorraad_defaults_state AS PERMISSIVE FOR SELECT TO authenticated USING (true);
11417
+ DROP POLICY IF EXISTS voorraad_floriday_artikel_wachtrij_lezen ON public.voorraad_floriday_artikel_wachtrij;
11418
+ CREATE POLICY voorraad_floriday_artikel_wachtrij_lezen ON public.voorraad_floriday_artikel_wachtrij AS PERMISSIVE FOR SELECT TO authenticated USING (true);
11419
+ DROP POLICY IF EXISTS voorraad_instellingen_lezen ON public.voorraad_instellingen;
11420
+ CREATE POLICY voorraad_instellingen_lezen ON public.voorraad_instellingen AS PERMISSIVE FOR SELECT TO authenticated USING (true);
11421
+ DROP POLICY IF EXISTS voorraad_koppel_log_lezen ON public.voorraad_koppel_log;
11422
+ CREATE POLICY voorraad_koppel_log_lezen ON public.voorraad_koppel_log AS PERMISSIVE FOR SELECT TO authenticated USING (true);
11423
+ DROP POLICY IF EXISTS voorraad_koppel_twijfel_lezen ON public.voorraad_koppel_twijfel;
11424
+ CREATE POLICY voorraad_koppel_twijfel_lezen ON public.voorraad_koppel_twijfel AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10445
11425
  DROP POLICY IF EXISTS "Ingelogd mag ladingdragers lezen" ON public.voorraad_load_carrier_types;
10446
11426
  CREATE POLICY "Ingelogd mag ladingdragers lezen" ON public.voorraad_load_carrier_types AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10447
11427
  DROP POLICY IF EXISTS "Lokale context lezen" ON public.voorraad_local_context;
@@ -10466,6 +11446,10 @@ DROP POLICY IF EXISTS "Authenticated can update learnings" ON public.voorraad_pu
10466
11446
  CREATE POLICY "Authenticated can update learnings" ON public.voorraad_publish_learnings AS PERMISSIVE FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
10467
11447
  DROP POLICY IF EXISTS "Users manage their own publish steps" ON public.voorraad_publish_steps;
10468
11448
  CREATE POLICY "Users manage their own publish steps" ON public.voorraad_publish_steps AS PERMISSIVE FOR ALL TO authenticated USING ((auth.uid() = user_id)) WITH CHECK ((auth.uid() = user_id));
11449
+ DROP POLICY IF EXISTS voorraad_telmoment_lezen ON public.voorraad_telmoment;
11450
+ CREATE POLICY voorraad_telmoment_lezen ON public.voorraad_telmoment AS PERMISSIVE FOR SELECT TO authenticated USING (true);
11451
+ DROP POLICY IF EXISTS voorraad_telmoment_regels_lezen ON public.voorraad_telmoment_regels;
11452
+ CREATE POLICY voorraad_telmoment_regels_lezen ON public.voorraad_telmoment_regels AS PERMISSIVE FOR SELECT TO authenticated USING (true);
10469
11453
 
10470
11454
  -- triggers
10471
11455
  DO $g$ BEGIN IF to_regclass('public.cart_control_sessions') IS NULL THEN RAISE NOTICE 'Voorraad: cart_control_sessions (andere module) ontbreekt, triggers overgeslagen; draai de schema-update opnieuw na die module'; ELSE EXECUTE $q$CREATE TRIGGER trg_cart_session_consume AFTER UPDATE OF stock_consumed_at ON public.cart_control_sessions FOR EACH ROW EXECUTE FUNCTION trg_cart_session_consume_fn()$q$; END IF; END $g$;
@@ -10544,6 +11528,7 @@ CREATE TRIGGER trg_product_tray_stickers_touch BEFORE UPDATE ON public.product_t
10544
11528
  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$;
10545
11529
  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$;
10546
11530
  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$;
11531
+ 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_velden_aangepast BEFORE UPDATE OF product, image_url, barcode ON public.products FOR EACH ROW EXECUTE FUNCTION trg_products_floriday_velden_aangepast()$q$; END IF; END $g$;
10547
11532
  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$;
10548
11533
  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$;
10549
11534
  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$;
@@ -10604,6 +11589,8 @@ CREATE TRIGGER update_voorraad_publish_learnings_updated_at BEFORE UPDATE ON pub
10604
11589
  DROP TRIGGER IF EXISTS update_voorraad_publish_steps_updated_at ON public.voorraad_publish_steps;
10605
11590
  CREATE TRIGGER update_voorraad_publish_steps_updated_at BEFORE UPDATE ON public.voorraad_publish_steps FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
10606
11591
 
11592
+ -- standaardgegevens (systeemgegevens bijwerken, klantinstellingen alleen als ze ontbreken)
11593
+ SELECT public.voorraad_ensure_defaults();
10607
11594
  -- vaste taken
10608
11595
  DO $cron$
10609
11596
  BEGIN