From 7e3c6df7962da1e77dcf8aab333cda872b9bc0db Mon Sep 17 00:00:00 2001 From: tsygankoviva Date: Thu, 1 Oct 2026 11:41:11 +0300 Subject: [PATCH] =?UTF-8?q?columns-svod-2:=20=D0=BF=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BE=D0=BA?= =?UTF-8?q?=20=D1=81=D0=B2=D0=BE=D0=B4=D0=B0=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../versions/0045_summary2_frontend_fields.py | 15 + .../sql/0045_summary2_frontend_fields.sql | 636 ++++++++++++++++++ 2 files changed, 651 insertions(+) create mode 100644 api/alembic/versions/0045_summary2_frontend_fields.py create mode 100644 api/alembic/versions/sql/0045_summary2_frontend_fields.sql diff --git a/api/alembic/versions/0045_summary2_frontend_fields.py b/api/alembic/versions/0045_summary2_frontend_fields.py new file mode 100644 index 0000000..e3de8f6 --- /dev/null +++ b/api/alembic/versions/0045_summary2_frontend_fields.py @@ -0,0 +1,15 @@ +from sql_migration import run_sql_file_migration + + +revision = "0045" +down_revision = "0044" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + run_sql_file_migration("0045_summary2_frontend_fields.sql") + + +def downgrade() -> None: + pass diff --git a/api/alembic/versions/sql/0045_summary2_frontend_fields.sql b/api/alembic/versions/sql/0045_summary2_frontend_fields.sql new file mode 100644 index 0000000..8c1d0bb --- /dev/null +++ b/api/alembic/versions/sql/0045_summary2_frontend_fields.sql @@ -0,0 +1,636 @@ +CREATE OR REPLACE FUNCTION v3.v_svod2_go( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_offset integer DEFAULT NULL, + p_limit integer DEFAULT NULL, + p_sort_by varchar DEFAULT 'org_name', + p_sort_direction varchar DEFAULT 'asc' +) +RETURNS TABLE( + source_form varchar, source_id integer, source_org_unit_id integer, + org_name varchar, smeta_type varchar, + source_line_id integer, sort_order bigint, data jsonb +) +LANGUAGE sql STABLE SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH empty_sections AS MATERIALIZED ( + SELECT + (to_jsonb(jsonb_populate_record(NULL::v3.plan, '{}'::jsonb)) - 'line_id') + || jsonb_build_object('plan_year', NULL) AS plan, + (to_jsonb(jsonb_populate_record(NULL::v3.sequestration, '{}'::jsonb)) + - 'id' - 'line_id' - 'actor') || jsonb_build_object('adj_year', NULL) AS sequestration, + (to_jsonb(jsonb_populate_record(NULL::v3.reserve, '{}'::jsonb)) - 'line_id') + || jsonb_build_object('amount_year', NULL) AS reserve, + jsonb_build_object( + 'approved_q1', NULL, 'approved_q2', NULL, + 'approved_q3', NULL, 'approved_q4', NULL, + 'approved_year', NULL + ) AS approved, + to_jsonb(jsonb_populate_record(NULL::v3.contract_summary, '{}'::jsonb)) - 'line_id' AS contract_summary, + to_jsonb(jsonb_populate_record(NULL::v3.allocation, '{}'::jsonb)) - 'line_id' AS allocation, + to_jsonb(jsonb_populate_record(NULL::v3.collegial_approval, '{}'::jsonb)) - 'line_id' AS collegial, + to_jsonb(jsonb_populate_record(NULL::v3.ckk, '{}'::jsonb)) - 'line_id' AS ckk, + to_jsonb(jsonb_populate_record(NULL::v3.contract_detail, '{}'::jsonb)) - 'line_id' AS contract_detail, + to_jsonb(jsonb_populate_record(NULL::v3.booking, '{}'::jsonb)) - 'id' - 'line_id' AS booking, + to_jsonb(jsonb_populate_record(NULL::v3.budget_line_quarter, '{}'::jsonb)) + - 'line_id' - 'quarter' AS quarter +), eligible_lines AS ( + SELECT + bl.id AS line_id, + bf.form_type_code, + bf.id AS form_id, + bf.org_unit_id, + ou.title AS org_name, + ei.section_code, + ei.item_id, + CASE ei.sheet WHEN 'AHR' THEN 'АХР' WHEN 'CAP' THEN 'КВ' + WHEN 'OPER' THEN 'Операц' END::varchar AS smeta_type + FROM v3.budget_form bf + JOIN v3.budget_line bl ON bl.budget_form_id = bf.id + JOIN v3.expense_item ei ON ei.id = bl.expense_item_id + JOIN v3.contract_detail cd ON cd.line_id = bl.id + LEFT JOIN v3.org_unit ou ON ou.id = bf.org_unit_id + WHERE bf.year = p_year + AND bf.form_type_code IN ('FORM_1', 'FORM_4') + 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)) +), numbered_lines AS ( + SELECT el.*, + row_number() OVER ( + ORDER BY + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'asc' + THEN el.org_name END ASC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'desc' + THEN el.org_name END DESC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'asc' + THEN el.item_id END ASC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'desc' + THEN el.item_id END DESC NULLS LAST, + CASE WHEN p_sort_by = 'section_code' AND lower(p_sort_direction) = 'asc' + THEN el.section_code END ASC NULLS LAST, + CASE WHEN p_sort_by = 'section_code' AND lower(p_sort_direction) = 'desc' + THEN el.section_code END DESC NULLS LAST, + el.form_type_code, el.form_id, el.line_id + ) AS sort_order + FROM eligible_lines el +), page AS MATERIALIZED ( + SELECT * FROM numbered_lines + ORDER BY sort_order + LIMIT p_limit OFFSET COALESCE(p_offset, 0) +), booking_data AS ( + SELECT b.line_id, + jsonb_agg(to_jsonb(b) - 'id' - 'line_id' ORDER BY b.quarter, b.source) AS booking + FROM page pg + JOIN v3.booking b ON b.line_id = pg.line_id + GROUP BY b.line_id +) +SELECT + pg.form_type_code, + pg.form_id, + pg.org_unit_id, + pg.org_name, + pg.smeta_type, + pg.line_id, + pg.sort_order, + jsonb_build_object( + 'line_id', bl.id, + 'header', jsonb_build_object( + 'section_code', ei.section_code, 'item_id', ei.item_id, + 'num_group', ei.num_group_id, 'name', COALESCE(bl.name, ei.name), + 'expense_item_id', ei.id, 'justification', bl.justification, + 'internal_order', bl.internal_order, 'vsp_id', bl.vsp_id, + 'project_id', bl.project_id, 'direction', bl.direction, + 'smeta_direction', CASE bl.direction + WHEN 'Support' THEN 'Поддержка' + WHEN 'Development' THEN 'Развитие' + ELSE NULL + END, + 'source_form', pg.form_type_code, 'source_id', pg.form_id, + 'source_org_unit_id', pg.org_unit_id, 'org_name', pg.org_name, + 'smeta_type', pg.smeta_type), + 'plan', COALESCE( + (to_jsonb(pl) - 'line_id') || jsonb_build_object( + 'plan_year', COALESCE(pl.plan_q1, 0) + COALESCE(pl.plan_q2, 0) + + COALESCE(pl.plan_q3, 0) + COALESCE(pl.plan_q4, 0)), + e.plan || jsonb_build_object('plan_year', NULL)), + 'sequestration', jsonb_build_object( + 'DFIP', COALESCE( + (to_jsonb(sd) - 'id' - 'line_id' - 'actor') || jsonb_build_object( + 'adj_year', COALESCE(sd.adj_q1, 0) + COALESCE(sd.adj_q2, 0) + + COALESCE(sd.adj_q3, 0) + COALESCE(sd.adj_q4, 0)), + e.sequestration || jsonb_build_object('adj_year', NULL)), + 'SSP_GO', COALESCE( + (to_jsonb(ss) - 'id' - 'line_id' - 'actor') || jsonb_build_object( + 'adj_year', COALESCE(ss.adj_q1, 0) + COALESCE(ss.adj_q2, 0) + + COALESCE(ss.adj_q3, 0) + COALESCE(ss.adj_q4, 0)), + e.sequestration || jsonb_build_object('adj_year', NULL))), + 'reserve', COALESCE( + (to_jsonb(rv) - 'line_id') || jsonb_build_object( + 'amount_year', COALESCE(rv.amount_q1, 0) + COALESCE(rv.amount_q2, 0) + + COALESCE(rv.amount_q3, 0) + COALESCE(rv.amount_q4, 0)), + e.reserve || jsonb_build_object('amount_year', NULL)), + 'approved', CASE WHEN pl.line_id IS NULL AND sd.id IS NULL + AND rv.line_id IS NULL + THEN e.approved + ELSE jsonb_build_object( + 'approved_q1', COALESCE(pl.plan_q1, 0) + COALESCE(sd.adj_q1, 0) + + COALESCE(rv.amount_q1, 0), + 'approved_q2', COALESCE(pl.plan_q2, 0) + COALESCE(sd.adj_q2, 0) + + COALESCE(rv.amount_q2, 0), + 'approved_q3', COALESCE(pl.plan_q3, 0) + COALESCE(sd.adj_q3, 0) + + COALESCE(rv.amount_q3, 0), + 'approved_q4', COALESCE(pl.plan_q4, 0) + COALESCE(sd.adj_q4, 0) + + COALESCE(rv.amount_q4, 0), + 'approved_year', COALESCE(pl.plan_q1, 0) + COALESCE(pl.plan_q2, 0) + + COALESCE(pl.plan_q3, 0) + COALESCE(pl.plan_q4, 0) + + COALESCE(sd.adj_q1, 0) + COALESCE(sd.adj_q2, 0) + + COALESCE(sd.adj_q3, 0) + COALESCE(sd.adj_q4, 0) + + COALESCE(rv.amount_q1, 0) + COALESCE(rv.amount_q2, 0) + + COALESCE(rv.amount_q3, 0) + COALESCE(rv.amount_q4, 0)) END, + 'contract_summary', COALESCE(to_jsonb(cs) - 'line_id', e.contract_summary), + 'allocation', COALESCE(to_jsonb(al) - 'line_id', e.allocation), + 'collegial', COALESCE(to_jsonb(ca) - 'line_id', e.collegial), + 'ckk', COALESCE(to_jsonb(ck) - 'line_id', e.ckk), + 'contract_detail', COALESCE(to_jsonb(cd) - 'line_id', e.contract_detail), + 'booking', COALESCE(bk.booking, jsonb_build_array(e.booking)), + 'q1', COALESCE(to_jsonb(q1) - 'line_id' - 'quarter', e.quarter) || jsonb_build_object( + 'booking_amount', CASE WHEN pg.form_type_code = 'FORM_1' + THEN CASE WHEN COALESCE(cd.expenses_q1, 0) > 0 THEN cd.expenses_q1 ELSE ck.expenses_q1 END + ELSE COALESCE(q1.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q1 + WHEN ck.expenses_q1 > 0 THEN ck.expenses_q1 + ELSE cd.expenses_q1 END) END), + 'q2', COALESCE(to_jsonb(q2) - 'line_id' - 'quarter', e.quarter) || jsonb_build_object( + 'booking_amount', CASE WHEN pg.form_type_code = 'FORM_1' + THEN CASE WHEN COALESCE(cd.expenses_q2, 0) > 0 THEN cd.expenses_q2 ELSE ck.expenses_q2 END + ELSE COALESCE(q2.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q2 + WHEN ck.expenses_q2 > 0 THEN ck.expenses_q2 + ELSE cd.expenses_q2 END) END, + 'plan_revision_eco_change', COALESCE(q2.target_change, q2.plan_revision_eco_change), + 'plan_revision_item_adj', COALESCE(q2.base_plan_correction, q2.plan_revision_item_adj)), + 'q3', COALESCE(to_jsonb(q3) - 'line_id' - 'quarter', e.quarter) || jsonb_build_object( + 'booking_amount', CASE WHEN pg.form_type_code = 'FORM_1' + THEN CASE WHEN COALESCE(cd.expenses_q3, 0) > 0 THEN cd.expenses_q3 ELSE ck.expenses_q3 END + ELSE COALESCE(q3.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q3 + WHEN ck.expenses_q3 > 0 THEN ck.expenses_q3 + ELSE cd.expenses_q3 END) END, + 'plan_revision_eco_change', COALESCE(q3.target_change, q3.plan_revision_eco_change), + 'plan_revision_item_adj', COALESCE(q3.base_plan_correction, q3.plan_revision_item_adj)), + 'q4', COALESCE(to_jsonb(q4) - 'line_id' - 'quarter', e.quarter) || jsonb_build_object( + 'booking_amount', CASE WHEN pg.form_type_code = 'FORM_1' + THEN CASE WHEN COALESCE(cd.expenses_q4, 0) > 0 THEN cd.expenses_q4 ELSE ck.expenses_q4 END + ELSE COALESCE(q4.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q4 + WHEN ck.expenses_q4 > 0 THEN ck.expenses_q4 + ELSE cd.expenses_q4 END) END, + 'plan_revision_eco_change', COALESCE(q4.target_change, q4.plan_revision_eco_change), + 'plan_revision_item_adj', COALESCE(q4.base_plan_correction, q4.plan_revision_item_adj)) + ) AS data +FROM page pg +JOIN v3.budget_line bl ON bl.id = pg.line_id +JOIN v3.expense_item ei ON ei.id = bl.expense_item_id +JOIN v3.contract_detail cd ON cd.line_id = bl.id +CROSS JOIN empty_sections e +LEFT JOIN v3.plan pl ON pl.line_id = bl.id +LEFT JOIN v3.sequestration sd ON sd.line_id = bl.id AND sd.actor = 'DFIP' +LEFT JOIN v3.sequestration ss ON ss.line_id = bl.id AND ss.actor = 'SSP_GO' +LEFT JOIN v3.reserve rv ON rv.line_id = bl.id +LEFT JOIN v3.contract_summary cs ON cs.line_id = bl.id +LEFT JOIN v3.allocation al ON al.line_id = bl.id +LEFT JOIN v3.collegial_approval ca ON ca.line_id = bl.id +LEFT JOIN v3.ckk ck ON ck.line_id = bl.id +LEFT JOIN booking_data bk ON bk.line_id = bl.id +LEFT JOIN v3.budget_line_quarter q1 ON q1.line_id = bl.id AND q1.quarter = 1 +LEFT JOIN v3.budget_line_quarter q2 ON q2.line_id = bl.id AND q2.quarter = 2 +LEFT JOIN v3.budget_line_quarter q3 ON q3.line_id = bl.id AND q3.quarter = 3 +LEFT JOIN v3.budget_line_quarter q4 ON q4.line_id = bl.id AND q4.quarter = 4 +ORDER BY pg.sort_order; +$function$; + +CREATE OR REPLACE FUNCTION v3.v_svod2_rf( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_offset integer DEFAULT NULL, + p_limit integer DEFAULT NULL, + p_sort_by varchar DEFAULT 'org_name', + p_sort_direction varchar DEFAULT 'asc' +) +RETURNS TABLE( + source_form varchar, source_id integer, source_org_unit_id integer, + org_name varchar, smeta_type varchar, + source_line_id integer, sort_order bigint, data jsonb +) +LANGUAGE sql STABLE SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH empty_sections AS MATERIALIZED ( + SELECT + (to_jsonb(jsonb_populate_record(NULL::v3.plan, '{}'::jsonb)) - 'line_id') + || jsonb_build_object('plan_year', NULL) AS plan, + (to_jsonb(jsonb_populate_record(NULL::v3.sequestration, '{}'::jsonb)) + - 'id' - 'line_id' - 'actor') || jsonb_build_object('adj_year', NULL) AS sequestration, + (to_jsonb(jsonb_populate_record(NULL::v3.reserve, '{}'::jsonb)) - 'line_id') + || jsonb_build_object('amount_year', NULL) AS reserve, + jsonb_build_object( + 'approved_q1', NULL, 'approved_q2', NULL, + 'approved_q3', NULL, 'approved_q4', NULL, + 'approved_year', NULL + ) AS approved, + to_jsonb(jsonb_populate_record(NULL::v3.contract_summary, '{}'::jsonb)) - 'line_id' AS contract_summary, + to_jsonb(jsonb_populate_record(NULL::v3.allocation, '{}'::jsonb)) - 'line_id' AS allocation, + to_jsonb(jsonb_populate_record(NULL::v3.collegial_approval, '{}'::jsonb)) - 'line_id' AS collegial, + to_jsonb(jsonb_populate_record(NULL::v3.ckk, '{}'::jsonb)) - 'line_id' AS ckk, + to_jsonb(jsonb_populate_record(NULL::v3.contract_detail, '{}'::jsonb)) - 'line_id' AS contract_detail, + to_jsonb(jsonb_populate_record(NULL::v3.booking, '{}'::jsonb)) - 'id' - 'line_id' AS booking, + to_jsonb(jsonb_populate_record(NULL::v3.budget_line_quarter, '{}'::jsonb)) + - 'line_id' - 'quarter' AS budget_quarter +), eligible_lines AS ( + SELECT + 'FORM_2'::varchar AS form_type_code, + bl.id AS line_id, + bf.id AS source_id, + bf.org_unit_id, + ou.title AS org_name, + ei.section_code, + ei.item_id, + CASE ei.sheet WHEN 'AHR' THEN 'АХР' WHEN 'CAP' THEN 'КВ' + WHEN 'OPER' THEN 'Операц' END::varchar AS smeta_type + FROM v3.budget_form bf + JOIN v3.budget_line bl ON bl.budget_form_id = bf.id + JOIN v3.expense_item ei ON ei.id = bl.expense_item_id + JOIN v3.contract_detail cd ON cd.line_id = bl.id + LEFT JOIN v3.org_unit ou ON ou.id = bf.org_unit_id + WHERE bf.year = p_year AND bf.form_type_code = 'FORM_2' + 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)) +), numbered_lines AS ( + SELECT el.*, + row_number() OVER ( + ORDER BY + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'asc' + THEN el.org_name END ASC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'desc' + THEN el.org_name END DESC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'asc' + THEN el.item_id END ASC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'desc' + THEN el.item_id END DESC NULLS LAST, + CASE WHEN p_sort_by = 'section_code' AND lower(p_sort_direction) = 'asc' + THEN el.section_code END ASC NULLS LAST, + CASE WHEN p_sort_by = 'section_code' AND lower(p_sort_direction) = 'desc' + THEN el.section_code END DESC NULLS LAST, + el.form_type_code, el.source_id, el.line_id + ) AS sort_order + FROM eligible_lines el +), page AS MATERIALIZED ( + SELECT * FROM numbered_lines + ORDER BY sort_order + LIMIT p_limit OFFSET COALESCE(p_offset, 0) +), booking_data AS ( + SELECT b.line_id, + jsonb_agg(to_jsonb(b) - 'id' - 'line_id' ORDER BY b.quarter, b.source) AS booking + FROM page pg + JOIN v3.booking b ON b.line_id = pg.line_id + GROUP BY b.line_id +) +SELECT + pg.form_type_code AS source_form, pg.source_id, + pg.org_unit_id AS source_org_unit_id, pg.org_name, pg.smeta_type, + pg.line_id AS source_line_id, pg.sort_order, + jsonb_build_object( + 'line_id', bl.id, + 'header', jsonb_build_object( + 'section_code', ei.section_code, 'item_id', ei.item_id, + 'num_group', ei.num_group_id, 'name', COALESCE(bl.name, ei.name), + 'expense_item_id', ei.id, 'justification', bl.justification, + 'internal_order', bl.internal_order, 'vsp_id', bl.vsp_id, + 'project_id', bl.project_id, 'direction', bl.direction, + 'smeta_direction', CASE bl.direction + WHEN 'Support' THEN 'Поддержка' + WHEN 'Development' THEN 'Развитие' + ELSE NULL + END, + 'source_form', pg.form_type_code, 'source_id', pg.source_id, + 'source_org_unit_id', pg.org_unit_id, 'org_name', pg.org_name, + 'smeta_type', pg.smeta_type), + 'plan', COALESCE( + (to_jsonb(pl) - 'line_id') || jsonb_build_object( + 'plan_year', COALESCE(pl.plan_q1, 0) + COALESCE(pl.plan_q2, 0) + + COALESCE(pl.plan_q3, 0) + COALESCE(pl.plan_q4, 0)), + e.plan || jsonb_build_object('plan_year', NULL)), + 'sequestration', jsonb_build_object( + 'DFIP', COALESCE( + (to_jsonb(sd) - 'id' - 'line_id' - 'actor') || jsonb_build_object( + 'adj_year', COALESCE(sd.adj_q1, 0) + COALESCE(sd.adj_q2, 0) + + COALESCE(sd.adj_q3, 0) + COALESCE(sd.adj_q4, 0)), + e.sequestration || jsonb_build_object('adj_year', NULL)), + 'SSP_GO', COALESCE( + (to_jsonb(ss) - 'id' - 'line_id' - 'actor') || jsonb_build_object( + 'adj_year', COALESCE(ss.adj_q1, 0) + COALESCE(ss.adj_q2, 0) + + COALESCE(ss.adj_q3, 0) + COALESCE(ss.adj_q4, 0)), + e.sequestration || jsonb_build_object('adj_year', NULL))), + 'reserve', COALESCE( + (to_jsonb(rv) - 'line_id') || jsonb_build_object( + 'amount_year', COALESCE(rv.amount_q1, 0) + COALESCE(rv.amount_q2, 0) + + COALESCE(rv.amount_q3, 0) + COALESCE(rv.amount_q4, 0)), + e.reserve || jsonb_build_object('amount_year', NULL)), + 'approved', CASE WHEN pl.line_id IS NULL AND sd.id IS NULL + AND ss.id IS NULL AND rv.line_id IS NULL + THEN e.approved + ELSE jsonb_build_object( + 'approved_q1', COALESCE(pl.plan_q1, 0) + COALESCE(sd.adj_q1, 0) + + COALESCE(ss.adj_q1, 0) + COALESCE(rv.amount_q1, 0), + 'approved_q2', COALESCE(pl.plan_q2, 0) + COALESCE(sd.adj_q2, 0) + + COALESCE(ss.adj_q2, 0) + COALESCE(rv.amount_q2, 0), + 'approved_q3', COALESCE(pl.plan_q3, 0) + COALESCE(sd.adj_q3, 0) + + COALESCE(ss.adj_q3, 0) + COALESCE(rv.amount_q3, 0), + 'approved_q4', COALESCE(pl.plan_q4, 0) + COALESCE(sd.adj_q4, 0) + + COALESCE(ss.adj_q4, 0) + COALESCE(rv.amount_q4, 0), + 'approved_year', COALESCE(pl.plan_q1, 0) + COALESCE(pl.plan_q2, 0) + + COALESCE(pl.plan_q3, 0) + COALESCE(pl.plan_q4, 0) + + COALESCE(sd.adj_q1, 0) + COALESCE(sd.adj_q2, 0) + + COALESCE(sd.adj_q3, 0) + COALESCE(sd.adj_q4, 0) + + COALESCE(ss.adj_q1, 0) + COALESCE(ss.adj_q2, 0) + + COALESCE(ss.adj_q3, 0) + COALESCE(ss.adj_q4, 0) + + COALESCE(rv.amount_q1, 0) + COALESCE(rv.amount_q2, 0) + + COALESCE(rv.amount_q3, 0) + COALESCE(rv.amount_q4, 0)) END, + 'contract_summary', COALESCE(to_jsonb(cs) - 'line_id', e.contract_summary), + 'allocation', COALESCE(to_jsonb(al) - 'line_id', e.allocation), + 'collegial', COALESCE(to_jsonb(ca) - 'line_id', e.collegial), + 'ckk', COALESCE(to_jsonb(ck) - 'line_id', e.ckk), + 'contract_detail', COALESCE(to_jsonb(cd) - 'line_id', e.contract_detail) || jsonb_build_object( + 'expenses_q1', COALESCE(cd.expenses_q1, ck.expenses_q1), + 'expenses_q2', COALESCE(cd.expenses_q2, ck.expenses_q2), + 'expenses_q3', COALESCE(cd.expenses_q3, ck.expenses_q3), + 'expenses_q4', COALESCE(cd.expenses_q4, ck.expenses_q4)), + 'booking', COALESCE(bk.booking, jsonb_build_array(e.booking)), + 'q1', COALESCE(to_jsonb(q1) - 'line_id' - 'quarter', e.budget_quarter) || jsonb_build_object( + 'booking_amount', COALESCE(q1.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q1 + WHEN ck.expenses_q1 > 0 THEN ck.expenses_q1 + ELSE cd.expenses_q1 END)), + 'q2', COALESCE(to_jsonb(q2) - 'line_id' - 'quarter', e.budget_quarter) || jsonb_build_object( + 'booking_amount', COALESCE(q2.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q2 + WHEN ck.expenses_q2 > 0 THEN ck.expenses_q2 + ELSE cd.expenses_q2 END), + 'plan_revision_eco_change', COALESCE(q2.target_change, q2.plan_revision_eco_change), + 'plan_revision_item_adj', COALESCE(q2.base_plan_correction, q2.plan_revision_item_adj)), + 'q3', COALESCE(to_jsonb(q3) - 'line_id' - 'quarter', e.budget_quarter) || jsonb_build_object( + 'booking_amount', COALESCE(q3.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q3 + WHEN ck.expenses_q3 > 0 THEN ck.expenses_q3 + ELSE cd.expenses_q3 END), + 'plan_revision_eco_change', COALESCE(q3.target_change, q3.plan_revision_eco_change), + 'plan_revision_item_adj', COALESCE(q3.base_plan_correction, q3.plan_revision_item_adj)), + 'q4', COALESCE(to_jsonb(q4) - 'line_id' - 'quarter', e.budget_quarter) || jsonb_build_object( + 'booking_amount', COALESCE(q4.booking_amount, + CASE WHEN ei.sheet = 'AHR' THEN ck.expenses_q4 + WHEN ck.expenses_q4 > 0 THEN ck.expenses_q4 + ELSE cd.expenses_q4 END), + 'plan_revision_eco_change', COALESCE(q4.target_change, q4.plan_revision_eco_change), + 'plan_revision_item_adj', COALESCE(q4.base_plan_correction, q4.plan_revision_item_adj)) + ) AS data +FROM page pg +JOIN v3.budget_line bl ON bl.id = pg.line_id +JOIN v3.expense_item ei ON ei.id = bl.expense_item_id +JOIN v3.contract_detail cd ON cd.line_id = bl.id +CROSS JOIN empty_sections e +LEFT JOIN v3.plan pl ON pl.line_id = bl.id +LEFT JOIN v3.sequestration sd ON sd.line_id = bl.id AND sd.actor = 'DFIP' +LEFT JOIN v3.sequestration ss ON ss.line_id = bl.id AND ss.actor = 'SSP_GO' +LEFT JOIN v3.reserve rv ON rv.line_id = bl.id +LEFT JOIN v3.contract_summary cs ON cs.line_id = bl.id +LEFT JOIN v3.allocation al ON al.line_id = bl.id +LEFT JOIN v3.collegial_approval ca ON ca.line_id = bl.id +LEFT JOIN v3.ckk ck ON ck.line_id = bl.id +LEFT JOIN booking_data bk ON bk.line_id = bl.id +LEFT JOIN v3.budget_line_quarter q1 ON q1.line_id = bl.id AND q1.quarter = 1 +LEFT JOIN v3.budget_line_quarter q2 ON q2.line_id = bl.id AND q2.quarter = 2 +LEFT JOIN v3.budget_line_quarter q3 ON q3.line_id = bl.id AND q3.quarter = 3 +LEFT JOIN v3.budget_line_quarter q4 ON q4.line_id = bl.id AND q4.quarter = 4 +ORDER BY pg.sort_order; +$function$; + +CREATE OR REPLACE FUNCTION v3.v_svod2_go_export( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_sort_by varchar DEFAULT 'org_name', + p_sort_direction varchar DEFAULT 'asc' +) +RETURNS TABLE(sort_order bigint, row_values text[]) +LANGUAGE sql +STABLE +SET search_path TO 'v3', 'pg_catalog' +AS $function$ +WITH eligible_lines AS ( + SELECT + bl.id AS line_id, + bf.form_type_code, + bf.id AS form_id, + bf.org_unit_id, + ou.title AS org_name, + ei.section_code, + ei.item_id, + ei.num_group_id, + COALESCE(bl.name, ei.name) AS name, + bl.justification, + CASE bl.direction + WHEN 'Support' THEN 'Поддержка' + WHEN 'Development' THEN 'Развитие' + END::varchar AS smeta_direction, + CASE ei.sheet + WHEN 'AHR' THEN 'АХР' + WHEN 'CAP' THEN 'КВ' + WHEN 'OPER' THEN 'Операц' + END::varchar AS smeta_type, + ei.sheet, + cd.counterparty, + cd.reference, + cd.subject, + cd.currency, + cd.ceiling_amount, + cd.expenses_q1, + cd.expenses_q2, + cd.expenses_q3, + cd.expenses_q4, + cd.vat_rate, + cd.deadline + FROM v3.budget_form bf + JOIN v3.budget_line bl ON bl.budget_form_id = bf.id + JOIN v3.expense_item ei ON ei.id = bl.expense_item_id + JOIN v3.contract_detail cd ON cd.line_id = bl.id + LEFT JOIN v3.org_unit ou ON ou.id = bf.org_unit_id + WHERE bf.year = p_year + AND bf.form_type_code IN ('FORM_1', 'FORM_4') + 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) + ) +), page AS MATERIALIZED ( + SELECT + el.*, + row_number() OVER ( + ORDER BY + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'asc' THEN el.org_name END ASC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'desc' THEN el.org_name END DESC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'asc' THEN el.item_id END ASC NULLS LAST, + CASE WHEN p_sort_by = 'org_name' AND lower(p_sort_direction) = 'desc' THEN el.item_id END DESC NULLS LAST, + CASE WHEN p_sort_by = 'section_code' AND lower(p_sort_direction) = 'asc' THEN el.section_code END ASC NULLS LAST, + CASE WHEN p_sort_by = 'section_code' AND lower(p_sort_direction) = 'desc' THEN el.section_code END DESC NULLS LAST, + el.form_type_code, + el.form_id, + el.line_id + ) AS sort_order + FROM eligible_lines el +) +SELECT + pg.sort_order, + ARRAY[ + pg.smeta_type::text, + pg.smeta_direction::text, + pg.org_name::text, + pg.name::text, + pg.item_id::text, + pg.num_group_id::text, + pg.justification::text, + pl.plan_q1::text, + pl.plan_q2::text, + pl.plan_q3::text, + pl.plan_q4::text, + al.internal_order::text, + al.property_object::text, + sd.adj_q1::text, + sd.adj_q2::text, + sd.adj_q3::text, + sd.adj_q4::text, + rv.amount_q1::text, + rv.amount_q2::text, + rv.amount_q3::text, + rv.amount_q4::text, + (CASE WHEN pl.line_id IS NULL AND sd.id IS NULL AND rv.line_id IS NULL THEN NULL ELSE COALESCE(pl.plan_q1, 0) + COALESCE(sd.adj_q1, 0) + COALESCE(rv.amount_q1, 0) END)::text, + (CASE WHEN pl.line_id IS NULL AND sd.id IS NULL AND rv.line_id IS NULL THEN NULL ELSE COALESCE(pl.plan_q2, 0) + COALESCE(sd.adj_q2, 0) + COALESCE(rv.amount_q2, 0) END)::text, + (CASE WHEN pl.line_id IS NULL AND sd.id IS NULL AND rv.line_id IS NULL THEN NULL ELSE COALESCE(pl.plan_q3, 0) + COALESCE(sd.adj_q3, 0) + COALESCE(rv.amount_q3, 0) END)::text, + (CASE WHEN pl.line_id IS NULL AND sd.id IS NULL AND rv.line_id IS NULL THEN NULL ELSE COALESCE(pl.plan_q4, 0) + COALESCE(sd.adj_q4, 0) + COALESCE(rv.amount_q4, 0) END)::text, + pg.counterparty::text, + pg.reference::text, + pg.subject::text, + pg.currency::text, + pg.ceiling_amount::text, + pg.expenses_q1::text, + pg.expenses_q2::text, + pg.expenses_q3::text, + pg.expenses_q4::text, + pg.vat_rate::text, + pg.deadline::text, + q1.adj_current::text, + q1.adj_ssp::text, + q1.adj_rf::text, + q1.adj_reserve::text, + q1.payment_date::text, + q1.payment_amount::text, + q1.payment_amount_ho::text, + q1.payment_amount_rf::text, + q1.payment_act::text, + (CASE WHEN pg.form_type_code = 'FORM_1' THEN CASE WHEN COALESCE(cd.expenses_q1, 0) > 0 THEN cd.expenses_q1 ELSE ck.expenses_q1 END ELSE COALESCE(q1.booking_amount, + CASE WHEN pg.sheet = 'AHR' THEN ck.expenses_q1 + WHEN ck.expenses_q1 > 0 THEN ck.expenses_q1 + ELSE cd.expenses_q1 END) END)::text, + q1.actual_m1::text, + q1.actual_m2::text, + q1.actual_m3::text, + q1.transfer_to_q2::text, + q1.transfer_to_q3::text, + q1.transfer_to_q4::text, + q1.transfer_to_economy::text, + q2.adj_current::text, + q2.adj_ssp::text, + q2.adj_rf::text, + q2.adj_reserve::text, + q2.payment_date::text, + q2.payment_amount::text, + q2.payment_amount_ho::text, + q2.payment_amount_rf::text, + q2.payment_act::text, + (CASE WHEN pg.form_type_code = 'FORM_1' THEN CASE WHEN COALESCE(cd.expenses_q2, 0) > 0 THEN cd.expenses_q2 ELSE ck.expenses_q2 END ELSE COALESCE(q2.booking_amount, + CASE WHEN pg.sheet = 'AHR' THEN ck.expenses_q2 + WHEN ck.expenses_q2 > 0 THEN ck.expenses_q2 + ELSE cd.expenses_q2 END) END)::text, + q2.actual_m1::text, + q2.actual_m2::text, + q2.actual_m3::text, + COALESCE(q2.target_change, q2.plan_revision_eco_change)::text, + COALESCE(q2.base_plan_correction, q2.plan_revision_item_adj)::text, + q2.plan_revision_increase::text, + q2.plan_revision_sequester::text, + q2.transfer_to_q3::text, + q2.transfer_to_q4::text, + q2.transfer_to_economy::text, + q3.adj_current::text, + q3.adj_ssp::text, + q3.adj_rf::text, + q3.adj_reserve::text, + q3.payment_date::text, + q3.payment_amount::text, + q3.payment_amount_ho::text, + q3.payment_amount_rf::text, + q3.payment_act::text, + (CASE WHEN pg.form_type_code = 'FORM_1' THEN CASE WHEN COALESCE(cd.expenses_q3, 0) > 0 THEN cd.expenses_q3 ELSE ck.expenses_q3 END ELSE COALESCE(q3.booking_amount, + CASE WHEN pg.sheet = 'AHR' THEN ck.expenses_q3 + WHEN ck.expenses_q3 > 0 THEN ck.expenses_q3 + ELSE cd.expenses_q3 END) END)::text, + q3.actual_m1::text, + q3.actual_m2::text, + q3.actual_m3::text, + COALESCE(q3.target_change, q3.plan_revision_eco_change)::text, + COALESCE(q3.base_plan_correction, q3.plan_revision_item_adj)::text, + q3.plan_revision_increase::text, + q3.plan_revision_sequester::text, + q3.transfer_to_q4::text, + q3.transfer_to_economy::text, + q4.adj_current::text, + q4.adj_ssp::text, + q4.adj_rf::text, + q4.adj_reserve::text, + q4.payment_date::text, + q4.payment_amount::text, + q4.payment_amount_ho::text, + q4.payment_amount_rf::text, + q4.payment_act::text, + (CASE WHEN pg.form_type_code = 'FORM_1' THEN CASE WHEN COALESCE(cd.expenses_q4, 0) > 0 THEN cd.expenses_q4 ELSE ck.expenses_q4 END ELSE COALESCE(q4.booking_amount, + CASE WHEN pg.sheet = 'AHR' THEN ck.expenses_q4 + WHEN ck.expenses_q4 > 0 THEN ck.expenses_q4 + ELSE cd.expenses_q4 END) END)::text, + q4.actual_m1::text, + q4.actual_m2::text, + q4.actual_m3::text, + q4.actual_spod::text, + COALESCE(q4.target_change, q4.plan_revision_eco_change)::text, + COALESCE(q4.base_plan_correction, q4.plan_revision_item_adj)::text, + q4.plan_revision_increase::text, + q4.plan_revision_sequester::text + ]::text[] AS row_values +FROM page pg +LEFT JOIN v3.contract_detail cd ON cd.line_id = pg.line_id +LEFT JOIN v3.ckk ck ON ck.line_id = pg.line_id +LEFT JOIN v3.plan pl ON pl.line_id = pg.line_id +LEFT JOIN v3.sequestration sd + ON sd.line_id = pg.line_id + AND sd.actor = 'DFIP' +LEFT JOIN v3.reserve rv ON rv.line_id = pg.line_id +LEFT JOIN v3.allocation al ON al.line_id = pg.line_id +LEFT JOIN v3.budget_line_quarter q1 + ON q1.line_id = pg.line_id AND q1.quarter = 1 +LEFT JOIN v3.budget_line_quarter q2 + ON q2.line_id = pg.line_id AND q2.quarter = 2 +LEFT JOIN v3.budget_line_quarter q3 + ON q3.line_id = pg.line_id AND q3.quarter = 3 +LEFT JOIN v3.budget_line_quarter q4 + ON q4.line_id = pg.line_id AND q4.quarter = 4 +ORDER BY pg.sort_order; +$function$; -- 2.47.2