From 6f6f35c8b1b43a0d45b67d192439626095d72282 Mon Sep 17 00:00:00 2001 From: tsygankoviva Date: Thu, 20 Aug 2026 16:48:30 +0300 Subject: [PATCH] =?UTF-8?q?svod:=20=D1=81=D0=B2=D0=BE=D0=B4=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/alembic/versions/0021_summary_views.py | 82 + .../versions/sql/0021_summary_views.sql | 1833 +++++++++++++++++ api/src/api/v1/router.py | 3 +- api/src/api/v1/summary.py | 88 + api/src/repository/summary_repository.py | 30 + api/src/services/summary_service.py | 21 + .../integration/test_summary_api_smoke.py | 40 + 7 files changed, 2096 insertions(+), 1 deletion(-) create mode 100644 api/alembic/versions/0021_summary_views.py create mode 100644 api/alembic/versions/sql/0021_summary_views.sql create mode 100644 api/src/api/v1/summary.py create mode 100644 api/src/repository/summary_repository.py create mode 100644 api/src/services/summary_service.py create mode 100644 api/tests/integration/test_summary_api_smoke.py diff --git a/api/alembic/versions/0021_summary_views.py b/api/alembic/versions/0021_summary_views.py new file mode 100644 index 0000000..5a76e4d --- /dev/null +++ b/api/alembic/versions/0021_summary_views.py @@ -0,0 +1,82 @@ +import os +import re + +from alembic import op + + +revision = "0021" +down_revision = "0020" +branch_labels = None +depends_on = None + + +_DOLLAR_TAG_RE = re.compile(r"\$\w+\$") + + +def _find_dollar_tag(line: str) -> str | None: + m = _DOLLAR_TAG_RE.search(line.strip()) + return m.group(0) if m else None + + +def _split_statements(sql: str) -> list[str]: + statements: list[str] = [] + current: list[str] = [] + in_dollar = False + dollar_tag: str | None = None + + for line in sql.split("\n"): + stripped = line.strip() + if stripped.startswith("--"): + continue + + if not in_dollar: + tag = _find_dollar_tag(stripped) + if tag and tag.endswith("$") and tag.startswith("$"): + dollar_tag = tag + in_dollar = True + current.append(line) + continue + + if in_dollar and dollar_tag and stripped.startswith(dollar_tag): + after = stripped[len(dollar_tag):].strip() + if after == ";" or after == "": + in_dollar = False + dollar_tag = None + if after == ";": + current.append(line) + statements.append("\n".join(current)) + current = [] + continue + + if not in_dollar and stripped.rstrip().endswith(";"): + current.append(line) + statements.append("\n".join(current)) + current = [] + continue + + current.append(line) + + remaining = "\n".join(current).strip() + if remaining: + statements.append(remaining) + + return statements + + +def upgrade() -> None: + ddl_path = os.path.join(os.path.dirname(__file__), "sql", "0021_summary_views.sql") + with open(ddl_path) as f: + content = f.read() + + statements = _split_statements(content) + for stmt in statements: + stripped = stmt.strip().rstrip(";").strip() + if not stripped: + continue + if all(l.strip().startswith("--") or not l.strip() for l in stripped.split("\n")): + continue + op.execute(stripped) + + +def downgrade() -> None: + pass \ No newline at end of file diff --git a/api/alembic/versions/sql/0021_summary_views.sql b/api/alembic/versions/sql/0021_summary_views.sql new file mode 100644 index 0000000..fc4cd4e --- /dev/null +++ b/api/alembic/versions/sql/0021_summary_views.sql @@ -0,0 +1,1833 @@ +-- ============================================================================= +-- МИГРАЦИЯ: итоговые своды (зеркала листов «смета»/«свод» исходных форм) +-- Источник требований: «Свод 1 - АВРОРА - СУЖЦ ПО Confluence», раздел 10.3. +-- +-- * 1форм_ССП — форма «Смета ГО» (FORM_1): функция v_1form_ssp(p_year, p_org_unit_ids) + view v_1form_ssp +-- * 2форм_РФ_П — форма «РФ Поддержка» (FORM_2): функция v_2form_rf_p(p_year, p_org_unit_ids) + view v_2form_rf_p (только Поддержка) +-- * 3форм_РФ_Р — форма «Отчёт РФ развитие» (FORM_3): функция v_3form_rf_r(p_year, p_org_unit_ids) + view v_3form_rf_r (только Развитие) +-- * 4форм_ПРОЕКТ — форма «Проектная деятельность» (FORM_4): функция v_4form_project(p_year, p_org_unit_ids) + view v_4form_project (только Развитие) +-- * main_format — консолидированный свод: функция v_main_format(p_year, p_org_unit_ids) + view v_main_format +-- * v_summary_view — API-диспетчер по листам свода (sheet: FORM_1/FORM_2/FORM_3/FORM_4/MAIN) +-- ============================================================================= + +-- ============================================================================= +-- 1форм_ССП — ФУНКЦИЯ +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_1form_ssp(integer); + +CREATE OR REPLACE FUNCTION v3.v_1form_ssp(p_year integer, p_org_unit_ids integer[] DEFAULT NULL) + RETURNS TABLE( + section_code character varying, + name character varying, + plan_support_q1 numeric, + plan_support_q2 numeric, + plan_support_q3 numeric, + plan_support_q4 numeric, + plan_support_year numeric, + plan_development_q1 numeric, + plan_development_q2 numeric, + plan_development_q3 numeric, + plan_development_q4 numeric, + plan_development_year numeric, + plan_total_year numeric, + approved_support_q1 numeric, + approved_support_q2 numeric, + approved_support_q3 numeric, + approved_support_q4 numeric, + approved_support_year numeric, + approved_development_q1 numeric, + approved_development_q2 numeric, + approved_development_q3 numeric, + approved_development_q4 numeric, + approved_development_year numeric, + approved_total_year numeric, + fact_support_q1 numeric, + fact_support_q2 numeric, + fact_support_q3 numeric, + fact_support_q4 numeric, + fact_support_year numeric, + fact_development_q1 numeric, + fact_development_q2 numeric, + fact_development_q3 numeric, + fact_development_q4 numeric, + fact_development_year numeric, + fact_total_year numeric, + corrected_support_q2 numeric, + corrected_support_q3 numeric, + corrected_support_q4 numeric, + corrected_development_q2 numeric, + corrected_development_q3 numeric, + corrected_development_q4 numeric + ) + LANGUAGE sql + STABLE + SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH +form_lines AS ( + SELECT + bl.id AS line_id, + bl.expense_item_id AS eid, + CASE WHEN bl.direction = 'Development' THEN 'Development' ELSE 'Support' END AS bucket + FROM v3.budget_line AS bl + JOIN v3.budget_form AS bf ON bf.id = bl.budget_form_id + JOIN v3.expense_item AS ei ON ei.id = bl.expense_item_id + WHERE bf.form_type_code = 'FORM_1' + AND bf.year = p_year + AND ei.sheet IN ('AHR', 'CAP', 'OPER') + AND (p_org_unit_ids IS NULL OR cardinality(p_org_unit_ids) = 0 OR bf.org_unit_id = ANY(p_org_unit_ids)) +), +-- Квартальные данные, свёрнутые по строке (избегаем размножения при JOIN) +q_per_line AS ( + SELECT line_id, + SUM(CASE WHEN quarter = 1 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) + COALESCE(actual_spod, 0) END) AS fq4, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q2 END) AS t1q2, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q3 END) AS t1q3, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q4 END) AS t1q4, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q3 END) AS t2q3, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q4 END) AS t2q4, + SUM(CASE WHEN quarter = 3 THEN transfer_to_q4 END) AS t3q4, + SUM(CASE WHEN quarter = 2 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev4 + FROM v3.budget_line_quarter + GROUP BY line_id +), +-- Агрегаты уровня «статья × направление» +line_agg AS ( + SELECT + fl.eid, + fl.bucket, + SUM(p.plan_q1) AS pq1, SUM(p.plan_q2) AS pq2, SUM(p.plan_q3) AS pq3, SUM(p.plan_q4) AS pq4, + SUM(sd.adj_q1) AS sd1, SUM(sd.adj_q2) AS sd2, SUM(sd.adj_q3) AS sd3, SUM(sd.adj_q4) AS sd4, + SUM(r.amount_q1) AS rq1, SUM(r.amount_q2) AS rq2, SUM(r.amount_q3) AS rq3, SUM(r.amount_q4) AS rq4, + SUM(qp.fq1) AS fq1, SUM(qp.fq2) AS fq2, SUM(qp.fq3) AS fq3, SUM(qp.fq4) AS fq4, + SUM(qp.t1q2) AS t1q2, SUM(qp.t1q3) AS t1q3, SUM(qp.t1q4) AS t1q4, + SUM(qp.t2q3) AS t2q3, SUM(qp.t2q4) AS t2q4, SUM(qp.t3q4) AS t3q4, + SUM(qp.rev2) AS rev2, SUM(qp.rev3) AS rev3, SUM(qp.rev4) AS rev4 + FROM form_lines AS fl + LEFT JOIN v3.plan AS p ON p.line_id = fl.line_id + LEFT JOIN v3.sequestration AS sd ON sd.line_id = fl.line_id AND sd.actor = 'DFIP' + LEFT JOIN v3.reserve AS r ON r.line_id = fl.line_id + LEFT JOIN q_per_line AS qp ON qp.line_id = fl.line_id + GROUP BY fl.eid, fl.bucket +), +-- Узлы дерева, отображаемые на листе «смета» (ROOT/GROUP/ITEM) +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_1' + WHERE t.depth < 3 +), +-- Свёртка по иерархии: узел = сумма по всем потомкам +rolled AS ( + SELECT + tn.item_id, + tn.name, + SUM(a.pq1) FILTER (WHERE a.bucket = 'Support') AS s_pq1, + SUM(a.pq2) FILTER (WHERE a.bucket = 'Support') AS s_pq2, + SUM(a.pq3) FILTER (WHERE a.bucket = 'Support') AS s_pq3, + SUM(a.pq4) FILTER (WHERE a.bucket = 'Support') AS s_pq4, + SUM(a.sd1) FILTER (WHERE a.bucket = 'Support') AS s_sd1, + SUM(a.sd2) FILTER (WHERE a.bucket = 'Support') AS s_sd2, + SUM(a.sd3) FILTER (WHERE a.bucket = 'Support') AS s_sd3, + SUM(a.sd4) FILTER (WHERE a.bucket = 'Support') AS s_sd4, + SUM(a.rq1) FILTER (WHERE a.bucket = 'Support') AS s_rq1, + SUM(a.rq2) FILTER (WHERE a.bucket = 'Support') AS s_rq2, + SUM(a.rq3) FILTER (WHERE a.bucket = 'Support') AS s_rq3, + SUM(a.rq4) FILTER (WHERE a.bucket = 'Support') AS s_rq4, + SUM(a.fq1) FILTER (WHERE a.bucket = 'Support') AS s_fq1, + SUM(a.fq2) FILTER (WHERE a.bucket = 'Support') AS s_fq2, + SUM(a.fq3) FILTER (WHERE a.bucket = 'Support') AS s_fq3, + SUM(a.fq4) FILTER (WHERE a.bucket = 'Support') AS s_fq4, + SUM(a.t1q2) FILTER (WHERE a.bucket = 'Support') AS s_t1q2, + SUM(a.t1q3) FILTER (WHERE a.bucket = 'Support') AS s_t1q3, + SUM(a.t1q4) FILTER (WHERE a.bucket = 'Support') AS s_t1q4, + SUM(a.t2q3) FILTER (WHERE a.bucket = 'Support') AS s_t2q3, + SUM(a.t2q4) FILTER (WHERE a.bucket = 'Support') AS s_t2q4, + SUM(a.t3q4) FILTER (WHERE a.bucket = 'Support') AS s_t3q4, + SUM(a.rev2) FILTER (WHERE a.bucket = 'Support') AS s_rev2, + SUM(a.rev3) FILTER (WHERE a.bucket = 'Support') AS s_rev3, + SUM(a.rev4) FILTER (WHERE a.bucket = 'Support') AS s_rev4, + SUM(a.pq1) FILTER (WHERE a.bucket = 'Development') AS d_pq1, + SUM(a.pq2) FILTER (WHERE a.bucket = 'Development') AS d_pq2, + SUM(a.pq3) FILTER (WHERE a.bucket = 'Development') AS d_pq3, + SUM(a.pq4) FILTER (WHERE a.bucket = 'Development') AS d_pq4, + SUM(a.sd1) FILTER (WHERE a.bucket = 'Development') AS d_sd1, + SUM(a.sd2) FILTER (WHERE a.bucket = 'Development') AS d_sd2, + SUM(a.sd3) FILTER (WHERE a.bucket = 'Development') AS d_sd3, + SUM(a.sd4) FILTER (WHERE a.bucket = 'Development') AS d_sd4, + SUM(a.rq1) FILTER (WHERE a.bucket = 'Development') AS d_rq1, + SUM(a.rq2) FILTER (WHERE a.bucket = 'Development') AS d_rq2, + SUM(a.rq3) FILTER (WHERE a.bucket = 'Development') AS d_rq3, + SUM(a.rq4) FILTER (WHERE a.bucket = 'Development') AS d_rq4, + SUM(a.fq1) FILTER (WHERE a.bucket = 'Development') AS d_fq1, + SUM(a.fq2) FILTER (WHERE a.bucket = 'Development') AS d_fq2, + SUM(a.fq3) FILTER (WHERE a.bucket = 'Development') AS d_fq3, + SUM(a.fq4) FILTER (WHERE a.bucket = 'Development') AS d_fq4, + SUM(a.t1q2) FILTER (WHERE a.bucket = 'Development') AS d_t1q2, + SUM(a.t1q3) FILTER (WHERE a.bucket = 'Development') AS d_t1q3, + SUM(a.t1q4) FILTER (WHERE a.bucket = 'Development') AS d_t1q4, + SUM(a.t2q3) FILTER (WHERE a.bucket = 'Development') AS d_t2q3, + SUM(a.t2q4) FILTER (WHERE a.bucket = 'Development') AS d_t2q4, + SUM(a.t3q4) FILTER (WHERE a.bucket = 'Development') AS d_t3q4, + SUM(a.rev2) FILTER (WHERE a.bucket = 'Development') AS d_rev2, + SUM(a.rev3) FILTER (WHERE a.bucket = 'Development') AS d_rev3, + SUM(a.rev4) FILTER (WHERE a.bucket = 'Development') AS d_rev4 + FROM tree_nodes AS tn + LEFT JOIN line_agg AS a ON a.eid = ANY (tn.desc_ids) + GROUP BY tn.item_id, tn.name +) +SELECT + r.item_id AS section_code, + r.name, + COALESCE(r.s_pq1, 0) AS plan_support_q1, + COALESCE(r.s_pq2, 0) AS plan_support_q2, + COALESCE(r.s_pq3, 0) AS plan_support_q3, + COALESCE(r.s_pq4, 0) AS plan_support_q4, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_pq2, 0) + COALESCE(r.s_pq3, 0) + COALESCE(r.s_pq4, 0) AS plan_support_year, + COALESCE(r.d_pq1, 0) AS plan_development_q1, + COALESCE(r.d_pq2, 0) AS plan_development_q2, + COALESCE(r.d_pq3, 0) AS plan_development_q3, + COALESCE(r.d_pq4, 0) AS plan_development_q4, + COALESCE(r.d_pq1, 0) + COALESCE(r.d_pq2, 0) + COALESCE(r.d_pq3, 0) + COALESCE(r.d_pq4, 0) AS plan_development_year, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_pq2, 0) + COALESCE(r.s_pq3, 0) + COALESCE(r.s_pq4, 0) + + COALESCE(r.d_pq1, 0) + COALESCE(r.d_pq2, 0) + COALESCE(r.d_pq3, 0) + COALESCE(r.d_pq4, 0) AS plan_total_year, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_sd1, 0) + COALESCE(r.s_rq1, 0) AS approved_support_q1, + COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0) AS approved_support_q2, + COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0) AS approved_support_q3, + COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0) AS approved_support_q4, + (COALESCE(r.s_pq1, 0) + COALESCE(r.s_sd1, 0) + COALESCE(r.s_rq1, 0)) + + (COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0)) + + (COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0)) + + (COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0)) AS approved_support_year, + COALESCE(r.d_pq1, 0) + COALESCE(r.d_sd1, 0) + COALESCE(r.d_rq1, 0) AS approved_development_q1, + COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0) AS approved_development_q2, + COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0) AS approved_development_q3, + COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0) AS approved_development_q4, + (COALESCE(r.d_pq1, 0) + COALESCE(r.d_sd1, 0) + COALESCE(r.d_rq1, 0)) + + (COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0)) + + (COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0)) + + (COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0)) AS approved_development_year, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_sd1, 0) + COALESCE(r.s_rq1, 0) + + COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0) + + COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0) + + COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0) + + COALESCE(r.d_pq1, 0) + COALESCE(r.d_sd1, 0) + COALESCE(r.d_rq1, 0) + + COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0) + + COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0) + + COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0) AS approved_total_year, + COALESCE(r.s_fq1, 0) AS fact_support_q1, + COALESCE(r.s_fq2, 0) AS fact_support_q2, + COALESCE(r.s_fq3, 0) AS fact_support_q3, + COALESCE(r.s_fq4, 0) AS fact_support_q4, + COALESCE(r.s_fq1, 0) + COALESCE(r.s_fq2, 0) + COALESCE(r.s_fq3, 0) + COALESCE(r.s_fq4, 0) AS fact_support_year, + COALESCE(r.d_fq1, 0) AS fact_development_q1, + COALESCE(r.d_fq2, 0) AS fact_development_q2, + COALESCE(r.d_fq3, 0) AS fact_development_q3, + COALESCE(r.d_fq4, 0) AS fact_development_q4, + COALESCE(r.d_fq1, 0) + COALESCE(r.d_fq2, 0) + COALESCE(r.d_fq3, 0) + COALESCE(r.d_fq4, 0) AS fact_development_year, + COALESCE(r.s_fq1, 0) + COALESCE(r.s_fq2, 0) + COALESCE(r.s_fq3, 0) + COALESCE(r.s_fq4, 0) + + COALESCE(r.d_fq1, 0) + COALESCE(r.d_fq2, 0) + COALESCE(r.d_fq3, 0) + COALESCE(r.d_fq4, 0) AS fact_total_year, + COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0) + + COALESCE(r.s_t1q2, 0) + COALESCE(r.s_rev2, 0) AS corrected_support_q2, + COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0) + + COALESCE(r.s_t1q3, 0) + COALESCE(r.s_t2q3, 0) + COALESCE(r.s_rev3, 0) AS corrected_support_q3, + COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0) + + COALESCE(r.s_t1q4, 0) + COALESCE(r.s_t2q4, 0) + COALESCE(r.s_t3q4, 0) + COALESCE(r.s_rev4, 0) AS corrected_support_q4, + COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0) + + COALESCE(r.d_t1q2, 0) + COALESCE(r.d_rev2, 0) AS corrected_development_q2, + COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0) + + COALESCE(r.d_t1q3, 0) + COALESCE(r.d_t2q3, 0) + COALESCE(r.d_rev3, 0) AS corrected_development_q3, + COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0) + + COALESCE(r.d_t1q4, 0) + COALESCE(r.d_t2q4, 0) + COALESCE(r.d_t3q4, 0) + COALESCE(r.d_rev4, 0) AS corrected_development_q4 +FROM rolled AS r; +$function$; + +-- ============================================================================= +-- 1форм_ССП — VIEW +-- ============================================================================= + +-- DROP VIEW IF EXISTS v3.v_1form_ssp; + +CREATE OR REPLACE VIEW v3.v_1form_ssp AS +WITH +form_lines AS ( + SELECT + bf.year, + bl.id AS line_id, + bl.expense_item_id AS eid, + CASE WHEN bl.direction = 'Development' THEN 'Development' ELSE 'Support' END AS bucket + FROM v3.budget_line AS bl + JOIN v3.budget_form AS bf ON bf.id = bl.budget_form_id + JOIN v3.expense_item AS ei ON ei.id = bl.expense_item_id + WHERE bf.form_type_code = 'FORM_1' + AND ei.sheet IN ('AHR', 'CAP', 'OPER') +), +q_per_line AS ( + SELECT line_id, + SUM(CASE WHEN quarter = 1 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) + COALESCE(actual_spod, 0) END) AS fq4, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q2 END) AS t1q2, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q3 END) AS t1q3, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q4 END) AS t1q4, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q3 END) AS t2q3, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q4 END) AS t2q4, + SUM(CASE WHEN quarter = 3 THEN transfer_to_q4 END) AS t3q4, + SUM(CASE WHEN quarter = 2 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev4 + FROM v3.budget_line_quarter + GROUP BY line_id +), +line_agg AS ( + SELECT + fl.year, + fl.eid, + fl.bucket, + SUM(p.plan_q1) AS pq1, SUM(p.plan_q2) AS pq2, SUM(p.plan_q3) AS pq3, SUM(p.plan_q4) AS pq4, + SUM(sd.adj_q1) AS sd1, SUM(sd.adj_q2) AS sd2, SUM(sd.adj_q3) AS sd3, SUM(sd.adj_q4) AS sd4, + SUM(r.amount_q1) AS rq1, SUM(r.amount_q2) AS rq2, SUM(r.amount_q3) AS rq3, SUM(r.amount_q4) AS rq4, + SUM(qp.fq1) AS fq1, SUM(qp.fq2) AS fq2, SUM(qp.fq3) AS fq3, SUM(qp.fq4) AS fq4, + SUM(qp.t1q2) AS t1q2, SUM(qp.t1q3) AS t1q3, SUM(qp.t1q4) AS t1q4, + SUM(qp.t2q3) AS t2q3, SUM(qp.t2q4) AS t2q4, SUM(qp.t3q4) AS t3q4, + SUM(qp.rev2) AS rev2, SUM(qp.rev3) AS rev3, SUM(qp.rev4) AS rev4 + FROM form_lines AS fl + LEFT JOIN v3.plan AS p ON p.line_id = fl.line_id + LEFT JOIN v3.sequestration AS sd ON sd.line_id = fl.line_id AND sd.actor = 'DFIP' + LEFT JOIN v3.reserve AS r ON r.line_id = fl.line_id + LEFT JOIN q_per_line AS qp ON qp.line_id = fl.line_id + GROUP BY fl.year, fl.eid, fl.bucket +), +years AS ( + SELECT DISTINCT bf.year + FROM v3.budget_form AS bf + WHERE bf.form_type_code = 'FORM_1' +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_1' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + y.year, + tn.item_id, + tn.name, + SUM(a.pq1) FILTER (WHERE a.bucket = 'Support') AS s_pq1, + SUM(a.pq2) FILTER (WHERE a.bucket = 'Support') AS s_pq2, + SUM(a.pq3) FILTER (WHERE a.bucket = 'Support') AS s_pq3, + SUM(a.pq4) FILTER (WHERE a.bucket = 'Support') AS s_pq4, + SUM(a.sd1) FILTER (WHERE a.bucket = 'Support') AS s_sd1, + SUM(a.sd2) FILTER (WHERE a.bucket = 'Support') AS s_sd2, + SUM(a.sd3) FILTER (WHERE a.bucket = 'Support') AS s_sd3, + SUM(a.sd4) FILTER (WHERE a.bucket = 'Support') AS s_sd4, + SUM(a.rq1) FILTER (WHERE a.bucket = 'Support') AS s_rq1, + SUM(a.rq2) FILTER (WHERE a.bucket = 'Support') AS s_rq2, + SUM(a.rq3) FILTER (WHERE a.bucket = 'Support') AS s_rq3, + SUM(a.rq4) FILTER (WHERE a.bucket = 'Support') AS s_rq4, + SUM(a.fq1) FILTER (WHERE a.bucket = 'Support') AS s_fq1, + SUM(a.fq2) FILTER (WHERE a.bucket = 'Support') AS s_fq2, + SUM(a.fq3) FILTER (WHERE a.bucket = 'Support') AS s_fq3, + SUM(a.fq4) FILTER (WHERE a.bucket = 'Support') AS s_fq4, + SUM(a.t1q2) FILTER (WHERE a.bucket = 'Support') AS s_t1q2, + SUM(a.t1q3) FILTER (WHERE a.bucket = 'Support') AS s_t1q3, + SUM(a.t1q4) FILTER (WHERE a.bucket = 'Support') AS s_t1q4, + SUM(a.t2q3) FILTER (WHERE a.bucket = 'Support') AS s_t2q3, + SUM(a.t2q4) FILTER (WHERE a.bucket = 'Support') AS s_t2q4, + SUM(a.t3q4) FILTER (WHERE a.bucket = 'Support') AS s_t3q4, + SUM(a.rev2) FILTER (WHERE a.bucket = 'Support') AS s_rev2, + SUM(a.rev3) FILTER (WHERE a.bucket = 'Support') AS s_rev3, + SUM(a.rev4) FILTER (WHERE a.bucket = 'Support') AS s_rev4, + SUM(a.pq1) FILTER (WHERE a.bucket = 'Development') AS d_pq1, + SUM(a.pq2) FILTER (WHERE a.bucket = 'Development') AS d_pq2, + SUM(a.pq3) FILTER (WHERE a.bucket = 'Development') AS d_pq3, + SUM(a.pq4) FILTER (WHERE a.bucket = 'Development') AS d_pq4, + SUM(a.sd1) FILTER (WHERE a.bucket = 'Development') AS d_sd1, + SUM(a.sd2) FILTER (WHERE a.bucket = 'Development') AS d_sd2, + SUM(a.sd3) FILTER (WHERE a.bucket = 'Development') AS d_sd3, + SUM(a.sd4) FILTER (WHERE a.bucket = 'Development') AS d_sd4, + SUM(a.rq1) FILTER (WHERE a.bucket = 'Development') AS d_rq1, + SUM(a.rq2) FILTER (WHERE a.bucket = 'Development') AS d_rq2, + SUM(a.rq3) FILTER (WHERE a.bucket = 'Development') AS d_rq3, + SUM(a.rq4) FILTER (WHERE a.bucket = 'Development') AS d_rq4, + SUM(a.fq1) FILTER (WHERE a.bucket = 'Development') AS d_fq1, + SUM(a.fq2) FILTER (WHERE a.bucket = 'Development') AS d_fq2, + SUM(a.fq3) FILTER (WHERE a.bucket = 'Development') AS d_fq3, + SUM(a.fq4) FILTER (WHERE a.bucket = 'Development') AS d_fq4, + SUM(a.t1q2) FILTER (WHERE a.bucket = 'Development') AS d_t1q2, + SUM(a.t1q3) FILTER (WHERE a.bucket = 'Development') AS d_t1q3, + SUM(a.t1q4) FILTER (WHERE a.bucket = 'Development') AS d_t1q4, + SUM(a.t2q3) FILTER (WHERE a.bucket = 'Development') AS d_t2q3, + SUM(a.t2q4) FILTER (WHERE a.bucket = 'Development') AS d_t2q4, + SUM(a.t3q4) FILTER (WHERE a.bucket = 'Development') AS d_t3q4, + SUM(a.rev2) FILTER (WHERE a.bucket = 'Development') AS d_rev2, + SUM(a.rev3) FILTER (WHERE a.bucket = 'Development') AS d_rev3, + SUM(a.rev4) FILTER (WHERE a.bucket = 'Development') AS d_rev4 + FROM tree_nodes AS tn + CROSS JOIN years AS y + LEFT JOIN line_agg AS a + ON a.eid = ANY (tn.desc_ids) + AND a.year = y.year + GROUP BY y.year, tn.item_id, tn.name +) +SELECT + r.year, + r.item_id AS section_code, + r.name, + COALESCE(r.s_pq1, 0) AS plan_support_q1, + COALESCE(r.s_pq2, 0) AS plan_support_q2, + COALESCE(r.s_pq3, 0) AS plan_support_q3, + COALESCE(r.s_pq4, 0) AS plan_support_q4, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_pq2, 0) + COALESCE(r.s_pq3, 0) + COALESCE(r.s_pq4, 0) AS plan_support_year, + COALESCE(r.d_pq1, 0) AS plan_development_q1, + COALESCE(r.d_pq2, 0) AS plan_development_q2, + COALESCE(r.d_pq3, 0) AS plan_development_q3, + COALESCE(r.d_pq4, 0) AS plan_development_q4, + COALESCE(r.d_pq1, 0) + COALESCE(r.d_pq2, 0) + COALESCE(r.d_pq3, 0) + COALESCE(r.d_pq4, 0) AS plan_development_year, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_pq2, 0) + COALESCE(r.s_pq3, 0) + COALESCE(r.s_pq4, 0) + + COALESCE(r.d_pq1, 0) + COALESCE(r.d_pq2, 0) + COALESCE(r.d_pq3, 0) + COALESCE(r.d_pq4, 0) AS plan_total_year, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_sd1, 0) + COALESCE(r.s_rq1, 0) AS approved_support_q1, + COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0) AS approved_support_q2, + COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0) AS approved_support_q3, + COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0) AS approved_support_q4, + (COALESCE(r.s_pq1, 0) + COALESCE(r.s_sd1, 0) + COALESCE(r.s_rq1, 0)) + + (COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0)) + + (COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0)) + + (COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0)) AS approved_support_year, + COALESCE(r.d_pq1, 0) + COALESCE(r.d_sd1, 0) + COALESCE(r.d_rq1, 0) AS approved_development_q1, + COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0) AS approved_development_q2, + COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0) AS approved_development_q3, + COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0) AS approved_development_q4, + (COALESCE(r.d_pq1, 0) + COALESCE(r.d_sd1, 0) + COALESCE(r.d_rq1, 0)) + + (COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0)) + + (COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0)) + + (COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0)) AS approved_development_year, + COALESCE(r.s_pq1, 0) + COALESCE(r.s_sd1, 0) + COALESCE(r.s_rq1, 0) + + COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0) + + COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0) + + COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0) + + COALESCE(r.d_pq1, 0) + COALESCE(r.d_sd1, 0) + COALESCE(r.d_rq1, 0) + + COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0) + + COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0) + + COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0) AS approved_total_year, + COALESCE(r.s_fq1, 0) AS fact_support_q1, + COALESCE(r.s_fq2, 0) AS fact_support_q2, + COALESCE(r.s_fq3, 0) AS fact_support_q3, + COALESCE(r.s_fq4, 0) AS fact_support_q4, + COALESCE(r.s_fq1, 0) + COALESCE(r.s_fq2, 0) + COALESCE(r.s_fq3, 0) + COALESCE(r.s_fq4, 0) AS fact_support_year, + COALESCE(r.d_fq1, 0) AS fact_development_q1, + COALESCE(r.d_fq2, 0) AS fact_development_q2, + COALESCE(r.d_fq3, 0) AS fact_development_q3, + COALESCE(r.d_fq4, 0) AS fact_development_q4, + COALESCE(r.d_fq1, 0) + COALESCE(r.d_fq2, 0) + COALESCE(r.d_fq3, 0) + COALESCE(r.d_fq4, 0) AS fact_development_year, + COALESCE(r.s_fq1, 0) + COALESCE(r.s_fq2, 0) + COALESCE(r.s_fq3, 0) + COALESCE(r.s_fq4, 0) + + COALESCE(r.d_fq1, 0) + COALESCE(r.d_fq2, 0) + COALESCE(r.d_fq3, 0) + COALESCE(r.d_fq4, 0) AS fact_total_year, + COALESCE(r.s_pq2, 0) + COALESCE(r.s_sd2, 0) + COALESCE(r.s_rq2, 0) + + COALESCE(r.s_t1q2, 0) + COALESCE(r.s_rev2, 0) AS corrected_support_q2, + COALESCE(r.s_pq3, 0) + COALESCE(r.s_sd3, 0) + COALESCE(r.s_rq3, 0) + + COALESCE(r.s_t1q3, 0) + COALESCE(r.s_t2q3, 0) + COALESCE(r.s_rev3, 0) AS corrected_support_q3, + COALESCE(r.s_pq4, 0) + COALESCE(r.s_sd4, 0) + COALESCE(r.s_rq4, 0) + + COALESCE(r.s_t1q4, 0) + COALESCE(r.s_t2q4, 0) + COALESCE(r.s_t3q4, 0) + COALESCE(r.s_rev4, 0) AS corrected_support_q4, + COALESCE(r.d_pq2, 0) + COALESCE(r.d_sd2, 0) + COALESCE(r.d_rq2, 0) + + COALESCE(r.d_t1q2, 0) + COALESCE(r.d_rev2, 0) AS corrected_development_q2, + COALESCE(r.d_pq3, 0) + COALESCE(r.d_sd3, 0) + COALESCE(r.d_rq3, 0) + + COALESCE(r.d_t1q3, 0) + COALESCE(r.d_t2q3, 0) + COALESCE(r.d_rev3, 0) AS corrected_development_q3, + COALESCE(r.d_pq4, 0) + COALESCE(r.d_sd4, 0) + COALESCE(r.d_rq4, 0) + + COALESCE(r.d_t1q4, 0) + COALESCE(r.d_t2q4, 0) + COALESCE(r.d_t3q4, 0) + COALESCE(r.d_rev4, 0) AS corrected_development_q4 +FROM rolled AS r; + +-- ============================================================================= +-- 2форм_РФ_П — ФУНКЦИЯ +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_2form_rf_p(integer); + +CREATE OR REPLACE FUNCTION v3.v_2form_rf_p(p_year integer, p_org_unit_ids integer[] DEFAULT NULL) + RETURNS TABLE( + section_code character varying, + name character varying, + plan_support_q1 numeric, + plan_support_q2 numeric, + plan_support_q3 numeric, + plan_support_q4 numeric, + plan_support_year numeric, + approved_support_q1 numeric, + approved_support_q2 numeric, + approved_support_q3 numeric, + approved_support_q4 numeric, + approved_support_year numeric, + fact_support_q1 numeric, + fact_support_q2 numeric, + fact_support_q3 numeric, + fact_support_q4 numeric, + fact_support_year numeric, + corrected_support_q2 numeric, + corrected_support_q3 numeric, + corrected_support_q4 numeric + ) + LANGUAGE sql + STABLE + SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH +form_lines AS ( + SELECT bl.id AS line_id, bl.expense_item_id AS eid + FROM v3.budget_line AS bl + JOIN v3.budget_form AS bf ON bf.id = bl.budget_form_id + JOIN v3.expense_item AS ei ON ei.id = bl.expense_item_id + WHERE bf.form_type_code = 'FORM_2' + AND bf.year = p_year + AND ei.sheet IN ('AHR', 'CAP', 'OPER') + AND (p_org_unit_ids IS NULL OR cardinality(p_org_unit_ids) = 0 OR bf.org_unit_id = ANY(p_org_unit_ids)) +), +q_per_line AS ( + SELECT line_id, + SUM(CASE WHEN quarter = 1 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) + COALESCE(actual_spod, 0) END) AS fq4, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q2 END) AS t1q2, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q3 END) AS t1q3, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q4 END) AS t1q4, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q3 END) AS t2q3, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q4 END) AS t2q4, + SUM(CASE WHEN quarter = 3 THEN transfer_to_q4 END) AS t3q4, + SUM(CASE WHEN quarter = 1 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj4, + SUM(CASE WHEN quarter = 2 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev4 + FROM v3.budget_line_quarter + GROUP BY line_id +), +line_agg AS ( + SELECT + fl.eid, + SUM(p.plan_q1) AS pq1, SUM(p.plan_q2) AS pq2, SUM(p.plan_q3) AS pq3, SUM(p.plan_q4) AS pq4, + SUM(sd.adj_q1) AS sd1, SUM(sd.adj_q2) AS sd2, SUM(sd.adj_q3) AS sd3, SUM(sd.adj_q4) AS sd4, + SUM(sg.adj_q1) AS sg1, SUM(sg.adj_q2) AS sg2, SUM(sg.adj_q3) AS sg3, SUM(sg.adj_q4) AS sg4, + SUM(r.amount_q1) AS rq1, SUM(r.amount_q2) AS rq2, SUM(r.amount_q3) AS rq3, SUM(r.amount_q4) AS rq4, + SUM(qp.fq1) AS fq1, SUM(qp.fq2) AS fq2, SUM(qp.fq3) AS fq3, SUM(qp.fq4) AS fq4, + SUM(qp.t1q2) AS t1q2, SUM(qp.t1q3) AS t1q3, SUM(qp.t1q4) AS t1q4, + SUM(qp.t2q3) AS t2q3, SUM(qp.t2q4) AS t2q4, SUM(qp.t3q4) AS t3q4, + SUM(qp.adj1) AS adj1, SUM(qp.adj2) AS adj2, SUM(qp.adj3) AS adj3, SUM(qp.adj4) AS adj4, + SUM(qp.rev2) AS rev2, SUM(qp.rev3) AS rev3, SUM(qp.rev4) AS rev4 + FROM form_lines AS fl + LEFT JOIN v3.plan AS p ON p.line_id = fl.line_id + LEFT JOIN v3.sequestration AS sd ON sd.line_id = fl.line_id AND sd.actor = 'DFIP' + LEFT JOIN v3.sequestration AS sg ON sg.line_id = fl.line_id AND sg.actor = 'SSP_GO' + LEFT JOIN v3.reserve AS r ON r.line_id = fl.line_id + LEFT JOIN q_per_line AS qp ON qp.line_id = fl.line_id + GROUP BY fl.eid +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_2' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + tn.item_id, + tn.name, + SUM(a.pq1) AS pq1, SUM(a.pq2) AS pq2, SUM(a.pq3) AS pq3, SUM(a.pq4) AS pq4, + SUM(a.sd1) AS sd1, SUM(a.sd2) AS sd2, SUM(a.sd3) AS sd3, SUM(a.sd4) AS sd4, + SUM(a.sg1) AS sg1, SUM(a.sg2) AS sg2, SUM(a.sg3) AS sg3, SUM(a.sg4) AS sg4, + SUM(a.rq1) AS rq1, SUM(a.rq2) AS rq2, SUM(a.rq3) AS rq3, SUM(a.rq4) AS rq4, + SUM(a.fq1) AS fq1, SUM(a.fq2) AS fq2, SUM(a.fq3) AS fq3, SUM(a.fq4) AS fq4, + SUM(a.t1q2) AS t1q2, SUM(a.t1q3) AS t1q3, SUM(a.t1q4) AS t1q4, + SUM(a.t2q3) AS t2q3, SUM(a.t2q4) AS t2q4, SUM(a.t3q4) AS t3q4, + SUM(a.adj1) AS adj1, SUM(a.adj2) AS adj2, SUM(a.adj3) AS adj3, SUM(a.adj4) AS adj4, + SUM(a.rev2) AS rev2, SUM(a.rev3) AS rev3, SUM(a.rev4) AS rev4 + FROM tree_nodes AS tn + LEFT JOIN line_agg AS a ON a.eid = ANY (tn.desc_ids) + GROUP BY tn.item_id, tn.name +) +SELECT + r.item_id AS section_code, r.name, + COALESCE(r.pq1, 0) AS plan_support_q1, COALESCE(r.pq2, 0) AS plan_support_q2, COALESCE(r.pq3, 0) AS plan_support_q3, COALESCE(r.pq4, 0) AS plan_support_q4, + COALESCE(r.pq1, 0) + COALESCE(r.pq2, 0) + COALESCE(r.pq3, 0) + COALESCE(r.pq4, 0) AS plan_support_year, + COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0) AS approved_support_q1, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) AS approved_support_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) AS approved_support_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) AS approved_support_q4, + (COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0)) + + (COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0)) + + (COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0)) + + (COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0)) AS approved_support_year, + COALESCE(r.fq1, 0) AS fact_support_q1, COALESCE(r.fq2, 0) AS fact_support_q2, COALESCE(r.fq3, 0) AS fact_support_q3, COALESCE(r.fq4, 0) AS fact_support_q4, + COALESCE(r.fq1, 0) + COALESCE(r.fq2, 0) + COALESCE(r.fq3, 0) + COALESCE(r.fq4, 0) AS fact_support_year, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) + + COALESCE(r.t1q2, 0) + COALESCE(r.rev2, 0) + COALESCE(r.adj2, 0) AS corrected_support_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) + + COALESCE(r.t1q3, 0) + COALESCE(r.t2q3, 0) + COALESCE(r.rev3, 0) + COALESCE(r.adj3, 0) AS corrected_support_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) + + COALESCE(r.t1q4, 0) + COALESCE(r.t2q4, 0) + COALESCE(r.t3q4, 0) + COALESCE(r.rev4, 0) + COALESCE(r.adj4, 0) AS corrected_support_q4 +FROM rolled AS r; +$function$; + +-- ============================================================================= +-- 2форм_РФ_П — VIEW +-- ============================================================================= + +DROP VIEW IF EXISTS v3.v_2form_rf_p CASCADE; + +CREATE OR REPLACE VIEW v3.v_2form_rf_p AS +WITH +form_lines AS ( + SELECT bf.year, bl.id AS line_id, bl.expense_item_id AS eid + FROM v3.budget_line AS bl + JOIN v3.budget_form AS bf ON bf.id = bl.budget_form_id + JOIN v3.expense_item AS ei ON ei.id = bl.expense_item_id + WHERE bf.form_type_code = 'FORM_2' + AND ei.sheet IN ('AHR', 'CAP', 'OPER') +), +q_per_line AS ( + SELECT line_id, + SUM(CASE WHEN quarter = 1 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) + COALESCE(actual_spod, 0) END) AS fq4, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q2 END) AS t1q2, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q3 END) AS t1q3, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q4 END) AS t1q4, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q3 END) AS t2q3, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q4 END) AS t2q4, + SUM(CASE WHEN quarter = 3 THEN transfer_to_q4 END) AS t3q4, + SUM(CASE WHEN quarter = 1 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj4, + SUM(CASE WHEN quarter = 2 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(plan_revision_eco_change, 0) + COALESCE(plan_revision_item_adj, 0) + COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) END) AS rev4 + FROM v3.budget_line_quarter + GROUP BY line_id +), +line_agg AS ( + SELECT + fl.year, + fl.eid, + SUM(p.plan_q1) AS pq1, SUM(p.plan_q2) AS pq2, SUM(p.plan_q3) AS pq3, SUM(p.plan_q4) AS pq4, + SUM(sd.adj_q1) AS sd1, SUM(sd.adj_q2) AS sd2, SUM(sd.adj_q3) AS sd3, SUM(sd.adj_q4) AS sd4, + SUM(sg.adj_q1) AS sg1, SUM(sg.adj_q2) AS sg2, SUM(sg.adj_q3) AS sg3, SUM(sg.adj_q4) AS sg4, + SUM(r.amount_q1) AS rq1, SUM(r.amount_q2) AS rq2, SUM(r.amount_q3) AS rq3, SUM(r.amount_q4) AS rq4, + SUM(qp.fq1) AS fq1, SUM(qp.fq2) AS fq2, SUM(qp.fq3) AS fq3, SUM(qp.fq4) AS fq4, + SUM(qp.t1q2) AS t1q2, SUM(qp.t1q3) AS t1q3, SUM(qp.t1q4) AS t1q4, + SUM(qp.t2q3) AS t2q3, SUM(qp.t2q4) AS t2q4, SUM(qp.t3q4) AS t3q4, + SUM(qp.adj1) AS adj1, SUM(qp.adj2) AS adj2, SUM(qp.adj3) AS adj3, SUM(qp.adj4) AS adj4, + SUM(qp.rev2) AS rev2, SUM(qp.rev3) AS rev3, SUM(qp.rev4) AS rev4 + FROM form_lines AS fl + LEFT JOIN v3.plan AS p ON p.line_id = fl.line_id + LEFT JOIN v3.sequestration AS sd ON sd.line_id = fl.line_id AND sd.actor = 'DFIP' + LEFT JOIN v3.sequestration AS sg ON sg.line_id = fl.line_id AND sg.actor = 'SSP_GO' + LEFT JOIN v3.reserve AS r ON r.line_id = fl.line_id + LEFT JOIN q_per_line AS qp ON qp.line_id = fl.line_id + GROUP BY fl.year, fl.eid +), +years AS ( + SELECT DISTINCT bf.year + FROM v3.budget_form AS bf + WHERE bf.form_type_code = 'FORM_2' +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_2' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + y.year, + tn.item_id, + tn.name, + SUM(a.pq1) AS pq1, SUM(a.pq2) AS pq2, SUM(a.pq3) AS pq3, SUM(a.pq4) AS pq4, + SUM(a.sd1) AS sd1, SUM(a.sd2) AS sd2, SUM(a.sd3) AS sd3, SUM(a.sd4) AS sd4, + SUM(a.sg1) AS sg1, SUM(a.sg2) AS sg2, SUM(a.sg3) AS sg3, SUM(a.sg4) AS sg4, + SUM(a.rq1) AS rq1, SUM(a.rq2) AS rq2, SUM(a.rq3) AS rq3, SUM(a.rq4) AS rq4, + SUM(a.fq1) AS fq1, SUM(a.fq2) AS fq2, SUM(a.fq3) AS fq3, SUM(a.fq4) AS fq4, + SUM(a.t1q2) AS t1q2, SUM(a.t1q3) AS t1q3, SUM(a.t1q4) AS t1q4, + SUM(a.t2q3) AS t2q3, SUM(a.t2q4) AS t2q4, SUM(a.t3q4) AS t3q4, + SUM(a.adj1) AS adj1, SUM(a.adj2) AS adj2, SUM(a.adj3) AS adj3, SUM(a.adj4) AS adj4, + SUM(a.rev2) AS rev2, SUM(a.rev3) AS rev3, SUM(a.rev4) AS rev4 + FROM tree_nodes AS tn + CROSS JOIN years AS y + LEFT JOIN line_agg AS a ON a.eid = ANY (tn.desc_ids) AND a.year = y.year + GROUP BY y.year, tn.item_id, tn.name +) +SELECT + r.year, r.item_id AS section_code, r.name, + COALESCE(r.pq1, 0) AS plan_support_q1, COALESCE(r.pq2, 0) AS plan_support_q2, COALESCE(r.pq3, 0) AS plan_support_q3, COALESCE(r.pq4, 0) AS plan_support_q4, + COALESCE(r.pq1, 0) + COALESCE(r.pq2, 0) + COALESCE(r.pq3, 0) + COALESCE(r.pq4, 0) AS plan_support_year, + COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0) AS approved_support_q1, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) AS approved_support_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) AS approved_support_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) AS approved_support_q4, + (COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0)) + + (COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0)) + + (COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0)) + + (COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0)) AS approved_support_year, + COALESCE(r.fq1, 0) AS fact_support_q1, COALESCE(r.fq2, 0) AS fact_support_q2, COALESCE(r.fq3, 0) AS fact_support_q3, COALESCE(r.fq4, 0) AS fact_support_q4, + COALESCE(r.fq1, 0) + COALESCE(r.fq2, 0) + COALESCE(r.fq3, 0) + COALESCE(r.fq4, 0) AS fact_support_year, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) + + COALESCE(r.t1q2, 0) + COALESCE(r.rev2, 0) + COALESCE(r.adj2, 0) AS corrected_support_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) + + COALESCE(r.t1q3, 0) + COALESCE(r.t2q3, 0) + COALESCE(r.rev3, 0) + COALESCE(r.adj3, 0) AS corrected_support_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) + + COALESCE(r.t1q4, 0) + COALESCE(r.t2q4, 0) + COALESCE(r.t3q4, 0) + COALESCE(r.rev4, 0) + COALESCE(r.adj4, 0) AS corrected_support_q4 +FROM rolled AS r; + +-- ============================================================================= +-- 3форм_РФ_Р — ФУНКЦИЯ +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_3form_rf_r(integer); + +CREATE OR REPLACE FUNCTION v3.v_3form_rf_r(p_year integer, p_org_unit_ids integer[] DEFAULT NULL) + RETURNS TABLE( + section_code character varying, + name character varying, + plan_development_q1 numeric, + plan_development_q2 numeric, + plan_development_q3 numeric, + plan_development_q4 numeric, + plan_development_year numeric, + approved_development_q1 numeric, + approved_development_q2 numeric, + approved_development_q3 numeric, + approved_development_q4 numeric, + approved_development_year numeric, + fact_development_q1 numeric, + fact_development_q2 numeric, + fact_development_q3 numeric, + fact_development_q4 numeric, + fact_development_year numeric, + corrected_development_q2 numeric, + corrected_development_q3 numeric, + corrected_development_q4 numeric + ) + LANGUAGE sql + STABLE + SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH +-- Источник данных: отчёт РФ развитие (FORM_3). Направление всегда «Развитие». +-- Маппинг на структуру листа «2форм_РФ_П»: +-- план = base_plan +-- утверждено = base_plan + adj_by_items + adj_increase +-- факт = actual_m1 + actual_m2 + actual_m3 (+ actual_spod в Q4) +-- скорректировано = corrected_plan (II–IV квартал) +report_lines AS ( + SELECT + l.expense_item_id AS eid, + q.quarter, + q.base_plan, + q.adj_by_items, + q.adj_increase, + q.actual_m1, + q.actual_m2, + q.actual_m3, + q.actual_spod, + q.corrected_plan + FROM v3.rf_project_report AS r + JOIN v3.rf_project_year AS rpry ON rpry.id = r.rf_project_year_id + JOIN v3.project AS p ON p.id = r.project_id + JOIN v3.rf_project_report_line AS l ON l.rf_project_report_id = r.id + JOIN v3.rf_project_report_quarter AS q ON q.rf_project_report_line_id = l.id + WHERE rpry.year = p_year + AND (p_org_unit_ids IS NULL OR cardinality(p_org_unit_ids) = 0 OR p.org_unit_id = ANY(p_org_unit_ids)) +), +agg AS ( + SELECT + eid, + SUM(CASE WHEN quarter = 1 THEN base_plan END) AS bp1, + SUM(CASE WHEN quarter = 2 THEN base_plan END) AS bp2, + SUM(CASE WHEN quarter = 3 THEN base_plan END) AS bp3, + SUM(CASE WHEN quarter = 4 THEN base_plan END) AS bp4, + SUM(CASE WHEN quarter = 1 THEN adj_by_items END) AS abi1, + SUM(CASE WHEN quarter = 2 THEN adj_by_items END) AS abi2, + SUM(CASE WHEN quarter = 3 THEN adj_by_items END) AS abi3, + SUM(CASE WHEN quarter = 4 THEN adj_by_items END) AS abi4, + SUM(CASE WHEN quarter = 1 THEN adj_increase END) AS ai1, + SUM(CASE WHEN quarter = 2 THEN adj_increase END) AS ai2, + SUM(CASE WHEN quarter = 3 THEN adj_increase END) AS ai3, + SUM(CASE WHEN quarter = 4 THEN adj_increase END) AS ai4, + SUM(CASE WHEN quarter = 1 THEN actual_m1 END) AS m1_1, + SUM(CASE WHEN quarter = 2 THEN actual_m1 END) AS m1_2, + SUM(CASE WHEN quarter = 3 THEN actual_m1 END) AS m1_3, + SUM(CASE WHEN quarter = 4 THEN actual_m1 END) AS m1_4, + SUM(CASE WHEN quarter = 1 THEN actual_m2 END) AS m2_1, + SUM(CASE WHEN quarter = 2 THEN actual_m2 END) AS m2_2, + SUM(CASE WHEN quarter = 3 THEN actual_m2 END) AS m2_3, + SUM(CASE WHEN quarter = 4 THEN actual_m2 END) AS m2_4, + SUM(CASE WHEN quarter = 1 THEN actual_m3 END) AS m3_1, + SUM(CASE WHEN quarter = 2 THEN actual_m3 END) AS m3_2, + SUM(CASE WHEN quarter = 3 THEN actual_m3 END) AS m3_3, + SUM(CASE WHEN quarter = 4 THEN actual_m3 END) AS m3_4, + SUM(CASE WHEN quarter = 4 THEN actual_spod END) AS spod4, + SUM(CASE WHEN quarter = 2 THEN corrected_plan END) AS cp2, + SUM(CASE WHEN quarter = 3 THEN corrected_plan END) AS cp3, + SUM(CASE WHEN quarter = 4 THEN corrected_plan END) AS cp4 + FROM report_lines + GROUP BY eid +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_3' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + tn.item_id, + tn.name, + SUM(a.bp1) AS bp1, SUM(a.bp2) AS bp2, SUM(a.bp3) AS bp3, SUM(a.bp4) AS bp4, + SUM(a.abi1) AS abi1, SUM(a.abi2) AS abi2, SUM(a.abi3) AS abi3, SUM(a.abi4) AS abi4, + SUM(a.ai1) AS ai1, SUM(a.ai2) AS ai2, SUM(a.ai3) AS ai3, SUM(a.ai4) AS ai4, + SUM(a.m1_1) AS m1_1, SUM(a.m1_2) AS m1_2, SUM(a.m1_3) AS m1_3, SUM(a.m1_4) AS m1_4, + SUM(a.m2_1) AS m2_1, SUM(a.m2_2) AS m2_2, SUM(a.m2_3) AS m2_3, SUM(a.m2_4) AS m2_4, + SUM(a.m3_1) AS m3_1, SUM(a.m3_2) AS m3_2, SUM(a.m3_3) AS m3_3, SUM(a.m3_4) AS m3_4, + SUM(a.spod4) AS spod4, + SUM(a.cp2) AS cp2, SUM(a.cp3) AS cp3, SUM(a.cp4) AS cp4 + FROM tree_nodes AS tn + LEFT JOIN agg AS a ON a.eid = ANY (tn.desc_ids) + GROUP BY tn.item_id, tn.name +) +SELECT + r.item_id AS section_code, + r.name, + COALESCE(r.bp1, 0) AS plan_development_q1, + COALESCE(r.bp2, 0) AS plan_development_q2, + COALESCE(r.bp3, 0) AS plan_development_q3, + COALESCE(r.bp4, 0) AS plan_development_q4, + COALESCE(r.bp1, 0) + COALESCE(r.bp2, 0) + COALESCE(r.bp3, 0) + COALESCE(r.bp4, 0) AS plan_development_year, + COALESCE(r.bp1, 0) + COALESCE(r.abi1, 0) + COALESCE(r.ai1, 0) AS approved_development_q1, + COALESCE(r.bp2, 0) + COALESCE(r.abi2, 0) + COALESCE(r.ai2, 0) AS approved_development_q2, + COALESCE(r.bp3, 0) + COALESCE(r.abi3, 0) + COALESCE(r.ai3, 0) AS approved_development_q3, + COALESCE(r.bp4, 0) + COALESCE(r.abi4, 0) + COALESCE(r.ai4, 0) AS approved_development_q4, + (COALESCE(r.bp1, 0) + COALESCE(r.abi1, 0) + COALESCE(r.ai1, 0)) + + (COALESCE(r.bp2, 0) + COALESCE(r.abi2, 0) + COALESCE(r.ai2, 0)) + + (COALESCE(r.bp3, 0) + COALESCE(r.abi3, 0) + COALESCE(r.ai3, 0)) + + (COALESCE(r.bp4, 0) + COALESCE(r.abi4, 0) + COALESCE(r.ai4, 0)) AS approved_development_year, + COALESCE(r.m1_1, 0) + COALESCE(r.m2_1, 0) + COALESCE(r.m3_1, 0) AS fact_development_q1, + COALESCE(r.m1_2, 0) + COALESCE(r.m2_2, 0) + COALESCE(r.m3_2, 0) AS fact_development_q2, + COALESCE(r.m1_3, 0) + COALESCE(r.m2_3, 0) + COALESCE(r.m3_3, 0) AS fact_development_q3, + COALESCE(r.m1_4, 0) + COALESCE(r.m2_4, 0) + COALESCE(r.m3_4, 0) + COALESCE(r.spod4, 0) AS fact_development_q4, + COALESCE(r.m1_1, 0) + COALESCE(r.m2_1, 0) + COALESCE(r.m3_1, 0) + + COALESCE(r.m1_2, 0) + COALESCE(r.m2_2, 0) + COALESCE(r.m3_2, 0) + + COALESCE(r.m1_3, 0) + COALESCE(r.m2_3, 0) + COALESCE(r.m3_3, 0) + + COALESCE(r.m1_4, 0) + COALESCE(r.m2_4, 0) + COALESCE(r.m3_4, 0) + COALESCE(r.spod4, 0) AS fact_development_year, + COALESCE(r.cp2, 0) AS corrected_development_q2, + COALESCE(r.cp3, 0) AS corrected_development_q3, + COALESCE(r.cp4, 0) AS corrected_development_q4 +FROM rolled AS r; +$function$; + +-- ============================================================================= +-- 3форм_РФ_Р — VIEW +-- ============================================================================= + +DROP VIEW IF EXISTS v3.v_3form_rf_r CASCADE; + +CREATE OR REPLACE VIEW v3.v_3form_rf_r AS +WITH +report_lines AS ( + SELECT + rpry.year, + l.expense_item_id AS eid, + q.quarter, + q.base_plan, + q.adj_by_items, + q.adj_increase, + q.actual_m1, + q.actual_m2, + q.actual_m3, + q.actual_spod, + q.corrected_plan + FROM v3.rf_project_report AS r + JOIN v3.rf_project_year AS rpry ON rpry.id = r.rf_project_year_id + JOIN v3.rf_project_report_line AS l ON l.rf_project_report_id = r.id + JOIN v3.rf_project_report_quarter AS q ON q.rf_project_report_line_id = l.id +), +agg AS ( + SELECT + year, + eid, + SUM(CASE WHEN quarter = 1 THEN base_plan END) AS bp1, + SUM(CASE WHEN quarter = 2 THEN base_plan END) AS bp2, + SUM(CASE WHEN quarter = 3 THEN base_plan END) AS bp3, + SUM(CASE WHEN quarter = 4 THEN base_plan END) AS bp4, + SUM(CASE WHEN quarter = 1 THEN adj_by_items END) AS abi1, + SUM(CASE WHEN quarter = 2 THEN adj_by_items END) AS abi2, + SUM(CASE WHEN quarter = 3 THEN adj_by_items END) AS abi3, + SUM(CASE WHEN quarter = 4 THEN adj_by_items END) AS abi4, + SUM(CASE WHEN quarter = 1 THEN adj_increase END) AS ai1, + SUM(CASE WHEN quarter = 2 THEN adj_increase END) AS ai2, + SUM(CASE WHEN quarter = 3 THEN adj_increase END) AS ai3, + SUM(CASE WHEN quarter = 4 THEN adj_increase END) AS ai4, + SUM(CASE WHEN quarter = 1 THEN actual_m1 END) AS m1_1, + SUM(CASE WHEN quarter = 2 THEN actual_m1 END) AS m1_2, + SUM(CASE WHEN quarter = 3 THEN actual_m1 END) AS m1_3, + SUM(CASE WHEN quarter = 4 THEN actual_m1 END) AS m1_4, + SUM(CASE WHEN quarter = 1 THEN actual_m2 END) AS m2_1, + SUM(CASE WHEN quarter = 2 THEN actual_m2 END) AS m2_2, + SUM(CASE WHEN quarter = 3 THEN actual_m2 END) AS m2_3, + SUM(CASE WHEN quarter = 4 THEN actual_m2 END) AS m2_4, + SUM(CASE WHEN quarter = 1 THEN actual_m3 END) AS m3_1, + SUM(CASE WHEN quarter = 2 THEN actual_m3 END) AS m3_2, + SUM(CASE WHEN quarter = 3 THEN actual_m3 END) AS m3_3, + SUM(CASE WHEN quarter = 4 THEN actual_m3 END) AS m3_4, + SUM(CASE WHEN quarter = 4 THEN actual_spod END) AS spod4, + SUM(CASE WHEN quarter = 2 THEN corrected_plan END) AS cp2, + SUM(CASE WHEN quarter = 3 THEN corrected_plan END) AS cp3, + SUM(CASE WHEN quarter = 4 THEN corrected_plan END) AS cp4 + FROM report_lines + GROUP BY year, eid +), +years AS ( + SELECT DISTINCT rpry.year + FROM v3.rf_project_report AS r + JOIN v3.rf_project_year AS rpry ON rpry.id = r.rf_project_year_id +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_3' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + y.year, + tn.item_id, + tn.name, + SUM(a.bp1) AS bp1, SUM(a.bp2) AS bp2, SUM(a.bp3) AS bp3, SUM(a.bp4) AS bp4, + SUM(a.abi1) AS abi1, SUM(a.abi2) AS abi2, SUM(a.abi3) AS abi3, SUM(a.abi4) AS abi4, + SUM(a.ai1) AS ai1, SUM(a.ai2) AS ai2, SUM(a.ai3) AS ai3, SUM(a.ai4) AS ai4, + SUM(a.m1_1) AS m1_1, SUM(a.m1_2) AS m1_2, SUM(a.m1_3) AS m1_3, SUM(a.m1_4) AS m1_4, + SUM(a.m2_1) AS m2_1, SUM(a.m2_2) AS m2_2, SUM(a.m2_3) AS m2_3, SUM(a.m2_4) AS m2_4, + SUM(a.m3_1) AS m3_1, SUM(a.m3_2) AS m3_2, SUM(a.m3_3) AS m3_3, SUM(a.m3_4) AS m3_4, + SUM(a.spod4) AS spod4, + SUM(a.cp2) AS cp2, SUM(a.cp3) AS cp3, SUM(a.cp4) AS cp4 + FROM tree_nodes AS tn + CROSS JOIN years AS y + LEFT JOIN agg AS a + ON a.eid = ANY (tn.desc_ids) + AND a.year = y.year + GROUP BY y.year, tn.item_id, tn.name +) +SELECT + r.year, + r.item_id AS section_code, + r.name, + COALESCE(r.bp1, 0) AS plan_development_q1, + COALESCE(r.bp2, 0) AS plan_development_q2, + COALESCE(r.bp3, 0) AS plan_development_q3, + COALESCE(r.bp4, 0) AS plan_development_q4, + COALESCE(r.bp1, 0) + COALESCE(r.bp2, 0) + COALESCE(r.bp3, 0) + COALESCE(r.bp4, 0) AS plan_development_year, + COALESCE(r.bp1, 0) + COALESCE(r.abi1, 0) + COALESCE(r.ai1, 0) AS approved_development_q1, + COALESCE(r.bp2, 0) + COALESCE(r.abi2, 0) + COALESCE(r.ai2, 0) AS approved_development_q2, + COALESCE(r.bp3, 0) + COALESCE(r.abi3, 0) + COALESCE(r.ai3, 0) AS approved_development_q3, + COALESCE(r.bp4, 0) + COALESCE(r.abi4, 0) + COALESCE(r.ai4, 0) AS approved_development_q4, + (COALESCE(r.bp1, 0) + COALESCE(r.abi1, 0) + COALESCE(r.ai1, 0)) + + (COALESCE(r.bp2, 0) + COALESCE(r.abi2, 0) + COALESCE(r.ai2, 0)) + + (COALESCE(r.bp3, 0) + COALESCE(r.abi3, 0) + COALESCE(r.ai3, 0)) + + (COALESCE(r.bp4, 0) + COALESCE(r.abi4, 0) + COALESCE(r.ai4, 0)) AS approved_development_year, + COALESCE(r.m1_1, 0) + COALESCE(r.m2_1, 0) + COALESCE(r.m3_1, 0) AS fact_development_q1, + COALESCE(r.m1_2, 0) + COALESCE(r.m2_2, 0) + COALESCE(r.m3_2, 0) AS fact_development_q2, + COALESCE(r.m1_3, 0) + COALESCE(r.m2_3, 0) + COALESCE(r.m3_3, 0) AS fact_development_q3, + COALESCE(r.m1_4, 0) + COALESCE(r.m2_4, 0) + COALESCE(r.m3_4, 0) + COALESCE(r.spod4, 0) AS fact_development_q4, + COALESCE(r.m1_1, 0) + COALESCE(r.m2_1, 0) + COALESCE(r.m3_1, 0) + + COALESCE(r.m1_2, 0) + COALESCE(r.m2_2, 0) + COALESCE(r.m3_2, 0) + + COALESCE(r.m1_3, 0) + COALESCE(r.m2_3, 0) + COALESCE(r.m3_3, 0) + + COALESCE(r.m1_4, 0) + COALESCE(r.m2_4, 0) + COALESCE(r.m3_4, 0) + COALESCE(r.spod4, 0) AS fact_development_year, + COALESCE(r.cp2, 0) AS corrected_development_q2, + COALESCE(r.cp3, 0) AS corrected_development_q3, + COALESCE(r.cp4, 0) AS corrected_development_q4 +FROM rolled AS r; + +-- ============================================================================= +-- 4форм_ПРОЕКТ — ФУНКЦИЯ +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_4form_project(integer); + +CREATE OR REPLACE FUNCTION v3.v_4form_project(p_year integer, p_org_unit_ids integer[] DEFAULT NULL) + RETURNS TABLE( + section_code character varying, + name character varying, + plan_development_q1 numeric, + plan_development_q2 numeric, + plan_development_q3 numeric, + plan_development_q4 numeric, + plan_development_year numeric, + approved_development_q1 numeric, + approved_development_q2 numeric, + approved_development_q3 numeric, + approved_development_q4 numeric, + approved_development_year numeric, + fact_development_q1 numeric, + fact_development_q2 numeric, + fact_development_q3 numeric, + fact_development_q4 numeric, + fact_development_year numeric, + corrected_development_q1 numeric, + corrected_development_q2 numeric, + corrected_development_q3 numeric, + corrected_development_q4 numeric, + corrected_development_year numeric + ) + LANGUAGE sql + STABLE + SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH +form_lines AS ( + SELECT bl.id AS line_id, bl.expense_item_id AS eid + FROM v3.budget_line AS bl + JOIN v3.budget_form AS bf ON bf.id = bl.budget_form_id + JOIN v3.expense_item AS ei ON ei.id = bl.expense_item_id + WHERE bf.form_type_code = 'FORM_4' + AND bf.year = p_year + AND ei.sheet IN ('AHR', 'CAP', 'OPER') + AND (p_org_unit_ids IS NULL OR cardinality(p_org_unit_ids) = 0 OR bf.org_unit_id = ANY(p_org_unit_ids)) +), +q_per_line AS ( + SELECT line_id, + SUM(CASE WHEN quarter = 1 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) + COALESCE(actual_spod, 0) END) AS fq4, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q2 END) AS t1q2, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q3 END) AS t1q3, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q4 END) AS t1q4, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q3 END) AS t2q3, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q4 END) AS t2q4, + SUM(CASE WHEN quarter = 3 THEN transfer_to_q4 END) AS t3q4, + SUM(CASE WHEN quarter = 1 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj4, + SUM(CASE WHEN quarter = 2 THEN COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) + COALESCE(target_change, 0) + COALESCE(base_plan_correction, 0) END) AS rev2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) + COALESCE(target_change, 0) + COALESCE(base_plan_correction, 0) END) AS rev3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) + COALESCE(target_change, 0) + COALESCE(base_plan_correction, 0) END) AS rev4 + FROM v3.budget_line_quarter + GROUP BY line_id +), +line_agg AS ( + SELECT + fl.eid, + SUM(p.plan_q1) AS pq1, SUM(p.plan_q2) AS pq2, SUM(p.plan_q3) AS pq3, SUM(p.plan_q4) AS pq4, + SUM(sd.adj_q1) AS sd1, SUM(sd.adj_q2) AS sd2, SUM(sd.adj_q3) AS sd3, SUM(sd.adj_q4) AS sd4, + SUM(sg.adj_q1) AS sg1, SUM(sg.adj_q2) AS sg2, SUM(sg.adj_q3) AS sg3, SUM(sg.adj_q4) AS sg4, + SUM(r.amount_q1) AS rq1, SUM(r.amount_q2) AS rq2, SUM(r.amount_q3) AS rq3, SUM(r.amount_q4) AS rq4, + SUM(qp.fq1) AS fq1, SUM(qp.fq2) AS fq2, SUM(qp.fq3) AS fq3, SUM(qp.fq4) AS fq4, + SUM(qp.t1q2) AS t1q2, SUM(qp.t1q3) AS t1q3, SUM(qp.t1q4) AS t1q4, + SUM(qp.t2q3) AS t2q3, SUM(qp.t2q4) AS t2q4, SUM(qp.t3q4) AS t3q4, + SUM(qp.adj1) AS adj1, SUM(qp.adj2) AS adj2, SUM(qp.adj3) AS adj3, SUM(qp.adj4) AS adj4, + SUM(qp.rev2) AS rev2, SUM(qp.rev3) AS rev3, SUM(qp.rev4) AS rev4 + FROM form_lines AS fl + LEFT JOIN v3.plan AS p ON p.line_id = fl.line_id + LEFT JOIN v3.sequestration AS sd ON sd.line_id = fl.line_id AND sd.actor = 'DFIP' + LEFT JOIN v3.sequestration AS sg ON sg.line_id = fl.line_id AND sg.actor = 'SSP_GO' + LEFT JOIN v3.reserve AS r ON r.line_id = fl.line_id + LEFT JOIN q_per_line AS qp ON qp.line_id = fl.line_id + GROUP BY fl.eid +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_4' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + tn.item_id, + tn.name, + SUM(a.pq1) AS pq1, SUM(a.pq2) AS pq2, SUM(a.pq3) AS pq3, SUM(a.pq4) AS pq4, + SUM(a.sd1) AS sd1, SUM(a.sd2) AS sd2, SUM(a.sd3) AS sd3, SUM(a.sd4) AS sd4, + SUM(a.sg1) AS sg1, SUM(a.sg2) AS sg2, SUM(a.sg3) AS sg3, SUM(a.sg4) AS sg4, + SUM(a.rq1) AS rq1, SUM(a.rq2) AS rq2, SUM(a.rq3) AS rq3, SUM(a.rq4) AS rq4, + SUM(a.fq1) AS fq1, SUM(a.fq2) AS fq2, SUM(a.fq3) AS fq3, SUM(a.fq4) AS fq4, + SUM(a.t1q2) AS t1q2, SUM(a.t1q3) AS t1q3, SUM(a.t1q4) AS t1q4, + SUM(a.t2q3) AS t2q3, SUM(a.t2q4) AS t2q4, SUM(a.t3q4) AS t3q4, + SUM(a.adj1) AS adj1, SUM(a.adj2) AS adj2, SUM(a.adj3) AS adj3, SUM(a.adj4) AS adj4, + SUM(a.rev2) AS rev2, SUM(a.rev3) AS rev3, SUM(a.rev4) AS rev4 + FROM tree_nodes AS tn + LEFT JOIN line_agg AS a ON a.eid = ANY (tn.desc_ids) + GROUP BY tn.item_id, tn.name +) +SELECT + r.item_id AS section_code, r.name, + COALESCE(r.pq1, 0) AS plan_development_q1, COALESCE(r.pq2, 0) AS plan_development_q2, COALESCE(r.pq3, 0) AS plan_development_q3, COALESCE(r.pq4, 0) AS plan_development_q4, + COALESCE(r.pq1, 0) + COALESCE(r.pq2, 0) + COALESCE(r.pq3, 0) + COALESCE(r.pq4, 0) AS plan_development_year, + COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0) AS approved_development_q1, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) AS approved_development_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) AS approved_development_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) AS approved_development_q4, + (COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0)) + + (COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0)) + + (COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0)) + + (COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0)) AS approved_development_year, + COALESCE(r.fq1, 0) AS fact_development_q1, COALESCE(r.fq2, 0) AS fact_development_q2, COALESCE(r.fq3, 0) AS fact_development_q3, COALESCE(r.fq4, 0) AS fact_development_q4, + COALESCE(r.fq1, 0) + COALESCE(r.fq2, 0) + COALESCE(r.fq3, 0) + COALESCE(r.fq4, 0) AS fact_development_year, + COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0) + + COALESCE(r.adj1, 0) AS corrected_development_q1, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) + + COALESCE(r.t1q2, 0) + COALESCE(r.rev2, 0) + COALESCE(r.adj2, 0) AS corrected_development_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) + + COALESCE(r.t1q3, 0) + COALESCE(r.t2q3, 0) + COALESCE(r.rev3, 0) + COALESCE(r.adj3, 0) AS corrected_development_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) + + COALESCE(r.t1q4, 0) + COALESCE(r.t2q4, 0) + COALESCE(r.t3q4, 0) + COALESCE(r.rev4, 0) + COALESCE(r.adj4, 0) AS corrected_development_q4, + COALESCE(r.pq1, 0) + COALESCE(r.pq2, 0) + COALESCE(r.pq3, 0) + COALESCE(r.pq4, 0) + + COALESCE(r.sd1, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sd4, 0) + + COALESCE(r.sg1, 0) + COALESCE(r.sg2, 0) + COALESCE(r.sg3, 0) + COALESCE(r.sg4, 0) + + COALESCE(r.rq1, 0) + COALESCE(r.rq2, 0) + COALESCE(r.rq3, 0) + COALESCE(r.rq4, 0) + + COALESCE(r.adj1, 0) + COALESCE(r.adj2, 0) + COALESCE(r.adj3, 0) + COALESCE(r.adj4, 0) + + COALESCE(r.rev2, 0) + COALESCE(r.rev3, 0) + COALESCE(r.rev4, 0) AS corrected_development_year +FROM rolled AS r; +$function$; + +-- ============================================================================= +-- 4форм_ПРОЕКТ — VIEW +-- ============================================================================= + +DROP VIEW IF EXISTS v3.v_4form_project CASCADE; + +CREATE OR REPLACE VIEW v3.v_4form_project AS +WITH +form_lines AS ( + SELECT bf.year, bl.id AS line_id, bl.expense_item_id AS eid + FROM v3.budget_line AS bl + JOIN v3.budget_form AS bf ON bf.id = bl.budget_form_id + JOIN v3.expense_item AS ei ON ei.id = bl.expense_item_id + WHERE bf.form_type_code = 'FORM_4' + AND ei.sheet IN ('AHR', 'CAP', 'OPER') +), +q_per_line AS ( + SELECT line_id, + SUM(CASE WHEN quarter = 1 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) END) AS fq3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(actual_m1, 0) + COALESCE(actual_m2, 0) + COALESCE(actual_m3, 0) + COALESCE(actual_spod, 0) END) AS fq4, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q2 END) AS t1q2, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q3 END) AS t1q3, + SUM(CASE WHEN quarter = 1 THEN transfer_to_q4 END) AS t1q4, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q3 END) AS t2q3, + SUM(CASE WHEN quarter = 2 THEN transfer_to_q4 END) AS t2q4, + SUM(CASE WHEN quarter = 3 THEN transfer_to_q4 END) AS t3q4, + SUM(CASE WHEN quarter = 1 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj1, + SUM(CASE WHEN quarter = 2 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(adj_current, 0) + COALESCE(adj_ssp, 0) + COALESCE(adj_reserve, 0) END) AS adj4, + SUM(CASE WHEN quarter = 2 THEN COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) + COALESCE(target_change, 0) + COALESCE(base_plan_correction, 0) END) AS rev2, + SUM(CASE WHEN quarter = 3 THEN COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) + COALESCE(target_change, 0) + COALESCE(base_plan_correction, 0) END) AS rev3, + SUM(CASE WHEN quarter = 4 THEN COALESCE(plan_revision_increase, 0) + COALESCE(plan_revision_sequester, 0) + COALESCE(target_change, 0) + COALESCE(base_plan_correction, 0) END) AS rev4 + FROM v3.budget_line_quarter + GROUP BY line_id +), +line_agg AS ( + SELECT + fl.year, + fl.eid, + SUM(p.plan_q1) AS pq1, SUM(p.plan_q2) AS pq2, SUM(p.plan_q3) AS pq3, SUM(p.plan_q4) AS pq4, + SUM(sd.adj_q1) AS sd1, SUM(sd.adj_q2) AS sd2, SUM(sd.adj_q3) AS sd3, SUM(sd.adj_q4) AS sd4, + SUM(sg.adj_q1) AS sg1, SUM(sg.adj_q2) AS sg2, SUM(sg.adj_q3) AS sg3, SUM(sg.adj_q4) AS sg4, + SUM(r.amount_q1) AS rq1, SUM(r.amount_q2) AS rq2, SUM(r.amount_q3) AS rq3, SUM(r.amount_q4) AS rq4, + SUM(qp.fq1) AS fq1, SUM(qp.fq2) AS fq2, SUM(qp.fq3) AS fq3, SUM(qp.fq4) AS fq4, + SUM(qp.t1q2) AS t1q2, SUM(qp.t1q3) AS t1q3, SUM(qp.t1q4) AS t1q4, + SUM(qp.t2q3) AS t2q3, SUM(qp.t2q4) AS t2q4, SUM(qp.t3q4) AS t3q4, + SUM(qp.adj1) AS adj1, SUM(qp.adj2) AS adj2, SUM(qp.adj3) AS adj3, SUM(qp.adj4) AS adj4, + SUM(qp.rev2) AS rev2, SUM(qp.rev3) AS rev3, SUM(qp.rev4) AS rev4 + FROM form_lines AS fl + LEFT JOIN v3.plan AS p ON p.line_id = fl.line_id + LEFT JOIN v3.sequestration AS sd ON sd.line_id = fl.line_id AND sd.actor = 'DFIP' + LEFT JOIN v3.sequestration AS sg ON sg.line_id = fl.line_id AND sg.actor = 'SSP_GO' + LEFT JOIN v3.reserve AS r ON r.line_id = fl.line_id + LEFT JOIN q_per_line AS qp ON qp.line_id = fl.line_id + GROUP BY fl.year, fl.eid +), +years AS ( + SELECT DISTINCT bf.year + FROM v3.budget_form AS bf + WHERE bf.form_type_code = 'FORM_4' +), +tree_nodes AS ( + SELECT t.id, t.item_id, t.name, t.desc_ids + FROM v3.mv_expense_item_tree AS t + JOIN v3.expense_item_form_type AS eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_4' + WHERE t.depth < 3 +), +rolled AS ( + SELECT + y.year, + tn.item_id, + tn.name, + SUM(a.pq1) AS pq1, SUM(a.pq2) AS pq2, SUM(a.pq3) AS pq3, SUM(a.pq4) AS pq4, + SUM(a.sd1) AS sd1, SUM(a.sd2) AS sd2, SUM(a.sd3) AS sd3, SUM(a.sd4) AS sd4, + SUM(a.sg1) AS sg1, SUM(a.sg2) AS sg2, SUM(a.sg3) AS sg3, SUM(a.sg4) AS sg4, + SUM(a.rq1) AS rq1, SUM(a.rq2) AS rq2, SUM(a.rq3) AS rq3, SUM(a.rq4) AS rq4, + SUM(a.fq1) AS fq1, SUM(a.fq2) AS fq2, SUM(a.fq3) AS fq3, SUM(a.fq4) AS fq4, + SUM(a.t1q2) AS t1q2, SUM(a.t1q3) AS t1q3, SUM(a.t1q4) AS t1q4, + SUM(a.t2q3) AS t2q3, SUM(a.t2q4) AS t2q4, SUM(a.t3q4) AS t3q4, + SUM(a.adj1) AS adj1, SUM(a.adj2) AS adj2, SUM(a.adj3) AS adj3, SUM(a.adj4) AS adj4, + SUM(a.rev2) AS rev2, SUM(a.rev3) AS rev3, SUM(a.rev4) AS rev4 + FROM tree_nodes AS tn + CROSS JOIN years AS y + LEFT JOIN line_agg AS a ON a.eid = ANY (tn.desc_ids) AND a.year = y.year + GROUP BY y.year, tn.item_id, tn.name +) +SELECT + r.year, r.item_id AS section_code, r.name, + COALESCE(r.pq1, 0) AS plan_development_q1, COALESCE(r.pq2, 0) AS plan_development_q2, COALESCE(r.pq3, 0) AS plan_development_q3, COALESCE(r.pq4, 0) AS plan_development_q4, + COALESCE(r.pq1, 0) + COALESCE(r.pq2, 0) + COALESCE(r.pq3, 0) + COALESCE(r.pq4, 0) AS plan_development_year, + COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0) AS approved_development_q1, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) AS approved_development_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) AS approved_development_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) AS approved_development_q4, + (COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0)) + + (COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0)) + + (COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0)) + + (COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0)) AS approved_development_year, + COALESCE(r.fq1, 0) AS fact_development_q1, COALESCE(r.fq2, 0) AS fact_development_q2, COALESCE(r.fq3, 0) AS fact_development_q3, COALESCE(r.fq4, 0) AS fact_development_q4, + COALESCE(r.fq1, 0) + COALESCE(r.fq2, 0) + COALESCE(r.fq3, 0) + COALESCE(r.fq4, 0) AS fact_development_year, + COALESCE(r.pq1, 0) + COALESCE(r.sd1, 0) + COALESCE(r.sg1, 0) + COALESCE(r.rq1, 0) + + COALESCE(r.adj1, 0) AS corrected_development_q1, + COALESCE(r.pq2, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sg2, 0) + COALESCE(r.rq2, 0) + + COALESCE(r.t1q2, 0) + COALESCE(r.rev2, 0) + COALESCE(r.adj2, 0) AS corrected_development_q2, + COALESCE(r.pq3, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sg3, 0) + COALESCE(r.rq3, 0) + + COALESCE(r.t1q3, 0) + COALESCE(r.t2q3, 0) + COALESCE(r.rev3, 0) + COALESCE(r.adj3, 0) AS corrected_development_q3, + COALESCE(r.pq4, 0) + COALESCE(r.sd4, 0) + COALESCE(r.sg4, 0) + COALESCE(r.rq4, 0) + + COALESCE(r.t1q4, 0) + COALESCE(r.t2q4, 0) + COALESCE(r.t3q4, 0) + COALESCE(r.rev4, 0) + COALESCE(r.adj4, 0) AS corrected_development_q4, + COALESCE(r.pq1, 0) + COALESCE(r.pq2, 0) + COALESCE(r.pq3, 0) + COALESCE(r.pq4, 0) + + COALESCE(r.sd1, 0) + COALESCE(r.sd2, 0) + COALESCE(r.sd3, 0) + COALESCE(r.sd4, 0) + + COALESCE(r.sg1, 0) + COALESCE(r.sg2, 0) + COALESCE(r.sg3, 0) + COALESCE(r.sg4, 0) + + COALESCE(r.rq1, 0) + COALESCE(r.rq2, 0) + COALESCE(r.rq3, 0) + COALESCE(r.rq4, 0) + + COALESCE(r.adj1, 0) + COALESCE(r.adj2, 0) + COALESCE(r.adj3, 0) + COALESCE(r.adj4, 0) + + COALESCE(r.rev2, 0) + COALESCE(r.rev3, 0) + COALESCE(r.rev4, 0) AS corrected_development_year +FROM rolled AS r; + +-- ============================================================================= +-- main_format — ФУНКЦИЯ +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_main_format(integer); + +CREATE OR REPLACE FUNCTION v3.v_main_format(p_year integer, p_org_unit_ids integer[] DEFAULT NULL) + RETURNS TABLE( + section_code character varying, + name character varying, + plan_support_q1 numeric, + plan_support_q2 numeric, + plan_support_q3 numeric, + plan_support_q4 numeric, + plan_support_year numeric, + plan_development_q1 numeric, + plan_development_q2 numeric, + plan_development_q3 numeric, + plan_development_q4 numeric, + plan_development_year numeric, + plan_total_year numeric, + approved_support_q1 numeric, + approved_support_q2 numeric, + approved_support_q3 numeric, + approved_support_q4 numeric, + approved_support_year numeric, + approved_development_q1 numeric, + approved_development_q2 numeric, + approved_development_q3 numeric, + approved_development_q4 numeric, + approved_development_year numeric, + approved_total_year numeric, + fact_support_q1 numeric, + fact_support_q2 numeric, + fact_support_q3 numeric, + fact_support_q4 numeric, + fact_support_year numeric, + fact_development_q1 numeric, + fact_development_q2 numeric, + fact_development_q3 numeric, + fact_development_q4 numeric, + fact_development_year numeric, + fact_total_year numeric, + corrected_support_q2 numeric, + corrected_support_q3 numeric, + corrected_support_q4 numeric, + corrected_development_q2 numeric, + corrected_development_q3 numeric, + corrected_development_q4 numeric + ) + LANGUAGE sql + STABLE + SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH unioned AS ( +( SELECT f.section_code, f.name, f.plan_support_q1, f.plan_support_q2, f.plan_support_q3, f.plan_support_q4, f.plan_support_year, f.approved_support_q1, f.approved_support_q2, f.approved_support_q3, f.approved_support_q4, f.approved_support_year, f.fact_support_q1, f.fact_support_q2, f.fact_support_q3, f.fact_support_q4, f.fact_support_year, f.corrected_support_q2, f.corrected_support_q3, f.corrected_support_q4, f.plan_development_q1, f.plan_development_q2, f.plan_development_q3, f.plan_development_q4, f.plan_development_year, f.approved_development_q1, f.approved_development_q2, f.approved_development_q3, f.approved_development_q4, f.approved_development_year, f.fact_development_q1, f.fact_development_q2, f.fact_development_q3, f.fact_development_q4, f.fact_development_year, f.corrected_development_q2, f.corrected_development_q3, f.corrected_development_q4 + FROM v3.v_1form_ssp(p_year, p_org_unit_ids) AS f) + +UNION ALL + +( SELECT f.section_code, f.name, f.plan_support_q1, f.plan_support_q2, f.plan_support_q3, f.plan_support_q4, f.plan_support_year, f.approved_support_q1, f.approved_support_q2, f.approved_support_q3, f.approved_support_q4, f.approved_support_year, f.fact_support_q1, f.fact_support_q2, f.fact_support_q3, f.fact_support_q4, f.fact_support_year, f.corrected_support_q2, f.corrected_support_q3, f.corrected_support_q4, 0 AS plan_development_q1, 0 AS plan_development_q2, 0 AS plan_development_q3, 0 AS plan_development_q4, 0 AS plan_development_year, 0 AS approved_development_q1, 0 AS approved_development_q2, 0 AS approved_development_q3, 0 AS approved_development_q4, 0 AS approved_development_year, 0 AS fact_development_q1, 0 AS fact_development_q2, 0 AS fact_development_q3, 0 AS fact_development_q4, 0 AS fact_development_year, 0 AS corrected_development_q2, 0 AS corrected_development_q3, 0 AS corrected_development_q4 + FROM v3.v_2form_rf_p(p_year, p_org_unit_ids) AS f) + +UNION ALL + +( SELECT f.section_code, f.name, 0 AS plan_support_q1, 0 AS plan_support_q2, 0 AS plan_support_q3, 0 AS plan_support_q4, 0 AS plan_support_year, 0 AS approved_support_q1, 0 AS approved_support_q2, 0 AS approved_support_q3, 0 AS approved_support_q4, 0 AS approved_support_year, 0 AS fact_support_q1, 0 AS fact_support_q2, 0 AS fact_support_q3, 0 AS fact_support_q4, 0 AS fact_support_year, 0 AS corrected_support_q2, 0 AS corrected_support_q3, 0 AS corrected_support_q4, f.plan_development_q1, f.plan_development_q2, f.plan_development_q3, f.plan_development_q4, f.plan_development_year, f.approved_development_q1, f.approved_development_q2, f.approved_development_q3, f.approved_development_q4, f.approved_development_year, f.fact_development_q1, f.fact_development_q2, f.fact_development_q3, f.fact_development_q4, f.fact_development_year, f.corrected_development_q2, f.corrected_development_q3, f.corrected_development_q4 + FROM v3.v_3form_rf_r(p_year, p_org_unit_ids) AS f) + +UNION ALL + +( SELECT f.section_code, f.name, 0 AS plan_support_q1, 0 AS plan_support_q2, 0 AS plan_support_q3, 0 AS plan_support_q4, 0 AS plan_support_year, 0 AS approved_support_q1, 0 AS approved_support_q2, 0 AS approved_support_q3, 0 AS approved_support_q4, 0 AS approved_support_year, 0 AS fact_support_q1, 0 AS fact_support_q2, 0 AS fact_support_q3, 0 AS fact_support_q4, 0 AS fact_support_year, 0 AS corrected_support_q2, 0 AS corrected_support_q3, 0 AS corrected_support_q4, f.plan_development_q1, f.plan_development_q2, f.plan_development_q3, f.plan_development_q4, f.plan_development_year, f.approved_development_q1, f.approved_development_q2, f.approved_development_q3, f.approved_development_q4, f.approved_development_year, f.fact_development_q1, f.fact_development_q2, f.fact_development_q3, f.fact_development_q4, f.fact_development_year, f.corrected_development_q2, f.corrected_development_q3, f.corrected_development_q4 + FROM v3.v_4form_project(p_year, p_org_unit_ids) AS f) +), +summed AS ( + SELECT + u.section_code, u.name, + SUM(u.plan_support_q1) AS plan_support_q1, + SUM(u.plan_support_q2) AS plan_support_q2, + SUM(u.plan_support_q3) AS plan_support_q3, + SUM(u.plan_support_q4) AS plan_support_q4, + SUM(u.plan_support_year) AS plan_support_year, + SUM(u.approved_support_q1) AS approved_support_q1, + SUM(u.approved_support_q2) AS approved_support_q2, + SUM(u.approved_support_q3) AS approved_support_q3, + SUM(u.approved_support_q4) AS approved_support_q4, + SUM(u.approved_support_year) AS approved_support_year, + SUM(u.fact_support_q1) AS fact_support_q1, + SUM(u.fact_support_q2) AS fact_support_q2, + SUM(u.fact_support_q3) AS fact_support_q3, + SUM(u.fact_support_q4) AS fact_support_q4, + SUM(u.fact_support_year) AS fact_support_year, + SUM(u.corrected_support_q2) AS corrected_support_q2, + SUM(u.corrected_support_q3) AS corrected_support_q3, + SUM(u.corrected_support_q4) AS corrected_support_q4, + SUM(u.plan_development_q1) AS plan_development_q1, + SUM(u.plan_development_q2) AS plan_development_q2, + SUM(u.plan_development_q3) AS plan_development_q3, + SUM(u.plan_development_q4) AS plan_development_q4, + SUM(u.plan_development_year) AS plan_development_year, + SUM(u.approved_development_q1) AS approved_development_q1, + SUM(u.approved_development_q2) AS approved_development_q2, + SUM(u.approved_development_q3) AS approved_development_q3, + SUM(u.approved_development_q4) AS approved_development_q4, + SUM(u.approved_development_year) AS approved_development_year, + SUM(u.fact_development_q1) AS fact_development_q1, + SUM(u.fact_development_q2) AS fact_development_q2, + SUM(u.fact_development_q3) AS fact_development_q3, + SUM(u.fact_development_q4) AS fact_development_q4, + SUM(u.fact_development_year) AS fact_development_year, + SUM(u.corrected_development_q2) AS corrected_development_q2, + SUM(u.corrected_development_q3) AS corrected_development_q3, + SUM(u.corrected_development_q4) AS corrected_development_q4 + FROM unioned AS u + GROUP BY u.section_code, u.name +) +SELECT + s.section_code, s.name, + s.plan_support_q1, s.plan_support_q2, s.plan_support_q3, s.plan_support_q4, s.plan_support_year, + s.approved_support_q1, s.approved_support_q2, s.approved_support_q3, s.approved_support_q4, s.approved_support_year, + s.plan_support_year + s.plan_development_year AS plan_total_year, + s.fact_support_q1, s.fact_support_q2, s.fact_support_q3, s.fact_support_q4, s.fact_support_year, + s.corrected_support_q2, s.corrected_support_q3, s.corrected_support_q4, s.plan_development_q1, s.plan_development_q2, + s.approved_support_year + s.approved_development_year AS approved_total_year, + s.plan_development_q3, s.plan_development_q4, s.plan_development_year, s.approved_development_q1, s.approved_development_q2, + s.approved_development_q3, s.approved_development_q4, s.approved_development_year, s.fact_development_q1, s.fact_development_q2, + s.fact_support_year + s.fact_development_year AS fact_total_year, + s.fact_development_q3, s.fact_development_q4, s.fact_development_year, + s.corrected_development_q2, s.corrected_development_q3, s.corrected_development_q4 +FROM summed AS s; +$function$; + +-- ============================================================================= +-- main_format — VIEW +-- ============================================================================= + +DROP VIEW IF EXISTS v3.v_main_format; + +CREATE OR REPLACE VIEW v3.v_main_format AS +WITH unioned AS ( +( SELECT f.year, f.section_code, f.name, f.plan_support_q1, f.plan_support_q2, f.plan_support_q3, f.plan_support_q4, f.plan_support_year, f.approved_support_q1, f.approved_support_q2, f.approved_support_q3, f.approved_support_q4, f.approved_support_year, f.fact_support_q1, f.fact_support_q2, f.fact_support_q3, f.fact_support_q4, f.fact_support_year, f.corrected_support_q2, f.corrected_support_q3, f.corrected_support_q4, f.plan_development_q1, f.plan_development_q2, f.plan_development_q3, f.plan_development_q4, f.plan_development_year, f.approved_development_q1, f.approved_development_q2, f.approved_development_q3, f.approved_development_q4, f.approved_development_year, f.fact_development_q1, f.fact_development_q2, f.fact_development_q3, f.fact_development_q4, f.fact_development_year, f.corrected_development_q2, f.corrected_development_q3, f.corrected_development_q4 + FROM v3.v_1form_ssp AS f) + +UNION ALL + +( SELECT f.year, f.section_code, f.name, f.plan_support_q1, f.plan_support_q2, f.plan_support_q3, f.plan_support_q4, f.plan_support_year, f.approved_support_q1, f.approved_support_q2, f.approved_support_q3, f.approved_support_q4, f.approved_support_year, f.fact_support_q1, f.fact_support_q2, f.fact_support_q3, f.fact_support_q4, f.fact_support_year, f.corrected_support_q2, f.corrected_support_q3, f.corrected_support_q4, 0 AS plan_development_q1, 0 AS plan_development_q2, 0 AS plan_development_q3, 0 AS plan_development_q4, 0 AS plan_development_year, 0 AS approved_development_q1, 0 AS approved_development_q2, 0 AS approved_development_q3, 0 AS approved_development_q4, 0 AS approved_development_year, 0 AS fact_development_q1, 0 AS fact_development_q2, 0 AS fact_development_q3, 0 AS fact_development_q4, 0 AS fact_development_year, 0 AS corrected_development_q2, 0 AS corrected_development_q3, 0 AS corrected_development_q4 + FROM v3.v_2form_rf_p AS f) + +UNION ALL + +( SELECT f.year, f.section_code, f.name, 0 AS plan_support_q1, 0 AS plan_support_q2, 0 AS plan_support_q3, 0 AS plan_support_q4, 0 AS plan_support_year, 0 AS approved_support_q1, 0 AS approved_support_q2, 0 AS approved_support_q3, 0 AS approved_support_q4, 0 AS approved_support_year, 0 AS fact_support_q1, 0 AS fact_support_q2, 0 AS fact_support_q3, 0 AS fact_support_q4, 0 AS fact_support_year, 0 AS corrected_support_q2, 0 AS corrected_support_q3, 0 AS corrected_support_q4, f.plan_development_q1, f.plan_development_q2, f.plan_development_q3, f.plan_development_q4, f.plan_development_year, f.approved_development_q1, f.approved_development_q2, f.approved_development_q3, f.approved_development_q4, f.approved_development_year, f.fact_development_q1, f.fact_development_q2, f.fact_development_q3, f.fact_development_q4, f.fact_development_year, f.corrected_development_q2, f.corrected_development_q3, f.corrected_development_q4 + FROM v3.v_3form_rf_r AS f) + +UNION ALL + +( SELECT f.year, f.section_code, f.name, 0 AS plan_support_q1, 0 AS plan_support_q2, 0 AS plan_support_q3, 0 AS plan_support_q4, 0 AS plan_support_year, 0 AS approved_support_q1, 0 AS approved_support_q2, 0 AS approved_support_q3, 0 AS approved_support_q4, 0 AS approved_support_year, 0 AS fact_support_q1, 0 AS fact_support_q2, 0 AS fact_support_q3, 0 AS fact_support_q4, 0 AS fact_support_year, 0 AS corrected_support_q2, 0 AS corrected_support_q3, 0 AS corrected_support_q4, f.plan_development_q1, f.plan_development_q2, f.plan_development_q3, f.plan_development_q4, f.plan_development_year, f.approved_development_q1, f.approved_development_q2, f.approved_development_q3, f.approved_development_q4, f.approved_development_year, f.fact_development_q1, f.fact_development_q2, f.fact_development_q3, f.fact_development_q4, f.fact_development_year, f.corrected_development_q2, f.corrected_development_q3, f.corrected_development_q4 + FROM v3.v_4form_project AS f) +), +summed AS ( + SELECT + u.year, u.section_code, u.name, + SUM(u.plan_support_q1) AS plan_support_q1, + SUM(u.plan_support_q2) AS plan_support_q2, + SUM(u.plan_support_q3) AS plan_support_q3, + SUM(u.plan_support_q4) AS plan_support_q4, + SUM(u.plan_support_year) AS plan_support_year, + SUM(u.approved_support_q1) AS approved_support_q1, + SUM(u.approved_support_q2) AS approved_support_q2, + SUM(u.approved_support_q3) AS approved_support_q3, + SUM(u.approved_support_q4) AS approved_support_q4, + SUM(u.approved_support_year) AS approved_support_year, + SUM(u.fact_support_q1) AS fact_support_q1, + SUM(u.fact_support_q2) AS fact_support_q2, + SUM(u.fact_support_q3) AS fact_support_q3, + SUM(u.fact_support_q4) AS fact_support_q4, + SUM(u.fact_support_year) AS fact_support_year, + SUM(u.corrected_support_q2) AS corrected_support_q2, + SUM(u.corrected_support_q3) AS corrected_support_q3, + SUM(u.corrected_support_q4) AS corrected_support_q4, + SUM(u.plan_development_q1) AS plan_development_q1, + SUM(u.plan_development_q2) AS plan_development_q2, + SUM(u.plan_development_q3) AS plan_development_q3, + SUM(u.plan_development_q4) AS plan_development_q4, + SUM(u.plan_development_year) AS plan_development_year, + SUM(u.approved_development_q1) AS approved_development_q1, + SUM(u.approved_development_q2) AS approved_development_q2, + SUM(u.approved_development_q3) AS approved_development_q3, + SUM(u.approved_development_q4) AS approved_development_q4, + SUM(u.approved_development_year) AS approved_development_year, + SUM(u.fact_development_q1) AS fact_development_q1, + SUM(u.fact_development_q2) AS fact_development_q2, + SUM(u.fact_development_q3) AS fact_development_q3, + SUM(u.fact_development_q4) AS fact_development_q4, + SUM(u.fact_development_year) AS fact_development_year, + SUM(u.corrected_development_q2) AS corrected_development_q2, + SUM(u.corrected_development_q3) AS corrected_development_q3, + SUM(u.corrected_development_q4) AS corrected_development_q4 + FROM unioned AS u + GROUP BY u.year, u.section_code, u.name +) +SELECT + r.year, r.section_code, r.name, + r.plan_support_q1, r.plan_support_q2, r.plan_support_q3, r.plan_support_q4, r.plan_support_year, + r.approved_support_q1, r.approved_support_q2, r.approved_support_q3, r.approved_support_q4, r.approved_support_year, + r.plan_support_year + r.plan_development_year AS plan_total_year, + r.fact_support_q1, r.fact_support_q2, r.fact_support_q3, r.fact_support_q4, r.fact_support_year, + r.corrected_support_q2, r.corrected_support_q3, r.corrected_support_q4, r.plan_development_q1, r.plan_development_q2, + r.approved_support_year + r.approved_development_year AS approved_total_year, + r.plan_development_q3, r.plan_development_q4, r.plan_development_year, r.approved_development_q1, r.approved_development_q2, + r.approved_development_q3, r.approved_development_q4, r.approved_development_year, r.fact_development_q1, r.fact_development_q2, + r.fact_support_year + r.fact_development_year AS fact_total_year, + r.fact_development_q3, r.fact_development_q4, r.fact_development_year, + r.corrected_development_q2, r.corrected_development_q3, r.corrected_development_q4 +FROM summed AS r; + + + +-- ============================================================================= +-- СВОДНЫЙ VIEW ДЛЯ API — диспетчер по листам свода (аналог v_form_view) +-- Возвращает данные в том же виде, что и лист «смета» формы: +-- (row_type, depth, sort_order, data jsonb) +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_summary_view(integer, character varying, integer[]); + +CREATE OR REPLACE FUNCTION v3.v_summary_view( + p_year integer, + p_sheet character varying, + p_org_unit_ids integer[] DEFAULT NULL +) +RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb) +LANGUAGE plpgsql +STABLE +SET search_path TO 'v3', 'pg_catalog' +AS $function$ +BEGIN + + -- ── 1форм_ССП (FORM_1) ────────────────────────────────────────────────── + IF p_sheet = 'FORM_1' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', jsonb_build_object('q1', s.plan_support_q1, 'q2', s.plan_support_q2, 'q3', s.plan_support_q3, 'q4', s.plan_support_q4, 'year', s.plan_support_year), + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year), + 'total_year', s.plan_total_year + ), + 'approved', jsonb_build_object( + 'support', jsonb_build_object('q1', s.approved_support_q1, 'q2', s.approved_support_q2, 'q3', s.approved_support_q3, 'q4', s.approved_support_q4, 'year', s.approved_support_year), + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year), + 'total_year', s.approved_total_year + ), + 'fact', jsonb_build_object( + 'support', jsonb_build_object('q1', s.fact_support_q1, 'q2', s.fact_support_q2, 'q3', s.fact_support_q3, 'q4', s.fact_support_q4, 'year', s.fact_support_year), + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year), + 'total_year', s.fact_total_year + ), + 'corrected', jsonb_build_object( + 'support', jsonb_build_object('q2', s.corrected_support_q2, 'q3', s.corrected_support_q3, 'q4', s.corrected_support_q4), + 'development', jsonb_build_object('q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4) + ) + ) + FROM v3.v_1form_ssp(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── 2форм_РФ_П (FORM_2, только Поддержка) ────────────────────────────── + IF p_sheet = 'FORM_2' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', jsonb_build_object('q1', s.plan_support_q1, 'q2', s.plan_support_q2, 'q3', s.plan_support_q3, 'q4', s.plan_support_q4, 'year', s.plan_support_year), + 'development', NULL + ), + 'approved', jsonb_build_object( + 'support', jsonb_build_object('q1', s.approved_support_q1, 'q2', s.approved_support_q2, 'q3', s.approved_support_q3, 'q4', s.approved_support_q4, 'year', s.approved_support_year), + 'development', NULL + ), + 'fact', jsonb_build_object( + 'support', jsonb_build_object('q1', s.fact_support_q1, 'q2', s.fact_support_q2, 'q3', s.fact_support_q3, 'q4', s.fact_support_q4, 'year', s.fact_support_year), + 'development', NULL + ), + 'corrected', jsonb_build_object( + 'support', jsonb_build_object('q2', s.corrected_support_q2, 'q3', s.corrected_support_q3, 'q4', s.corrected_support_q4), + 'development', NULL + ) + ) + FROM v3.v_2form_rf_p(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── 3форм_РФ_Р (FORM_3, только Развитие) ─────────────────────────────── + IF p_sheet = 'FORM_3' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year) + ), + 'approved', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year) + ), + 'fact', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year) + ), + 'corrected', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4) + ) + ) + FROM v3.v_3form_rf_r(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── 4форм_ПРОЕКТ (FORM_4, только Развитие) ───────────────────────────── + IF p_sheet = 'FORM_4' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year) + ), + 'approved', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year) + ), + 'fact', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year) + ), + 'corrected', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.corrected_development_q1, 'q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4, 'year', s.corrected_development_year) + ) + ) + FROM v3.v_4form_project(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── main_format (консолидированный свод) ─────────────────────────────── + IF p_sheet = 'MAIN' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', jsonb_build_object('q1', s.plan_support_q1, 'q2', s.plan_support_q2, 'q3', s.plan_support_q3, 'q4', s.plan_support_q4, 'year', s.plan_support_year), + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year), + 'total_year', s.plan_total_year + ), + 'approved', jsonb_build_object( + 'support', jsonb_build_object('q1', s.approved_support_q1, 'q2', s.approved_support_q2, 'q3', s.approved_support_q3, 'q4', s.approved_support_q4, 'year', s.approved_support_year), + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year), + 'total_year', s.approved_total_year + ), + 'fact', jsonb_build_object( + 'support', jsonb_build_object('q1', s.fact_support_q1, 'q2', s.fact_support_q2, 'q3', s.fact_support_q3, 'q4', s.fact_support_q4, 'year', s.fact_support_year), + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year), + 'total_year', s.fact_total_year + ), + 'corrected', jsonb_build_object( + 'support', jsonb_build_object('q2', s.corrected_support_q2, 'q3', s.corrected_support_q3, 'q4', s.corrected_support_q4), + 'development', jsonb_build_object('q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4) + ) + ) + FROM v3.v_main_format(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + RAISE EXCEPTION 'Unknown summary sheet: %', p_sheet + USING HINT = 'Use FORM_1 / FORM_2 / FORM_3 / FORM_4 / MAIN'; + +END; +$function$; + +-- ============================================================================= +-- СВОДНЫЙ VIEW ДЛЯ API — диспетчер по листам свода (аналог v_form_view) +-- Возвращает данные в том же виде, что и лист «смета» формы: +-- (row_type, depth, sort_order, data jsonb) +-- ============================================================================= + +DROP FUNCTION IF EXISTS v3.v_summary_view(integer, character varying, integer[]); + +CREATE OR REPLACE FUNCTION v3.v_summary_view( + p_year integer, + p_sheet character varying, + p_org_unit_ids integer[] DEFAULT NULL +) +RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb) +LANGUAGE plpgsql +STABLE +SET search_path TO 'v3', 'pg_catalog' +AS $function$ +BEGIN + + -- ── 1форм_ССП (FORM_1) ────────────────────────────────────────────────── + IF p_sheet = 'FORM_1' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', jsonb_build_object('q1', s.plan_support_q1, 'q2', s.plan_support_q2, 'q3', s.plan_support_q3, 'q4', s.plan_support_q4, 'year', s.plan_support_year), + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year), + 'total_year', s.plan_total_year + ), + 'approved', jsonb_build_object( + 'support', jsonb_build_object('q1', s.approved_support_q1, 'q2', s.approved_support_q2, 'q3', s.approved_support_q3, 'q4', s.approved_support_q4, 'year', s.approved_support_year), + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year), + 'total_year', s.approved_total_year + ), + 'fact', jsonb_build_object( + 'support', jsonb_build_object('q1', s.fact_support_q1, 'q2', s.fact_support_q2, 'q3', s.fact_support_q3, 'q4', s.fact_support_q4, 'year', s.fact_support_year), + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year), + 'total_year', s.fact_total_year + ), + 'corrected', jsonb_build_object( + 'support', jsonb_build_object('q2', s.corrected_support_q2, 'q3', s.corrected_support_q3, 'q4', s.corrected_support_q4), + 'development', jsonb_build_object('q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4) + ) + ) + FROM v3.v_1form_ssp(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── 2форм_РФ_П (FORM_2, только Поддержка) ────────────────────────────── + IF p_sheet = 'FORM_2' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', jsonb_build_object('q1', s.plan_support_q1, 'q2', s.plan_support_q2, 'q3', s.plan_support_q3, 'q4', s.plan_support_q4, 'year', s.plan_support_year), + 'development', NULL + ), + 'approved', jsonb_build_object( + 'support', jsonb_build_object('q1', s.approved_support_q1, 'q2', s.approved_support_q2, 'q3', s.approved_support_q3, 'q4', s.approved_support_q4, 'year', s.approved_support_year), + 'development', NULL + ), + 'fact', jsonb_build_object( + 'support', jsonb_build_object('q1', s.fact_support_q1, 'q2', s.fact_support_q2, 'q3', s.fact_support_q3, 'q4', s.fact_support_q4, 'year', s.fact_support_year), + 'development', NULL + ), + 'corrected', jsonb_build_object( + 'support', jsonb_build_object('q2', s.corrected_support_q2, 'q3', s.corrected_support_q3, 'q4', s.corrected_support_q4), + 'development', NULL + ) + ) + FROM v3.v_2form_rf_p(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── 3форм_РФ_Р (FORM_3, только Развитие) ─────────────────────────────── + IF p_sheet = 'FORM_3' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year) + ), + 'approved', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year) + ), + 'fact', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year) + ), + 'corrected', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4) + ) + ) + FROM v3.v_3form_rf_r(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── 4форм_ПРОЕКТ (FORM_4, только Развитие) ───────────────────────────── + IF p_sheet = 'FORM_4' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year) + ), + 'approved', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year) + ), + 'fact', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year) + ), + 'corrected', jsonb_build_object( + 'support', NULL, + 'development', jsonb_build_object('q1', s.corrected_development_q1, 'q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4, 'year', s.corrected_development_year) + ) + ) + FROM v3.v_4form_project(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + -- ── main_format (консолидированный свод) ─────────────────────────────── + IF p_sheet = 'MAIN' THEN + RETURN QUERY + SELECT + (CASE t.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' ELSE 'ITEM' END)::character varying, + t.depth, + ROW_NUMBER() OVER (ORDER BY t.item_id), + jsonb_build_object( + 'section_code', s.section_code, + 'name', s.name, + 'plan', jsonb_build_object( + 'support', jsonb_build_object('q1', s.plan_support_q1, 'q2', s.plan_support_q2, 'q3', s.plan_support_q3, 'q4', s.plan_support_q4, 'year', s.plan_support_year), + 'development', jsonb_build_object('q1', s.plan_development_q1, 'q2', s.plan_development_q2, 'q3', s.plan_development_q3, 'q4', s.plan_development_q4, 'year', s.plan_development_year), + 'total_year', s.plan_total_year + ), + 'approved', jsonb_build_object( + 'support', jsonb_build_object('q1', s.approved_support_q1, 'q2', s.approved_support_q2, 'q3', s.approved_support_q3, 'q4', s.approved_support_q4, 'year', s.approved_support_year), + 'development', jsonb_build_object('q1', s.approved_development_q1, 'q2', s.approved_development_q2, 'q3', s.approved_development_q3, 'q4', s.approved_development_q4, 'year', s.approved_development_year), + 'total_year', s.approved_total_year + ), + 'fact', jsonb_build_object( + 'support', jsonb_build_object('q1', s.fact_support_q1, 'q2', s.fact_support_q2, 'q3', s.fact_support_q3, 'q4', s.fact_support_q4, 'year', s.fact_support_year), + 'development', jsonb_build_object('q1', s.fact_development_q1, 'q2', s.fact_development_q2, 'q3', s.fact_development_q3, 'q4', s.fact_development_q4, 'year', s.fact_development_year), + 'total_year', s.fact_total_year + ), + 'corrected', jsonb_build_object( + 'support', jsonb_build_object('q2', s.corrected_support_q2, 'q3', s.corrected_support_q3, 'q4', s.corrected_support_q4), + 'development', jsonb_build_object('q2', s.corrected_development_q2, 'q3', s.corrected_development_q3, 'q4', s.corrected_development_q4) + ) + ) + FROM v3.v_main_format(p_year, p_org_unit_ids) s + JOIN v3.mv_expense_item_tree t ON t.item_id = s.section_code AND t.depth < 3; + RETURN; + END IF; + + RAISE EXCEPTION 'Unknown summary sheet: %', p_sheet + USING HINT = 'Use FORM_1 / FORM_2 / FORM_3 / FORM_4 / MAIN'; + +END; +$function$; diff --git a/api/src/api/v1/router.py b/api/src/api/v1/router.py index ebf0fd4..fbd8a08 100644 --- a/api/src/api/v1/router.py +++ b/api/src/api/v1/router.py @@ -1,7 +1,7 @@ from fastapi import APIRouter from src.api.v1 import ( - auth, users, admin, audit, forms, form_phases, projects, export, org_unit, vsp, expense_item + auth, users, admin, audit, forms, form_phases, projects, export, org_unit, vsp, expense_item, summary ) from src.api.v1 import websocket @@ -20,3 +20,4 @@ api_router.include_router(websocket.router) api_router.include_router(org_unit.router) api_router.include_router(vsp.router) api_router.include_router(expense_item.router) +api_router.include_router(summary.router) diff --git a/api/src/api/v1/summary.py b/api/src/api/v1/summary.py new file mode 100644 index 0000000..26481a3 --- /dev/null +++ b/api/src/api/v1/summary.py @@ -0,0 +1,88 @@ +import logging +import time +from typing import Optional + +from fastapi import APIRouter, Depends, HTTPException, Response +from sqlalchemy.ext.asyncio import AsyncSession + +from src.api.v1.deps import get_current_active_user_with_set_db +from src.db.models.app_user import AppUser +from src.db.session import get_db +from src.domain.schemas import BaseListResponse, SheetResponse +from src.services.summary_service import SummaryService + + +logger = logging.getLogger() + +router = APIRouter(prefix="/svod/1", tags=["svod"]) + +VALID_SUMMARY_SHEETS = { + "FORM_1", + "FORM_2", + "FORM_3", + "FORM_4", + "MAIN", +} + + +def _rows_to_sheet_response(result: list[tuple]) -> list[SheetResponse]: + return [ + SheetResponse( + row_type=el[0], + depth=el[1], + sort_order=el[2], + data=el[3], + ) for el in result + ] + + +def _parse_org_ids(org_ids: Optional[str]) -> Optional[list[int]]: + if not org_ids: + return None + try: + parsed = [int(x.strip()) for x in org_ids.split(",") if x.strip()] + except ValueError: + raise HTTPException(400, "org_ids должен быть списком целых чисел") + return parsed or None + + +@router.get("/{sheet}/{year}") +async def get_summary( + sheet: str, + year: int, + response: Response, + org_ids: Optional[str] = None, + db: AsyncSession = Depends(get_db), + current_user: AppUser = Depends(get_current_active_user_with_set_db), +) -> BaseListResponse[SheetResponse]: + if sheet not in VALID_SUMMARY_SHEETS: + raise HTTPException( + 404, + f"Лист свода {sheet} должен быть одни из: {', '.join(sorted(VALID_SUMMARY_SHEETS))}", + ) + + t0 = time.perf_counter() + summary_service = SummaryService(db) + rows = await summary_service.get_rows( + year=year, + sheet=sheet, + org_ids=_parse_org_ids(org_ids), + ) + db_ms = (time.perf_counter() - t0) * 1000 + response.headers["X-DB-Time-Ms"] = f"{db_ms:.2f}" + + extra = { + "type": "db_time", + "time_ms": f"{db_ms:.2f}", + "handler": "get_summary", + "sheet": sheet, + "year": year, + "org_ids": org_ids, + "user": current_user.id, + } + logger.info(f"db_time: {extra}", extra=extra) + + return BaseListResponse( + count=len(rows), + result=_rows_to_sheet_response(rows), + ) diff --git a/api/src/repository/summary_repository.py b/api/src/repository/summary_repository.py new file mode 100644 index 0000000..1cb1e99 --- /dev/null +++ b/api/src/repository/summary_repository.py @@ -0,0 +1,30 @@ +from sqlalchemy import text +from sqlalchemy.ext.asyncio import AsyncSession + + +class SummaryRepository: + def __init__(self, db: AsyncSession): + self.db = db + + async def get_rows( + self, + year: int, + sheet: str, + org_ids: list[int] | None = None, + ) -> list[tuple]: + query = text( + """ + SELECT row_type, depth, sort_order, data + FROM v3.v_summary_view( + CAST(:year AS INT), + CAST(:sheet AS TEXT), + CAST(:org_ids AS INT[]) + ) + """ + ) + return ( + await self.db.execute( + query, + {"year": year, "sheet": sheet, "org_ids": org_ids}, + ) + ).all() diff --git a/api/src/services/summary_service.py b/api/src/services/summary_service.py new file mode 100644 index 0000000..6086043 --- /dev/null +++ b/api/src/services/summary_service.py @@ -0,0 +1,21 @@ +from sqlalchemy.ext.asyncio import AsyncSession + +from src.repository.summary_repository import SummaryRepository + + +class SummaryService: + def __init__(self, db: AsyncSession): + self.db = db + self.summary_repo = SummaryRepository(db) + + async def get_rows( + self, + year: int, + sheet: str, + org_ids: list[int] | None = None, + ) -> list[tuple]: + return await self.summary_repo.get_rows( + year=year, + sheet=sheet, + org_ids=org_ids, + ) diff --git a/api/tests/integration/test_summary_api_smoke.py b/api/tests/integration/test_summary_api_smoke.py new file mode 100644 index 0000000..a96376b --- /dev/null +++ b/api/tests/integration/test_summary_api_smoke.py @@ -0,0 +1,40 @@ +import pytest + + +@pytest.mark.parametrize( + "sheet", + ["FORM_1", "FORM_2", "FORM_3", "FORM_4", "MAIN"], +) +def test_summary_sheets_smoke(client, admin_tokens, auth_headers, sheet): + response = client.get( + f"/api/v1/svod/1/{sheet}/2026", + headers=auth_headers(admin_tokens), + ) + assert response.status_code == 200, f"sheet={sheet}: {response.text}" + payload = response.json() + assert "result" in payload + assert "count" in payload + assert isinstance(payload["result"], list) + + +def test_summary_sheet_with_org_ids(client, admin_tokens, auth_headers): + response = client.get( + "/api/v1/svod/1/FORM_1/2026?org_ids=1,2,3", + headers=auth_headers(admin_tokens), + ) + assert response.status_code == 200 + payload = response.json() + assert "result" in payload + assert payload["result"] + row = payload["result"][0] + assert "row_type" in row + assert "depth" in row + assert "data" in row + + +def test_summary_sheet_unknown(client, admin_tokens, auth_headers): + response = client.get( + "/api/v1/svod/1/unknown_sheet/2026", + headers=auth_headers(admin_tokens), + ) + assert response.status_code == 404 -- 2.47.2