From adfc2dda81d18869962960f366968b180fe8276f Mon Sep 17 00:00:00 2001 From: tsygankoviva Date: Thu, 24 Sep 2026 12:28:27 +0300 Subject: [PATCH] =?UTF-8?q?form3-pages:=20=D0=BD=D0=BE=D0=B2=D0=B0=D1=8F?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=82=D0=BA=D0=B0=20=D1=82?= =?UTF-8?q?=D1=80=D0=B5=D1=82=D1=8C=D0=B5=D0=B9=20=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D1=8B,=20=D1=81=D0=B2=D0=BE=D0=B4=D0=BD=D1=8B=D0=B5=20=D0=BE?= =?UTF-8?q?=D1=82=D1=87=D0=B5=D1=82=D1=8B=20=D0=BF=D0=BE=20=D1=82=D1=80?= =?UTF-8?q?=D0=B5=D1=82=D1=8C=D0=B5=D0=B9=20=D1=84=D0=BE=D1=80=D0=BC=D0=B5?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=B1=D1=8D=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../versions/0035_project_plan_summary.py | 15 + .../sql/0035_project_plan_summary.sql | 521 ++++++++ api/src/api/v1/projects.py | 112 ++ api/src/repository/project_repository.py | 63 + api/src/services/project_service.py | 62 + .../constants/PROJECT/CURRENT_EXPENSES.js | 1177 +++------------- .../RealtimeTable/constants/PROJECT/LIMIT.js | 1180 +++-------------- 7 files changed, 1159 insertions(+), 1971 deletions(-) create mode 100644 api/alembic/versions/0035_project_plan_summary.py create mode 100644 api/alembic/versions/sql/0035_project_plan_summary.sql diff --git a/api/alembic/versions/0035_project_plan_summary.py b/api/alembic/versions/0035_project_plan_summary.py new file mode 100644 index 0000000..4fb3a56 --- /dev/null +++ b/api/alembic/versions/0035_project_plan_summary.py @@ -0,0 +1,15 @@ +from sql_migration import run_sql_file_migration + + +revision = "0035" +down_revision = "0034" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + run_sql_file_migration("0035_project_plan_summary.sql") + + +def downgrade() -> None: + pass diff --git a/api/alembic/versions/sql/0035_project_plan_summary.sql b/api/alembic/versions/sql/0035_project_plan_summary.sql new file mode 100644 index 0000000..be5a4a0 --- /dev/null +++ b/api/alembic/versions/sql/0035_project_plan_summary.sql @@ -0,0 +1,521 @@ +-- DROP FUNCTION v3.v_project_summary_all_jsonb(integer, integer[], character varying); + +CREATE OR REPLACE FUNCTION v3.v_project_summary_all_jsonb( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_project_type character varying DEFAULT NULL +) +RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb) +LANGUAGE sql +STABLE +AS $function$ +WITH + filtered_projects AS ( + SELECT DISTINCT p.id + FROM v3.project p + JOIN v3.rf_project_year rpy + ON rpy.project_id = p.id + AND rpy.year = p_year + WHERE (p_org_unit_ids IS NULL OR p.org_unit_id = ANY(p_org_unit_ids)) + AND (p_project_type IS NULL OR p.project_type = p_project_type) + ), + form3_items AS ( + SELECT + t.id, + t.depth, + t.path, + t.parent_item_id, + t.desc_ids, + t.item_id, + t.num_group_id, + t.name + FROM v3.mv_expense_item_tree t + JOIN v3.expense_item_form_type eft + ON eft.expense_item_id = t.id + AND eft.form_type_code = 'FORM_3' + ), + matching_reports AS ( + SELECT r.id, r.report_type + FROM filtered_projects fp + JOIN v3.rf_project_report r + ON r.project_id = fp.id + JOIN v3.rf_project_year rpy + ON rpy.id = r.rf_project_year_id + AND rpy.year = p_year + ), + line_values AS ( + SELECT + l.expense_item_id, + mr.report_type, + q.quarter, + SUM(q.base_plan) AS base_plan, + SUM(q.corrected_plan) AS corrected_plan, + SUM(q.adj_by_items) AS adj_by_items, + SUM(q.adj_increase) AS adj_increase, + SUM(q.actual_m1) AS actual_m1, + SUM(q.actual_m2) AS actual_m2, + SUM(q.actual_m3) AS actual_m3, + SUM( + COALESCE(q.actual_m1, 0) + + COALESCE(q.actual_m2, 0) + + COALESCE(q.actual_m3, 0) + + CASE WHEN q.quarter = 4 THEN COALESCE(q.actual_spod, 0) ELSE 0 END + ) AS actual_amount + FROM matching_reports mr + JOIN v3.rf_project_report_line l + ON l.rf_project_report_id = mr.id + JOIN v3.rf_project_report_quarter q + ON q.rf_project_report_line_id = l.id + GROUP BY l.expense_item_id, mr.report_type, q.quarter + ), + aggregated AS ( + SELECT + fi.id AS expense_item_id, + CASE WHEN fi.depth < 3 THEN fi.item_id ELSE fi.parent_item_id END AS section_code, + CASE WHEN fi.depth = 3 THEN fi.item_id ELSE NULL END AS item_id, + fi.num_group_id, + fi.name, + fi.depth, + fi.path, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 1), 0) AS base_limit_q1, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 2), 0) AS base_limit_q2, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 3), 0) AS base_limit_q3, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 4), 0) AS base_limit_q4, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 1), 0) AS base_current_q1, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 2), 0) AS base_current_q2, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 3), 0) AS base_current_q3, + COALESCE(SUM(lv.base_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 4), 0) AS base_current_q4, + COALESCE(SUM(lv.corrected_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 2), 0) AS correction_limit_q2, + COALESCE(SUM(lv.corrected_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 3), 0) AS correction_limit_q3, + COALESCE(SUM(lv.corrected_plan) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 4), 0) AS correction_limit_q4, + COALESCE(SUM(lv.corrected_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 2), 0) AS correction_current_q2, + COALESCE(SUM(lv.corrected_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 3), 0) AS correction_current_q3, + COALESCE(SUM(lv.corrected_plan) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 4), 0) AS correction_current_q4, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 1), 0) AS fact_limit_q1, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 2), 0) AS fact_limit_q2, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 3), 0) AS fact_limit_q3, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'LIMIT' AND lv.quarter = 4), 0) AS fact_limit_q4, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 1), 0) AS fact_current_q1, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 2), 0) AS fact_current_q2, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 3), 0) AS fact_current_q3, + COALESCE(SUM(lv.actual_amount) FILTER (WHERE lv.report_type = 'CURRENT_EXPENSES' AND lv.quarter = 4), 0) AS fact_current_q4, + COALESCE(SUM(lv.adj_by_items) FILTER (WHERE lv.quarter = 1), 0) AS detail_adj_by_items_q1, + COALESCE(SUM(lv.adj_by_items) FILTER (WHERE lv.quarter = 2), 0) AS detail_adj_by_items_q2, + COALESCE(SUM(lv.adj_by_items) FILTER (WHERE lv.quarter = 3), 0) AS detail_adj_by_items_q3, + COALESCE(SUM(lv.adj_by_items) FILTER (WHERE lv.quarter = 4), 0) AS detail_adj_by_items_q4, + COALESCE(SUM(lv.adj_increase) FILTER (WHERE lv.quarter = 1), 0) AS detail_adj_increase_q1, + COALESCE(SUM(lv.adj_increase) FILTER (WHERE lv.quarter = 2), 0) AS detail_adj_increase_q2, + COALESCE(SUM(lv.adj_increase) FILTER (WHERE lv.quarter = 3), 0) AS detail_adj_increase_q3, + COALESCE(SUM(lv.adj_increase) FILTER (WHERE lv.quarter = 4), 0) AS detail_adj_increase_q4, + COALESCE(SUM(lv.actual_m1) FILTER (WHERE lv.quarter = 1), 0) AS detail_actual_m1_q1, + COALESCE(SUM(lv.actual_m1) FILTER (WHERE lv.quarter = 2), 0) AS detail_actual_m1_q2, + COALESCE(SUM(lv.actual_m1) FILTER (WHERE lv.quarter = 3), 0) AS detail_actual_m1_q3, + COALESCE(SUM(lv.actual_m1) FILTER (WHERE lv.quarter = 4), 0) AS detail_actual_m1_q4, + COALESCE(SUM(lv.actual_m2) FILTER (WHERE lv.quarter = 1), 0) AS detail_actual_m2_q1, + COALESCE(SUM(lv.actual_m2) FILTER (WHERE lv.quarter = 2), 0) AS detail_actual_m2_q2, + COALESCE(SUM(lv.actual_m2) FILTER (WHERE lv.quarter = 3), 0) AS detail_actual_m2_q3, + COALESCE(SUM(lv.actual_m2) FILTER (WHERE lv.quarter = 4), 0) AS detail_actual_m2_q4, + COALESCE(SUM(lv.actual_m3) FILTER (WHERE lv.quarter = 1), 0) AS detail_actual_m3_q1, + COALESCE(SUM(lv.actual_m3) FILTER (WHERE lv.quarter = 2), 0) AS detail_actual_m3_q2, + COALESCE(SUM(lv.actual_m3) FILTER (WHERE lv.quarter = 3), 0) AS detail_actual_m3_q3, + COALESCE(SUM(lv.actual_m3) FILTER (WHERE lv.quarter = 4), 0) AS detail_actual_m3_q4 + FROM form3_items fi + LEFT JOIN line_values lv + ON lv.expense_item_id = ANY(fi.desc_ids) + GROUP BY fi.id, fi.depth, fi.path, fi.parent_item_id, fi.item_id, fi.num_group_id, fi.name + ) +SELECT + CASE a.depth WHEN 0 THEN 'ROOT' WHEN 1 THEN 'GROUP' WHEN 2 THEN 'ITEM' ELSE 'SUB_ITEM' END::varchar AS row_type, + COALESCE(a.depth, 0)::integer AS depth, + ROW_NUMBER() OVER (ORDER BY a.path) AS sort_order, + jsonb_build_object( + 'header', jsonb_build_object( + 'expense_item_id', a.expense_item_id, + 'section_code', a.section_code, + 'item_id', a.item_id, + 'num_group_id', a.num_group_id, + 'name', a.name, + 'year', p_year + ), + 'base', jsonb_build_object( + 'limit', jsonb_build_object('q1', a.base_limit_q1, 'q2', a.base_limit_q2, 'q3', a.base_limit_q3, 'q4', a.base_limit_q4, 'year', a.base_limit_q1 + a.base_limit_q2 + a.base_limit_q3 + a.base_limit_q4), + 'current', jsonb_build_object('q1', a.base_current_q1, 'q2', a.base_current_q2, 'q3', a.base_current_q3, 'q4', a.base_current_q4, 'year', a.base_current_q1 + a.base_current_q2 + a.base_current_q3 + a.base_current_q4), + 'total', jsonb_build_object( + 'q1', a.base_limit_q1 + a.base_current_q1, + 'q2', a.base_limit_q2 + a.base_current_q2, + 'q3', a.base_limit_q3 + a.base_current_q3, + 'q4', a.base_limit_q4 + a.base_current_q4, + 'year', a.base_limit_q1 + a.base_limit_q2 + a.base_limit_q3 + a.base_limit_q4 + a.base_current_q1 + a.base_current_q2 + a.base_current_q3 + a.base_current_q4 + ) + ), + 'correction', jsonb_build_object( + 'limit', jsonb_build_object('q2', a.correction_limit_q2, 'q3', a.correction_limit_q3, 'q4', a.correction_limit_q4, 'year', a.correction_limit_q2 + a.correction_limit_q3 + a.correction_limit_q4), + 'current', jsonb_build_object('q2', a.correction_current_q2, 'q3', a.correction_current_q3, 'q4', a.correction_current_q4, 'year', a.correction_current_q2 + a.correction_current_q3 + a.correction_current_q4), + 'total', jsonb_build_object( + 'q2', a.correction_limit_q2 + a.correction_current_q2, + 'q3', a.correction_limit_q3 + a.correction_current_q3, + 'q4', a.correction_limit_q4 + a.correction_current_q4, + 'year', a.correction_limit_q2 + a.correction_limit_q3 + a.correction_limit_q4 + a.correction_current_q2 + a.correction_current_q3 + a.correction_current_q4 + ) + ), + 'fact', jsonb_build_object( + 'limit', jsonb_build_object('q1', a.fact_limit_q1, 'q2', a.fact_limit_q2, 'q3', a.fact_limit_q3, 'q4', a.fact_limit_q4, 'year', a.fact_limit_q1 + a.fact_limit_q2 + a.fact_limit_q3 + a.fact_limit_q4), + 'current', jsonb_build_object('q1', a.fact_current_q1, 'q2', a.fact_current_q2, 'q3', a.fact_current_q3, 'q4', a.fact_current_q4, 'year', a.fact_current_q1 + a.fact_current_q2 + a.fact_current_q3 + a.fact_current_q4), + 'total', jsonb_build_object( + 'q1', a.fact_limit_q1 + a.fact_current_q1, + 'q2', a.fact_limit_q2 + a.fact_current_q2, + 'q3', a.fact_limit_q3 + a.fact_current_q3, + 'q4', a.fact_limit_q4 + a.fact_current_q4, + 'year', a.fact_limit_q1 + a.fact_limit_q2 + a.fact_limit_q3 + a.fact_limit_q4 + a.fact_current_q1 + a.fact_current_q2 + a.fact_current_q3 + a.fact_current_q4 + ) + ), + 'detail', jsonb_build_object( + 'q1', jsonb_build_object('adj_by_items', a.detail_adj_by_items_q1, 'adj_increase', a.detail_adj_increase_q1, 'actual_m1', a.detail_actual_m1_q1, 'actual_m2', a.detail_actual_m2_q1, 'actual_m3', a.detail_actual_m3_q1, 'quarter', a.detail_actual_m1_q1 + a.detail_actual_m2_q1 + a.detail_actual_m3_q1, 'residual', a.detail_adj_by_items_q1 + a.detail_adj_increase_q1 - (a.detail_actual_m1_q1 + a.detail_actual_m2_q1 + a.detail_actual_m3_q1)), + 'q2', jsonb_build_object('adj_by_items', a.detail_adj_by_items_q2, 'adj_increase', a.detail_adj_increase_q2, 'actual_m1', a.detail_actual_m1_q2, 'actual_m2', a.detail_actual_m2_q2, 'actual_m3', a.detail_actual_m3_q2, 'quarter', a.detail_actual_m1_q2 + a.detail_actual_m2_q2 + a.detail_actual_m3_q2, 'residual', a.detail_adj_by_items_q2 + a.detail_adj_increase_q2 - (a.detail_actual_m1_q2 + a.detail_actual_m2_q2 + a.detail_actual_m3_q2)), + 'q3', jsonb_build_object('adj_by_items', a.detail_adj_by_items_q3, 'adj_increase', a.detail_adj_increase_q3, 'actual_m1', a.detail_actual_m1_q3, 'actual_m2', a.detail_actual_m2_q3, 'actual_m3', a.detail_actual_m3_q3, 'quarter', a.detail_actual_m1_q3 + a.detail_actual_m2_q3 + a.detail_actual_m3_q3, 'residual', a.detail_adj_by_items_q3 + a.detail_adj_increase_q3 - (a.detail_actual_m1_q3 + a.detail_actual_m2_q3 + a.detail_actual_m3_q3)), + 'q4', jsonb_build_object('adj_by_items', a.detail_adj_by_items_q4, 'adj_increase', a.detail_adj_increase_q4, 'actual_m1', a.detail_actual_m1_q4, 'actual_m2', a.detail_actual_m2_q4, 'actual_m3', a.detail_actual_m3_q4, 'quarter', a.detail_actual_m1_q4 + a.detail_actual_m2_q4 + a.detail_actual_m3_q4, 'residual', a.detail_adj_by_items_q4 + a.detail_adj_increase_q4 - (a.detail_actual_m1_q4 + a.detail_actual_m2_q4 + a.detail_actual_m3_q4)), + 'year', (a.detail_actual_m1_q1 + a.detail_actual_m2_q1 + a.detail_actual_m3_q1) + (a.detail_actual_m1_q2 + a.detail_actual_m2_q2 + a.detail_actual_m3_q2) + (a.detail_actual_m1_q3 + a.detail_actual_m2_q3 + a.detail_actual_m3_q3) + (a.detail_actual_m1_q4 + a.detail_actual_m2_q4 + a.detail_actual_m3_q4) + ) + ) AS data +FROM aggregated a +ORDER BY a.path; +$function$ +; + +-- DROP FUNCTION v3.v_form4_sheet_lines_jsonb(int4, varchar, _text); + +CREATE OR REPLACE FUNCTION v3.v_form4_sheet_lines_jsonb(p_form_id integer, p_sheet character varying, p_sections text[] DEFAULT NULL::text[]) + RETURNS TABLE(row_type character varying, depth integer, line_id integer, header jsonb, plan_data jsonb, seq_dfip_data jsonb, approved_data jsonb, contract_summary_data jsonb, allocation_data jsonb, reserve_data jsonb, collegial_data jsonb, ckk_data jsonb, contract_data jsonb, booking_data jsonb, q1_data jsonb, q2_data jsonb, q3_data jsonb, q4_data jsonb, totals_data jsonb, _sort_path integer[]) + LANGUAGE sql + STABLE +AS $function$ + WITH flags AS ( + SELECT + (p_sections IS NULL OR 'plan' = ANY(p_sections)) AS s_plan, + (p_sections IS NULL OR 'seq_dfip' = ANY(p_sections)) AS s_seq_d, + (p_sections IS NULL OR 'approved' = ANY(p_sections)) AS s_appr, + (p_sections IS NULL OR 'contract_summary' = ANY(p_sections)) AS s_cs, + (p_sections IS NULL OR 'allocation' = ANY(p_sections)) AS s_al, + (p_sections IS NULL OR 'reserve' = ANY(p_sections)) AS s_rsv, + (p_sections IS NULL OR 'collegial' = ANY(p_sections)) AS s_col, + (p_sections IS NULL OR 'ckk' = ANY(p_sections)) AS s_ckk, + (p_sections IS NULL OR 'contract' = ANY(p_sections)) AS s_cd, + (p_sections IS NULL OR 'booking' = ANY(p_sections)) AS s_book, + (p_sections IS NULL OR 'q1' = ANY(p_sections)) AS s_q1, + (p_sections IS NULL OR 'q2' = ANY(p_sections)) AS s_q2, + (p_sections IS NULL OR 'q3' = ANY(p_sections)) AS s_q3, + (p_sections IS NULL OR 'q4' = ANY(p_sections)) AS s_q4, + (p_sections IS NULL OR 'totals' = ANY(p_sections)) AS s_tot + ) + SELECT + s.row_type, s.depth, s.line_id, + + jsonb_build_object( + 'section_code', s.col_section_code, + 'item_id', s.col_item_id, + 'num_group', s.col_num_group_id, + 'name', s.col_name, + 'justification', s.col_justification, + 'internal_order', s.col_internal_order, + 'vsp_id', s.col_vsp_id, + 'vsp_address', s.col_vsp_address, + 'expense_item_id', CASE WHEN s.row_type = 'INPUT' + THEN s._sort_path[array_upper(s._sort_path,1)-1] + ELSE s._sort_path[array_upper(s._sort_path,1)] END + ) AS header, + + CASE WHEN f.s_plan THEN jsonb_build_object( + 'q1', s.col_plan_q1, 'q2', s.col_plan_q2, + 'q3', s.col_plan_q3, 'q4', s.col_plan_q4, + 'year', s.col_plan_year, 'comment', s.col_plan_comment + ) END AS plan_data, + + CASE WHEN f.s_seq_d THEN jsonb_build_object( + 'q1', s.col_seq_dfip_q1, 'q2', s.col_seq_dfip_q2, + 'q3', s.col_seq_dfip_q3, 'q4', s.col_seq_dfip_q4, + 'year', s.col_seq_dfip_year, + 'justification', s.col_seq_dfip_just + ) END AS seq_dfip_data, + + CASE WHEN f.s_appr THEN jsonb_build_object( + 'q1', s.col_appr_q1, 'q2', s.col_appr_q2, + 'q3', s.col_appr_q3, 'q4', s.col_appr_q4, + 'year', s.col_appr_year + ) END AS approved_data, + + CASE WHEN f.s_cs THEN jsonb_build_object( + 'total', s.col_cs_amount, + 'reference', s.col_cs_reference, + 'counterparty', s.col_cs_counterparty, + 'deadline', s.col_cs_deadline, + 'comment', s.col_cs_comment, + 'future_y1', s.col_cs_future_y1, + 'future_y2', s.col_cs_future_y2, + 'other_ssp', s.col_cs_other_ssp, + 'centralized_flag', s.col_cs_centralized_flag + ) END AS contract_summary_data, + + CASE WHEN f.s_al THEN jsonb_build_object( + 'contract_ref', s.col_al_contract_ref, + 'allocation_purpose', s.col_al_purpose + ) END AS allocation_data, + + CASE WHEN f.s_rsv THEN jsonb_build_object( + 'q1', s.col_rsv_q1, 'q2', s.col_rsv_q2, + 'q3', s.col_rsv_q3, 'q4', s.col_rsv_q4, + 'year', s.col_rsv_year, + 'justification', s.col_rsv_just + ) END AS reserve_data, + + CASE WHEN f.s_col THEN jsonb_build_object( + 'approved', s.col_col_amount, + 'protocol', s.col_col_protocol, + 'note', s.col_col_note + ) END AS collegial_data, + + CASE WHEN f.s_ckk THEN jsonb_build_object( + 'ceiling', s.col_ckk_ceiling, + 'q1', s.col_ckk_q1, + 'q2', s.col_ckk_q2, + 'q3', s.col_ckk_q3, + 'q4', s.col_ckk_q4, + 'rf_schedule', s.col_ckk_rf_schedule, + 'deadline', s.col_ckk_delivery_deadline, + 'proc_plan', s.col_ckk_procurement_plan, + 'proc_method', s.col_ckk_procurement_method, + 'comment', s.col_ckk_comment + ) END AS ckk_data, + + CASE WHEN f.s_cd THEN jsonb_build_object( + 'counterparty', s.col_cd_counterparty, + 'reference', s.col_cd_reference, + 'addenda', s.col_cd_addenda, + 'date', TO_CHAR(s.col_cd_date, 'DD.MM.YYYY'), + 'subject', s.col_cd_subject, + 'currency', s.col_cd_currency, + 'ceiling', s.col_cd_ceiling, + 'q1', s.col_cd_q1, + 'q2', s.col_cd_q2, + 'q3', s.col_cd_q3, + 'q4', s.col_cd_q4, + 'rf_schedule', s.col_cd_rf_schedule, + 'vat_rate', s.col_cd_vat_rate, + 'exchange_rate', s.col_cd_exchange_rate, + 'amount_foreign', s.col_cd_amount_foreign, + 'deadline', s.col_cd_deadline, + 'scheme', s.col_cd_scheme, + 'act', s.col_cd_act, + 'comment', s.col_cd_comment + ) END AS contract_data, + + CASE WHEN f.s_book THEN jsonb_build_object( + 'y2026', jsonb_build_object('q1', s.col_book_q1, 'q2', s.col_book_q2, 'q3', s.col_book_q3, 'q4', s.col_book_q4), + 'y2027', jsonb_build_object('q1', s.col_book_next_q1, 'q2', s.col_book_next_q2, 'q3', s.col_book_next_q3, 'q4', s.col_book_next_q4) + ) END AS booking_data, + + CASE WHEN f.s_q1 THEN jsonb_build_object( + 'adj_current', s.col_q1_adj_current, + 'adj_ssp', s.col_q1_adj_ssp, + 'adj_rf', s.col_q1_adj_rf, + 'adj_reserve', s.col_q1_adj_reserve, + 'adj_comment', s.col_q1_adj_comment, + 'corrected_plan', s.col_q1_corrected_plan, + 'pay_date', TO_CHAR(s.col_q1_pay_date, 'DD.MM.YYYY'), + 'pay_amount', s.col_q1_pay_amount, + 'pay_ho', s.col_q1_pay_ho, + 'pay_rf', s.col_q1_pay_rf, + 'pay_comment', s.col_q1_pay_comment, + 'pay_act', s.col_q1_pay_act, + 'booking', s.col_q1_booking, + 'actual_m1', s.col_q1_actual_m1, + 'actual_m2', s.col_q1_actual_m2, + 'actual_m3', s.col_q1_actual_m3, + 'actual_quarter', s.col_q1_actual_quarter, + 'residual_after_booking', s.col_q1_residual_after_booking, + 'residual_after_actual', s.col_q1_residual_after_actual, + 'transfer_q2', s.col_q1_transfer_q2, + 'transfer_q3', s.col_q1_transfer_q3, + 'transfer_q4', s.col_q1_transfer_q4, + 'transfer_econ', s.col_q1_transfer_econ, + 'total', s.col_q1_total + ) END AS q1_data, + + CASE WHEN f.s_q2 THEN jsonb_build_object( + 'target_change', s.col_q2_target_change, + 'base_correction', s.col_q2_base_correction, + 'base_correction_comment', s.col_q2_base_correction_comment, + 'revision_inc', s.col_q2_revision_inc, + 'revision_seq', s.col_q2_revision_seq, + 'revision_comment', s.col_q2_revision_comment, + 'new_plan', s.col_q2_new_plan, + 'adj_current', s.col_q2_adj_current, + 'adj_ssp', s.col_q2_adj_ssp, + 'adj_rf', s.col_q2_adj_rf, + 'adj_reserve', s.col_q2_adj_reserve, + 'adj_comment', s.col_q2_adj_comment, + 'corrected_plan', s.col_q2_corrected_plan, + 'pay_date', TO_CHAR(s.col_q2_pay_date, 'DD.MM.YYYY'), + 'pay_amount', s.col_q2_pay_amount, + 'pay_ho', s.col_q2_pay_ho, + 'pay_rf', s.col_q2_pay_rf, + 'pay_comment', s.col_q2_pay_comment, + 'pay_act', s.col_q2_pay_act, + 'booking', s.col_q2_booking, + 'actual_m1', s.col_q2_actual_m1, + 'actual_m2', s.col_q2_actual_m2, + 'actual_m3', s.col_q2_actual_m3, + 'actual_quarter', s.col_q2_actual_quarter, + 'residual_after_booking', s.col_q2_residual_after_booking, + 'residual_after_actual', s.col_q2_residual_after_actual, + 'transfer_q3', s.col_q2_transfer_q3, + 'transfer_q4', s.col_q2_transfer_q4, + 'transfer_econ', s.col_q2_transfer_econ, + 'total', s.col_q2_total + ) END AS q2_data, + + CASE WHEN f.s_q3 THEN jsonb_build_object( + 'target_change', s.col_q3_target_change, + 'base_correction', s.col_q3_base_correction, + 'base_correction_comment', s.col_q3_base_correction_comment, + 'revision_inc', s.col_q3_revision_inc, + 'revision_seq', s.col_q3_revision_seq, + 'revision_comment', s.col_q3_revision_comment, + 'new_plan', s.col_q3_new_plan, + 'adj_current', s.col_q3_adj_current, + 'adj_ssp', s.col_q3_adj_ssp, + 'adj_rf', s.col_q3_adj_rf, + 'adj_reserve', s.col_q3_adj_reserve, + 'adj_comment', s.col_q3_adj_comment, + 'corrected_plan', s.col_q3_corrected_plan, + 'pay_date', TO_CHAR(s.col_q3_pay_date, 'DD.MM.YYYY'), + 'pay_amount', s.col_q3_pay_amount, + 'pay_ho', s.col_q3_pay_ho, + 'pay_rf', s.col_q3_pay_rf, + 'pay_comment', s.col_q3_pay_comment, + 'pay_act', s.col_q3_pay_act, + 'booking', s.col_q3_booking, + 'actual_m1', s.col_q3_actual_m1, + 'actual_m2', s.col_q3_actual_m2, + 'actual_m3', s.col_q3_actual_m3, + 'actual_quarter', s.col_q3_actual_quarter, + 'residual_after_booking', s.col_q3_residual_after_booking, + 'residual_after_actual', s.col_q3_residual_after_actual, + 'transfer_q4', s.col_q3_transfer_q4, + 'transfer_econ', s.col_q3_transfer_econ, + 'total', s.col_q3_total + ) END AS q3_data, + + CASE WHEN f.s_q4 THEN jsonb_build_object( + 'target_change', s.col_q4_target_change, + 'base_correction', s.col_q4_base_correction, + 'base_correction_comment', s.col_q4_base_correction_comment, + 'revision_inc', s.col_q4_revision_inc, + 'revision_seq', s.col_q4_revision_seq, + 'revision_comment', s.col_q4_revision_comment, + 'new_plan', s.col_q4_new_plan, + 'adj_current', s.col_q4_adj_current, + 'adj_ssp', s.col_q4_adj_ssp, + 'adj_rf', s.col_q4_adj_rf, + 'adj_reserve', s.col_q4_adj_reserve, + 'adj_comment', s.col_q4_adj_comment, + 'corrected_plan', s.col_q4_corrected_plan, + 'pay_date', TO_CHAR(s.col_q4_pay_date, 'DD.MM.YYYY'), + 'pay_amount', s.col_q4_pay_amount, + 'pay_ho', s.col_q4_pay_ho, + 'pay_rf', s.col_q4_pay_rf, + 'pay_comment', s.col_q4_pay_comment, + 'pay_act', s.col_q4_pay_act, + 'booking', s.col_q4_booking, + 'actual_m1', s.col_q4_actual_m1, + 'actual_m2', s.col_q4_actual_m2, + 'actual_m3', s.col_q4_actual_m3, + 'actual_spod', s.col_q4_actual_spod, + 'actual_rsbu_spod', COALESCE(s.col_q4_actual_m1, 0) + COALESCE(s.col_q4_actual_m2, 0) + COALESCE(s.col_q4_actual_m3, 0) + COALESCE(s.col_q4_actual_spod, 0), + 'actual_quarter', COALESCE(s.col_q4_actual_m1, 0) + COALESCE(s.col_q4_actual_m2, 0) + COALESCE(s.col_q4_actual_m3, 0), + 'residual_after_booking', s.col_q4_residual_after_booking, + 'residual_after_actual', s.col_q4_residual_after_actual, + 'transfer_econ', s.col_q4_transfer_econ, + 'total', s.col_q4_total + ) END AS q4_data, + + CASE WHEN f.s_tot THEN jsonb_build_object( + 'fact_year', s.col_fact_year + ) END AS totals_data, + + s._sort_path + FROM v3.v_form4_sheet_sections(p_form_id, p_sheet, p_sections) s + CROSS JOIN flags f + ORDER BY s._sort_path; +$function$ +; + + +-- DROP FUNCTION v3.v_project_plan_summary_jsonb(integer, integer[], character varying); + +CREATE OR REPLACE FUNCTION v3.v_project_plan_summary_jsonb( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_project_type character varying DEFAULT NULL +) +RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb) +LANGUAGE sql +STABLE +AS $function$ + SELECT + row_type, + depth, + sort_order, + jsonb_build_object( + 'header', data->'header', + 'base', data->'base', + 'correction', data->'correction' + ) AS data + FROM v3.v_project_summary_all_jsonb(p_year, p_org_unit_ids, p_project_type); +$function$ +; + +-- DROP FUNCTION v3.v_project_fact_summary_jsonb(integer, integer[], character varying); + +CREATE OR REPLACE FUNCTION v3.v_project_fact_summary_jsonb( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_project_type character varying DEFAULT NULL +) +RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb) +LANGUAGE sql +STABLE +AS $function$ + SELECT + row_type, + depth, + sort_order, + jsonb_build_object( + 'header', data->'header', + 'fact', data->'fact' + ) AS data + FROM v3.v_project_summary_all_jsonb(p_year, p_org_unit_ids, p_project_type); +$function$ +; + +-- DROP FUNCTION v3.v_project_detail_summary_jsonb(integer, integer[], character varying); + +CREATE OR REPLACE FUNCTION v3.v_project_detail_summary_jsonb( + p_year integer, + p_org_unit_ids integer[] DEFAULT NULL, + p_project_type character varying DEFAULT NULL +) +RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb) +LANGUAGE sql +STABLE +AS $function$ + SELECT + row_type, + depth, + sort_order, + jsonb_build_object( + 'header', data->'header', + 'detail', data->'detail' + ) AS data + FROM v3.v_project_summary_all_jsonb(p_year, p_org_unit_ids, p_project_type); +$function$ +; diff --git a/api/src/api/v1/projects.py b/api/src/api/v1/projects.py index 8017e95..e929082 100644 --- a/api/src/api/v1/projects.py +++ b/api/src/api/v1/projects.py @@ -114,6 +114,118 @@ async def get_projects_with_reports( return BaseListResponse(result=projects, count=count) +async def _get_projects_summary_response( + *, + year: int, + response: Response, + branch_id: Optional[str], + project_type: Optional[str], + handler_name: str, + rows, + current_user: AppUser, +) -> BaseListResponse[SheetResponse]: + db_ms = (time.perf_counter() - rows["t0"]) * 1000 + response.headers["X-DB-Time-Ms"] = f"{db_ms:.2f}" + extra = { + "type": "db_time", + "time_ms": f"{db_ms:.2f}", + "handler": handler_name, + "year": year, + "branch_id": branch_id, + "project_type": project_type, + "user": current_user.id, + } + logger.info(f"db_time: {extra}", extra=extra) + return BaseListResponse(count=len(rows["data"]), result=_rows_to_payload(rows["data"])) + + +@router.get("/projects/plan-summary") +async def get_projects_plan_summary( + year: int, + response: Response, + branch_id: Optional[str] = None, + project_type: Optional[str] = None, + db: AsyncSession = Depends(get_db), + current_user: AppUser = Depends(get_current_active_user_with_set_db), +) -> BaseListResponse[SheetResponse]: + branch_ids = _parse_org_units_csv(branch_id) + project_service = ProjectService(db) + t0 = time.perf_counter() + rows = await project_service.get_plan_summary_rows( + year=year, + branch_ids=branch_ids, + user=current_user, + project_type=project_type, + ) + return await _get_projects_summary_response( + year=year, + response=response, + branch_id=branch_id, + project_type=project_type, + handler_name="get_projects_plan_summary", + rows={"t0": t0, "data": rows}, + current_user=current_user, + ) + + +@router.get("/projects/fact-summary") +async def get_projects_fact_summary( + year: int, + response: Response, + branch_id: Optional[str] = None, + project_type: Optional[str] = None, + db: AsyncSession = Depends(get_db), + current_user: AppUser = Depends(get_current_active_user_with_set_db), +) -> BaseListResponse[SheetResponse]: + branch_ids = _parse_org_units_csv(branch_id) + project_service = ProjectService(db) + t0 = time.perf_counter() + rows = await project_service.get_fact_summary_rows( + year=year, + branch_ids=branch_ids, + user=current_user, + project_type=project_type, + ) + return await _get_projects_summary_response( + year=year, + response=response, + branch_id=branch_id, + project_type=project_type, + handler_name="get_projects_fact_summary", + rows={"t0": t0, "data": rows}, + current_user=current_user, + ) + + +@router.get("/projects/detail-summary") +async def get_projects_detail_summary( + year: int, + response: Response, + branch_id: Optional[str] = None, + project_type: Optional[str] = None, + db: AsyncSession = Depends(get_db), + current_user: AppUser = Depends(get_current_active_user_with_set_db), +) -> BaseListResponse[SheetResponse]: + branch_ids = _parse_org_units_csv(branch_id) + project_service = ProjectService(db) + t0 = time.perf_counter() + rows = await project_service.get_detail_summary_rows( + year=year, + branch_ids=branch_ids, + user=current_user, + project_type=project_type, + ) + return await _get_projects_summary_response( + year=year, + response=response, + branch_id=branch_id, + project_type=project_type, + handler_name="get_projects_detail_summary", + rows={"t0": t0, "data": rows}, + current_user=current_user, + ) + + @router.get("/projects/{project_id}") async def get_project( project_id: int, diff --git a/api/src/repository/project_repository.py b/api/src/repository/project_repository.py index a43fc67..3a95d64 100644 --- a/api/src/repository/project_repository.py +++ b/api/src/repository/project_repository.py @@ -408,6 +408,69 @@ class ProjectRepository: await self.db.execute(query, {"project_id": project_id}) ).all() + async def _get_project_summary_rows( + self, + function_name: str, + year: int, + branch_ids: list[int] | None, + project_type: str | None = None, + ) -> list[tuple]: + query = text( + f""" + SELECT row_type, depth, sort_order, data + FROM {function_name}( + CAST(:year AS INT), + CAST(:branch_ids AS INT[]), + CAST(:project_type AS VARCHAR) + ) + """ + ) + return ( + await self.db.execute( + query, + {"year": year, "branch_ids": branch_ids, "project_type": project_type}, + ) + ).all() + + async def get_plan_summary_rows( + self, + year: int, + branch_ids: list[int] | None, + project_type: str | None = None, + ) -> list[tuple]: + return await self._get_project_summary_rows( + function_name="v3.v_project_plan_summary_jsonb", + year=year, + branch_ids=branch_ids, + project_type=project_type, + ) + + async def get_fact_summary_rows( + self, + year: int, + branch_ids: list[int] | None, + project_type: str | None = None, + ) -> list[tuple]: + return await self._get_project_summary_rows( + function_name="v3.v_project_fact_summary_jsonb", + year=year, + branch_ids=branch_ids, + project_type=project_type, + ) + + async def get_detail_summary_rows( + self, + year: int, + branch_ids: list[int] | None, + project_type: str | None = None, + ) -> list[tuple]: + return await self._get_project_summary_rows( + function_name="v3.v_project_detail_summary_jsonb", + year=year, + branch_ids=branch_ids, + project_type=project_type, + ) + async def upd_form3_cell( self, report_id: int, diff --git a/api/src/services/project_service.py b/api/src/services/project_service.py index 1f55470..f042487 100644 --- a/api/src/services/project_service.py +++ b/api/src/services/project_service.py @@ -133,6 +133,68 @@ class ProjectService: raise ValidationException("Проект не найден") return await self.project_repo.get_project_summary_rows(project_id=project_id) + async def _allowed_summary_branch_ids( + self, + branch_ids: list[int] | None, + user: AppUser, + ) -> list[int] | None: + org_unit_ids = await self._allowed_org_unit_ids(user) + if org_unit_ids is None: + return branch_ids + + allowed = set(org_unit_ids) + if branch_ids is None: + return list(allowed) + return [branch_id for branch_id in branch_ids if branch_id in allowed] + + async def get_plan_summary_rows( + self, + year: int, + branch_ids: list[int] | None, + user: AppUser, + project_type: str | None = None, + ) -> list[tuple]: + branch_ids = await self._allowed_summary_branch_ids(branch_ids=branch_ids, user=user) + if branch_ids == []: + return [] + return await self.project_repo.get_plan_summary_rows( + year=year, + branch_ids=branch_ids, + project_type=project_type, + ) + + async def get_fact_summary_rows( + self, + year: int, + branch_ids: list[int] | None, + user: AppUser, + project_type: str | None = None, + ) -> list[tuple]: + branch_ids = await self._allowed_summary_branch_ids(branch_ids=branch_ids, user=user) + if branch_ids == []: + return [] + return await self.project_repo.get_fact_summary_rows( + year=year, + branch_ids=branch_ids, + project_type=project_type, + ) + + async def get_detail_summary_rows( + self, + year: int, + branch_ids: list[int] | None, + user: AppUser, + project_type: str | None = None, + ) -> list[tuple]: + branch_ids = await self._allowed_summary_branch_ids(branch_ids=branch_ids, user=user) + if branch_ids == []: + return [] + return await self.project_repo.get_detail_summary_rows( + year=year, + branch_ids=branch_ids, + project_type=project_type, + ) + async def upd_form3_cell( self, project_id: int, diff --git a/web/src/components/RealtimeTable/constants/PROJECT/CURRENT_EXPENSES.js b/web/src/components/RealtimeTable/constants/PROJECT/CURRENT_EXPENSES.js index 9f3d78c..c0b5f5c 100644 --- a/web/src/components/RealtimeTable/constants/PROJECT/CURRENT_EXPENSES.js +++ b/web/src/components/RealtimeTable/constants/PROJECT/CURRENT_EXPENSES.js @@ -1,995 +1,204 @@ import { greenColumn } from '../columnColors'; + +const planTitle = 'Текущим расходам'; + +const headerCellProps = { + sx: { + backgroundColor: '#C2D69B', + color: '#000000', + }, +}; + +const baseColumn = (header, accessorKey, columnLetter, size = 150) => ({ + header, + accessorKey, + columnLetter, + size, + filterFn: 'contains', + muiTableHeadCellProps: headerCellProps, +}); + +const groupColumn = (header, accessorKey, columns) => ({ + header, + accessorKey, + columns, + muiTableHeadCellProps: headerCellProps, +}); + +const translit = (value) => + value + .toLowerCase() + .replaceAll(' ', '_') + .replace(/[^\wа-яё]/gi, '') + .replace(/[а-яё]/gi, (char) => { + const map = { + а: 'a', + б: 'b', + в: 'v', + г: 'g', + д: 'd', + е: 'e', + ё: 'e', + ж: 'zh', + з: 'z', + и: 'i', + й: 'y', + к: 'k', + л: 'l', + м: 'm', + н: 'n', + о: 'o', + п: 'p', + р: 'r', + с: 's', + т: 't', + у: 'u', + ф: 'f', + х: 'h', + ц: 'c', + ч: 'ch', + ш: 'sh', + щ: 'sch', + ъ: '', + ы: 'y', + ь: '', + э: 'e', + ю: 'yu', + я: 'ya', + }; + return map[char] ?? char; + }); + +const planKeys = ['data.q1.base_plan', 'data.q2.base_plan', 'data.q3.base_plan', 'data.q4.base_plan', 'data.totals.base_plan']; +const correctionKeys = ['data.q2.corrected_plan', 'data.q3.corrected_plan', 'data.q4.corrected_plan']; +const factKeys = [ + 'data.q1.adj_by_items', + 'data.q1.adj_increase', + 'data.q1.m1', + 'data.q1.m2', + 'data.q1.m3', + 'data.q1.quarter_actual', + 'data.q1.economy', + 'data.q2.adj_by_items', + 'data.q2.adj_increase', + 'data.q2.m1', + 'data.q2.m2', + 'data.q2.m3', + 'data.q2.quarter_actual', + 'data.q2.economy', + 'data.q3.adj_by_items', + 'data.q3.adj_increase', + 'data.q3.m1', + 'data.q3.m2', + 'data.q3.m3', + 'data.q3.quarter_actual', + 'data.q3.economy', + 'data.q4.adj_by_items', + 'data.q4.adj_increase', + 'data.q4.m1', + 'data.q4.m2', + 'data.q4.m3', + 'data.q4.spod', + 'data.q4.quarter_actual', + 'data.q4.economy', + 'data.totals.total_actual', +]; + +const headerKeys = ['data.header.section_code', 'data.header.item_id', 'data.header.num_group_id', 'data.header.name']; +const allKeys = [...headerKeys, ...planKeys, ...correctionKeys, ...factKeys]; + +const makeColors = () => + Object.fromEntries( + allKeys.map((accessorKey) => [ + accessorKey, + { + color_type: greenColumn, + accessorKey, + }, + ]), + ); + +const headerColumns = [ + groupColumn('Код раздела', 'field_kod_razdela', [baseColumn('', 'data.header.section_code', 'A')]), + groupColumn('ID Статьи', 'field_id_stati', [baseColumn('', 'data.header.item_id', 'B')]), + groupColumn('ID Группы номенклатуры', 'field_id_gruppy_nomenklatury', [ + baseColumn('', 'data.header.num_group_id', 'C'), + ]), + groupColumn('Наименование', 'field_naimenovanie', [baseColumn('', 'data.header.name', 'D', 400)]), +]; + +const basePlanColumns = [ + baseColumn('I квартал', 'data.q1.base_plan', 'E'), + baseColumn('II квартал', 'data.q2.base_plan', 'F'), + baseColumn('III квартал', 'data.q3.base_plan', 'G'), + baseColumn('IV квартал', 'data.q4.base_plan', 'H'), + baseColumn('Год', 'data.totals.base_plan', 'I'), +]; + +const correctionPlanColumns = [ + baseColumn('II квартал', 'data.q2.corrected_plan', 'K'), + baseColumn('III квартал', 'data.q3.corrected_plan', 'L'), + baseColumn('IV квартал', 'data.q4.corrected_plan', 'M'), +]; + +const quarterFactColumns = [ + { + quarter: '1 квартал', + accessor: 'q1', + letters: ['O', 'P', 'Q', 'R', 'S', 'T', 'U'], + months: ['январь', 'февраль', 'март'], + total: 'I квартал', + }, + { + quarter: '2 квартал', + accessor: 'q2', + letters: ['V', 'W', 'X', 'Y', 'Z', 'AA', 'AB'], + months: ['апрель', 'май', 'июнь'], + total: 'II квартал', + }, + { + quarter: '3 квартал', + accessor: 'q3', + letters: ['AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI'], + months: ['июль', 'август', 'сентябрь'], + total: 'III квартал', + }, + { + quarter: '4 квартал', + accessor: 'q4', + letters: ['AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ'], + months: ['октябрь', 'ноябрь', 'декабрь'], + total: 'IV квартал', + }, +]; + +const makeQuarterColumns = ({ quarter, accessor, letters, months, total }) => + groupColumn(quarter, `fact_${accessor}`, [ + baseColumn('коррет по статьям (=0)', `data.${accessor}.adj_by_items`, letters[0], 180), + baseColumn('увелич сметы из ГО (>0)', `data.${accessor}.adj_increase`, letters[1], 200), + baseColumn(months[0], `data.${accessor}.m1`, letters[2]), + baseColumn(months[1], `data.${accessor}.m2`, letters[3]), + baseColumn(months[2], `data.${accessor}.m3`, letters[4]), + ...(accessor === 'q4' ? [baseColumn('СПОД', 'data.q4.spod', letters[5])] : []), + baseColumn(total, `data.${accessor}.quarter_actual`, accessor === 'q4' ? letters[6] : letters[5], 160), + baseColumn('Остаток', `data.${accessor}.economy`, accessor === 'q4' ? letters[7] : letters[6], 160), + ]); + export const config = { config: { - colors: { - 'data.header.section_code': { - color_type: greenColumn, - accessorKey: 'data.header.section_code', - }, - 'data.header.item_id': { - color_type: greenColumn, - accessorKey: 'data.header.item_id', - }, - 'data.header.num_group_id': { - color_type: greenColumn, - accessorKey: 'data.header.num_group_id', - }, - 'data.header.name': { - color_type: greenColumn, - accessorKey: 'data.header.name', - }, - 'data.q1.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q1.adj_by_items', - }, - 'data.q1.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q1.adj_increase', - }, - 'data.q1.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q1.total_corr', - }, - 'data.q1.m1': { - color_type: greenColumn, - accessorKey: 'data.q1.m1', - }, - 'data.q1.m2': { - color_type: greenColumn, - accessorKey: 'data.q1.m2', - }, - 'data.q1.m3': { - color_type: greenColumn, - accessorKey: 'data.q1.m3', - }, - 'data.q1.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q1.quarter_actual', - }, - 'data.q1.economy': { - color_type: greenColumn, - accessorKey: 'data.q1.economy', - }, - 'data.q2.carryover': { - color_type: greenColumn, - accessorKey: 'data.q2.carryover', - }, - 'data.q2.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q2.adj_by_items', - }, - 'data.q2.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q2.adj_increase', - }, - 'data.q2.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q2.total_corr', - }, - 'data.q2.m1': { - color_type: greenColumn, - accessorKey: 'data.q2.m1', - }, - 'data.q2.m2': { - color_type: greenColumn, - accessorKey: 'data.q2.m2', - }, - 'data.q2.m3': { - color_type: greenColumn, - accessorKey: 'data.q2.m3', - }, - 'data.q2.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q2.quarter_actual', - }, - 'data.q2.economy': { - color_type: greenColumn, - accessorKey: 'data.q2.economy', - }, - 'data.q3.carryover': { - color_type: greenColumn, - accessorKey: 'data.q3.carryover', - }, - 'data.q3.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q3.adj_by_items', - }, - 'data.q3.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q3.adj_increase', - }, - 'data.q3.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q3.total_corr', - }, - 'data.q3.m1': { - color_type: greenColumn, - accessorKey: 'data.q3.m1', - }, - 'data.q3.m2': { - color_type: greenColumn, - accessorKey: 'data.q3.m2', - }, - 'data.q3.m3': { - color_type: greenColumn, - accessorKey: 'data.q3.m3', - }, - 'data.q3.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q3.quarter_actual', - }, - 'data.q3.economy': { - color_type: greenColumn, - accessorKey: 'data.q3.economy', - }, - 'data.q4.carryover': { - color_type: greenColumn, - accessorKey: 'data.q4.carryover', - }, - 'data.q4.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q4.adj_by_items', - }, - 'data.q4.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q4.adj_increase', - }, - 'data.q4.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q4.total_corr', - }, - 'data.q4.m1': { - color_type: greenColumn, - accessorKey: 'data.q4.m1', - }, - 'data.q4.m2': { - color_type: greenColumn, - accessorKey: 'data.q4.m2', - }, - 'data.q4.m3': { - color_type: greenColumn, - accessorKey: 'data.q4.m3', - }, - 'data.q4.spod': { - color_type: greenColumn, - accessorKey: 'data.q4.spod', - }, - 'data.q4.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q4.quarter_actual', - }, - 'data.q4.economy': { - color_type: greenColumn, - accessorKey: 'data.q4.economy', - }, - }, + colors: makeColors(), columns: [ { header: '', accessorKey: 'field', - columns: [ - { - header: 'Код раздела', - accessorKey: 'field_kod_razdela', - columns: [ - { - header: '', - accessorKey: 'data.header.section_code', - columnLetter: 'A', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'ID Статьи', - accessorKey: 'field_id_stati', - columns: [ - { - header: '', - accessorKey: 'data.header.item_id', - columnLetter: 'B', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'ID Группы номенклатуры', - accessorKey: 'field_id_gruppy_nomenklatury', - columns: [ - { - header: '', - accessorKey: 'data.header.num_group_id', - columnLetter: 'C', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Наименование', - accessorKey: 'field_naimenovanie', - columns: [ - { - header: '', - accessorKey: 'data.header.name', - columnLetter: 'D', - size: 400, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении текущих расходов в I квартале', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_i_kvartale', - columns: [ - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_i_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q1.adj_by_items', - columnLetter: 'E', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q1.adj_increase', - columnLetter: 'F', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_i_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q1.total_corr', - columnLetter: 'G', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_i_kvartale_fakt', - columns: [ - { - header: 'За январь', - accessorKey: 'data.q1.m1', - columnLetter: 'H', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За февраль', - accessorKey: 'data.q1.m2', - columnLetter: 'I', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За март', - accessorKey: 'data.q1.m3', - columnLetter: 'J', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого I квартал', - accessorKey: 'data.q1.quarter_actual', - columnLetter: 'K', - size: 160, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_i_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q1.economy', - columnLetter: 'L', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении текущих расходов в II квартале', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_ii_kvartale', - columns: [ - { - header: 'Лимит затрат / остаток лимита затрат на II квартал', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_ii_kvartale_limit_zatrat_ostatok_limita_zatrat_na_ii_kvartal', - columns: [ - { - header: '', - accessorKey: 'data.q2.carryover', - columnLetter: 'N', - size: 250, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_ii_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q2.adj_by_items', - columnLetter: 'O', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q2.adj_increase', - columnLetter: 'P', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_ii_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q2.total_corr', - columnLetter: 'Q', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_ii_kvartale_fakt', - columns: [ - { - header: 'За апрель', - accessorKey: 'data.q2.m1', - columnLetter: 'R', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За май', - accessorKey: 'data.q2.m2', - columnLetter: 'S', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За июнь', - accessorKey: 'data.q2.m3', - columnLetter: 'T', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого II квартал', - accessorKey: 'data.q2.quarter_actual', - columnLetter: 'U', - size: 170, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_ii_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q2.economy', - columnLetter: 'V', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении текущих расходов в III квартале', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iii_kvartale', - columns: [ - { - header: 'Лимит затрат / остаток лимита затрат на III квартал', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iii_kvartale_limit_zatrat_ostatok_limita_zatrat_na_iii_kvartal', - columns: [ - { - header: '', - accessorKey: 'data.q3.carryover', - columnLetter: 'X', - size: 250, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iii_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q3.adj_by_items', - columnLetter: 'Y', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q3.adj_increase', - columnLetter: 'Z', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iii_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q3.total_corr', - columnLetter: 'AA', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iii_kvartale_fakt', - columns: [ - { - header: 'За июль', - accessorKey: 'data.q3.m1', - columnLetter: 'AB', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За август', - accessorKey: 'data.q3.m2', - columnLetter: 'AC', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За сентябрь', - accessorKey: 'data.q3.m3', - columnLetter: 'AD', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого III квартал', - accessorKey: 'data.q3.quarter_actual', - columnLetter: 'AE', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iii_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q3.economy', - columnLetter: 'AF', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении текущих расходов в IV квартале', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iv_kvartale', - columns: [ - { - header: 'Лимит затрат / остаток лимита затрат на IV квартал', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iv_kvartale_limit_zatrat_ostatok_limita_zatrat_na_iv_kvartal', - columns: [ - { - header: '', - accessorKey: 'data.q4.carryover', - columnLetter: 'AH', - size: 250, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iv_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q4.adj_by_items', - columnLetter: 'AI', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q4.adj_increase', - columnLetter: 'AJ', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iv_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q4.total_corr', - columnLetter: 'AK', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iv_kvartale_fakt', - columns: [ - { - header: 'За октябрь', - accessorKey: 'data.q4.m1', - columnLetter: 'AL', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За ноябрь', - accessorKey: 'data.q4.m2', - columnLetter: 'AM', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За декабрь', - accessorKey: 'data.q4.m3', - columnLetter: 'AN', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'СПОД', - accessorKey: 'data.q4.spod', - columnLetter: 'AO', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого IV квартал', - accessorKey: 'data.q4.quarter_actual', - columnLetter: 'AP', - size: 170, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_tekuschikh_raskhodov_v_iv_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q4.economy', - columnLetter: 'AQ', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], + columns: headerColumns, }, + groupColumn(`Базовый план по ${planTitle}`, `base_plan_${translit(planTitle)}`, basePlanColumns), + groupColumn(`Скоррект план по ${planTitle}`, `corrected_plan_${translit(planTitle)}`, correctionPlanColumns), + groupColumn(`Фактические затраты по ${planTitle}`, `fact_${translit(planTitle)}`, [ + ...quarterFactColumns.map(makeQuarterColumns), + baseColumn('Год', 'data.totals.total_actual', 'AR'), + ]), ], }, }; diff --git a/web/src/components/RealtimeTable/constants/PROJECT/LIMIT.js b/web/src/components/RealtimeTable/constants/PROJECT/LIMIT.js index e47b2a9..d881865 100644 --- a/web/src/components/RealtimeTable/constants/PROJECT/LIMIT.js +++ b/web/src/components/RealtimeTable/constants/PROJECT/LIMIT.js @@ -1,998 +1,204 @@ import { greenColumn } from '../columnColors'; + +const planTitle = 'Лимиту Правления'; + +const headerCellProps = { + sx: { + backgroundColor: '#C2D69B', + color: '#000000', + }, +}; + +const baseColumn = (header, accessorKey, columnLetter, size = 150) => ({ + header, + accessorKey, + columnLetter, + size, + filterFn: 'contains', + muiTableHeadCellProps: headerCellProps, +}); + +const groupColumn = (header, accessorKey, columns) => ({ + header, + accessorKey, + columns, + muiTableHeadCellProps: headerCellProps, +}); + +const translit = (value) => + value + .toLowerCase() + .replaceAll(' ', '_') + .replace(/[^\wа-яё]/gi, '') + .replace(/[а-яё]/gi, (char) => { + const map = { + а: 'a', + б: 'b', + в: 'v', + г: 'g', + д: 'd', + е: 'e', + ё: 'e', + ж: 'zh', + з: 'z', + и: 'i', + й: 'y', + к: 'k', + л: 'l', + м: 'm', + н: 'n', + о: 'o', + п: 'p', + р: 'r', + с: 's', + т: 't', + у: 'u', + ф: 'f', + х: 'h', + ц: 'c', + ч: 'ch', + ш: 'sh', + щ: 'sch', + ъ: '', + ы: 'y', + ь: '', + э: 'e', + ю: 'yu', + я: 'ya', + }; + return map[char] ?? char; + }); + +const planKeys = ['data.q1.base_plan', 'data.q2.base_plan', 'data.q3.base_plan', 'data.q4.base_plan', 'data.totals.base_plan']; +const correctionKeys = ['data.q2.corrected_plan', 'data.q3.corrected_plan', 'data.q4.corrected_plan']; +const factKeys = [ + 'data.q1.adj_by_items', + 'data.q1.adj_increase', + 'data.q1.m1', + 'data.q1.m2', + 'data.q1.m3', + 'data.q1.quarter_actual', + 'data.q1.economy', + 'data.q2.adj_by_items', + 'data.q2.adj_increase', + 'data.q2.m1', + 'data.q2.m2', + 'data.q2.m3', + 'data.q2.quarter_actual', + 'data.q2.economy', + 'data.q3.adj_by_items', + 'data.q3.adj_increase', + 'data.q3.m1', + 'data.q3.m2', + 'data.q3.m3', + 'data.q3.quarter_actual', + 'data.q3.economy', + 'data.q4.adj_by_items', + 'data.q4.adj_increase', + 'data.q4.m1', + 'data.q4.m2', + 'data.q4.m3', + 'data.q4.spod', + 'data.q4.quarter_actual', + 'data.q4.economy', + 'data.totals.total_actual', +]; + +const headerKeys = ['data.header.section_code', 'data.header.item_id', 'data.header.num_group_id', 'data.header.name']; +const allKeys = [...headerKeys, ...planKeys, ...correctionKeys, ...factKeys]; + +const makeColors = () => + Object.fromEntries( + allKeys.map((accessorKey) => [ + accessorKey, + { + color_type: greenColumn, + accessorKey, + }, + ]), + ); + +const headerColumns = [ + groupColumn('Код раздела', 'field_kod_razdela', [baseColumn('', 'data.header.section_code', 'A')]), + groupColumn('ID Статьи', 'field_id_stati', [baseColumn('', 'data.header.item_id', 'B')]), + groupColumn('ID Группы номенклатуры', 'field_id_gruppy_nomenklatury', [ + baseColumn('', 'data.header.num_group_id', 'C'), + ]), + groupColumn('Наименование', 'field_naimenovanie', [baseColumn('', 'data.header.name', 'D', 400)]), +]; + +const basePlanColumns = [ + baseColumn('I квартал', 'data.q1.base_plan', 'E'), + baseColumn('II квартал', 'data.q2.base_plan', 'F'), + baseColumn('III квартал', 'data.q3.base_plan', 'G'), + baseColumn('IV квартал', 'data.q4.base_plan', 'H'), + baseColumn('Год', 'data.totals.base_plan', 'I'), +]; + +const correctionPlanColumns = [ + baseColumn('II квартал', 'data.q2.corrected_plan', 'K'), + baseColumn('III квартал', 'data.q3.corrected_plan', 'L'), + baseColumn('IV квартал', 'data.q4.corrected_plan', 'M'), +]; + +const quarterFactColumns = [ + { + quarter: '1 квартал', + accessor: 'q1', + letters: ['O', 'P', 'Q', 'R', 'S', 'T', 'U'], + months: ['январь', 'февраль', 'март'], + total: 'I квартал', + }, + { + quarter: '2 квартал', + accessor: 'q2', + letters: ['V', 'W', 'X', 'Y', 'Z', 'AA', 'AB'], + months: ['апрель', 'май', 'июнь'], + total: 'II квартал', + }, + { + quarter: '3 квартал', + accessor: 'q3', + letters: ['AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI'], + months: ['июль', 'август', 'сентябрь'], + total: 'III квартал', + }, + { + quarter: '4 квартал', + accessor: 'q4', + letters: ['AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ'], + months: ['октябрь', 'ноябрь', 'декабрь'], + total: 'IV квартал', + }, +]; + +const makeQuarterColumns = ({ quarter, accessor, letters, months, total }) => + groupColumn(quarter, `fact_${accessor}`, [ + baseColumn('коррет по статьям (=0)', `data.${accessor}.adj_by_items`, letters[0], 180), + baseColumn('увелич сметы из ГО (>0)', `data.${accessor}.adj_increase`, letters[1], 200), + baseColumn(months[0], `data.${accessor}.m1`, letters[2]), + baseColumn(months[1], `data.${accessor}.m2`, letters[3]), + baseColumn(months[2], `data.${accessor}.m3`, letters[4]), + ...(accessor === 'q4' ? [baseColumn('СПОД', 'data.q4.spod', letters[5])] : []), + baseColumn(total, `data.${accessor}.quarter_actual`, accessor === 'q4' ? letters[6] : letters[5], 160), + baseColumn('Остаток', `data.${accessor}.economy`, accessor === 'q4' ? letters[7] : letters[6], 160), + ]); + export const config = { config: { - colors: { - 'data.header.section_code': { - color_type: greenColumn, - accessorKey: 'data.header.section_code', - }, - 'data.header.item_id': { - color_type: greenColumn, - accessorKey: 'data.header.item_id', - }, - 'data.header.num_group_id': { - color_type: greenColumn, - accessorKey: 'data.header.num_group_id', - }, - 'data.header.name': { - color_type: greenColumn, - accessorKey: 'data.header.name', - }, - 'data.q1.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q1.adj_by_items', - }, - 'data.q1.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q1.adj_increase', - }, - 'data.q1.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q1.total_corr', - }, - 'data.q1.m1': { - color_type: greenColumn, - accessorKey: 'data.q1.m1', - }, - 'data.q1.m2': { - color_type: greenColumn, - accessorKey: 'data.q1.m2', - }, - 'data.q1.m3': { - color_type: greenColumn, - accessorKey: 'data.q1.m3', - }, - 'data.q1.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q1.quarter_actual', - }, - 'data.q1.economy': { - color_type: greenColumn, - accessorKey: 'data.q1.economy', - }, - 'data.q2.carryover': { - color_type: greenColumn, - accessorKey: 'data.q2.carryover', - }, - 'data.q2.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q2.adj_by_items', - }, - 'data.q2.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q2.adj_increase', - }, - 'data.q2.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q2.total_corr', - }, - 'data.q2.m1': { - color_type: greenColumn, - accessorKey: 'data.q2.m1', - }, - 'data.q2.m2': { - color_type: greenColumn, - accessorKey: 'data.q2.m2', - }, - 'data.q2.m3': { - color_type: greenColumn, - accessorKey: 'data.q2.m3', - }, - 'data.q2.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q2.quarter_actual', - }, - 'data.q2.economy': { - color_type: greenColumn, - accessorKey: 'data.q2.economy', - }, - 'data.q3.carryover': { - color_type: greenColumn, - accessorKey: 'data.q3.carryover', - }, - 'data.q3.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q3.adj_by_items', - }, - 'data.q3.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q3.adj_increase', - }, - 'data.q3.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q3.total_corr', - }, - 'data.q3.m1': { - color_type: greenColumn, - accessorKey: 'data.q3.m1', - }, - 'data.q3.m2': { - color_type: greenColumn, - accessorKey: 'data.q3.m2', - }, - 'data.q3.m3': { - color_type: greenColumn, - accessorKey: 'data.q3.m3', - }, - 'data.q3.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q3.quarter_actual', - }, - 'data.q3.economy': { - color_type: greenColumn, - accessorKey: 'data.q3.economy', - }, - 'data.q4.carryover': { - color_type: greenColumn, - accessorKey: 'data.q4.carryover', - }, - 'data.q4.adj_by_items': { - color_type: greenColumn, - accessorKey: 'data.q4.adj_by_items', - }, - 'data.q4.adj_increase': { - color_type: greenColumn, - accessorKey: 'data.q4.adj_increase', - }, - 'data.q4.total_corr': { - color_type: greenColumn, - accessorKey: 'data.q4.total_corr', - }, - 'data.q4.m1': { - color_type: greenColumn, - accessorKey: 'data.q4.m1', - }, - 'data.q4.m2': { - color_type: greenColumn, - accessorKey: 'data.q4.m2', - }, - 'data.q4.m3': { - color_type: greenColumn, - accessorKey: 'data.q4.m3', - }, - 'data.q4.spod': { - color_type: greenColumn, - accessorKey: 'data.q4.spod', - }, - 'data.q4.quarter_actual': { - color_type: greenColumn, - accessorKey: 'data.q4.quarter_actual', - }, - 'data.q4.economy': { - color_type: greenColumn, - accessorKey: 'data.q4.economy', - }, - }, + colors: makeColors(), columns: [ { header: '', accessorKey: 'field', - columns: [ - { - header: 'Код раздела', - accessorKey: 'field_kod_razdela', - columns: [ - { - header: '', - accessorKey: 'data.header.section_code', - columnLetter: 'A', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'ID Статьи', - accessorKey: 'field_id_stati', - columns: [ - { - header: '', - accessorKey: 'data.header.item_id', - columnLetter: 'B', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'ID Группы номенклатуры', - accessorKey: 'field_id_gruppy_nomenklatury', - columns: [ - { - header: '', - accessorKey: 'data.header.num_group_id', - columnLetter: 'C', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Наименование', - accessorKey: 'field_naimenovanie', - columns: [ - { - header: '', - accessorKey: 'data.header.name', - columnLetter: 'D', - size: 400, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении лимита затрат, утверждённого Правлением Банка в I квартале', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_i_kvartale', - columns: [ - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_i_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q1.adj_by_items', - columnLetter: 'E', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q1.adj_increase', - columnLetter: 'F', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_i_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q1.total_corr', - columnLetter: 'G', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_i_kvartale_fakt', - columns: [ - { - header: 'За январь', - accessorKey: 'data.q1.m1', - columnLetter: 'H', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За февраль', - accessorKey: 'data.q1.m2', - columnLetter: 'I', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За март', - accessorKey: 'data.q1.m3', - columnLetter: 'J', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого I квартал', - accessorKey: 'data.q1.quarter_actual', - columnLetter: 'K', - size: 160, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_i_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q1.economy', - columnLetter: 'L', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении лимита затрат, утверждённого Правлением Банка в II квартале', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_ii_kvartale', - columns: [ - { - header: 'Лимит затрат / остаток лимита затрат на II квартал', - accessorKey: - 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_ii_kvartale_limit_zatrat_ostatok_limita_zatrat_na_ii_kvartal', - columns: [ - { - header: '', - accessorKey: 'data.q2.carryover', - columnLetter: 'N', - size: 250, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_ii_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q2.adj_by_items', - columnLetter: 'O', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q2.adj_increase', - columnLetter: 'P', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_ii_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q2.total_corr', - columnLetter: 'Q', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_ii_kvartale_fakt', - columns: [ - { - header: 'За апрель', - accessorKey: 'data.q2.m1', - columnLetter: 'R', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За май', - accessorKey: 'data.q2.m2', - columnLetter: 'S', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За июнь', - accessorKey: 'data.q2.m3', - columnLetter: 'T', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого II квартал', - accessorKey: 'data.q2.quarter_actual', - columnLetter: 'U', - size: 170, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_ii_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q2.economy', - columnLetter: 'V', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении лимита затрат, утверждённого Правлением Банка в III квартале', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iii_kvartale', - columns: [ - { - header: 'Лимит затрат / остаток лимита затрат на III квартал', - accessorKey: - 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iii_kvartale_limit_zatrat_ostatok_limita_zatrat_na_iii_kvartal', - columns: [ - { - header: '', - accessorKey: 'data.q3.carryover', - columnLetter: 'X', - size: 250, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iii_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q3.adj_by_items', - columnLetter: 'Y', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q3.adj_increase', - columnLetter: 'Z', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iii_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q3.total_corr', - columnLetter: 'AA', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iii_kvartale_fakt', - columns: [ - { - header: 'За июль', - accessorKey: 'data.q3.m1', - columnLetter: 'AB', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За август', - accessorKey: 'data.q3.m2', - columnLetter: 'AC', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За сентябрь', - accessorKey: 'data.q3.m3', - columnLetter: 'AD', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого III квартал', - accessorKey: 'data.q3.quarter_actual', - columnLetter: 'AE', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iii_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q3.economy', - columnLetter: 'AF', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - }, - { - header: 'Отчет об исполнении лимита затрат, утверждённого Правлением Банка в IV квартале', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iv_kvartale', - columns: [ - { - header: 'Лимит затрат / остаток лимита затрат на IV квартал', - accessorKey: - 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iv_kvartale_limit_zatrat_ostatok_limita_zatrat_na_iv_kvartal', - columns: [ - { - header: '', - accessorKey: 'data.q4.carryover', - columnLetter: 'AH', - size: 250, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Корректировка лимита', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iv_kvartale_korrektirovka_limita', - columns: [ - { - header: 'По статьям сметы*', - accessorKey: 'data.q4.adj_by_items', - columnLetter: 'AI', - size: 180, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Увеличение сметы**', - accessorKey: 'data.q4.adj_increase', - columnLetter: 'AJ', - size: 200, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iv_kvartale_itogo', - columns: [ - { - header: '', - accessorKey: 'data.q4.total_corr', - columnLetter: 'AK', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Факт', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iv_kvartale_fakt', - columns: [ - { - header: 'За октябрь', - accessorKey: 'data.q4.m1', - columnLetter: 'AL', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За ноябрь', - accessorKey: 'data.q4.m2', - columnLetter: 'AM', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'За декабрь', - accessorKey: 'data.q4.m3', - columnLetter: 'AN', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'СПОД', - accessorKey: 'data.q4.spod', - columnLetter: 'AO', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Итого IV квартал', - accessorKey: 'data.q4.quarter_actual', - columnLetter: 'AP', - size: 170, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - { - header: 'Экономия (+), перерасход (-)', - accessorKey: 'otchet_ob_ispolnenii_limita_zatrat_utverzhdennogo_pravleniem_banka_v_iv_kvartale_ekonomiya_pereraskhod', - columns: [ - { - header: '', - accessorKey: 'data.q4.economy', - columnLetter: 'AQ', - size: 150, - filterFn: 'contains', - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], - muiTableHeadCellProps: { - sx: { - backgroundColor: '#C2D69B', - color: '#000000', - }, - }, - }, - ], + columns: headerColumns, }, + groupColumn(`Базовый план по ${planTitle}`, `base_plan_${translit(planTitle)}`, basePlanColumns), + groupColumn(`Скоррект план по ${planTitle}`, `corrected_plan_${translit(planTitle)}`, correctionPlanColumns), + groupColumn(`Фактические затраты по ${planTitle}`, `fact_${translit(planTitle)}`, [ + ...quarterFactColumns.map(makeQuarterColumns), + baseColumn('Год', 'data.totals.total_actual', 'AR'), + ]), ], }, };