@flowselections/pick-schermen-kwekers 1.0.93 → 1.0.95

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.
@@ -37,4 +37,10 @@ export declare function reprintQuestion(printedAt: string | null, tz: string | n
37
37
  export declare const ACCEPTED_STATUSES: Set<string>;
38
38
  /** Wachtrij-telling als echt getal: "12 orders nog te printen". */
39
39
  export declare function todoCountText(n: number): string;
40
+ /**
41
+ * Bevestigvraag van de Engine (`payload.bevestigVraag`) voor een kaart: de
42
+ * eerste gevulde vraag van zijn karregels, anders null. Het scherm rekent zelf
43
+ * nooit of een kar vol is; het toont alleen wat de Engine vraagt.
44
+ */
45
+ export declare function confirmQuestionOf(card: WerkvloerCard | null | undefined): string | null;
40
46
  //# sourceMappingURL=werkvloer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"werkvloer.d.ts","sourceRoot":"","sources":["../../src/lib/werkvloer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAIrD;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAsBlE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAM7D;AASD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAIvD;AAcD,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,OAAa,GAAG,MAAM,GAAG,IAAI,CASjG;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAE9E;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAI1F;AAED,qDAAqD;AACrD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGnF;AAED,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,aAA6E,CAAC;AAE5G,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C"}
1
+ {"version":3,"file":"werkvloer.d.ts","sourceRoot":"","sources":["../../src/lib/werkvloer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAIrD;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAsBlE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAM7D;AASD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAIvD;AAcD,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,OAAa,GAAG,MAAM,GAAG,IAAI,CASjG;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAE9E;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAI1F;AAED,qDAAqD;AACrD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGnF;AAED,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,aAA6E,CAAC;AAE5G,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAQvF"}
@@ -119,3 +119,18 @@ export function todoCountText(n) {
119
119
  function textOf(v) {
120
120
  return typeof v === "string" && v.trim() ? v.trim() : null;
121
121
  }
122
+ /**
123
+ * Bevestigvraag van de Engine (`payload.bevestigVraag`) voor een kaart: de
124
+ * eerste gevulde vraag van zijn karregels, anders null. Het scherm rekent zelf
125
+ * nooit of een kar vol is; het toont alleen wat de Engine vraagt.
126
+ */
127
+ export function confirmQuestionOf(card) {
128
+ const rows = Array.isArray(card?.rows) ? card.rows : [];
129
+ for (const r of rows) {
130
+ const p = (r.payload && typeof r.payload === "object" ? r.payload : {});
131
+ const q = p["bevestigVraag"];
132
+ if (typeof q === "string" && q.trim() !== "")
133
+ return q.trim();
134
+ }
135
+ return null;
136
+ }
@@ -47,3 +47,13 @@ describe("werkvloer", () => {
47
47
  expect(todoCountText(12)).toBe("12 orders nog te printen");
48
48
  });
49
49
  });
50
+ import { confirmQuestionOf as _cq } from "./werkvloer.js";
51
+ describe("confirmQuestionOf (bevestigVraag van de Engine)", () => {
52
+ const card = (payloads) => ({ key: "k", rows: payloads.map((payload, i) => ({ id: String(i), payload })) });
53
+ it("geeft de vraag van de Engine terug als die gevuld is", () => {
54
+ expect(_cq(card([{}, { bevestigVraag: "Deze kar is nog niet vol. Toch nu printen?" }]))).toBe("Deze kar is nog niet vol. Toch nu printen?");
55
+ });
56
+ it("geen vraag bij een volle kar (leeg veld)", () => {
57
+ expect(_cq(card([{ bevestigVraag: "" }, { bevestigVraag: null }]))).toBeNull();
58
+ });
59
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/pick-schermen-kwekers",
3
- "version": "1.0.93",
3
+ "version": "1.0.95",
4
4
  "flowselections": {
5
5
  "moduleId": "pick-schermen",
6
6
  "schema": {
@@ -20,6 +20,14 @@
20
20
  "nav": false,
21
21
  "public": true
22
22
  }
23
+ ],
24
+ "crons": [
25
+ {
26
+ "name": "pick-history-cleanup",
27
+ "kind": "sql",
28
+ "schedule": "35 * * * *",
29
+ "sql": "SELECT public.pick_cleanup_history();"
30
+ }
23
31
  ]
24
32
  },
25
33
  "private": false,
@@ -6441,4 +6441,182 @@ BEGIN
6441
6441
  END IF;
6442
6442
  END $mig$;
6443
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;
6444
+ GRANT EXECUTE ON FUNCTION public.pick_ensure_defaults_intern() TO service_role;
6445
+ -- ===== Golf 1: pickhistorie (20261110191301_eb6ef686-ecc0-446d-a7d8-65dfa16a2855.sql) =====
6446
+ -- Golf 1: pickhistorie alleen gewijzigde velden + eigen opruiming in porties
6447
+ CREATE OR REPLACE FUNCTION public.pick_queue_audit()
6448
+ RETURNS trigger
6449
+ LANGUAGE plpgsql
6450
+ SECURITY DEFINER
6451
+ SET search_path TO 'public'
6452
+ AS $function$
6453
+ DECLARE
6454
+ v_old jsonb; v_new jsonb; v_o jsonb := '{}'::jsonb; v_n jsonb := '{}'::jsonb; k text;
6455
+ BEGIN
6456
+ IF TG_OP = 'INSERT' THEN
6457
+ INSERT INTO public.pick_station_history(entity_table, entity_id, action, changed_by, old_data, new_data)
6458
+ VALUES ('pick_queue', NEW.id, TG_OP, auth.uid(), NULL, jsonb_strip_nulls(to_jsonb(NEW)));
6459
+ RETURN NEW;
6460
+ ELSIF TG_OP = 'DELETE' THEN
6461
+ INSERT INTO public.pick_station_history(entity_table, entity_id, action, changed_by, old_data, new_data)
6462
+ VALUES ('pick_queue', OLD.id, TG_OP, auth.uid(), jsonb_strip_nulls(to_jsonb(OLD)), NULL);
6463
+ RETURN OLD;
6464
+ END IF;
6465
+
6466
+ v_old := to_jsonb(OLD); v_new := to_jsonb(NEW);
6467
+ FOR k IN SELECT jsonb_object_keys(v_new) LOOP
6468
+ IF k <> 'updated_at' AND (v_old -> k) IS DISTINCT FROM (v_new -> k) THEN
6469
+ v_o := v_o || jsonb_build_object(k, v_old -> k);
6470
+ v_n := v_n || jsonb_build_object(k, v_new -> k);
6471
+ END IF;
6472
+ END LOOP;
6473
+ IF v_n = '{}'::jsonb THEN RETURN NEW; END IF; -- niets wezenlijks gewijzigd
6474
+ v_o := v_o || jsonb_build_object('updated_at', v_old -> 'updated_at');
6475
+ v_n := v_n || jsonb_build_object('updated_at', v_new -> 'updated_at');
6476
+ INSERT INTO public.pick_station_history(entity_table, entity_id, action, changed_by, old_data, new_data)
6477
+ VALUES ('pick_queue', NEW.id, TG_OP, auth.uid(), v_o, v_n);
6478
+ RETURN NEW;
6479
+ END; $function$;
6480
+ GRANT EXECUTE ON FUNCTION public.pick_queue_audit() TO anon, authenticated, service_role;
6481
+
6482
+ CREATE OR REPLACE FUNCTION public.pick_cleanup_history()
6483
+ RETURNS jsonb
6484
+ LANGUAGE plpgsql
6485
+ VOLATILE
6486
+ SECURITY DEFINER
6487
+ SET search_path TO 'public'
6488
+ AS $function$
6489
+ DECLARE
6490
+ v_days integer; v_start timestamptz := clock_timestamp(); v_total integer := 0; n integer; v_bron text := 'standaard';
6491
+ BEGIN
6492
+ IF current_user NOT IN ('postgres','service_role','supabase_admin')
6493
+ AND NOT COALESCE(public.has_role(auth.uid(), 'admin'), false) THEN
6494
+ RAISE EXCEPTION 'Geen toegang tot het opruimen van de pickhistorie.' USING ERRCODE = '42501';
6495
+ END IF;
6496
+ IF to_regprocedure('public.logistics_retention_days(text)') IS NOT NULL THEN
6497
+ BEGIN
6498
+ EXECUTE 'SELECT public.logistics_retention_days($1)' INTO v_days USING 'pick_history_retention_days';
6499
+ v_bron := 'engine';
6500
+ EXCEPTION WHEN OTHERS THEN
6501
+ RAISE WARNING 'pick_cleanup_history: termijn uit Engine niet leesbaar (%), standaard 30 dagen', SQLERRM;
6502
+ v_days := NULL;
6503
+ END;
6504
+ END IF;
6505
+ IF v_days IS NULL OR v_days < 1 THEN v_days := 30; v_bron := 'standaard'; END IF;
6506
+
6507
+ LOOP
6508
+ WITH weg AS (SELECT id FROM public.pick_station_history
6509
+ WHERE created_at < now() - make_interval(days => v_days)
6510
+ ORDER BY created_at LIMIT 10000)
6511
+ DELETE FROM public.pick_station_history h USING weg WHERE h.id = weg.id;
6512
+ GET DIAGNOSTICS n = ROW_COUNT;
6513
+ v_total := v_total + n;
6514
+ EXIT WHEN n = 0 OR clock_timestamp() - v_start > interval '20 seconds';
6515
+ END LOOP;
6516
+ RETURN jsonb_build_object('verwijderd', v_total, 'termijn_dagen', v_days, 'bron', v_bron,
6517
+ 'duur_ms', round(extract(epoch FROM clock_timestamp() - v_start) * 1000));
6518
+ END $function$;
6519
+ REVOKE ALL ON FUNCTION public.pick_cleanup_history() FROM PUBLIC, anon, authenticated;
6520
+ GRANT EXECUTE ON FUNCTION public.pick_cleanup_history() TO service_role;
6521
+
6522
+ COMMENT ON FUNCTION public.pick_reset_print(uuid, text) IS 'Verouderd: niet meer in gebruik (scherm gebruikt variant met _cart_id via p_device_key-wrapper). Verwijderen als handmatige stap.';
6523
+ COMMENT ON FUNCTION public.pick_enqueue_print_job(uuid, uuid, text, boolean) IS 'Verouderd: niet meer door het scherm aangeroepen; nog genest gebruikt door oude kernvarianten. Verwijderen als handmatige stap na controle.';
6524
+ -- 20261110194034_4411e109-0b93-4bc4-833b-fc93487e214c.sql
6525
+ -- Golf 1 aanvulling: binnen payload alleen gewijzigde onderdelen in de historie
6526
+ CREATE OR REPLACE FUNCTION public.pick_queue_audit()
6527
+ RETURNS trigger
6528
+ LANGUAGE plpgsql
6529
+ SECURITY DEFINER
6530
+ SET search_path TO 'public'
6531
+ AS $function$
6532
+ DECLARE
6533
+ v_old jsonb; v_new jsonb; v_o jsonb := '{}'::jsonb; v_n jsonb := '{}'::jsonb; k text; s text;
6534
+ v_po jsonb; v_pn jsonb;
6535
+ BEGIN
6536
+ IF TG_OP = 'INSERT' THEN
6537
+ INSERT INTO public.pick_station_history(entity_table, entity_id, action, changed_by, old_data, new_data)
6538
+ VALUES ('pick_queue', NEW.id, TG_OP, auth.uid(), NULL, jsonb_strip_nulls(to_jsonb(NEW)));
6539
+ RETURN NEW;
6540
+ ELSIF TG_OP = 'DELETE' THEN
6541
+ INSERT INTO public.pick_station_history(entity_table, entity_id, action, changed_by, old_data, new_data)
6542
+ VALUES ('pick_queue', OLD.id, TG_OP, auth.uid(), jsonb_strip_nulls(to_jsonb(OLD)), NULL);
6543
+ RETURN OLD;
6544
+ END IF;
6545
+
6546
+ v_old := to_jsonb(OLD); v_new := to_jsonb(NEW);
6547
+ FOR k IN SELECT jsonb_object_keys(v_new) LOOP
6548
+ IF k <> 'updated_at' AND (v_old -> k) IS DISTINCT FROM (v_new -> k) THEN
6549
+ IF jsonb_typeof(v_old -> k) = 'object' AND jsonb_typeof(v_new -> k) = 'object' THEN
6550
+ v_po := '{}'::jsonb; v_pn := '{}'::jsonb;
6551
+ FOR s IN SELECT jsonb_object_keys(v_old -> k) UNION SELECT jsonb_object_keys(v_new -> k) LOOP
6552
+ IF (v_old -> k -> s) IS DISTINCT FROM (v_new -> k -> s) THEN
6553
+ v_po := v_po || jsonb_build_object(s, COALESCE(v_old -> k -> s, 'null'::jsonb));
6554
+ v_pn := v_pn || jsonb_build_object(s, COALESCE(v_new -> k -> s, 'null'::jsonb));
6555
+ END IF;
6556
+ END LOOP;
6557
+ v_o := v_o || jsonb_build_object(k, v_po);
6558
+ v_n := v_n || jsonb_build_object(k, v_pn);
6559
+ ELSE
6560
+ v_o := v_o || jsonb_build_object(k, v_old -> k);
6561
+ v_n := v_n || jsonb_build_object(k, v_new -> k);
6562
+ END IF;
6563
+ END IF;
6564
+ END LOOP;
6565
+ IF v_n = '{}'::jsonb THEN RETURN NEW; END IF;
6566
+ v_o := v_o || jsonb_build_object('updated_at', v_old -> 'updated_at');
6567
+ v_n := v_n || jsonb_build_object('updated_at', v_new -> 'updated_at');
6568
+ INSERT INTO public.pick_station_history(entity_table, entity_id, action, changed_by, old_data, new_data)
6569
+ VALUES ('pick_queue', NEW.id, TG_OP, auth.uid(), v_o, v_n);
6570
+ RETURN NEW;
6571
+ END; $function$;
6572
+ GRANT EXECUTE ON FUNCTION public.pick_queue_audit() TO anon, authenticated, service_role;
6573
+ -- ==== 20261111093706_3c5ab944-e36a-4e47-9a41-681415615661.sql ====
6574
+ CREATE INDEX IF NOT EXISTS idx_pick_station_history_created_at ON public.pick_station_history USING btree (created_at);
6575
+
6576
+ CREATE OR REPLACE FUNCTION public.pick_cleanup_history()
6577
+ RETURNS jsonb
6578
+ LANGUAGE plpgsql
6579
+ VOLATILE
6580
+ SECURITY DEFINER
6581
+ SET search_path TO 'public'
6582
+ AS $function$
6583
+ DECLARE
6584
+ v_days integer; v_start timestamptz := clock_timestamp(); v_total integer := 0; n integer;
6585
+ v_bron text := 'standaard'; v_max integer := 5000; v_portie integer := 1000; v_rest boolean := false;
6586
+ BEGIN
6587
+ IF current_user NOT IN ('postgres','service_role','supabase_admin')
6588
+ AND NOT COALESCE(public.has_role(auth.uid(), 'admin'), false) THEN
6589
+ RAISE EXCEPTION 'Geen toegang tot het opruimen van de pickhistorie.' USING ERRCODE = '42501';
6590
+ END IF;
6591
+ IF to_regprocedure('public.logistics_retention_days(text)') IS NOT NULL THEN
6592
+ BEGIN
6593
+ EXECUTE 'SELECT public.logistics_retention_days($1)' INTO v_days USING 'pick_history_retention_days';
6594
+ v_bron := 'engine';
6595
+ EXCEPTION WHEN OTHERS THEN
6596
+ RAISE WARNING 'pick_cleanup_history: termijn uit Engine niet leesbaar (%), standaard 30 dagen', SQLERRM;
6597
+ v_days := NULL;
6598
+ END;
6599
+ END IF;
6600
+ IF v_days IS NULL OR v_days < 1 THEN v_days := 30; v_bron := 'standaard'; END IF;
6601
+
6602
+ BEGIN
6603
+ LOOP
6604
+ WITH weg AS (SELECT id FROM public.pick_station_history
6605
+ WHERE created_at < now() - make_interval(days => v_days)
6606
+ ORDER BY created_at LIMIT LEAST(v_portie, v_max - v_total))
6607
+ DELETE FROM public.pick_station_history h USING weg WHERE h.id = weg.id;
6608
+ GET DIAGNOSTICS n = ROW_COUNT;
6609
+ v_total := v_total + n;
6610
+ IF n = 0 THEN EXIT; END IF;
6611
+ IF v_total >= v_max OR clock_timestamp() - v_start > interval '10 seconds' THEN v_rest := true; EXIT; END IF;
6612
+ END LOOP;
6613
+ EXCEPTION WHEN OTHERS THEN
6614
+ RAISE WARNING 'pick_cleanup_history mislukt na % verwijderde regels: % (%)', v_total, SQLERRM, SQLSTATE;
6615
+ RAISE;
6616
+ END;
6617
+ RETURN jsonb_build_object('verwijderd', v_total, 'termijn_dagen', v_days, 'bron', v_bron,
6618
+ 'mogelijk_meer', v_rest,
6619
+ 'duur_ms', round(extract(epoch FROM clock_timestamp() - v_start) * 1000));
6620
+ END $function$;
6621
+ REVOKE ALL ON FUNCTION public.pick_cleanup_history() FROM PUBLIC, anon, authenticated;
6622
+ GRANT EXECUTE ON FUNCTION public.pick_cleanup_history() TO service_role;