Merge pull request 'form3-source: источник строки в своде формы 3' (#186) from form3-source into test

Reviewed-on: #186
This commit is contained in:
tsygankoviva 2026-10-01 13:30:26 +03:00
commit bcca6771e6
2 changed files with 201 additions and 0 deletions

View File

@ -0,0 +1,15 @@
from sql_migration import run_sql_file_migration
revision = "0046"
down_revision = "0045"
branch_labels = None
depends_on = None
def upgrade() -> None:
run_sql_file_migration("0046_project_summary_source.sql")
def downgrade() -> None:
pass

View File

@ -0,0 +1,186 @@
-- 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,
'source', ei.sheet,
'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
LEFT JOIN v3.expense_item ei ON ei.id = a.expense_item_id
ORDER BY a.path;
$function$
;