Files
ems/db/routines/R__044_fn_set_mode.sql
Dusan Vojacek a07f5d57cb
Some checks failed
CI and deploy / migration-check (push) Failing after 10s
CI and deploy / deploy (push) Has been skipped
fix 500
2026-04-20 11:11:47 +02:00

145 lines
4.7 KiB
PL/PgSQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================
-- R__044_fn_set_mode.sql
-- EMS Platform přepínání provozních režimů
-- Repeatable migration
-- =============================================================
CREATE OR REPLACE FUNCTION ems.fn_set_mode(
p_site_id INT,
p_mode_code TEXT,
p_activated_by TEXT DEFAULT 'system',
p_valid_until TIMESTAMPTZ DEFAULT NULL,
p_notes TEXT DEFAULT NULL
)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
v_current_mode TEXT;
v_mode_exists BOOLEAN;
BEGIN
-- Ověřit že režim existuje
SELECT EXISTS(SELECT 1 FROM ems.operating_mode_def WHERE code = p_mode_code)
INTO v_mode_exists;
IF NOT v_mode_exists THEN
RAISE EXCEPTION 'Neznámý provozní režim: %', p_mode_code;
END IF;
-- Zjistit aktuální režim (pro log a previous_mode)
SELECT mode_code INTO v_current_mode
FROM ems.site_operating_mode
WHERE site_id = p_site_id;
-- Pokud se režim nemění, nic nedělat
IF v_current_mode = p_mode_code THEN
RETURN p_mode_code;
END IF;
-- Uzavřít předchozí záznam v logu
UPDATE ems.site_operating_mode_log
SET deactivated_at = now()
WHERE site_id = p_site_id
AND deactivated_at IS NULL;
-- Upsert aktivního režimu
INSERT INTO ems.site_operating_mode
(site_id, mode_code, activated_at, activated_by, valid_until, previous_mode, notes)
VALUES
(p_site_id, p_mode_code, now(), p_activated_by, p_valid_until, v_current_mode, p_notes)
ON CONFLICT (site_id) DO UPDATE SET
mode_code = EXCLUDED.mode_code,
activated_at = EXCLUDED.activated_at,
activated_by = EXCLUDED.activated_by,
valid_until = EXCLUDED.valid_until,
previous_mode = EXCLUDED.previous_mode,
notes = EXCLUDED.notes;
-- Přidat záznam do logu
INSERT INTO ems.site_operating_mode_log
(site_id, mode_code, activated_at, activated_by, notes)
VALUES
(p_site_id, p_mode_code, now(), p_activated_by, p_notes);
RETURN p_mode_code;
END;
$$;
COMMENT ON FUNCTION ems.fn_set_mode(INT, TEXT, TEXT, TIMESTAMPTZ, TEXT) IS
'Přepne provozní režim lokality. Atomicky aktualizuje site_operating_mode a zapíše do audit logu.
Ignoruje přepnutí na stejný režim. Vyhodí výjimku pro neznámý kód režimu.
Příklad: SELECT ems.fn_set_mode(1, ''SELF_SUSTAIN'', ''user:jan'', NULL, ''Odjezd na dovolenou'');';
-- ============================================================
CREATE OR REPLACE FUNCTION ems.fn_restore_previous_mode(
p_site_id INT,
p_activated_by TEXT DEFAULT 'system'
)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
v_previous TEXT;
BEGIN
SELECT previous_mode INTO v_previous
FROM ems.site_operating_mode
WHERE site_id = p_site_id;
IF v_previous IS NULL THEN
-- Fallback na AUTO pokud není předchozí režim
v_previous := 'AUTO';
END IF;
RETURN ems.fn_set_mode(p_site_id, v_previous, p_activated_by, NULL, 'Obnova předchozího režimu');
END;
$$;
COMMENT ON FUNCTION ems.fn_restore_previous_mode(INT, TEXT) IS
'Přepne lokalitu zpět na předchozí provozní režim (uložený v previous_mode).
Pokud předchozí režim neexistuje, přepne na AUTO. Používat po skončení dočasného přepisu.';
-- ============================================================
drop function if exists ems.fn_expire_modes();
CREATE OR REPLACE FUNCTION ems.fn_expire_modes()
RETURNS TABLE(site_id INT, site_code TEXT, old_mode TEXT, new_mode TEXT)
LANGUAGE plpgsql
AS $$
DECLARE
v_rec RECORD;
v_new_mode TEXT;
BEGIN
FOR v_rec IN
SELECT som.site_id,
s.code AS site_code,
som.mode_code AS old_mode,
som.previous_mode
FROM ems.site_operating_mode som
JOIN ems.site s ON s.id = som.site_id
WHERE som.valid_until IS NOT NULL
AND som.valid_until <= now()
AND som.mode_code <> 'AUTO'
LOOP
v_new_mode := COALESCE(v_rec.previous_mode, 'AUTO');
PERFORM ems.fn_set_mode(
v_rec.site_id,
v_new_mode,
'system:expiry',
NULL,
'Automatické vypršení dočasného režimu'
);
site_id := v_rec.site_id;
site_code := v_rec.site_code;
old_mode := v_rec.old_mode;
new_mode := v_new_mode;
RETURN NEXT;
END LOOP;
END;
$$;
COMMENT ON FUNCTION ems.fn_expire_modes() IS
'Zkontroluje všechny lokality s dočasným režimem (valid_until IS NOT NULL) a přepne zpět ty s prosahlým časem.
Volat každou minutu jako scheduled task. Vrátí řádky (site_id, site_code, old_mode, new_mode) pro každé provedené přepnutí — backend z toho pošle Discord notifikace.';