diff --git a/api/alembic/versions/0037_form2_ahr_limit_depth_fix.py b/api/alembic/versions/0037_form2_ahr_limit_depth_fix.py new file mode 100644 index 0000000..f4cae3d --- /dev/null +++ b/api/alembic/versions/0037_form2_ahr_limit_depth_fix.py @@ -0,0 +1,15 @@ +from sql_migration import run_sql_file_migration + + +revision = "0037" +down_revision = "0036" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + run_sql_file_migration("0037_form2_ahr_limit_depth_fix.sql") + + +def downgrade() -> None: + pass diff --git a/api/alembic/versions/sql/0037_form2_ahr_limit_depth_fix.sql b/api/alembic/versions/sql/0037_form2_ahr_limit_depth_fix.sql new file mode 100644 index 0000000..8ac6461 --- /dev/null +++ b/api/alembic/versions/sql/0037_form2_ahr_limit_depth_fix.sql @@ -0,0 +1,113 @@ +-- After 0033 some AHR expense items with num_group_id became depth=4. +-- AHR_LIMIT synchronization still required depth=3, so limit rows such as +-- "принтеры", "МФУ", and "копировальные аппараты" stopped matching +-- expense_item.num_group_id = '204620030'. +-- +-- The same three limit rows also use a special quarterly amount formula: +-- qty * 0.57 * 10900 / 4. Other limit rows keep the previous formula. + +CREATE OR REPLACE FUNCTION v3._form2_ahr_limit_amount( + p_name character varying, + p_unit character varying, + p_limit_with_vat numeric, + p_qty numeric +) +RETURNS numeric +LANGUAGE sql +IMMUTABLE +AS $function$ + SELECT COALESCE(p_qty, 0) * + CASE + WHEN regexp_replace( + COALESCE(p_name, ''), + '^[[:space:]]*-[[:space:]]*', + '' + ) IN ('принтеры', 'МФУ', 'копировальные аппараты') + THEN 0.57 * 10900 / 4 + ELSE COALESCE(p_limit_with_vat, 0) * + CASE + WHEN p_unit LIKE '%/год' THEN 0.25 + WHEN p_unit LIKE '%/месяц' THEN 3 + ELSE 1 + END + END; +$function$; + +DO $do$ +DECLARE + v_signature regprocedure; + v_sql text; + v_next_sql text; +BEGIN + FOREACH v_signature IN ARRAY ARRAY[ + 'v3.v_form2_view(integer,character varying,text[])'::regprocedure, + 'v3.sync_form2_ahr_satellite_lines(integer)'::regprocedure, + 'v3.sync_form2_ahr_satellite_line(integer,character varying,integer)'::regprocedure + ] + LOOP + v_sql := pg_get_functiondef(v_signature); + + v_next_sql := regexp_replace( + v_sql, + $re$COALESCE\(fl\.qty_q([1-4]),[[:space:]]*0\)[[:space:]]*\*[[:space:]]*COALESCE\(lt\.limit_with_vat,[[:space:]]*0\)[[:space:]]*\*[[:space:]]*\(?[[:space:]]*CASE[[:space:]]+WHEN[[:space:]]+lt\.unit[[:space:]]+LIKE[[:space:]]+'%/год'[[:space:]]+THEN[[:space:]]+0\.25[[:space:]]+WHEN[[:space:]]+lt\.unit[[:space:]]+LIKE[[:space:]]+'%/месяц'[[:space:]]+THEN[[:space:]]+3[[:space:]]+ELSE[[:space:]]+1[[:space:]]+END[[:space:]]*\)?$re$, + $replace$v3._form2_ahr_limit_amount(lt.name, lt.unit, lt.limit_with_vat, fl.qty_q\1)$replace$, + 'g' + ); + + IF v_next_sql = v_sql THEN + RAISE EXCEPTION 'Expected AHR limit amount expression was not found in %', v_signature; + END IF; + + EXECUTE v_next_sql; + END LOOP; +END; +$do$; + +DO $do$ +DECLARE + v_signature regprocedure; + v_sql text; + v_next_sql text; +BEGIN + FOREACH v_signature IN ARRAY ARRAY[ + 'v3.sync_form2_ahr_satellite_lines(integer)'::regprocedure, + 'v3.sync_form2_ahr_satellite_line(integer,character varying,integer)'::regprocedure, + 'v3.get_form2_ahr_satellite_delta(integer,character varying,integer)'::regprocedure, + 'v3.is_form2_ahr_satellite_line(integer,integer)'::regprocedure + ] + LOOP + v_sql := pg_get_functiondef(v_signature); + + v_next_sql := regexp_replace( + v_sql, + 'AND\s+ei\.depth\s*=\s*3\s+AND\s*\(\s*ei\.item_id\s*=\s*lt\.expense_item_code\s+OR\s+ei\.num_group_id\s*=\s*lt\.expense_item_code\s*\)', + E'AND (\n (ei.depth = 3 AND ei.item_id = lt.expense_item_code)\n OR ei.num_group_id = lt.expense_item_code\n )', + 'g' + ); + + IF v_next_sql = v_sql THEN + IF v_sql ~ 'ei\.depth[[:space:]]*=[[:space:]]*3[[:space:]]+AND[[:space:]]+ei\.item_id[[:space:]]*=[[:space:]]*lt\.expense_item_code[[:space:]]*\)[[:space:]]+OR[[:space:]]+ei\.num_group_id[[:space:]]*=[[:space:]]*lt\.expense_item_code' THEN + CONTINUE; + END IF; + + RAISE EXCEPTION 'Expected depth=3 limit-template matcher was not found in %', v_signature; + END IF; + + EXECUTE v_next_sql; + END LOOP; +END; +$do$; + +DO $do$ +DECLARE + v_form_id integer; +BEGIN + FOR v_form_id IN + SELECT id + FROM v3.budget_form + WHERE form_type_code = 'FORM_2' + LOOP + PERFORM v3.sync_form2_ahr_satellite_lines(v_form_id); + END LOOP; +END; +$do$;