@flowselections/logistiek-engine 1.0.226 → 1.0.230
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.
- package/db/schema/logistiek-engine.sql +757 -0
- package/dist-lib/components/BeheerPage.d.ts.map +1 -1
- package/dist-lib/components/BeheerPage.js +2 -0
- package/dist-lib/components/FlowPage.d.ts.map +1 -1
- package/dist-lib/components/FlowPage.js +2 -0
- package/dist-lib/components/LadingdragersPage.d.ts.map +1 -1
- package/dist-lib/components/LadingdragersPage.js +2 -0
- package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
- package/dist-lib/components/LogistiekEnginePage.js +2 -1
- package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -1
- package/dist-lib/components/LogistiekEngineQueuePage.js +2 -0
- package/dist-lib/components/PlanWachtrijPage.d.ts.map +1 -1
- package/dist-lib/components/PlanWachtrijPage.js +2 -0
- package/dist-lib/components/ProefindelingPage.d.ts.map +1 -1
- package/dist-lib/components/ProefindelingPage.js +2 -0
- package/dist-lib/components/RegiePage.d.ts.map +1 -1
- package/dist-lib/components/RegiePage.js +2 -0
- package/dist-lib/components/RuleEnginePage.d.ts.map +1 -1
- package/dist-lib/components/RuleEnginePage.js +2 -0
- package/dist-lib/components/StandaardgegevensCard.d.ts +2 -0
- package/dist-lib/components/StandaardgegevensCard.d.ts.map +1 -0
- package/dist-lib/components/StandaardgegevensCard.js +42 -0
- package/dist-lib/hooks/useEngineZelfherstel.d.ts +22 -0
- package/dist-lib/hooks/useEngineZelfherstel.d.ts.map +1 -0
- package/dist-lib/hooks/useEngineZelfherstel.js +61 -0
- package/dist-lib/index.d.ts +2 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -0
- package/dist-lib/integrations/supabase/types.d.ts +1158 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
- package/dist-lib/lib/handlers/logistics-tick.server.js +11 -1
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/planQueue.server.d.ts +4 -1
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +5 -1
- package/package.json +2 -2
|
@@ -38972,3 +38972,760 @@ RETURNS TABLE(punt text, ok boolean, uitleg text) LANGUAGE sql STABLE SET search
|
|
|
38972
38972
|
$$;
|
|
38973
38973
|
REVOKE ALL ON FUNCTION public.logistics_install_check_223() FROM PUBLIC, anon, authenticated;
|
|
38974
38974
|
GRANT EXECUTE ON FUNCTION public.logistics_install_check_223() TO service_role;
|
|
38975
|
+
|
|
38976
|
+
-- ===== 1.0.227 = Standaardgegevens aanvullen (zelfherstel) =====
|
|
38977
|
+
-- bron: migratie 1.0.227
|
|
38978
|
+
-- 1.0.227: standaardgegevens Engine aanvullen (zelfherstel in nieuwe shells)
|
|
38979
|
+
CREATE OR REPLACE FUNCTION public.logistics_ensure_defaults()
|
|
38980
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$
|
|
38981
|
+
DECLARE
|
|
38982
|
+
v_ladingdragers text[] := '{}';
|
|
38983
|
+
v_ladingdrager_velden text[] := '{}';
|
|
38984
|
+
v_vertalingen text[] := '{}';
|
|
38985
|
+
v_instellingen text[] := '{}';
|
|
38986
|
+
v_tijd text := NULL;
|
|
38987
|
+
v_strategie boolean := false;
|
|
38988
|
+
v_meldingen text[] := '{}';
|
|
38989
|
+
v_gewijzigd boolean;
|
|
38990
|
+
v_res jsonb;
|
|
38991
|
+
v_heeft_orders boolean;
|
|
38992
|
+
BEGIN
|
|
38993
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_ensure_defaults');
|
|
38994
|
+
PERFORM pg_advisory_xact_lock(hashtext('logistics_ensure_defaults'));
|
|
38995
|
+
|
|
38996
|
+
-- 1. Ladingdragers (systeemgegevens, vaste codes; Voorraad koppelt via engine_code).
|
|
38997
|
+
WITH std(code, name, capacity_model, layers, len, wid, max_crates, max_boxes, max_kg, max_cm, mix, sort_order) AS (VALUES
|
|
38998
|
+
('trolley','Stapelwagen','layered',5,135,56,NULL::int,NULL::int,500::numeric,190,true,10),
|
|
38999
|
+
('danish_container','Deense container','layered',5,135,56,NULL,NULL,500,190,true,20),
|
|
39000
|
+
('euro_rolcontainer','Euro-rolcontainer','layered',6,120,80,NULL,NULL,600,200,true,30),
|
|
39001
|
+
('pallet','Pallet','stacked',4,120,80,NULL,40,800,180,true,40),
|
|
39002
|
+
('euro_pallet','Euro-pallet','single',1,60,40,1,1,20,40,false,50),
|
|
39003
|
+
('loose','Geen ladingdrager','none',1,0,0,NULL,NULL,NULL,NULL,false,60)
|
|
39004
|
+
), ins AS (
|
|
39005
|
+
INSERT INTO public.load_carrier_types (code, name, capacity_model, layers_per_carrier, layer_length_cm, layer_width_cm,
|
|
39006
|
+
max_crates_per_layer, max_boxes, max_weight_kg, max_height_cm, allow_mixing, is_active, is_default, sort_order)
|
|
39007
|
+
SELECT s.code, s.name, s.capacity_model, s.layers, s.len, s.wid, s.max_crates, s.max_boxes, s.max_kg, s.max_cm, s.mix, true,
|
|
39008
|
+
(s.code = 'trolley' AND NOT EXISTS (SELECT 1 FROM public.load_carrier_types d WHERE d.is_default)), s.sort_order
|
|
39009
|
+
FROM std s
|
|
39010
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.load_carrier_types l WHERE l.code = s.code)
|
|
39011
|
+
ON CONFLICT (code) DO NOTHING
|
|
39012
|
+
RETURNING code
|
|
39013
|
+
)
|
|
39014
|
+
SELECT coalesce(array_agg(code ORDER BY code), '{}') INTO v_ladingdragers FROM ins;
|
|
39015
|
+
|
|
39016
|
+
-- Bestaande codes: alleen lege velden aanvullen (ingevulde waarden zijn klantwaarden).
|
|
39017
|
+
WITH std(code, name, capacity_model, layers, len, wid, max_crates, max_boxes, max_kg, max_cm) AS (VALUES
|
|
39018
|
+
('trolley','Stapelwagen','layered',5,135,56,NULL::int,NULL::int,500::numeric,190),
|
|
39019
|
+
('danish_container','Deense container','layered',5,135,56,NULL,NULL,500,190),
|
|
39020
|
+
('euro_rolcontainer','Euro-rolcontainer','layered',6,120,80,NULL,NULL,600,200),
|
|
39021
|
+
('pallet','Pallet','stacked',4,120,80,NULL,40,800,180),
|
|
39022
|
+
('euro_pallet','Euro-pallet','single',1,60,40,1,1,20,40),
|
|
39023
|
+
('loose','Geen ladingdrager','none',1,0,0,NULL,NULL,NULL,NULL)
|
|
39024
|
+
), upd AS (
|
|
39025
|
+
UPDATE public.load_carrier_types l SET
|
|
39026
|
+
name = coalesce(nullif(btrim(l.name),''), s.name),
|
|
39027
|
+
capacity_model = coalesce(l.capacity_model, s.capacity_model),
|
|
39028
|
+
layers_per_carrier = coalesce(l.layers_per_carrier, s.layers),
|
|
39029
|
+
layer_length_cm = coalesce(l.layer_length_cm, s.len),
|
|
39030
|
+
layer_width_cm = coalesce(l.layer_width_cm, s.wid),
|
|
39031
|
+
max_crates_per_layer = coalesce(l.max_crates_per_layer, s.max_crates),
|
|
39032
|
+
max_boxes = coalesce(l.max_boxes, s.max_boxes),
|
|
39033
|
+
max_weight_kg = coalesce(l.max_weight_kg, s.max_kg),
|
|
39034
|
+
max_height_cm = coalesce(l.max_height_cm, s.max_cm),
|
|
39035
|
+
updated_at = now()
|
|
39036
|
+
FROM std s
|
|
39037
|
+
WHERE l.code = s.code AND NOT (l.code = ANY(v_ladingdragers))
|
|
39038
|
+
AND ( nullif(btrim(l.name),'') IS NULL
|
|
39039
|
+
OR l.capacity_model IS NULL OR l.layers_per_carrier IS NULL OR l.layer_length_cm IS NULL OR l.layer_width_cm IS NULL
|
|
39040
|
+
OR (l.max_crates_per_layer IS NULL AND s.max_crates IS NOT NULL)
|
|
39041
|
+
OR (l.max_boxes IS NULL AND s.max_boxes IS NOT NULL)
|
|
39042
|
+
OR (l.max_weight_kg IS NULL AND s.max_kg IS NOT NULL)
|
|
39043
|
+
OR (l.max_height_cm IS NULL AND s.max_cm IS NOT NULL))
|
|
39044
|
+
RETURNING l.code
|
|
39045
|
+
)
|
|
39046
|
+
SELECT coalesce(array_agg(code ORDER BY code), '{}') INTO v_ladingdrager_velden FROM upd;
|
|
39047
|
+
-- Vervallen systeemcodes: lijst is leeg. Komt er ooit een code bij die vervalt:
|
|
39048
|
+
-- UPDATE ... SET is_active = false WHERE code = ANY('{...}'); nooit verwijderen.
|
|
39049
|
+
|
|
39050
|
+
-- 2. Vertaling Floriday -> Engine (systeemgegevens): alleen ontbrekende floriday_code toevoegen.
|
|
39051
|
+
IF to_regclass('public.logistics_floriday_carrier_map') IS NOT NULL THEN
|
|
39052
|
+
WITH v(f, c) AS (VALUES
|
|
39053
|
+
('DANISH_TROLLEY','danish_container'), ('DANISH_TROLLEY_NON_CC_RFID','danish_container'),
|
|
39054
|
+
('DANISH_TROLLEY_WATER_TRAY','danish_container'), ('ONE_THIRD_DANISH_TROLLEY','danish_container'),
|
|
39055
|
+
('AUCTION_TROLLEY','trolley'),
|
|
39056
|
+
('EURO_TROLLEY','euro_rolcontainer'), ('WATERING_CONTAINER','euro_rolcontainer'),
|
|
39057
|
+
('EURO_PALLET','euro_pallet'), ('HT_EURO_PALLET','euro_pallet'),
|
|
39058
|
+
('PALLET','pallet'), ('BLOCK_PALLET','pallet'), ('IFCO_PALLET','pallet'),
|
|
39059
|
+
('CHEP_PALLET_BLUE','pallet'), ('CHEP_PALLET_RED','pallet'),
|
|
39060
|
+
('NONE','loose')
|
|
39061
|
+
), ins AS (
|
|
39062
|
+
INSERT INTO public.logistics_floriday_carrier_map (floriday_code, carrier_code)
|
|
39063
|
+
SELECT v.f, v.c FROM v
|
|
39064
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.logistics_floriday_carrier_map m WHERE upper(m.floriday_code) = v.f)
|
|
39065
|
+
ON CONFLICT DO NOTHING
|
|
39066
|
+
RETURNING floriday_code
|
|
39067
|
+
)
|
|
39068
|
+
SELECT coalesce(array_agg(floriday_code ORDER BY floriday_code), '{}') INTO v_vertalingen FROM ins;
|
|
39069
|
+
END IF;
|
|
39070
|
+
|
|
39071
|
+
-- 3. Plan-instellingen: alleen sleutels met één eenduidige terugval in de code, met precies die waarde.
|
|
39072
|
+
WITH v(k, w) AS (VALUES ('batch_size','10'), ('retention_days','7'), ('kick_debounce_seconds','5')),
|
|
39073
|
+
ins AS (
|
|
39074
|
+
INSERT INTO public.logistics_plan_settings (key, value)
|
|
39075
|
+
SELECT v.k, v.w FROM v WHERE NOT EXISTS (SELECT 1 FROM public.logistics_plan_settings p WHERE p.key = v.k)
|
|
39076
|
+
ON CONFLICT (key) DO NOTHING
|
|
39077
|
+
RETURNING key
|
|
39078
|
+
)
|
|
39079
|
+
SELECT coalesce(array_agg(key ORDER BY key), '{}') INTO v_instellingen FROM ins;
|
|
39080
|
+
|
|
39081
|
+
-- 4. Tijdinstellingen (klant): alleen als de rij ontbreekt.
|
|
39082
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_time_settings) THEN
|
|
39083
|
+
v_heeft_orders := EXISTS (SELECT 1 FROM public.orders);
|
|
39084
|
+
IF v_heeft_orders THEN
|
|
39085
|
+
-- Zelfde gedrag als zonder rij: vertrekregel uit, regel 160 valt terug op "nu".
|
|
39086
|
+
INSERT INTO public.logistics_time_settings (id, timezone, departure_rule_since, rule_160_since)
|
|
39087
|
+
VALUES (true, 'Europe/Amsterdam', NULL, NULL) ON CONFLICT DO NOTHING;
|
|
39088
|
+
v_tijd := 'aangemaakt zonder ingangsdata (er zijn al orders)';
|
|
39089
|
+
ELSE
|
|
39090
|
+
INSERT INTO public.logistics_time_settings (id, timezone, departure_rule_since, rule_160_since)
|
|
39091
|
+
VALUES (true, 'Europe/Amsterdam', now(), now()) ON CONFLICT DO NOTHING;
|
|
39092
|
+
v_tijd := 'aangemaakt met ingangsdata nu (lege shell)';
|
|
39093
|
+
END IF;
|
|
39094
|
+
END IF;
|
|
39095
|
+
|
|
39096
|
+
-- 5. Strategie (klant): alleen als er nog geen enkele bestaat.
|
|
39097
|
+
-- 5. Strategie (klant): alleen als er nog geen enkele bestaat. Een strategie hoort bij
|
|
39098
|
+
-- een gebruiker (user_id verplicht); zonder ingelogde gebruiker (serverronde) wachten.
|
|
39099
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_strategies) THEN
|
|
39100
|
+
IF auth.uid() IS NULL THEN
|
|
39101
|
+
v_meldingen := array_append(v_meldingen, 'Basisstrategie wordt aangemaakt bij het openen van de Engine door een gebruiker'::text);
|
|
39102
|
+
ELSE
|
|
39103
|
+
WITH s AS (
|
|
39104
|
+
INSERT INTO public.logistics_strategies (name, is_active, user_id)
|
|
39105
|
+
VALUES ('Basisstrategie', true, auth.uid()) RETURNING id
|
|
39106
|
+
)
|
|
39107
|
+
INSERT INTO public.logistics_rule_configs (name, status, is_active, settings, strategy_id, user_id)
|
|
39108
|
+
SELECT 'Werkwijze Basisstrategie', 'actief',
|
|
39109
|
+
NOT EXISTS (SELECT 1 FROM public.logistics_rule_configs r WHERE r.is_active),
|
|
39110
|
+
'{}'::jsonb, s.id, auth.uid() FROM s;
|
|
39111
|
+
v_strategie := true;
|
|
39112
|
+
END IF;
|
|
39113
|
+
END IF;
|
|
39114
|
+
IF NOT EXISTS (SELECT 1 FROM public.logistics_strategies WHERE is_active) THEN
|
|
39115
|
+
v_meldingen := array_append(v_meldingen, 'Geen actieve strategie'::text);
|
|
39116
|
+
END IF;
|
|
39117
|
+
|
|
39118
|
+
-- 6. Tabellen van andere modules: alleen melden.
|
|
39119
|
+
IF to_regclass('public.pick_station_types') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.pick_station_types) THEN
|
|
39120
|
+
v_meldingen := array_append(v_meldingen, 'Pickstation-soorten leeg (Pickmodule)'::text);
|
|
39121
|
+
END IF;
|
|
39122
|
+
IF to_regclass('public.pick_screen_document_types') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.pick_screen_document_types) THEN
|
|
39123
|
+
v_meldingen := array_append(v_meldingen, 'Pickscherm-documentsoorten leeg (Pickmodule)'::text);
|
|
39124
|
+
END IF;
|
|
39125
|
+
IF to_regclass('public.cart_planning_settings') IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.cart_planning_settings) THEN
|
|
39126
|
+
v_meldingen := array_append(v_meldingen, 'Karplanning-instellingen leeg (Verkoop)'::text);
|
|
39127
|
+
END IF;
|
|
39128
|
+
|
|
39129
|
+
v_gewijzigd := cardinality(v_ladingdragers) + cardinality(v_ladingdrager_velden) + cardinality(v_vertalingen)
|
|
39130
|
+
+ cardinality(v_instellingen) > 0 OR v_tijd IS NOT NULL OR v_strategie;
|
|
39131
|
+
v_res := jsonb_build_object(
|
|
39132
|
+
'gewijzigd', v_gewijzigd, 'op', now(),
|
|
39133
|
+
'ladingdragers', to_jsonb(v_ladingdragers),
|
|
39134
|
+
'ladingdrager_velden', to_jsonb(v_ladingdrager_velden),
|
|
39135
|
+
'floriday_vertalingen', to_jsonb(v_vertalingen),
|
|
39136
|
+
'plan_instellingen', to_jsonb(v_instellingen),
|
|
39137
|
+
'tijdinstellingen', v_tijd,
|
|
39138
|
+
'basisstrategie', v_strategie,
|
|
39139
|
+
'meldingen', to_jsonb(v_meldingen));
|
|
39140
|
+
|
|
39141
|
+
-- Alleen wegschrijven als er iets is aangevuld (geen schrijfactie per ronde).
|
|
39142
|
+
IF v_gewijzigd THEN
|
|
39143
|
+
INSERT INTO public.logistics_plan_settings (key, value) VALUES ('defaults_last_result', v_res::text)
|
|
39144
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now();
|
|
39145
|
+
END IF;
|
|
39146
|
+
RETURN v_res;
|
|
39147
|
+
END $$;
|
|
39148
|
+
REVOKE ALL ON FUNCTION public.logistics_ensure_defaults() FROM PUBLIC, anon;
|
|
39149
|
+
GRANT EXECUTE ON FUNCTION public.logistics_ensure_defaults() TO authenticated, service_role;
|
|
39150
|
+
|
|
39151
|
+
CREATE OR REPLACE FUNCTION public.logistics_defaults_status()
|
|
39152
|
+
RETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public AS $$
|
|
39153
|
+
SELECT public.logistics_acc_guard('ingelogd', 'logistics_defaults_status');
|
|
39154
|
+
SELECT coalesce((SELECT value::jsonb FROM public.logistics_plan_settings WHERE key = 'defaults_last_result'), 'null'::jsonb);
|
|
39155
|
+
$$;
|
|
39156
|
+
REVOKE ALL ON FUNCTION public.logistics_defaults_status() FROM PUBLIC, anon;
|
|
39157
|
+
GRANT EXECUTE ON FUNCTION public.logistics_defaults_status() TO authenticated, service_role;
|
|
39158
|
+
|
|
39159
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_227()
|
|
39160
|
+
RETURNS TABLE(punt text, ok boolean, uitleg text) LANGUAGE sql STABLE SET search_path TO 'public' AS $$
|
|
39161
|
+
SELECT 'standaardgegevens-functie', to_regprocedure('public.logistics_ensure_defaults()') IS NOT NULL,
|
|
39162
|
+
'logistics_ensure_defaults is aanwezig'
|
|
39163
|
+
UNION ALL
|
|
39164
|
+
SELECT 'rechten standaardgegevens',
|
|
39165
|
+
NOT has_function_privilege('anon', 'public.logistics_ensure_defaults()', 'EXECUTE')
|
|
39166
|
+
AND has_function_privilege('authenticated', 'public.logistics_ensure_defaults()', 'EXECUTE'),
|
|
39167
|
+
'Alleen ingelogde gebruikers en server mogen aanvullen'
|
|
39168
|
+
UNION ALL
|
|
39169
|
+
SELECT 'ladingdragers', (SELECT count(*) FROM public.load_carrier_types WHERE code IN
|
|
39170
|
+
('trolley','danish_container','euro_rolcontainer','pallet','euro_pallet','loose')) = 6,
|
|
39171
|
+
'De zes vaste ladingdragercodes zijn aanwezig'
|
|
39172
|
+
UNION ALL
|
|
39173
|
+
SELECT 'Floriday-vertaling', (SELECT count(*) FROM public.logistics_floriday_carrier_map) >= 15,
|
|
39174
|
+
'Vertaling Floriday naar Engine-ladingdrager is gevuld'
|
|
39175
|
+
UNION ALL
|
|
39176
|
+
SELECT 'tijdinstelling', EXISTS (SELECT 1 FROM public.logistics_time_settings), 'Tijdinstelling aanwezig'
|
|
39177
|
+
$$;
|
|
39178
|
+
REVOKE ALL ON FUNCTION public.logistics_install_check_227() FROM PUBLIC, anon, authenticated;
|
|
39179
|
+
GRANT EXECUTE ON FUNCTION public.logistics_install_check_227() TO service_role;
|
|
39180
|
+
|
|
39181
|
+
|
|
39182
|
+
-- ===== 1.0.228: NONE → loose, lus planwachtrij, opruimen, bewaartermijnen, onderhoudsstatus =====
|
|
39183
|
+
-- 1.0.228: NONE eenduidig naar loose; lus in de planwachtrij stoppen.
|
|
39184
|
+
|
|
39185
|
+
-- A1. Vertaling: alleen leeg = ontbreekt; NONE gaat via de vertaaltabel (bron floriday).
|
|
39186
|
+
CREATE OR REPLACE FUNCTION public.logistics_ladingdrager_resolve(p_code text)
|
|
39187
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
39188
|
+
DECLARE v text := nullif(btrim(p_code), ''); n int; m text;
|
|
39189
|
+
BEGIN
|
|
39190
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_ladingdrager_resolve');
|
|
39191
|
+
IF v IS NULL THEN
|
|
39192
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', v, 'bron', NULL, 'fout', 'ladingdrager ontbreekt');
|
|
39193
|
+
END IF;
|
|
39194
|
+
IF EXISTS (SELECT 1 FROM public.load_carrier_types t WHERE t.is_active AND t.code = v) THEN
|
|
39195
|
+
RETURN jsonb_build_object('code', v, 'invoer', v, 'bron', 'beheer', 'fout', NULL);
|
|
39196
|
+
END IF;
|
|
39197
|
+
IF to_regclass('public.logistics_floriday_carrier_map') IS NULL THEN
|
|
39198
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', v, 'bron', NULL, 'fout', format('ladingdrager %s onbekend in Beheer', v));
|
|
39199
|
+
END IF;
|
|
39200
|
+
SELECT count(DISTINCT c.carrier_code), min(c.carrier_code) INTO n, m
|
|
39201
|
+
FROM public.logistics_floriday_carrier_map c WHERE upper(c.floriday_code) = upper(v);
|
|
39202
|
+
IF coalesce(n, 0) = 0 THEN
|
|
39203
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', v, 'bron', NULL, 'fout', format('ladingdrager %s onbekend in Beheer', v));
|
|
39204
|
+
ELSIF n > 1 THEN
|
|
39205
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', v, 'bron', 'floriday', 'fout', format('ladingdrager niet eenduidig (%s)', v));
|
|
39206
|
+
ELSIF NOT EXISTS (SELECT 1 FROM public.load_carrier_types t WHERE t.is_active AND t.code = m) THEN
|
|
39207
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', v, 'bron', 'floriday', 'fout', format('ladingdrager %s onbekend in Beheer', v));
|
|
39208
|
+
END IF;
|
|
39209
|
+
RETURN jsonb_build_object('code', m, 'invoer', v, 'bron', 'floriday', 'fout', NULL);
|
|
39210
|
+
END $$;
|
|
39211
|
+
REVOKE ALL ON FUNCTION public.logistics_ladingdrager_resolve(text) FROM PUBLIC, anon;
|
|
39212
|
+
GRANT EXECUTE ON FUNCTION public.logistics_ladingdrager_resolve(text) TO authenticated, service_role;
|
|
39213
|
+
|
|
39214
|
+
-- A2. Planner-variant met het oude gedrag (regel 1.0.213: geen ladingdrager = niet op een kar).
|
|
39215
|
+
CREATE OR REPLACE FUNCTION public.logistics_ladingdrager_resolve_plan(p_code text)
|
|
39216
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
39217
|
+
DECLARE rc jsonb;
|
|
39218
|
+
BEGIN
|
|
39219
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_ladingdrager_resolve_plan');
|
|
39220
|
+
IF upper(nullif(btrim(p_code), '')) = 'NONE' THEN
|
|
39221
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', nullif(btrim(p_code), ''), 'bron', NULL, 'fout', 'ladingdrager ontbreekt');
|
|
39222
|
+
END IF;
|
|
39223
|
+
rc := public.logistics_ladingdrager_resolve(p_code);
|
|
39224
|
+
IF rc->>'code' = 'loose' AND rc->>'bron' = 'floriday' THEN
|
|
39225
|
+
RETURN jsonb_build_object('code', NULL, 'invoer', rc->>'invoer', 'bron', 'floriday', 'fout', 'ladingdrager ontbreekt');
|
|
39226
|
+
END IF;
|
|
39227
|
+
RETURN rc;
|
|
39228
|
+
END $$;
|
|
39229
|
+
REVOKE ALL ON FUNCTION public.logistics_ladingdrager_resolve_plan(text) FROM PUBLIC, anon;
|
|
39230
|
+
GRANT EXECUTE ON FUNCTION public.logistics_ladingdrager_resolve_plan(text) TO authenticated, service_role;
|
|
39231
|
+
|
|
39232
|
+
-- B1. Vingerafdruk van wat de planning van een order gebruikt (zonder eigen Engine-velden).
|
|
39233
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_inhoud_fp(p_order_id uuid)
|
|
39234
|
+
RETURNS text LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$
|
|
39235
|
+
SELECT md5(concat_ws('|',
|
|
39236
|
+
o.status, o.delivery_date, o.customer_id, o.deleted_at, o.is_reservation, to_jsonb(o)->>'carrier_id',
|
|
39237
|
+
o.custom_fields->>'delivery_location', o.custom_fields->>'delivery_location_id', o.custom_fields->>'delivery_location_gln',
|
|
39238
|
+
o.custom_fields->>'pickup_moment', o.custom_fields->>'pickup_datetime', o.custom_fields->>'manual_pick_day',
|
|
39239
|
+
o.custom_fields->>'own_transport', o.custom_fields->>'carrier',
|
|
39240
|
+
(SELECT string_agg(concat_ws(':', oi.id, oi.product_id, oi.quantity, oi.crates_per_layer, oi.layers_per_cart,
|
|
39241
|
+
oi.plants_per_crate, oi.quarantined_at), ',' ORDER BY oi.id)
|
|
39242
|
+
FROM logistics_active.order_items oi WHERE oi.order_id = o.id),
|
|
39243
|
+
(SELECT max(p.updated_at) FROM logistics_active.order_items oi JOIN public.products p ON p.id = oi.product_id
|
|
39244
|
+
WHERE oi.order_id = o.id)))
|
|
39245
|
+
FROM public.orders o WHERE o.id = p_order_id
|
|
39246
|
+
$$;
|
|
39247
|
+
REVOKE ALL ON FUNCTION public.logistics_plan_inhoud_fp(uuid) FROM PUBLIC, anon, authenticated;
|
|
39248
|
+
GRANT EXECUTE ON FUNCTION public.logistics_plan_inhoud_fp(uuid) TO service_role;
|
|
39249
|
+
|
|
39250
|
+
ALTER TABLE public.logistics_plan_queue ADD COLUMN IF NOT EXISTS order_fp text;
|
|
39251
|
+
CREATE INDEX IF NOT EXISTS logistics_plan_queue_order_upd_idx ON public.logistics_plan_queue (order_id, updated_at DESC);
|
|
39252
|
+
|
|
39253
|
+
-- B2. Reconcile: gearchiveerd = afgehandeld zolang de inhoud van de order niet is gewijzigd.
|
|
39254
|
+
CREATE OR REPLACE FUNCTION public.logistics_reconcile_missing_plan_queue()
|
|
39255
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $function$
|
|
39256
|
+
DECLARE r record; n integer := 0;
|
|
39257
|
+
BEGIN
|
|
39258
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_reconcile_missing_plan_queue');
|
|
39259
|
+
FOR r IN
|
|
39260
|
+
SELECT o.id FROM public.orders o
|
|
39261
|
+
WHERE o.deleted_at IS NULL
|
|
39262
|
+
AND COALESCE(o.is_reservation,false) = false
|
|
39263
|
+
AND o.plan_locked_at IS NULL
|
|
39264
|
+
AND o.order_number IS NOT NULL
|
|
39265
|
+
AND (o.created_at >= now() - interval '14 days' OR o.updated_at >= now() - interval '14 days')
|
|
39266
|
+
AND NOT EXISTS (SELECT 1 FROM public.logistics_tasks t WHERE t.order_ref = o.order_number)
|
|
39267
|
+
AND NOT EXISTS (SELECT 1 FROM public.logistics_plan_queue q
|
|
39268
|
+
WHERE q.order_id = o.id AND q.status IN ('pending','running'))
|
|
39269
|
+
AND NOT EXISTS (
|
|
39270
|
+
SELECT 1 FROM public.logistics_plan_queue q
|
|
39271
|
+
WHERE q.order_id = o.id AND q.status IN ('geblokkeerd', 'done', 'opgelost')
|
|
39272
|
+
AND q.updated_at >= COALESCE(o.updated_at, o.created_at)
|
|
39273
|
+
AND NOT EXISTS (SELECT 1 FROM logistics_active.order_items oi WHERE oi.order_id = o.id AND oi.created_at > q.updated_at)
|
|
39274
|
+
AND NOT EXISTS (SELECT 1 FROM logistics_active.order_items oi JOIN public.products p ON p.id = oi.product_id
|
|
39275
|
+
WHERE oi.order_id = o.id AND p.updated_at > q.updated_at))
|
|
39276
|
+
-- 1.0.228: gearchiveerd telt als afgehandeld; alleen een inhoudelijke wijziging biedt opnieuw aan.
|
|
39277
|
+
-- Oude rijen zonder vingerafdruk tellen ook als afgehandeld ("Opnieuw aanbieden" blijft mogelijk).
|
|
39278
|
+
AND NOT EXISTS (
|
|
39279
|
+
SELECT 1 FROM public.logistics_plan_queue q
|
|
39280
|
+
WHERE q.order_id = o.id AND q.status = 'gearchiveerd'
|
|
39281
|
+
AND (q.order_fp IS NULL OR q.order_fp = public.logistics_plan_inhoud_fp(o.id)))
|
|
39282
|
+
ORDER BY o.created_at ASC
|
|
39283
|
+
LIMIT 100
|
|
39284
|
+
LOOP
|
|
39285
|
+
PERFORM public.logistics_plan_enqueue(r.id, 'reconcile');
|
|
39286
|
+
n := n + 1;
|
|
39287
|
+
END LOOP;
|
|
39288
|
+
RETURN n;
|
|
39289
|
+
END;
|
|
39290
|
+
$function$;
|
|
39291
|
+
|
|
39292
|
+
-- B3. Housekeeping: vingerafdruk bewaren; per order hooguit één archiveringsmelding.
|
|
39293
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_housekeeping()
|
|
39294
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $function$
|
|
39295
|
+
DECLARE v_resolved int := 0; v_archived int := 0; v_nieuw int := 0; v_alerts int := 0; v_gone int := 0; v_refs text;
|
|
39296
|
+
BEGIN
|
|
39297
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_plan_housekeeping');
|
|
39298
|
+
UPDATE public.logistics_plan_queue q SET status='opgelost', error='opgelost: order is al verzonden',
|
|
39299
|
+
claimed_at=NULL, updated_at=now()
|
|
39300
|
+
FROM public.orders o
|
|
39301
|
+
WHERE o.id = q.order_id AND q.status IN ('geblokkeerd','failed')
|
|
39302
|
+
AND o.status IN ('Verzonden','Gereed voor facturatie');
|
|
39303
|
+
GET DIAGNOSTICS v_resolved = ROW_COUNT;
|
|
39304
|
+
UPDATE public.logistics_plan_queue q SET status='opgelost', error='order bestaat niet meer', claimed_at=NULL, updated_at=now()
|
|
39305
|
+
WHERE q.status IN ('geblokkeerd','failed')
|
|
39306
|
+
AND NOT EXISTS (SELECT 1 FROM public.orders o WHERE o.id = q.order_id AND o.deleted_at IS NULL);
|
|
39307
|
+
|
|
39308
|
+
WITH kand AS (
|
|
39309
|
+
SELECT q.id, q.order_id, o.order_number, public.logistics_plan_inhoud_fp(o.id) AS fp
|
|
39310
|
+
FROM public.logistics_plan_queue q JOIN public.orders o ON o.id = q.order_id
|
|
39311
|
+
WHERE q.status IN ('geblokkeerd','failed')
|
|
39312
|
+
AND o.deleted_at IS NULL
|
|
39313
|
+
AND COALESCE(o.status,'') NOT IN ('Verzonden','Gereed voor facturatie','geannuleerd')
|
|
39314
|
+
AND o.delivery_date IS NOT NULL AND o.delivery_date::date < current_date - 2
|
|
39315
|
+
), a AS (
|
|
39316
|
+
UPDATE public.logistics_plan_queue q SET status='gearchiveerd', error=COALESCE(q.error, q.reason),
|
|
39317
|
+
order_fp = k.fp, claimed_at=NULL, updated_at=now()
|
|
39318
|
+
FROM kand k WHERE q.id = k.id
|
|
39319
|
+
RETURNING q.id, k.order_id, k.order_number, k.fp
|
|
39320
|
+
), nieuw AS (
|
|
39321
|
+
SELECT DISTINCT a.order_number FROM a
|
|
39322
|
+
WHERE NOT EXISTS (SELECT 1 FROM public.logistics_plan_queue e
|
|
39323
|
+
WHERE e.order_id = a.order_id AND e.status = 'gearchiveerd' AND e.id <> a.id
|
|
39324
|
+
AND (e.order_fp IS NULL OR e.order_fp = a.fp))
|
|
39325
|
+
)
|
|
39326
|
+
SELECT (SELECT count(*) FROM a), (SELECT count(*) FROM nieuw), (SELECT string_agg(order_number, ', ' ORDER BY order_number) FROM nieuw)
|
|
39327
|
+
INTO v_archived, v_nieuw, v_refs;
|
|
39328
|
+
|
|
39329
|
+
IF v_nieuw > 0 THEN
|
|
39330
|
+
INSERT INTO public.notifications(user_id, title, message, read)
|
|
39331
|
+
SELECT DISTINCT ur.user_id, 'Niet geleverd en gearchiveerd',
|
|
39332
|
+
v_nieuw || ' geblokkeerde order(s) gearchiveerd (leverdatum voorbij): ' || v_refs ||
|
|
39333
|
+
'. Zie Engine › Wachtrij; "Opnieuw aanbieden" zet ze terug.', false
|
|
39334
|
+
FROM public.user_roles ur WHERE ur.role IN ('planner','admin');
|
|
39335
|
+
END IF;
|
|
39336
|
+
|
|
39337
|
+
UPDATE public.logistics_stock_alerts a SET status='resolved', resolved_at=now(),
|
|
39338
|
+
resolution_reason='automatisch opgelost: order verzonden/afgerond', updated_at=now()
|
|
39339
|
+
FROM public.orders o
|
|
39340
|
+
WHERE o.id = a.order_id AND a.status='open'
|
|
39341
|
+
AND o.status IN ('Verzonden','Gereed voor facturatie','geannuleerd');
|
|
39342
|
+
GET DIAGNOSTICS v_alerts = ROW_COUNT;
|
|
39343
|
+
|
|
39344
|
+
UPDATE public.logistics_stock_alerts a SET status='resolved', resolved_at=now(),
|
|
39345
|
+
resolution_reason='order bestaat niet meer', updated_at=now()
|
|
39346
|
+
WHERE a.status='open' AND a.order_id IS NOT NULL
|
|
39347
|
+
AND NOT EXISTS (SELECT 1 FROM public.orders o WHERE o.id = a.order_id AND o.deleted_at IS NULL);
|
|
39348
|
+
GET DIAGNOSTICS v_gone = ROW_COUNT;
|
|
39349
|
+
|
|
39350
|
+
RETURN jsonb_build_object('blokkadesOpgelost', v_resolved, 'gearchiveerd', v_archived, 'gemeld', v_nieuw,
|
|
39351
|
+
'meldingenOpgelost', v_alerts, 'meldingenZonderOrder', v_gone);
|
|
39352
|
+
END $function$;
|
|
39353
|
+
|
|
39354
|
+
-- B4. Prune: ook gearchiveerd/opgelost; nieuwste rij per order blijft; porties met tijdslimiet.
|
|
39355
|
+
CREATE OR REPLACE FUNCTION public.logistics_plan_prune()
|
|
39356
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $function$
|
|
39357
|
+
DECLARE v_n int := 0; r int; v_days int := LEAST(GREATEST(public.logistics_plan_setting('retention_days', 7)::int, 1), 365);
|
|
39358
|
+
v_eind timestamptz := clock_timestamp() + interval '5 seconds'; v_rondes int := 0;
|
|
39359
|
+
BEGIN
|
|
39360
|
+
PERFORM public.logistics_acc_guard('server', 'logistics_plan_prune');
|
|
39361
|
+
LOOP
|
|
39362
|
+
WITH rang AS (
|
|
39363
|
+
SELECT q.id, q.status, q.updated_at,
|
|
39364
|
+
row_number() OVER (PARTITION BY q.order_id ORDER BY q.updated_at DESC, q.id DESC) AS rn
|
|
39365
|
+
FROM public.logistics_plan_queue q
|
|
39366
|
+
), weg AS (
|
|
39367
|
+
SELECT id FROM rang
|
|
39368
|
+
WHERE rn > 1 AND status IN ('done','failed','gearchiveerd','opgelost')
|
|
39369
|
+
AND updated_at < now() - make_interval(days => v_days)
|
|
39370
|
+
LIMIT 5000)
|
|
39371
|
+
DELETE FROM public.logistics_plan_queue d USING weg WHERE d.id = weg.id;
|
|
39372
|
+
GET DIAGNOSTICS r = ROW_COUNT;
|
|
39373
|
+
v_n := v_n + r; v_rondes := v_rondes + 1;
|
|
39374
|
+
EXIT WHEN r < 5000 OR clock_timestamp() >= v_eind;
|
|
39375
|
+
END LOOP;
|
|
39376
|
+
PERFORM public.logistics_planner_diff_prune();
|
|
39377
|
+
IF v_n > 0 THEN
|
|
39378
|
+
INSERT INTO public.logistics_plan_settings (key, value)
|
|
39379
|
+
VALUES ('prune_last_result', jsonb_build_object('op', now(), 'verwijderd', v_n, 'porties', v_rondes)::text)
|
|
39380
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now();
|
|
39381
|
+
END IF;
|
|
39382
|
+
RETURN v_n;
|
|
39383
|
+
END;
|
|
39384
|
+
$function$;
|
|
39385
|
+
|
|
39386
|
+
-- B5. Bewaartermijnen: werkwijze die de planner gebruikt, anders veilige standaard; maximaal 365 dagen.
|
|
39387
|
+
CREATE OR REPLACE FUNCTION public.logistics_retention_days(p_key text)
|
|
39388
|
+
RETURNS integer LANGUAGE sql STABLE SET search_path TO 'public' AS $function$
|
|
39389
|
+
SELECT LEAST(365, GREATEST(1, COALESCE(
|
|
39390
|
+
(SELECT NULLIF(COALESCE(rc.settings->'opruimen'->'fields'->>p_key, rc.settings->'opruimen'->>p_key), '')::integer
|
|
39391
|
+
FROM public.logistics_rule_configs rc
|
|
39392
|
+
LEFT JOIN public.logistics_strategies s ON s.id = rc.strategy_id
|
|
39393
|
+
WHERE NULLIF(COALESCE(rc.settings->'opruimen'->'fields'->>p_key, rc.settings->'opruimen'->>p_key), '') IS NOT NULL
|
|
39394
|
+
ORDER BY (rc.is_active AND coalesce(s.is_active, false)) DESC, rc.is_active DESC, rc.updated_at DESC NULLS LAST
|
|
39395
|
+
LIMIT 1),
|
|
39396
|
+
CASE p_key WHEN 'task_retention_days' THEN 90 ELSE 30 END)))
|
|
39397
|
+
$function$;
|
|
39398
|
+
|
|
39399
|
+
-- B6. Status onderhoud voor de Engine-pagina.
|
|
39400
|
+
CREATE OR REPLACE FUNCTION public.logistics_onderhoud_status()
|
|
39401
|
+
RETURNS jsonb LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public AS $$
|
|
39402
|
+
DECLARE v_status jsonb; v_trace timestamptz; v_prune jsonb;
|
|
39403
|
+
BEGIN
|
|
39404
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_onderhoud_status');
|
|
39405
|
+
SELECT coalesce(jsonb_object_agg(status, n), '{}'::jsonb) INTO v_status
|
|
39406
|
+
FROM (SELECT status, count(*) n FROM public.logistics_plan_queue GROUP BY status) x;
|
|
39407
|
+
IF to_regclass('public.logistics_trace_events') IS NOT NULL THEN
|
|
39408
|
+
EXECUTE 'SELECT min(created_at) FROM public.logistics_trace_events' INTO v_trace;
|
|
39409
|
+
END IF;
|
|
39410
|
+
SELECT value::jsonb INTO v_prune FROM public.logistics_plan_settings WHERE key = 'prune_last_result';
|
|
39411
|
+
RETURN jsonb_build_object('wachtrij', v_status, 'oudsteTrace', v_trace, 'laatsteOpruimronde', v_prune,
|
|
39412
|
+
'bewaartermijnen', jsonb_build_object('trace', public.logistics_retention_days('trace_retention_days'),
|
|
39413
|
+
'pickhistorie', public.logistics_retention_days('pick_history_retention_days'),
|
|
39414
|
+
'barcodes', public.logistics_retention_days('barcode_retention_days'),
|
|
39415
|
+
'taken', public.logistics_retention_days('task_retention_days')));
|
|
39416
|
+
END $$;
|
|
39417
|
+
REVOKE ALL ON FUNCTION public.logistics_onderhoud_status() FROM PUBLIC, anon;
|
|
39418
|
+
GRANT EXECUTE ON FUNCTION public.logistics_onderhoud_status() TO authenticated, service_role;
|
|
39419
|
+
|
|
39420
|
+
CREATE OR REPLACE FUNCTION public.logistics_install_check_228()
|
|
39421
|
+
RETURNS TABLE(punt text, ok boolean, uitleg text) LANGUAGE sql STABLE SET search_path TO 'public' AS $$
|
|
39422
|
+
SELECT 'NONE wordt loose', position('''NONE''' IN pg_get_functiondef('public.logistics_ladingdrager_resolve(text)'::regprocedure)) = 0,
|
|
39423
|
+
'resolve vertaalt NONE via de vertaaltabel'
|
|
39424
|
+
UNION ALL SELECT 'planner-variant', to_regprocedure('public.logistics_ladingdrager_resolve_plan(text)') IS NOT NULL, 'Planner houdt regel 1.0.213'
|
|
39425
|
+
UNION ALL SELECT 'reconcile gearchiveerd', position('gearchiveerd' IN pg_get_functiondef('public.logistics_reconcile_missing_plan_queue()'::regprocedure)) > 0,
|
|
39426
|
+
'Gearchiveerde orders worden niet steeds opnieuw aangeboden'
|
|
39427
|
+
UNION ALL SELECT 'index wachtrij', EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'logistics_plan_queue_order_upd_idx'), 'Opruimen per order via index'
|
|
39428
|
+
$$;
|
|
39429
|
+
REVOKE ALL ON FUNCTION public.logistics_install_check_228() FROM PUBLIC, anon, authenticated;
|
|
39430
|
+
GRANT EXECUTE ON FUNCTION public.logistics_install_check_228() TO service_role;
|
|
39431
|
+
|
|
39432
|
+
-- 1.0.228: aanroepers van de ladingdragervertaling
|
|
39433
|
+
CREATE OR REPLACE FUNCTION public.logistics_ladingdrager_kies(p_regels jsonb)
|
|
39434
|
+
RETURNS jsonb
|
|
39435
|
+
LANGUAGE plpgsql
|
|
39436
|
+
STABLE SECURITY DEFINER
|
|
39437
|
+
SET search_path TO 'public'
|
|
39438
|
+
AS $function$
|
|
39439
|
+
DECLARE e jsonb; uit jsonb := '{}'; rc jsonb; hv jsonb; v_pid uuid; v_key text; v_def text; v_ti text; v_lc text;
|
|
39440
|
+
v_cache boolean := to_regclass('public.floriday_trade_items_cache') IS NOT NULL;
|
|
39441
|
+
BEGIN
|
|
39442
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_ladingdrager_kies');
|
|
39443
|
+
IF p_regels IS NULL OR jsonb_typeof(p_regels) <> 'array' THEN RETURN '{}'; END IF;
|
|
39444
|
+
IF jsonb_array_length(p_regels) > 2000 THEN
|
|
39445
|
+
RAISE EXCEPTION 'Maximaal 2000 regels per aanroep.' USING ERRCODE = '22023';
|
|
39446
|
+
END IF;
|
|
39447
|
+
SELECT nullif(btrim(coalesce(s.settings->'karrenindeling'->'fields'->>'default_carrier_type', s.settings->'karrenindeling'->>'default_carrier_type')), '')
|
|
39448
|
+
INTO v_def FROM public.logistics_rule_configs s WHERE s.is_active ORDER BY s.updated_at DESC LIMIT 1;
|
|
39449
|
+
IF v_def IS NULL OR NOT EXISTS (SELECT 1 FROM public.load_carrier_types t WHERE t.is_active AND t.code = v_def) THEN
|
|
39450
|
+
SELECT t.code INTO v_def FROM public.load_carrier_types t WHERE t.is_active AND t.is_default ORDER BY t.sort_order LIMIT 1;
|
|
39451
|
+
END IF;
|
|
39452
|
+
FOR e IN SELECT x FROM jsonb_array_elements(p_regels) x LOOP
|
|
39453
|
+
v_key := e->>'key';
|
|
39454
|
+
CONTINUE WHEN v_key IS NULL;
|
|
39455
|
+
v_pid := CASE WHEN nullif(btrim(e->>'product_id'), '') ~* '^[0-9a-f-]{36}$' THEN (e->>'product_id')::uuid END;
|
|
39456
|
+
-- 1. orderregel
|
|
39457
|
+
rc := public.logistics_ladingdrager_resolve_plan(e->>'regel_code');
|
|
39458
|
+
IF rc->>'code' IS NOT NULL THEN
|
|
39459
|
+
uit := uit || jsonb_build_object(v_key, jsonb_build_object('code', rc->>'code', 'bron', 'orderregel', 'invoer', rc->>'invoer'));
|
|
39460
|
+
CONTINUE;
|
|
39461
|
+
END IF;
|
|
39462
|
+
-- 2/3. product, dan voorraadartikel
|
|
39463
|
+
IF v_pid IS NOT NULL THEN
|
|
39464
|
+
hv := public.logistics_product_hoofdverpakking(v_pid);
|
|
39465
|
+
IF nullif(hv->>'ladingdrager', '') IS NOT NULL THEN
|
|
39466
|
+
rc := public.logistics_ladingdrager_resolve_plan(hv->>'ladingdrager');
|
|
39467
|
+
IF rc->>'code' IS NOT NULL THEN
|
|
39468
|
+
uit := uit || jsonb_build_object(v_key, jsonb_build_object('code', rc->>'code', 'bron', hv->>'bron', 'invoer', rc->>'invoer',
|
|
39469
|
+
'voorraadartikelId', hv->'voorraadartikelId'));
|
|
39470
|
+
CONTINUE;
|
|
39471
|
+
ELSIF upper(hv->>'ladingdrager') = 'NONE' OR rc->>'fout' = 'ladingdrager ontbreekt' THEN
|
|
39472
|
+
uit := uit || jsonb_build_object(v_key, jsonb_build_object('code', NULL, 'bron', hv->>'bron', 'fout', 'ladingdrager ontbreekt (geen ladingdrager)'));
|
|
39473
|
+
CONTINUE;
|
|
39474
|
+
END IF;
|
|
39475
|
+
ELSIF hv->>'fout' IS NOT NULL THEN
|
|
39476
|
+
uit := uit || jsonb_build_object(v_key, jsonb_build_object('code', NULL, 'bron', hv->>'bron', 'fout', hv->>'fout'));
|
|
39477
|
+
CONTINUE;
|
|
39478
|
+
END IF;
|
|
39479
|
+
-- 3b. Floriday-verpakking van het artikel (bestaand gedrag sinds 1.0.190).
|
|
39480
|
+
IF v_cache THEN
|
|
39481
|
+
v_lc := NULL;
|
|
39482
|
+
SELECT p.floriday_trade_item_id INTO v_ti FROM public.products p WHERE p.id = v_pid;
|
|
39483
|
+
IF v_ti IS NOT NULL THEN
|
|
39484
|
+
EXECUTE $q$SELECT c->>'loadCarrier' FROM public.floriday_trade_items_cache t,
|
|
39485
|
+
jsonb_array_elements(coalesce(t.data->'packingConfigurations', '[]')) c
|
|
39486
|
+
WHERE t.floriday_id = $1 AND NOT coalesce(t.is_deleted, false) AND nullif(c->>'loadCarrier', '') IS NOT NULL
|
|
39487
|
+
ORDER BY coalesce((c->>'primary')::boolean, false) DESC LIMIT 1$q$ INTO v_lc USING v_ti;
|
|
39488
|
+
rc := public.logistics_ladingdrager_resolve_plan(v_lc);
|
|
39489
|
+
IF rc->>'code' IS NOT NULL THEN
|
|
39490
|
+
uit := uit || jsonb_build_object(v_key, jsonb_build_object('code', rc->>'code', 'bron', 'floriday_verpakking', 'invoer', rc->>'invoer'));
|
|
39491
|
+
CONTINUE;
|
|
39492
|
+
END IF;
|
|
39493
|
+
END IF;
|
|
39494
|
+
END IF;
|
|
39495
|
+
END IF;
|
|
39496
|
+
-- 4. werkwijze, zichtbaar
|
|
39497
|
+
uit := uit || jsonb_build_object(v_key, jsonb_build_object('code', v_def, 'bron', CASE WHEN v_def IS NOT NULL THEN 'werkwijze' END,
|
|
39498
|
+
'waarschuwing', CASE WHEN v_def IS NOT NULL THEN 'ladingdrager uit de werkwijze, niet uit het artikel' END,
|
|
39499
|
+
'fout', CASE WHEN v_def IS NULL THEN 'ladingdrager ontbreekt' END));
|
|
39500
|
+
END LOOP;
|
|
39501
|
+
RETURN uit;
|
|
39502
|
+
END $function$;
|
|
39503
|
+
|
|
39504
|
+
CREATE OR REPLACE FUNCTION public.logistics_product_oordeel_many(p_product_ids uuid[])
|
|
39505
|
+
RETURNS TABLE(product_id uuid, oordeel text, tekst text, "actieUrl" text)
|
|
39506
|
+
LANGUAGE plpgsql
|
|
39507
|
+
STABLE SECURITY DEFINER
|
|
39508
|
+
SET search_path TO 'public'
|
|
39509
|
+
AS $function$
|
|
39510
|
+
#variable_conflict use_column
|
|
39511
|
+
DECLARE r record; c record; cd record; v_carrier text; hv jsonb; rs jsonb; v_code text; v_lfout text; ls int; fh numeric; ph numeric; cpl numeric; lpc numeric; laag numeric;
|
|
39512
|
+
blok text[]; waar text[]; mist text[]; hmist text[]; naam text; bron text;
|
|
39513
|
+
c_url constant text := '/logistiek-engine/beheer#gegevens-voor-karindeling';
|
|
39514
|
+
BEGIN
|
|
39515
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_product_oordeel_many');
|
|
39516
|
+
IF coalesce(cardinality(p_product_ids), 0) = 0 THEN RETURN; END IF;
|
|
39517
|
+
IF cardinality(p_product_ids) > 1000 THEN
|
|
39518
|
+
RAISE EXCEPTION 'Maximaal 1000 producten per aanroep (ontvangen: %).', cardinality(p_product_ids) USING ERRCODE = '22023';
|
|
39519
|
+
END IF;
|
|
39520
|
+
SELECT nullif(btrim(coalesce(s.settings->'karrenindeling'->'fields'->>'default_carrier_type', s.settings->'karrenindeling'->>'default_carrier_type')), '')
|
|
39521
|
+
INTO v_carrier FROM public.logistics_rule_configs s WHERE s.is_active ORDER BY s.updated_at DESC LIMIT 1;
|
|
39522
|
+
SELECT t.code, t.name, t.layer_length_cm, t.layer_width_cm, t.max_height_cm, t.max_crates_per_layer, t.layers_per_carrier INTO cd
|
|
39523
|
+
FROM public.load_carrier_types t
|
|
39524
|
+
WHERE t.is_active AND (t.code = v_carrier OR (v_carrier IS NULL AND t.is_default))
|
|
39525
|
+
ORDER BY (t.code = v_carrier) DESC NULLS LAST LIMIT 1;
|
|
39526
|
+
|
|
39527
|
+
FOR r IN SELECT * FROM public.logistics_data_gereedheid(p_product_ids) LOOP
|
|
39528
|
+
blok := '{}'; waar := '{}'; hmist := '{}';
|
|
39529
|
+
mist := array_remove(coalesce(r.ontbrekend, '{}'), 'weight');
|
|
39530
|
+
hv := public.logistics_product_hoofdverpakking(r.product_id);
|
|
39531
|
+
v_code := NULL; v_lfout := NULL;
|
|
39532
|
+
IF hv IS NOT NULL AND NOT coalesce((hv->>'aanwezig')::boolean, false) THEN
|
|
39533
|
+
mist := mist || 'belading niet ingesteld'::text;
|
|
39534
|
+
END IF;
|
|
39535
|
+
IF hv IS NOT NULL AND coalesce((hv->>'aanwezig')::boolean, false) AND nullif(hv->>'ladingdrager', '') IS NOT NULL THEN
|
|
39536
|
+
rs := public.logistics_ladingdrager_resolve(hv->>'ladingdrager');
|
|
39537
|
+
v_code := rs->>'code'; v_lfout := rs->>'fout';
|
|
39538
|
+
-- 1.0.228: geen ladingdrager (loose) = uitleg, geen blokkade; geen capaciteit, geen menging.
|
|
39539
|
+
IF v_code = 'loose' THEN
|
|
39540
|
+
product_id := r.product_id; "actieUrl" := c_url; oordeel := 'waarschuwing';
|
|
39541
|
+
tekst := format('%s: geen ladingdrager, niet op een kar.', r.product);
|
|
39542
|
+
RETURN NEXT;
|
|
39543
|
+
CONTINUE;
|
|
39544
|
+
END IF;
|
|
39545
|
+
END IF;
|
|
39546
|
+
SELECT NULL::text AS code, NULL::text AS name, NULL::int AS layer_length_cm, NULL::int AS layer_width_cm, NULL::int AS max_height_cm, NULL::int AS max_crates_per_layer, NULL::int AS layers_per_carrier INTO c;
|
|
39547
|
+
IF v_code IS NOT NULL THEN
|
|
39548
|
+
SELECT t.code, t.name, t.layer_length_cm, t.layer_width_cm, t.max_height_cm, t.max_crates_per_layer, t.layers_per_carrier INTO c
|
|
39549
|
+
FROM public.load_carrier_types t WHERE t.is_active AND t.code = v_code LIMIT 1;
|
|
39550
|
+
ELSIF v_lfout IS NULL THEN
|
|
39551
|
+
SELECT cd.code, cd.name, cd.layer_length_cm, cd.layer_width_cm, cd.max_height_cm, cd.max_crates_per_layer, cd.layers_per_carrier INTO c;
|
|
39552
|
+
ELSE
|
|
39553
|
+
mist := mist || v_lfout;
|
|
39554
|
+
END IF;
|
|
39555
|
+
naam := coalesce(c.name, c.code, 'de ladingdrager');
|
|
39556
|
+
bron := coalesce(r.velden->'crates_per_layer'->>'bron', 'product');
|
|
39557
|
+
cpl := coalesce(nullif(r.velden->'crates_per_layer'->>'waarde', '')::numeric, 0);
|
|
39558
|
+
lpc := coalesce(nullif(r.velden->'layers_per_cart'->>'waarde', '')::numeric, 0);
|
|
39559
|
+
fh := nullif(r.velden->'fust_height_mm'->>'waarde', '')::numeric / 10.0;
|
|
39560
|
+
ph := nullif(r.velden->'plant_height_cm'->>'waarde', '')::numeric;
|
|
39561
|
+
ls := public.logistics_max_fusten_per_laag(c.layer_length_cm, c.layer_width_cm,
|
|
39562
|
+
nullif(r.velden->'fust_length_mm'->>'waarde', '')::numeric / 10.0, nullif(r.velden->'fust_width_mm'->>'waarde', '')::numeric / 10.0);
|
|
39563
|
+
IF coalesce(fh,0) > 0 AND coalesce(ph,0) > 0 AND coalesce(c.max_height_cm,0) > 0 THEN
|
|
39564
|
+
laag := greatest(fh, ph);
|
|
39565
|
+
IF lpc * laag > c.max_height_cm + 1e-9 AND ph >= fh AND coalesce(r.velden->'plant_height_cm'->>'bron', '') ILIKE 'floricode%' THEN
|
|
39566
|
+
waar := waar || format('planthoogte volgens Floricode; controleer: %s lagen × %s cm = %s cm, hoger dan %s (%s cm)',
|
|
39567
|
+
lpc, trim_scale(round(laag,1)), trim_scale(round(lpc*laag,1)), naam, trim_scale(round(c.max_height_cm::numeric,1)));
|
|
39568
|
+
ELSIF lpc * laag > c.max_height_cm + 1e-9 THEN
|
|
39569
|
+
blok := blok || format('%s lagen × %s cm = %s cm, terwijl %s %s cm hoog is; er passen maximaal %s lagen',
|
|
39570
|
+
lpc, trim_scale(round(laag,1)), trim_scale(round(lpc*laag,1)), naam, trim_scale(round(c.max_height_cm::numeric,1)), floor(c.max_height_cm / laag));
|
|
39571
|
+
END IF;
|
|
39572
|
+
ELSE
|
|
39573
|
+
IF coalesce(fh,0) <= 0 THEN hmist := hmist || 'fusthoogte'::text; END IF;
|
|
39574
|
+
IF coalesce(ph,0) <= 0 THEN hmist := hmist || 'planthoogte'::text; END IF;
|
|
39575
|
+
IF coalesce(c.max_height_cm,0) <= 0 THEN hmist := hmist || ('hoogte van ' || naam); END IF;
|
|
39576
|
+
END IF;
|
|
39577
|
+
IF public.logistics_laag_tolerantie_tekst(c.layer_length_cm, c.layer_width_cm,
|
|
39578
|
+
nullif(r.velden->'fust_length_mm'->>'waarde', '')::numeric / 10.0, nullif(r.velden->'fust_width_mm'->>'waarde', '')::numeric / 10.0, cpl) IS NOT NULL THEN
|
|
39579
|
+
waar := waar || public.logistics_laag_tolerantie_tekst(c.layer_length_cm, c.layer_width_cm,
|
|
39580
|
+
nullif(r.velden->'fust_length_mm'->>'waarde', '')::numeric / 10.0, nullif(r.velden->'fust_width_mm'->>'waarde', '')::numeric / 10.0, cpl);
|
|
39581
|
+
END IF;
|
|
39582
|
+
IF ls IS NOT NULL AND cpl > ls THEN
|
|
39583
|
+
blok := blok || format('%s fust per laag (bron: %s), maar op een laag van %s passen er maximaal %s', cpl, bron, naam, ls);
|
|
39584
|
+
END IF;
|
|
39585
|
+
IF coalesce(c.max_crates_per_layer,0) > 0 AND cpl > c.max_crates_per_layer THEN
|
|
39586
|
+
blok := blok || format('%s fust per laag (bron: %s), maar %s staat maximaal %s fust per laag toe', cpl, bron, naam, c.max_crates_per_layer);
|
|
39587
|
+
END IF;
|
|
39588
|
+
IF cardinality(blok) = 0 AND cardinality(hmist) > 0 AND coalesce(c.layers_per_carrier,0) > 0 AND lpc > c.layers_per_carrier THEN
|
|
39589
|
+
waar := waar || format('%s lagen opgegeven, standaard %s; niet te controleren omdat de %s ontbreekt', lpc, c.layers_per_carrier, array_to_string(hmist, ', '));
|
|
39590
|
+
END IF;
|
|
39591
|
+
IF 'weight' = ANY(coalesce(r.ontbrekend, '{}')) THEN waar := waar || 'gewicht per fust ontbreekt'::text; END IF;
|
|
39592
|
+
|
|
39593
|
+
product_id := r.product_id; "actieUrl" := c_url;
|
|
39594
|
+
IF cardinality(blok) > 0 THEN
|
|
39595
|
+
oordeel := 'onmogelijk'; tekst := format('%s past niet op %s: %s.', r.product, naam, array_to_string(blok, '; '));
|
|
39596
|
+
ELSIF cardinality(mist) > 0 THEN
|
|
39597
|
+
oordeel := 'mist_gegevens';
|
|
39598
|
+
tekst := CASE WHEN 'belading niet ingesteld' = ANY(mist) THEN format('%s: belading niet ingesteld.', r.product)
|
|
39599
|
+
WHEN v_lfout IS NOT NULL AND v_lfout = ANY(mist) THEN format('%s: %s.', r.product, v_lfout)
|
|
39600
|
+
ELSE r.uitleg END;
|
|
39601
|
+
ELSIF cardinality(waar) > 0 THEN
|
|
39602
|
+
oordeel := 'waarschuwing'; tekst := format('%s: %s.', r.product, array_to_string(waar, '; '));
|
|
39603
|
+
ELSE
|
|
39604
|
+
oordeel := 'compleet'; tekst := format('%s: gegevens voor karindeling compleet.', r.product);
|
|
39605
|
+
END IF;
|
|
39606
|
+
RETURN NEXT;
|
|
39607
|
+
END LOOP;
|
|
39608
|
+
END $function$;
|
|
39609
|
+
|
|
39610
|
+
CREATE OR REPLACE FUNCTION public.logistics_product_oordeel_belading(p_regels jsonb)
|
|
39611
|
+
RETURNS jsonb
|
|
39612
|
+
LANGUAGE plpgsql
|
|
39613
|
+
STABLE SECURITY DEFINER
|
|
39614
|
+
SET search_path TO 'public'
|
|
39615
|
+
AS $function$
|
|
39616
|
+
DECLARE e jsonb; gj jsonb; gmap jsonb := '{}'::jsonb; c record; rc jsonb; hv jsonb; v_code text; v_eigen text; ids uuid[]; uit jsonb := '[]'::jsonb;
|
|
39617
|
+
ls int; fh numeric; ph numeric; cpl numeric; lpc numeric; ppc numeric; laag numeric; naam text; v_prod text; fl numeric; fb numeric;
|
|
39618
|
+
blok text[]; waar text[]; mist text[]; hmist text[]; v_pid uuid; v_oordeel text; v_tekst text; v_heeft_kol boolean; v_cfout text;
|
|
39619
|
+
BEGIN
|
|
39620
|
+
PERFORM public.logistics_acc_guard('ingelogd', 'logistics_product_oordeel_belading');
|
|
39621
|
+
IF p_regels IS NULL OR jsonb_typeof(p_regels) <> 'array' THEN RAISE EXCEPTION 'p_regels moet een lijst zijn.' USING ERRCODE = '22023'; END IF;
|
|
39622
|
+
IF jsonb_array_length(p_regels) > 1000 THEN
|
|
39623
|
+
RAISE EXCEPTION 'Maximaal 1000 regels per aanroep (ontvangen: %).', jsonb_array_length(p_regels) USING ERRCODE = '22023';
|
|
39624
|
+
END IF;
|
|
39625
|
+
SELECT array_agg(DISTINCT (x->>'product_id')::uuid) INTO ids FROM jsonb_array_elements(p_regels) x
|
|
39626
|
+
WHERE nullif(btrim(x->>'product_id'), '') ~* '^[0-9a-f-]{36}$';
|
|
39627
|
+
IF ids IS NOT NULL THEN
|
|
39628
|
+
SELECT coalesce(jsonb_object_agg(g.product_id::text, to_jsonb(g)), '{}'::jsonb) INTO gmap
|
|
39629
|
+
FROM public.logistics_data_gereedheid(ids) g;
|
|
39630
|
+
END IF;
|
|
39631
|
+
SELECT EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = to_regclass('public.products') AND attname = 'load_carrier_type' AND NOT attisdropped) INTO v_heeft_kol;
|
|
39632
|
+
|
|
39633
|
+
FOR e IN SELECT x FROM jsonb_array_elements(p_regels) x LOOP
|
|
39634
|
+
blok := '{}'; waar := '{}'; mist := '{}'; hmist := '{}'; v_eigen := NULL; v_cfout := NULL;
|
|
39635
|
+
SELECT NULL::text AS code, NULL::text AS name, NULL::numeric AS layer_length_cm, NULL::numeric AS layer_width_cm,
|
|
39636
|
+
NULL::numeric AS max_height_cm, NULL::integer AS max_crates_per_layer, NULL::integer AS layers_per_carrier INTO c;
|
|
39637
|
+
v_pid := CASE WHEN nullif(btrim(e->>'product_id'), '') ~* '^[0-9a-f-]{36}$' THEN (e->>'product_id')::uuid END;
|
|
39638
|
+
gj := CASE WHEN v_pid IS NULL THEN NULL ELSE gmap->(v_pid::text) END;
|
|
39639
|
+
IF gj IS NULL THEN
|
|
39640
|
+
uit := uit || jsonb_build_array(jsonb_build_object('product_id', v_pid, 'oordeel', 'mist_gegevens', 'tekst', 'product onbekend',
|
|
39641
|
+
'regels', jsonb_build_array('Product onbekend.')));
|
|
39642
|
+
CONTINUE;
|
|
39643
|
+
END IF;
|
|
39644
|
+
v_prod := coalesce(gj->>'product', 'Product');
|
|
39645
|
+
hv := public.logistics_product_hoofdverpakking(v_pid);
|
|
39646
|
+
v_code := nullif(btrim(e->>'carrier_code'), '');
|
|
39647
|
+
IF v_code IS NULL THEN v_code := nullif(hv->>'ladingdrager', ''); END IF;
|
|
39648
|
+
IF v_code IS NULL AND v_heeft_kol THEN
|
|
39649
|
+
EXECUTE 'SELECT nullif(btrim(load_carrier_type::text), '''') FROM public.products WHERE id = $1' INTO v_eigen USING v_pid;
|
|
39650
|
+
v_code := v_eigen;
|
|
39651
|
+
END IF;
|
|
39652
|
+
rc := public.logistics_ladingdrager_resolve(v_code);
|
|
39653
|
+
v_cfout := rc->>'fout';
|
|
39654
|
+
-- 1.0.228: geen ladingdrager (loose) = uitleg, geen blokkade; geen capaciteit, geen menging.
|
|
39655
|
+
IF rc->>'code' = 'loose' THEN
|
|
39656
|
+
uit := uit || jsonb_build_array(jsonb_build_object('product_id', v_pid, 'oordeel', 'waarschuwing',
|
|
39657
|
+
'tekst', format('%s: geen ladingdrager, niet op een kar.', v_prod),
|
|
39658
|
+
'ladingdrager', 'loose', 'ladingdragerInvoer', rc->>'invoer', 'ladingdragerBron', rc->>'bron',
|
|
39659
|
+
'regels', jsonb_build_array('Geen ladingdrager: niet op een kar.')));
|
|
39660
|
+
CONTINUE;
|
|
39661
|
+
END IF;
|
|
39662
|
+
IF rc->>'code' IS NOT NULL THEN
|
|
39663
|
+
SELECT t.code, t.name, t.layer_length_cm, t.layer_width_cm, t.max_height_cm, t.max_crates_per_layer, t.layers_per_carrier INTO c
|
|
39664
|
+
FROM public.load_carrier_types t WHERE t.is_active AND t.code = rc->>'code' LIMIT 1;
|
|
39665
|
+
END IF;
|
|
39666
|
+
naam := coalesce(c.name, c.code, 'de ladingdrager');
|
|
39667
|
+
ppc := nullif(e->>'plants_per_crate', '')::numeric;
|
|
39668
|
+
cpl := nullif(e->>'crates_per_layer', '')::numeric;
|
|
39669
|
+
lpc := nullif(e->>'layers_per_cart', '')::numeric;
|
|
39670
|
+
fh := nullif(gj->'velden'->'fust_height_mm'->>'waarde', '')::numeric / 10.0;
|
|
39671
|
+
ph := nullif(gj->'velden'->'plant_height_cm'->>'waarde', '')::numeric;
|
|
39672
|
+
fl := nullif(gj->'velden'->'fust_length_mm'->>'waarde', '')::numeric / 10.0;
|
|
39673
|
+
fb := nullif(gj->'velden'->'fust_width_mm'->>'waarde', '')::numeric / 10.0;
|
|
39674
|
+
IF hv IS NOT NULL AND NOT coalesce((hv->>'aanwezig')::boolean, false) THEN mist := mist || 'belading niet ingesteld'::text; END IF;
|
|
39675
|
+
IF coalesce(ppc, 0) <= 0 THEN mist := mist || 'planten per fust'::text; END IF;
|
|
39676
|
+
IF coalesce(cpl, 0) <= 0 THEN mist := mist || 'fusten per laag'::text; END IF;
|
|
39677
|
+
IF coalesce(lpc, 0) <= 0 THEN mist := mist || 'lagen per kar'::text; END IF;
|
|
39678
|
+
|
|
39679
|
+
IF c.code IS NULL THEN
|
|
39680
|
+
mist := mist || coalesce(v_cfout, 'ladingdrager ontbreekt');
|
|
39681
|
+
ls := public.logistics_max_fusten_per_laag_alle(fl, fb);
|
|
39682
|
+
IF ls IS NOT NULL AND coalesce(cpl,0) > ls THEN
|
|
39683
|
+
blok := blok || format('%s fust per laag, maar op geen enkele ladingdrager in Beheer passen er meer dan %s', cpl, ls);
|
|
39684
|
+
END IF;
|
|
39685
|
+
ELSE
|
|
39686
|
+
ls := public.logistics_max_fusten_per_laag(c.layer_length_cm, c.layer_width_cm, fl, fb);
|
|
39687
|
+
IF public.logistics_laag_tolerantie_tekst(c.layer_length_cm, c.layer_width_cm, fl, fb, cpl) IS NOT NULL THEN
|
|
39688
|
+
waar := waar || public.logistics_laag_tolerantie_tekst(c.layer_length_cm, c.layer_width_cm, fl, fb, cpl);
|
|
39689
|
+
END IF;
|
|
39690
|
+
IF coalesce(lpc,0) > 0 AND coalesce(fh,0) > 0 AND coalesce(ph,0) > 0 AND coalesce(c.max_height_cm,0) > 0 THEN
|
|
39691
|
+
laag := greatest(fh, ph);
|
|
39692
|
+
IF lpc * laag > c.max_height_cm + 1e-9 AND ph >= fh AND coalesce(gj->'velden'->'plant_height_cm'->>'bron', '') ILIKE 'floricode%' THEN
|
|
39693
|
+
waar := waar || format('planthoogte volgens Floricode; controleer: %s lagen × %s cm = %s cm, hoger dan %s (%s cm)',
|
|
39694
|
+
lpc, trim_scale(round(laag,1)), trim_scale(round(lpc*laag,1)), naam, trim_scale(round(c.max_height_cm::numeric,1)));
|
|
39695
|
+
ELSIF lpc * laag > c.max_height_cm + 1e-9 THEN
|
|
39696
|
+
blok := blok || format('%s lagen × %s cm = %s cm, terwijl %s %s cm hoog is; er passen maximaal %s lagen',
|
|
39697
|
+
lpc, trim_scale(round(laag,1)), trim_scale(round(lpc*laag,1)), naam, trim_scale(round(c.max_height_cm::numeric,1)), floor(c.max_height_cm / laag));
|
|
39698
|
+
END IF;
|
|
39699
|
+
ELSE
|
|
39700
|
+
IF coalesce(fh,0) <= 0 THEN hmist := hmist || 'fusthoogte'::text; END IF;
|
|
39701
|
+
IF coalesce(ph,0) <= 0 THEN hmist := hmist || 'planthoogte'::text; END IF;
|
|
39702
|
+
IF coalesce(c.max_height_cm,0) <= 0 THEN hmist := hmist || ('hoogte van ' || naam); END IF;
|
|
39703
|
+
END IF;
|
|
39704
|
+
IF ls IS NOT NULL AND coalesce(cpl,0) > ls THEN
|
|
39705
|
+
blok := blok || format('%s fust per laag, maar op een laag van %s passen er maximaal %s', cpl, naam, ls);
|
|
39706
|
+
END IF;
|
|
39707
|
+
IF coalesce(c.max_crates_per_layer,0) > 0 AND coalesce(cpl,0) > c.max_crates_per_layer THEN
|
|
39708
|
+
blok := blok || format('%s fust per laag, maar %s staat maximaal %s fust per laag toe', cpl, naam, c.max_crates_per_layer);
|
|
39709
|
+
END IF;
|
|
39710
|
+
IF cardinality(blok) = 0 AND cardinality(hmist) > 0 AND coalesce(c.layers_per_carrier,0) > 0 AND coalesce(lpc,0) > c.layers_per_carrier THEN
|
|
39711
|
+
waar := waar || format('%s lagen opgegeven, standaard %s; niet te controleren omdat de %s ontbreekt', lpc, c.layers_per_carrier, array_to_string(hmist, ', '));
|
|
39712
|
+
END IF;
|
|
39713
|
+
END IF;
|
|
39714
|
+
IF coalesce(gj->'ontbrekend', '[]'::jsonb) ? 'weight' THEN waar := waar || 'gewicht per fust ontbreekt'::text; END IF;
|
|
39715
|
+
IF cardinality(blok) > 0 THEN
|
|
39716
|
+
v_oordeel := 'onmogelijk'; v_tekst := format('%s past niet op %s.', v_prod, CASE WHEN c.code IS NULL THEN 'een ladingdrager' ELSE naam END);
|
|
39717
|
+
ELSIF cardinality(mist) > 0 THEN
|
|
39718
|
+
v_oordeel := 'mist_gegevens'; v_tekst := format('%s: %s.', v_prod, array_to_string(mist, ', '));
|
|
39719
|
+
ELSIF cardinality(waar) > 0 THEN
|
|
39720
|
+
v_oordeel := 'waarschuwing'; v_tekst := format('%s: belading mogelijk, met waarschuwing.', v_prod);
|
|
39721
|
+
ELSE
|
|
39722
|
+
v_oordeel := 'compleet'; v_tekst := format('%s: belading past.', v_prod);
|
|
39723
|
+
END IF;
|
|
39724
|
+
uit := uit || jsonb_build_array(jsonb_build_object('product_id', v_pid, 'oordeel', v_oordeel, 'tekst', v_tekst,
|
|
39725
|
+
'ladingdrager', rc->>'code', 'ladingdragerInvoer', rc->>'invoer', 'ladingdragerBron', rc->>'bron',
|
|
39726
|
+
'regels', to_jsonb(ARRAY(SELECT upper(left(z,1)) || substr(z,2) || '.' FROM unnest(blok || mist || waar) z))));
|
|
39727
|
+
END LOOP;
|
|
39728
|
+
RETURN uit;
|
|
39729
|
+
END $function$;
|
|
39730
|
+
REVOKE ALL ON FUNCTION public.logistics_ladingdrager_resolve_plan(text) FROM authenticated;
|
|
39731
|
+
|