@flowselections/pick-schermen-kwekers 1.0.89 → 1.0.93

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.
@@ -6012,3 +6012,433 @@ BEGIN
6012
6012
  END $function$;
6013
6013
  REVOKE ALL ON FUNCTION public.pickstation_shipping_note_status(text, uuid, uuid, text) FROM PUBLIC;
6014
6014
  GRANT EXECUTE ON FUNCTION public.pickstation_shipping_note_status(text, uuid, uuid, text) TO anon, authenticated, service_role;
6015
+
6016
+ -- 1.0.90 productiebonnen (gelijk aan migratie 20261109093814)
6017
+ -- Pickschermen 1.0.89: productiebonnen op een eigen pickstation.
6018
+ CREATE TABLE IF NOT EXISTS public.pick_productiebon_jobs (
6019
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
6020
+ productie_order_id uuid NOT NULL,
6021
+ station_id uuid NOT NULL,
6022
+ device_id uuid,
6023
+ job_id uuid,
6024
+ idempotency_key text NOT NULL,
6025
+ soort text NOT NULL DEFAULT 'print',
6026
+ created_at timestamptz NOT NULL DEFAULT now()
6027
+ );
6028
+ CREATE INDEX IF NOT EXISTS idx_pick_productiebon_jobs_po ON public.pick_productiebon_jobs(productie_order_id, created_at DESC);
6029
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_pick_productiebon_jobs_key ON public.pick_productiebon_jobs(idempotency_key);
6030
+ GRANT ALL ON public.pick_productiebon_jobs TO service_role;
6031
+ ALTER TABLE public.pick_productiebon_jobs ENABLE ROW LEVEL SECURITY;
6032
+
6033
+ CREATE OR REPLACE FUNCTION public._pick_try_uuid(p text)
6034
+ RETURNS uuid LANGUAGE plpgsql IMMUTABLE SET search_path TO 'public'
6035
+ AS $function$ BEGIN RETURN p::uuid; EXCEPTION WHEN others THEN RETURN NULL; END $function$;
6036
+
6037
+ CREATE OR REPLACE FUNCTION public._pick_productie_bron(p_device_key text, p_slug text)
6038
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6039
+ AS $function$
6040
+ DECLARE v_station uuid; v_dev_station uuid; v_device uuid;
6041
+ BEGIN
6042
+ SELECT s.id INTO v_station FROM public.pick_stations s
6043
+ WHERE s.slug = nullif(btrim(coalesce(p_slug, '')), '') AND s.active IS TRUE LIMIT 1;
6044
+ IF v_station IS NULL THEN
6045
+ RAISE EXCEPTION 'Dit pickstation is onbekend of niet actief.' USING ERRCODE = '42501';
6046
+ END IF;
6047
+ IF p_device_key IS NULL OR length(p_device_key) < 32 THEN
6048
+ RAISE EXCEPTION 'Dit apparaat is niet gekoppeld aan een pickstation.' USING ERRCODE = '42501';
6049
+ END IF;
6050
+ PERFORM public.pick_device_check(p_device_key, v_station, NULL, NULL, p_slug, NULL);
6051
+ SELECT d.id, d.station_id INTO v_device, v_dev_station FROM public.pick_station_devices d
6052
+ WHERE d.key_hash = public.pick_key_hash(p_device_key) AND d.ingetrokken_op IS NULL LIMIT 1;
6053
+ IF v_device IS NULL OR v_dev_station IS DISTINCT FROM v_station THEN
6054
+ RAISE EXCEPTION 'Dit apparaat is niet gekoppeld aan dit pickstation.' USING ERRCODE = '42501';
6055
+ END IF;
6056
+ RETURN jsonb_build_object('stationId', v_station, 'stationSlug', p_slug, 'deviceId', v_device);
6057
+ END $function$;
6058
+ REVOKE ALL ON FUNCTION public._pick_productie_bron(text, text) FROM PUBLIC, anon, authenticated;
6059
+
6060
+ CREATE OR REPLACE FUNCTION public.pickstation_productiebonnen(p_device_key text, p_slug text, p_geprint boolean DEFAULT false, p_offset integer DEFAULT 0, p_limit integer DEFAULT 25)
6061
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6062
+ AS $function$
6063
+ DECLARE v_bron jsonb; v_station uuid; v_items jsonb := '[]'::jsonb; v_total bigint; r record; v_po jsonb; v_lijst jsonb;
6064
+ v_vandaag date := (now() AT TIME ZONE 'Europe/Amsterdam')::date; v_plek uuid; v_job record;
6065
+ BEGIN
6066
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6067
+ v_station := (v_bron->>'stationId')::uuid;
6068
+ SELECT print_plek_id INTO v_plek FROM public.pick_station_print_plek(_station_id => v_station);
6069
+ SELECT count(*) INTO v_total FROM public.pick_queue q
6070
+ WHERE q.station_id = v_station AND q.payload ? 'productie_order_id' AND q.cancelled_at IS NULL
6071
+ AND CASE WHEN coalesce(p_geprint, false)
6072
+ THEN q.completed_at IS NOT NULL AND (q.completed_at AT TIME ZONE 'Europe/Amsterdam')::date = v_vandaag
6073
+ ELSE q.completed_at IS NULL END;
6074
+ FOR r IN SELECT q.* FROM public.pick_queue q
6075
+ WHERE q.station_id = v_station AND q.payload ? 'productie_order_id' AND q.cancelled_at IS NULL
6076
+ AND CASE WHEN coalesce(p_geprint, false)
6077
+ THEN q.completed_at IS NOT NULL AND (q.completed_at AT TIME ZONE 'Europe/Amsterdam')::date = v_vandaag
6078
+ ELSE q.completed_at IS NULL END
6079
+ ORDER BY q.created_at ASC, q.id
6080
+ LIMIT least(greatest(coalesce(p_limit, 25), 1), 100) OFFSET greatest(coalesce(p_offset, 0), 0)
6081
+ LOOP
6082
+ v_po := NULL;
6083
+ IF nullif(r.document_number, '') IS NOT NULL THEN
6084
+ v_lijst := public.productie_orders_lijst(NULL, NULL, NULL, r.document_number, 5, 0);
6085
+ SELECT e INTO v_po FROM jsonb_array_elements(coalesce(v_lijst->'rijen', '[]'::jsonb)) e
6086
+ WHERE e->>'id' = r.payload->>'productie_order_id' LIMIT 1;
6087
+ END IF;
6088
+ SELECT j.job_id, j.idempotency_key, j.soort INTO v_job FROM public.pick_productiebon_jobs j
6089
+ WHERE j.productie_order_id = public._pick_try_uuid(r.payload->>'productie_order_id')
6090
+ ORDER BY j.created_at DESC LIMIT 1;
6091
+ v_items := v_items || jsonb_build_object(
6092
+ 'queue_id', r.id, 'status_id', r.status_id, 'document_number', r.document_number,
6093
+ 'created_at', r.created_at, 'completed_at', r.completed_at, 'payload', r.payload,
6094
+ 'productie_order', v_po,
6095
+ 'foto', (SELECT p.image_url FROM public.products p WHERE p.id = public._pick_try_uuid(coalesce(r.payload->>'productId', v_po->>'product_id'))),
6096
+ 'laatste_job', CASE WHEN v_job.job_id IS NULL THEN NULL ELSE jsonb_build_object('job_id', v_job.job_id, 'idempotency_key', v_job.idempotency_key, 'soort', v_job.soort) END);
6097
+ END LOOP;
6098
+ RETURN jsonb_build_object('items', v_items, 'totaal', v_total, 'print_plek_id', v_plek, 'station_id', v_station);
6099
+ END $function$;
6100
+
6101
+ CREATE OR REPLACE FUNCTION public.pickstation_productiebon_printen(p_device_key text, p_slug text, p_productie_order_id uuid, p_idempotency_key text, p_herprint boolean DEFAULT false)
6102
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6103
+ AS $function$
6104
+ DECLARE v_bron jsonb; v_station uuid; v_q record; v_plek uuid; v_res jsonb; v_job uuid;
6105
+ BEGIN
6106
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6107
+ v_station := (v_bron->>'stationId')::uuid;
6108
+ SELECT q.id, q.payload INTO v_q FROM public.pick_queue q
6109
+ WHERE q.station_id = v_station AND q.payload->>'productie_order_id' = p_productie_order_id::text AND q.cancelled_at IS NULL
6110
+ ORDER BY q.created_at DESC LIMIT 1;
6111
+ IF v_q.id IS NULL THEN
6112
+ RETURN jsonb_build_object('ok', false, 'foutcode', 'NIET_OP_STATION', 'reden', 'Deze productiebon staat niet op dit station.');
6113
+ END IF;
6114
+ IF coalesce((v_q.payload->>'requiresApproval')::boolean, false) AND v_q.payload->>'approvedAt' IS NULL THEN
6115
+ RETURN jsonb_build_object('ok', false, 'foutcode', 'WACHT_OP_GOEDKEURING', 'reden', 'Deze productiebon wacht op goedkeuring.');
6116
+ END IF;
6117
+ SELECT print_plek_id INTO v_plek FROM public.pick_station_print_plek(_station_id => v_station);
6118
+ IF v_plek IS NULL THEN
6119
+ RETURN jsonb_build_object('ok', false, 'foutcode', 'GEEN_PRINTPLEK', 'reden', 'Dit station heeft geen printplek.');
6120
+ END IF;
6121
+ v_res := public.layouts_productiebon_printen(p_productie_order_id, v_plek, p_idempotency_key, 'pickstation');
6122
+ v_job := public._pick_try_uuid(v_res->>'job_id');
6123
+ IF v_job IS NOT NULL AND coalesce((v_res->>'ok')::boolean, false) THEN
6124
+ INSERT INTO public.pick_productiebon_jobs(productie_order_id, station_id, device_id, job_id, idempotency_key, soort)
6125
+ VALUES (p_productie_order_id, v_station, (v_bron->>'deviceId')::uuid, v_job, btrim(p_idempotency_key),
6126
+ CASE WHEN coalesce(p_herprint, false) THEN 'herprint' ELSE 'print' END)
6127
+ ON CONFLICT (idempotency_key) DO NOTHING;
6128
+ END IF;
6129
+ INSERT INTO public.pick_station_logs(station_id, queue_item_id, action, detail)
6130
+ VALUES (v_station, v_q.id, CASE WHEN coalesce(p_herprint, false) THEN 'productiebon_herprint' ELSE 'productiebon_print' END,
6131
+ v_bron || jsonb_build_object('productieOrderId', p_productie_order_id, 'resultaat', v_res));
6132
+ RETURN v_res;
6133
+ END $function$;
6134
+
6135
+ CREATE OR REPLACE FUNCTION public.pickstation_printjob_status(p_device_key text, p_slug text, p_job_id uuid)
6136
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6137
+ AS $function$
6138
+ DECLARE v_bron jsonb;
6139
+ BEGIN
6140
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6141
+ IF NOT EXISTS (SELECT 1 FROM public.pick_productiebon_jobs j WHERE j.job_id = p_job_id AND j.station_id = (v_bron->>'stationId')::uuid) THEN
6142
+ RETURN jsonb_build_object('job_id', p_job_id, 'status', 'mislukt', 'foutcode', 'NIET_VAN_STATION', 'reden', 'Deze printopdracht hoort niet bij dit station.');
6143
+ END IF;
6144
+ RETURN public.layouts_printjob_status(p_job_id);
6145
+ END $function$;
6146
+
6147
+ CREATE OR REPLACE FUNCTION public.pickstation_productie_verwerken(p_device_key text, p_slug text, p_productie_order_id uuid)
6148
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6149
+ AS $function$
6150
+ DECLARE v_bron jsonb; v_station uuid; v_q uuid; v_job uuid; v_st jsonb; v_res jsonb;
6151
+ BEGIN
6152
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6153
+ v_station := (v_bron->>'stationId')::uuid;
6154
+ SELECT q.id INTO v_q FROM public.pick_queue q
6155
+ WHERE q.station_id = v_station AND q.payload->>'productie_order_id' = p_productie_order_id::text AND q.cancelled_at IS NULL
6156
+ ORDER BY q.created_at DESC LIMIT 1;
6157
+ IF v_q IS NULL THEN
6158
+ RAISE EXCEPTION 'Deze productiebon staat niet op dit station.' USING ERRCODE = '42501';
6159
+ END IF;
6160
+ SELECT j.job_id INTO v_job FROM public.pick_productiebon_jobs j
6161
+ WHERE j.productie_order_id = p_productie_order_id AND j.station_id = v_station AND j.soort = 'print'
6162
+ ORDER BY j.created_at DESC LIMIT 1;
6163
+ IF v_job IS NULL THEN
6164
+ RAISE EXCEPTION 'Er is nog geen bon geprint voor deze productieorder.' USING ERRCODE = 'P0001';
6165
+ END IF;
6166
+ v_st := public.layouts_printjob_status(v_job);
6167
+ IF v_st->>'status' IS DISTINCT FROM 'geprint' THEN
6168
+ RAISE EXCEPTION 'De bon is nog niet geprint.' USING ERRCODE = 'P0001';
6169
+ END IF;
6170
+ v_res := public.productie_order_verwerken(p_productie_order_id);
6171
+ INSERT INTO public.pick_station_logs(station_id, queue_item_id, action, detail)
6172
+ VALUES (v_station, v_q, 'productie_verwerken', v_bron || jsonb_build_object('productieOrderId', p_productie_order_id, 'jobId', v_job, 'resultaat', v_res));
6173
+ RETURN v_res;
6174
+ END $function$;
6175
+
6176
+ CREATE OR REPLACE FUNCTION public.pickstation_productiebon_goedkeuren(p_device_key text, p_slug text, p_queue_id uuid)
6177
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6178
+ AS $function$
6179
+ DECLARE v_bron jsonb; v_res jsonb;
6180
+ BEGIN
6181
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6182
+ v_res := public.logistics_productiebon_goedkeuren_v2(p_queue_id, v_bron);
6183
+ INSERT INTO public.pick_station_logs(station_id, queue_item_id, action, detail)
6184
+ VALUES ((v_bron->>'stationId')::uuid, p_queue_id, 'productiebon_goedkeuren', v_bron || jsonb_build_object('resultaat', v_res));
6185
+ RETURN v_res;
6186
+ END $function$;
6187
+
6188
+ REVOKE ALL ON FUNCTION public.pickstation_productiebonnen(text, text, boolean, integer, integer) FROM PUBLIC;
6189
+ REVOKE ALL ON FUNCTION public.pickstation_productiebon_printen(text, text, uuid, text, boolean) FROM PUBLIC;
6190
+ REVOKE ALL ON FUNCTION public.pickstation_printjob_status(text, text, uuid) FROM PUBLIC;
6191
+ REVOKE ALL ON FUNCTION public.pickstation_productie_verwerken(text, text, uuid) FROM PUBLIC;
6192
+ REVOKE ALL ON FUNCTION public.pickstation_productiebon_goedkeuren(text, text, uuid) FROM PUBLIC;
6193
+ GRANT EXECUTE ON FUNCTION public.pickstation_productiebonnen(text, text, boolean, integer, integer) TO anon, authenticated, service_role;
6194
+ GRANT EXECUTE ON FUNCTION public.pickstation_productiebon_printen(text, text, uuid, text, boolean) TO anon, authenticated, service_role;
6195
+ GRANT EXECUTE ON FUNCTION public.pickstation_printjob_status(text, text, uuid) TO anon, authenticated, service_role;
6196
+ GRANT EXECUTE ON FUNCTION public.pickstation_productie_verwerken(text, text, uuid) TO anon, authenticated, service_role;
6197
+ GRANT EXECUTE ON FUNCTION public.pickstation_productiebon_goedkeuren(text, text, uuid) TO anon, authenticated, service_role;
6198
+
6199
+ -- ===== 1.0.91 productiestation, Voorraad-stationverwerking, standaardstations =====
6200
+ -- Pickschermen 1.0.91: productiestation via Engine, verwerken via Voorraad-stationfunctie, standaardstations.
6201
+ ALTER TABLE public.pick_stations ADD COLUMN IF NOT EXISTS system_code text;
6202
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_pick_stations_system_code ON public.pick_stations(system_code) WHERE system_code IS NOT NULL;
6203
+
6204
+ -- system_code is vast: alleen de eigen standaardgegevens-functie mag hem zetten, daarna nooit wijzigen.
6205
+ CREATE OR REPLACE FUNCTION public.pick_stations_system_code_guard()
6206
+ RETURNS trigger LANGUAGE plpgsql SET search_path TO 'public'
6207
+ AS $function$
6208
+ BEGIN
6209
+ IF TG_OP = 'INSERT' THEN
6210
+ IF NEW.system_code IS NOT NULL AND coalesce(current_setting('pick.defaults_apply', true), '') <> 'on' THEN
6211
+ RAISE EXCEPTION 'Een standaardstation kun je niet zelf aanmaken.' USING ERRCODE = '42501';
6212
+ END IF;
6213
+ ELSIF NEW.system_code IS DISTINCT FROM OLD.system_code THEN
6214
+ RAISE EXCEPTION 'De vaste code van een station kun je niet wijzigen.' USING ERRCODE = '42501';
6215
+ END IF;
6216
+ RETURN NEW;
6217
+ END $function$;
6218
+ DROP TRIGGER IF EXISTS pick_stations_system_code_guard ON public.pick_stations;
6219
+ CREATE TRIGGER pick_stations_system_code_guard BEFORE INSERT OR UPDATE ON public.pick_stations
6220
+ FOR EACH ROW EXECUTE FUNCTION public.pick_stations_system_code_guard();
6221
+
6222
+ -- Gebruik van een station: Engine-keuzes (als die functies bestaan) + open regels in de eigen wachtrij.
6223
+ -- Faalt nooit door de Engine: ontbrekend of fout → alleen de eigen controle.
6224
+ CREATE OR REPLACE FUNCTION public._pick_station_gebruik(p_station_id uuid)
6225
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6226
+ AS $function$
6227
+ DECLARE v_docs text[] := ARRAY[]::text[]; v_open bigint; v_r jsonb; e jsonb; v_t text; v_bron text := 'eigen';
6228
+ BEGIN
6229
+ IF to_regprocedure('public.logistics_station_in_gebruik(uuid)') IS NOT NULL THEN
6230
+ BEGIN
6231
+ EXECUTE 'SELECT public.logistics_station_in_gebruik($1)' INTO v_r USING p_station_id;
6232
+ v_bron := 'logistics_station_in_gebruik';
6233
+ FOR e IN SELECT x FROM jsonb_array_elements(CASE WHEN jsonb_typeof(v_r) = 'array' THEN v_r
6234
+ WHEN jsonb_typeof(v_r->'documenten') = 'array' THEN v_r->'documenten' ELSE '[]'::jsonb END) x LOOP
6235
+ v_t := CASE WHEN jsonb_typeof(e) = 'string' THEN e #>> '{}' ELSE coalesce(e->>'document', e->>'naam', e->>'name') END;
6236
+ IF nullif(btrim(v_t), '') IS NOT NULL AND NOT (v_t = ANY(v_docs)) THEN v_docs := v_docs || btrim(v_t); END IF;
6237
+ END LOOP;
6238
+ EXCEPTION WHEN OTHERS THEN
6239
+ RAISE WARNING 'pickschermen: logistics_station_in_gebruik mislukt (%): %', SQLSTATE, SQLERRM;
6240
+ v_bron := 'eigen';
6241
+ END;
6242
+ END IF;
6243
+ IF v_bron = 'eigen' AND to_regprocedure('public.logistics_productiebon_station()') IS NOT NULL THEN
6244
+ BEGIN
6245
+ EXECUTE 'SELECT public.logistics_productiebon_station()' INTO v_r;
6246
+ IF v_r->>'station_id' = p_station_id::text THEN v_docs := v_docs || 'productiebonnen'::text; END IF;
6247
+ v_bron := 'logistics_productiebon_station';
6248
+ EXCEPTION WHEN OTHERS THEN
6249
+ RAISE WARNING 'pickschermen: logistics_productiebon_station mislukt (%): %', SQLSTATE, SQLERRM;
6250
+ END;
6251
+ END IF;
6252
+ SELECT count(*) INTO v_open FROM public.pick_queue q
6253
+ WHERE q.station_id = p_station_id AND q.completed_at IS NULL AND q.cancelled_at IS NULL;
6254
+ RETURN jsonb_build_object('documenten', to_jsonb(v_docs), 'open', v_open, 'bron', v_bron);
6255
+ END $function$;
6256
+ REVOKE ALL ON FUNCTION public._pick_station_gebruik(uuid) FROM PUBLIC, anon, authenticated;
6257
+ GRANT EXECUTE ON FUNCTION public._pick_station_gebruik(uuid) TO service_role;
6258
+
6259
+ -- Beheerpagina (ingelogd): gebruik per station lezen.
6260
+ CREATE OR REPLACE FUNCTION public.pick_station_gebruik(p_station_ids uuid[])
6261
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6262
+ AS $function$
6263
+ DECLARE v jsonb := '{}'::jsonb; i uuid;
6264
+ BEGIN
6265
+ IF auth.uid() IS NULL AND coalesce(auth.role(), '') <> 'service_role' THEN
6266
+ RAISE EXCEPTION 'Geen toegang: log in om stationgebruik te lezen.' USING ERRCODE = '42501';
6267
+ END IF;
6268
+ FOREACH i IN ARRAY coalesce(p_station_ids[1:200], ARRAY[]::uuid[]) LOOP
6269
+ v := v || jsonb_build_object(i::text, public._pick_station_gebruik(i));
6270
+ END LOOP;
6271
+ RETURN v;
6272
+ END $function$;
6273
+ REVOKE ALL ON FUNCTION public.pick_station_gebruik(uuid[]) FROM PUBLIC, anon;
6274
+ GRANT EXECUTE ON FUNCTION public.pick_station_gebruik(uuid[]) TO authenticated, service_role;
6275
+
6276
+ -- Verwijderregel: standaardstation nooit; eigen station niet zolang gekozen of open regels.
6277
+ CREATE OR REPLACE FUNCTION public.pick_stations_delete_guard()
6278
+ RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public'
6279
+ AS $function$
6280
+ DECLARE g jsonb; v_docs text; v_open bigint; v_delen text[] := ARRAY[]::text[];
6281
+ BEGIN
6282
+ IF OLD.system_code IS NOT NULL THEN
6283
+ RAISE EXCEPTION 'Dit is een standaardstation; je kunt het hernoemen of uitzetten.' USING ERRCODE = '42501';
6284
+ END IF;
6285
+ g := public._pick_station_gebruik(OLD.id);
6286
+ SELECT string_agg(x, ', ') INTO v_docs FROM jsonb_array_elements_text(coalesce(g->'documenten', '[]'::jsonb)) x;
6287
+ v_open := coalesce((g->>'open')::bigint, 0);
6288
+ IF v_docs IS NOT NULL THEN v_delen := v_delen || ('gekozen voor ' || v_docs); END IF;
6289
+ IF v_open > 0 THEN v_delen := v_delen || (v_open || CASE WHEN v_open = 1 THEN ' open bon' ELSE ' open bonnen' END); END IF;
6290
+ IF array_length(v_delen, 1) > 0 THEN
6291
+ RAISE EXCEPTION 'Dit station is nog in gebruik (%). Kies eerst een ander station of zet het uit.', array_to_string(v_delen, ' / ')
6292
+ USING ERRCODE = '42501';
6293
+ END IF;
6294
+ RETURN OLD;
6295
+ END $function$;
6296
+ REVOKE ALL ON FUNCTION public.pick_stations_delete_guard() FROM PUBLIC, anon, authenticated;
6297
+ DROP TRIGGER IF EXISTS pick_stations_delete_guard ON public.pick_stations;
6298
+ CREATE TRIGGER pick_stations_delete_guard BEFORE DELETE ON public.pick_stations
6299
+ FOR EACH ROW EXECUTE FUNCTION public.pick_stations_delete_guard();
6300
+
6301
+ -- Pickscherm: is dit (gekoppelde) station het productiestation van de Engine?
6302
+ CREATE OR REPLACE FUNCTION public.pickstation_productie_station(p_device_key text, p_slug text)
6303
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6304
+ AS $function$
6305
+ DECLARE v_bron jsonb; v_r jsonb;
6306
+ BEGIN
6307
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6308
+ v_r := public.logistics_productiebon_station();
6309
+ RETURN jsonb_build_object(
6310
+ 'ingesteld', nullif(v_r->>'station_id', '') IS NOT NULL,
6311
+ 'productiestation', coalesce(v_r->>'station_id' = v_bron->>'stationId', false));
6312
+ END $function$;
6313
+ REVOKE ALL ON FUNCTION public.pickstation_productie_station(text, text) FROM PUBLIC;
6314
+ GRANT EXECUTE ON FUNCTION public.pickstation_productie_station(text, text) TO anon, authenticated, service_role;
6315
+
6316
+ -- Verwerken via de Voorraad-stationfunctie; antwoord ongewijzigd doorgeven.
6317
+ CREATE OR REPLACE FUNCTION public.pickstation_productie_verwerken(p_device_key text, p_slug text, p_productie_order_id uuid)
6318
+ RETURNS jsonb LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6319
+ AS $function$
6320
+ DECLARE v_bron jsonb; v_station uuid; v_q uuid; v_job uuid; v_st jsonb; v_res jsonb;
6321
+ BEGIN
6322
+ v_bron := public._pick_productie_bron(p_device_key, p_slug);
6323
+ v_station := (v_bron->>'stationId')::uuid;
6324
+ SELECT q.id INTO v_q FROM public.pick_queue q
6325
+ WHERE q.station_id = v_station AND q.payload->>'productie_order_id' = p_productie_order_id::text AND q.cancelled_at IS NULL
6326
+ ORDER BY q.created_at DESC LIMIT 1;
6327
+ IF v_q IS NULL THEN
6328
+ RAISE EXCEPTION 'Deze productiebon staat niet op dit station.' USING ERRCODE = '42501';
6329
+ END IF;
6330
+ SELECT j.job_id INTO v_job FROM public.pick_productiebon_jobs j
6331
+ WHERE j.productie_order_id = p_productie_order_id AND j.station_id = v_station AND j.soort = 'print'
6332
+ ORDER BY j.created_at DESC LIMIT 1;
6333
+ IF v_job IS NULL THEN
6334
+ RAISE EXCEPTION 'Er is nog geen bon geprint voor deze productieorder.' USING ERRCODE = 'P0001';
6335
+ END IF;
6336
+ v_st := public.layouts_printjob_status(v_job);
6337
+ IF v_st->>'status' IS DISTINCT FROM 'geprint' THEN
6338
+ RAISE EXCEPTION 'De bon is nog niet geprint.' USING ERRCODE = 'P0001';
6339
+ END IF;
6340
+ v_res := public.productie_order_verwerken_station(p_productie_order_id,
6341
+ jsonb_build_object('stationId', v_bron->>'stationId', 'stationSlug', v_bron->>'stationSlug', 'deviceId', v_bron->>'deviceId'));
6342
+ INSERT INTO public.pick_station_logs(station_id, queue_item_id, action, detail)
6343
+ VALUES (v_station, v_q, 'productie_verwerken', v_bron || jsonb_build_object('productieOrderId', p_productie_order_id, 'jobId', v_job, 'resultaat', v_res));
6344
+ RETURN v_res;
6345
+ END $function$;
6346
+ REVOKE ALL ON FUNCTION public.pickstation_productie_verwerken(text, text, uuid) FROM PUBLIC;
6347
+ GRANT EXECUTE ON FUNCTION public.pickstation_productie_verwerken(text, text, uuid) TO anon, authenticated, service_role;
6348
+
6349
+ -- Standaardgegevens versie 2: bestaande functie uitlezen en alleen de stationsstappen toevoegen
6350
+ -- (beveiliging, search_path en rechten blijven exact zoals ze waren).
6351
+ DO $mig$
6352
+ DECLARE d text;
6353
+ BEGIN
6354
+ d := pg_get_functiondef('public.pick_ensure_defaults_intern()'::regprocedure);
6355
+ IF position('c_stations' IN d) > 0 THEN RETURN; END IF;
6356
+ IF position('c_versie constant integer := 1;' IN d) = 0
6357
+ OR position('= jsonb_array_length(c_koppelingen)' || chr(10) || ' THEN' IN d) = 0
6358
+ OR position(' INSERT INTO public.pick_settings (id, device_key_required)' IN d) = 0 THEN
6359
+ RAISE EXCEPTION 'pick_ensure_defaults_intern heeft een onverwachte vorm; niet aangepast.';
6360
+ END IF;
6361
+ d := replace(d, 'c_versie constant integer := 1;', 'c_versie constant integer := 2;' || chr(10) ||
6362
+ ' c_stations constant jsonb := ''[{"system_code":"orders","name":"Orders","type":"orders","sort_order":10},{"system_code":"productie","name":"Productie","type":"production","sort_order":20}]'';');
6363
+ d := replace(d, '= jsonb_array_length(c_koppelingen)' || chr(10) || ' THEN',
6364
+ '= jsonb_array_length(c_koppelingen)' || chr(10) ||
6365
+ ' AND (SELECT count(*) FROM public.pick_stations WHERE system_code IN (SELECT e->>''system_code'' FROM jsonb_array_elements(c_stations) e)) = jsonb_array_length(c_stations)' || chr(10) || ' THEN');
6366
+ d := replace(d, ' INSERT INTO public.pick_settings (id, device_key_required)',
6367
+ ' -- Standaardstations: alleen aanmaken als er nog geen station met die system_code is; bestaande nooit aanpassen.' || chr(10) ||
6368
+ ' INSERT INTO public.pick_stations (name, system_code, type_id, sort_order, active)' || chr(10) ||
6369
+ ' SELECT e->>''name'', e->>''system_code'', (SELECT st.id FROM public.pick_station_types st WHERE st.code = e->>''type'' LIMIT 1), (e->>''sort_order'')::int, true' || chr(10) ||
6370
+ ' FROM jsonb_array_elements(c_stations) e' || chr(10) ||
6371
+ ' WHERE NOT EXISTS (SELECT 1 FROM public.pick_stations p WHERE p.system_code = e->>''system_code'')' || chr(10) ||
6372
+ ' ON CONFLICT DO NOTHING;' || chr(10) ||
6373
+ ' GET DIAGNOSTICS n = ROW_COUNT;' || chr(10) ||
6374
+ ' v_res := v_res || jsonb_build_object(''stations_aangemaakt'', n);' || chr(10) || chr(10) ||
6375
+ ' INSERT INTO public.pick_settings (id, device_key_required)');
6376
+ EXECUTE d;
6377
+ END $mig$;
6378
+ REVOKE ALL ON FUNCTION public.pick_ensure_defaults_intern() FROM PUBLIC, anon, authenticated;
6379
+ GRANT EXECUTE ON FUNCTION public.pick_ensure_defaults_intern() TO service_role;
6380
+
6381
+ -- ===== 1.0.92 productiebon niet claimen buiten productiestation, standaardstations alleen in lege shell =====
6382
+ -- Pickschermen 1.0.92
6383
+ CREATE OR REPLACE FUNCTION public._pick_is_productiestation(p_station_id uuid)
6384
+ RETURNS boolean LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO 'public'
6385
+ AS $function$
6386
+ DECLARE v jsonb;
6387
+ BEGIN
6388
+ IF p_station_id IS NULL OR to_regprocedure('public.logistics_productiebon_station()') IS NULL THEN RETURN false; END IF;
6389
+ BEGIN
6390
+ EXECUTE 'SELECT public.logistics_productiebon_station()' INTO v;
6391
+ EXCEPTION WHEN OTHERS THEN
6392
+ RAISE WARNING 'pickschermen: logistics_productiebon_station mislukt (%): %', SQLSTATE, SQLERRM;
6393
+ RETURN false;
6394
+ END;
6395
+ RETURN coalesce(v->>'station_id' = p_station_id::text, false);
6396
+ END $function$;
6397
+ REVOKE ALL ON FUNCTION public._pick_is_productiestation(uuid) FROM PUBLIC, anon, authenticated;
6398
+ GRANT EXECUTE ON FUNCTION public._pick_is_productiestation(uuid) TO service_role;
6399
+
6400
+ DO $mig$
6401
+ DECLARE d text;
6402
+ c_old constant text := 'COALESCE(q.payload->>''printbaar'', ''true'') <> ''false''';
6403
+ c_new constant text := 'COALESCE(q.payload->>''printbaar'', ''true'') <> ''false'' AND NOT (q.payload ? ''productie_order_id'' AND NOT public._pick_is_productiestation(_station_id))';
6404
+ BEGIN
6405
+ -- Volgende document
6406
+ d := pg_get_functiondef('public.pick_claim_next_document(uuid,uuid,text,text,integer,date)'::regprocedure);
6407
+ IF position('_pick_is_productiestation' IN d) = 0 THEN
6408
+ IF position(c_old IN d) = 0 THEN RAISE EXCEPTION 'pick_claim_next_document onverwachte vorm'; END IF;
6409
+ EXECUTE replace(d, c_old, c_new);
6410
+ END IF;
6411
+ -- Order vastzetten (Print volgende order)
6412
+ d := pg_get_functiondef('public._pick_claim_order_core(uuid,text,text[],text,date,integer)'::regprocedure);
6413
+ IF position('_pick_is_productiestation' IN d) = 0 THEN
6414
+ IF position(c_old IN d) = 0 THEN RAISE EXCEPTION '_pick_claim_order_core onverwachte vorm'; END IF;
6415
+ EXECUTE replace(d, c_old, c_new);
6416
+ END IF;
6417
+ -- Eén document vastzetten
6418
+ d := pg_get_functiondef('public.pick_claim_document(uuid,uuid,uuid,text,integer)'::regprocedure);
6419
+ IF position('_pick_is_productiestation' IN d) = 0 THEN
6420
+ IF position(' PERFORM public.pick_assert_printable(item);' IN d) = 0 THEN RAISE EXCEPTION 'pick_claim_document onverwachte vorm'; END IF;
6421
+ EXECUTE replace(d, ' PERFORM public.pick_assert_printable(item);',
6422
+ ' PERFORM public.pick_assert_printable(item);' || chr(10) ||
6423
+ ' IF item.payload ? ''productie_order_id'' AND NOT public._pick_is_productiestation(COALESCE(_station_id, item.station_id)) THEN' || chr(10) ||
6424
+ ' RAISE EXCEPTION ''Deze productiebon hoort op het productiestation.'' USING ERRCODE = ''P0001'';' || chr(10) ||
6425
+ ' END IF;');
6426
+ END IF;
6427
+ -- Standaardstations alleen in een lege shell
6428
+ d := pg_get_functiondef('public.pick_ensure_defaults_intern()'::regprocedure);
6429
+ IF position('c_versie constant integer := 2;' IN d) > 0 THEN
6430
+ IF position(' AND (SELECT count(*) FROM public.pick_stations WHERE system_code IN (SELECT e->>''system_code'' FROM jsonb_array_elements(c_stations) e)) = jsonb_array_length(c_stations)' IN d) = 0
6431
+ OR position(' WHERE NOT EXISTS (SELECT 1 FROM public.pick_stations p WHERE p.system_code = e->>''system_code'')' IN d) = 0 THEN
6432
+ RAISE EXCEPTION 'pick_ensure_defaults_intern onverwachte vorm';
6433
+ END IF;
6434
+ d := replace(d, 'c_versie constant integer := 2;', 'c_versie constant integer := 3;');
6435
+ d := replace(d, ' AND (SELECT count(*) FROM public.pick_stations WHERE system_code IN (SELECT e->>''system_code'' FROM jsonb_array_elements(c_stations) e)) = jsonb_array_length(c_stations)',
6436
+ ' AND EXISTS (SELECT 1 FROM public.pick_stations)');
6437
+ d := replace(d, ' WHERE NOT EXISTS (SELECT 1 FROM public.pick_stations p WHERE p.system_code = e->>''system_code'')',
6438
+ ' WHERE NOT EXISTS (SELECT 1 FROM public.pick_stations p WHERE p.system_code = e->>''system_code'')' || chr(10) ||
6439
+ ' AND NOT EXISTS (SELECT 1 FROM public.pick_stations p2 WHERE p2.system_code IS DISTINCT FROM e->>''system_code'' AND (p2.system_code IS NULL OR p2.system_code NOT IN (SELECT x->>''system_code'' FROM jsonb_array_elements(c_stations) x)))');
6440
+ EXECUTE d;
6441
+ END IF;
6442
+ END $mig$;
6443
+ REVOKE ALL ON FUNCTION public.pick_ensure_defaults_intern() FROM PUBLIC, anon, authenticated;
6444
+ GRANT EXECUTE ON FUNCTION public.pick_ensure_defaults_intern() TO service_role;