Files
ems/db/routines/R__037_fn_planning_run_commit.sql
Dusan Vojacek 7490ac3d70
Some checks failed
CI and deploy / migration-check (push) Failing after 20s
CI and deploy / deploy (push) Has been skipped
planner v2 vc. porovnani
2026-05-15 23:03:32 +02:00

167 lines
5.7 KiB
PL/PgSQL

-- uložení planning_run + planning_interval v jedné transakci
create or replace function ems.fn_planning_run_commit(
p_site_id int,
p_horizon_start timestamptz,
p_horizon_end timestamptz,
p_run_meta jsonb,
p_intervals jsonb,
p_activate_run boolean default true
)
returns int
language plpgsql
as $fn$
declare
v_run_id int;
r record;
v_has_slot_inputs boolean;
begin
v_has_slot_inputs := coalesce(
(jsonb_typeof(p_intervals) = 'array' and jsonb_array_length(p_intervals) > 0
and (p_intervals->0) ? 'load_baseline_w'),
false
);
insert into ems.planning_run (
site_id, horizon_start, horizon_end, status,
run_type, triggered_by, replan_from,
soc_at_replan_wh, solver_duration_ms, forecast_correction_factor,
solver_params
) values (
p_site_id,
p_horizon_start,
p_horizon_end,
case when p_activate_run then 'draft' else 'comparison' end,
nullif(trim(p_run_meta->>'run_type'), ''),
nullif(trim(p_run_meta->>'triggered_by'), ''),
case
when p_run_meta ? 'replan_from' and (p_run_meta->>'replan_from') is not null
and (p_run_meta->>'replan_from') <> 'null'
then (p_run_meta->>'replan_from')::timestamptz
else null::timestamptz
end,
(p_run_meta->>'soc_at_replan_wh')::numeric,
(p_run_meta->>'solver_duration_ms')::int,
(p_run_meta->>'forecast_correction_factor')::numeric,
case
when p_run_meta ? 'solver_params' and jsonb_typeof(p_run_meta->'solver_params') = 'object'
then p_run_meta->'solver_params'
else null::jsonb
end
)
returning id into v_run_id;
for r in select * from jsonb_array_elements(p_intervals) as elem(value)
loop
if v_has_slot_inputs then
insert into ems.planning_interval (
run_id, interval_start,
battery_setpoint_w, battery_soc_target_pct,
grid_setpoint_w,
deye_physical_mode,
deye_gen_cutoff_enabled,
ev1_setpoint_w, ev2_setpoint_w, ev1_via_bat_w, ev2_via_bat_w,
heat_pump_enabled, heat_pump_setpoint_w,
pv_a_curtailed_w, expected_cost_czk,
effective_buy_price, effective_sell_price,
is_predicted_price,
load_baseline_w,
pv_a_forecast_raw_w, pv_b_forecast_raw_w,
pv_a_forecast_solver_w, pv_b_forecast_solver_w
) values (
v_run_id,
(r.value->>'interval_start')::timestamptz,
(r.value->>'battery_setpoint_w')::int,
(r.value->>'battery_soc_target_pct')::numeric,
(r.value->>'grid_setpoint_w')::int,
nullif(trim(r.value->>'deye_physical_mode'), ''),
(r.value->>'deye_gen_cutoff_enabled')::boolean,
nullif(r.value->>'ev1_setpoint_w', '')::int,
nullif(r.value->>'ev2_setpoint_w', '')::int,
coalesce((r.value->>'ev1_via_bat_w')::int, 0),
coalesce((r.value->>'ev2_via_bat_w')::int, 0),
coalesce((r.value->>'heat_pump_enabled')::boolean, false),
(r.value->>'heat_pump_setpoint_w')::int,
(r.value->>'pv_a_curtailed_w')::int,
(r.value->>'expected_cost_czk')::numeric,
(r.value->>'effective_buy_price')::numeric,
(r.value->>'effective_sell_price')::numeric,
coalesce((r.value->>'is_predicted_price')::boolean, false),
(r.value->>'load_baseline_w')::int,
(r.value->>'pv_a_forecast_raw_w')::int,
(r.value->>'pv_b_forecast_raw_w')::int,
(r.value->>'pv_a_forecast_solver_w')::int,
(r.value->>'pv_b_forecast_solver_w')::int
);
else
insert into ems.planning_interval (
run_id, interval_start,
battery_setpoint_w, battery_soc_target_pct,
grid_setpoint_w,
deye_physical_mode,
deye_gen_cutoff_enabled,
ev1_setpoint_w, ev2_setpoint_w, ev1_via_bat_w, ev2_via_bat_w,
heat_pump_enabled, heat_pump_setpoint_w,
pv_a_curtailed_w, expected_cost_czk,
effective_buy_price, effective_sell_price,
is_predicted_price
) values (
v_run_id,
(r.value->>'interval_start')::timestamptz,
(r.value->>'battery_setpoint_w')::int,
(r.value->>'battery_soc_target_pct')::numeric,
(r.value->>'grid_setpoint_w')::int,
nullif(trim(r.value->>'deye_physical_mode'), ''),
(r.value->>'deye_gen_cutoff_enabled')::boolean,
nullif(r.value->>'ev1_setpoint_w', '')::int,
nullif(r.value->>'ev2_setpoint_w', '')::int,
coalesce((r.value->>'ev1_via_bat_w')::int, 0),
coalesce((r.value->>'ev2_via_bat_w')::int, 0),
coalesce((r.value->>'heat_pump_enabled')::boolean, false),
(r.value->>'heat_pump_setpoint_w')::int,
(r.value->>'pv_a_curtailed_w')::int,
(r.value->>'expected_cost_czk')::numeric,
(r.value->>'effective_buy_price')::numeric,
(r.value->>'effective_sell_price')::numeric,
coalesce((r.value->>'is_predicted_price')::boolean, false)
);
end if;
end loop;
update ems.planning_run
set status = 'superseded'
where p_activate_run
and site_id = p_site_id
and status = 'active'
and id <> v_run_id;
if p_activate_run then
update ems.planning_run
set status = 'active'
where id = v_run_id;
end if;
return v_run_id;
end;
$fn$;
create or replace function ems.fn_forecast_correction_log_insert(
p_site_id int,
p_window_start timestamptz,
p_window_end timestamptz,
p_actual_pv_wh numeric,
p_forecast_pv_wh numeric,
p_correction_factor numeric,
p_applied_to_run_id int
)
returns void
language sql
as $fn$
insert into ems.forecast_correction_log (
site_id, window_start, window_end,
actual_pv_wh, forecast_pv_wh, correction_factor, applied_to_run_id
) values (
p_site_id, p_window_start, p_window_end,
p_actual_pv_wh, p_forecast_pv_wh, p_correction_factor, p_applied_to_run_id
);
$fn$;