diff --git a/api/src/services/export_service/export_mappings.py b/api/src/services/export_service/export_mappings.py index 1e53225..4ed6a2c 100644 --- a/api/src/services/export_service/export_mappings.py +++ b/api/src/services/export_service/export_mappings.py @@ -49,7 +49,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "plan": { - "name": "План {year}(тыс. руб.) с учетом НДС", + "name": "План {year} (тыс. руб.) {vat_plan}", "children": { "q1": { "name": "1 кв. {year_short}", @@ -212,7 +212,7 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Коллегиальные органы", "children": { "approved": { - "name": "Сумма (с учетом НДC)", + "name": "Сумма ({vat})", }, "protocol": { "name": "Реквизиты протокола (дата, номер)", @@ -229,19 +229,19 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "ЦКК", "children": { "ceiling": { - "name": "Предельная ст-ть, тыс. руб. (с учетом НДC)", + "name": "Предельная ст-ть, тыс. руб. ({vat})", }, "q1": { - "name": "Расходы 1 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 1 кв. {year} г. тыс. руб. ({vat})", }, "q2": { - "name": "Расходы 2 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 2 кв. {year} г. тыс. руб. ({vat})", }, "q3": { - "name": "Расходы 3 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 3 кв. {year} г. тыс. руб. ({vat})", }, "q4": { - "name": "Расходы 4 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 4 кв. {year} г. тыс. руб. ({vat})", }, "rf_schedule": { "name": "по сметам РФ (1 кв, 2 кв, 3 кв, 4 кв)", @@ -279,19 +279,19 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Валюта договора", }, "ceiling": { - "name": "Предельная ст-ть, тыс. руб. (с учетом НДC)", + "name": "Предельная ст-ть, тыс. руб. ({vat})", }, "q1": { - "name": "Расходы 1 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 1 кв. {year} г. тыс. руб. ({vat})", }, "q2": { - "name": "Расходы 2 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 2 кв. {year} г. тыс. руб. ({vat})", }, "q3": { - "name": "Расходы 3 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 3 кв. {year} г. тыс. руб. ({vat})", }, "q4": { - "name": "Расходы 4 кв. {year} г. тыс. руб. (с учетом НДC)", + "name": "Расходы 4 кв. {year} г. тыс. руб. ({vat})", }, "rf_schedule": { "name": "по сметам РФ (1 кв, 2 кв, 3 кв, 4 кв)", @@ -303,7 +303,7 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Курс пересчета", }, "amount_foreign": { - "name": "Сумма (с учетом НДC), вал (с учетом НДC)", + "name": "Сумма ({vat}), вал ({vat})", }, "deadline": { "name": "Срок", @@ -333,7 +333,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_current": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -342,7 +342,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_ssp": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -351,7 +351,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_rf": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -360,7 +360,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_reserve": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -369,7 +369,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "sum": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -378,7 +378,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_comment": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -387,7 +387,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "corrected_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -402,13 +402,13 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Дата платежа" }, "pay_amount": { - "name": "Сумма, тыс. руб. (с учетом НДC)" + "name": "Сумма, тыс. руб. ({vat})" }, "pay_ho": { - "name": "в т.ч. сумма (с учетом НДC) ГО" + "name": "в т.ч. сумма ({vat}) ГО" }, "pay_rf": { - "name": "в т.ч. сумма (с учетом НДC) РФ" + "name": "в т.ч. сумма ({vat}) РФ" }, "pay_comment": { "name": "Комментарий" @@ -426,7 +426,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -435,7 +435,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m1": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -444,7 +444,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m2": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -453,7 +453,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m3": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -462,7 +462,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_quarter": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -471,7 +471,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -480,7 +480,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_actual": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -517,7 +517,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_eco": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -526,7 +526,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_item": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -535,7 +535,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_inc": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -544,7 +544,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_seq": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -553,7 +553,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_comment": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -562,7 +562,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "new_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -576,7 +576,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_current": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -585,7 +585,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_ssp": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -594,7 +594,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_rf": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -603,7 +603,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_reserve": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -612,7 +612,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "sum": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -621,7 +621,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "corrected_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -636,13 +636,13 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Дата платежа" }, "pay_amount": { - "name": "Сумма, тыс. руб. (с учетом НДC)" + "name": "Сумма, тыс. руб. ({vat})" }, "pay_ho": { - "name": "в т.ч. сумма (с учетом НДC) ГО" + "name": "в т.ч. сумма ({vat}) ГО" }, "pay_rf": { - "name": "в т.ч. сумма (с учетом НДC) РФ" + "name": "в т.ч. сумма ({vat}) РФ" }, "pay_comment": { "name": "Комментарий" @@ -657,7 +657,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -666,7 +666,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m1": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -675,7 +675,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m2": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -684,7 +684,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m3": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -693,7 +693,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_quarter": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -702,7 +702,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -711,7 +711,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_actual": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -744,7 +744,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_eco": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -753,7 +753,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_item": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -762,7 +762,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_inc": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -771,7 +771,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_seq": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -780,7 +780,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_comment": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -789,7 +789,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "new_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -803,7 +803,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_current": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -812,7 +812,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_ssp": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -821,7 +821,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_rf": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -830,7 +830,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_reserve": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -839,7 +839,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "sum": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -848,7 +848,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "corrected_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -863,13 +863,13 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Дата платежа" }, "pay_amount": { - "name": "Сумма, тыс. руб. (с учетом НДC)" + "name": "Сумма, тыс. руб. ({vat})" }, "pay_ho": { - "name": "в т.ч. сумма (с учетом НДC) ГО" + "name": "в т.ч. сумма ({vat}) ГО" }, "pay_rf": { - "name": "в т.ч. сумма (с учетом НДC) РФ" + "name": "в т.ч. сумма ({vat}) РФ" }, "pay_comment": { "name": "Комментарий" @@ -884,7 +884,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -893,7 +893,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m1": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -902,7 +902,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m2": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -911,7 +911,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m3": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -920,7 +920,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_quarter": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -929,7 +929,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -938,7 +938,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_actual": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -968,7 +968,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_eco": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -977,7 +977,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_item": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -986,7 +986,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_inc": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -995,7 +995,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_seq": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1004,10 +1004,10 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rev_comment": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", }, "adj_comment": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", }, } }, @@ -1016,7 +1016,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "new_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1030,7 +1030,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_current": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1039,7 +1039,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_ssp": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1048,7 +1048,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_rf": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1057,7 +1057,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "adj_reserve": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1066,7 +1066,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "corrected_plan": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1081,13 +1081,13 @@ FORM1_DEPTH_COLUMNS: dict = { "name": "Дата платежа" }, "pay_amount": { - "name": "Сумма, тыс. руб. (с учетом НДC)" + "name": "Сумма, тыс. руб. ({vat})" }, "pay_ho": { - "name": "в т.ч. сумма (с учетом НДC) ГО" + "name": "в т.ч. сумма ({vat}) ГО" }, "pay_rf": { - "name": "в т.ч. сумма (с учетом НДC) РФ" + "name": "в т.ч. сумма ({vat}) РФ" }, "pay_comment": { "name": "Комментарий" @@ -1102,7 +1102,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1111,7 +1111,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m1": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1120,7 +1120,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m2": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1129,7 +1129,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_m3": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1138,7 +1138,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_quarter": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1147,7 +1147,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "actual_spod": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1156,7 +1156,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_booking": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -1165,7 +1165,7 @@ FORM1_DEPTH_COLUMNS: dict = { "key": None, "children": { "rem_actual": { - "name": "Сумма, тыс. руб. (с учетом НДC)", + "name": "Сумма, тыс. руб. ({vat})", } } }, @@ -3406,45 +3406,45 @@ FORM4_OPER_COLORS: dict = _rename_color_paths( SMETA_FORM1_COLUMNS: list[tuple[str, str]] = [ ("section_code", "Код раздела"), ("name", "Наименование"), - ("plan_support_q1", "План поддержка I квартал"), - ("plan_support_q2", "План поддержка II квартал"), - ("plan_support_q3", "План поддержка III квартал"), - ("plan_support_q4", "План поддержка IV квартал"), - ("plan_support_year", "План поддержка Год"), - ("plan_development_q1", "План развитие I квартал"), - ("plan_development_q2", "План развитие II квартал"), - ("plan_development_q3", "План развитие III квартал"), - ("plan_development_q4", "План развитие IV квартал"), - ("plan_development_year", "План развитие Год"), - ("plan_total_year", "План ИТОГО Год"), - ("approved_support_q1", "Утверждено поддержка I квартал"), - ("approved_support_q2", "Утверждено поддержка II квартал"), - ("approved_support_q3", "Утверждено поддержка III квартал"), - ("approved_support_q4", "Утверждено поддержка IV квартал"), - ("approved_support_year", "Утверждено поддержка Год"), - ("approved_development_q1", "Утверждено развитие I квартал"), - ("approved_development_q2", "Утверждено развитие II квартал"), - ("approved_development_q3", "Утверждено развитие III квартал"), - ("approved_development_q4", "Утверждено развитие IV квартал"), - ("approved_development_year", "Утверждено развитие Год"), - ("approved_total_year", "Утверждено ИТОГО Год"), - ("fact_support_q1", "Факт поддержка I квартал"), - ("fact_support_q2", "Факт поддержка II квартал"), - ("fact_support_q3", "Факт поддержка III квартал"), - ("fact_support_q4", "Факт поддержка IV квартал"), - ("fact_support_year", "Факт поддержка Год"), - ("fact_development_q1", "Факт развитие I квартал"), - ("fact_development_q2", "Факт развитие II квартал"), - ("fact_development_q3", "Факт развитие III квартал"), - ("fact_development_q4", "Факт развитие IV квартал"), - ("fact_development_year", "Факт развитие Год"), - ("fact_total_year", "Факт ИТОГО Год"), - ("corrected_support_q2", "Корректировка поддержка II квартал"), - ("corrected_support_q3", "Корректировка поддержка III квартал"), - ("corrected_support_q4", "Корректировка поддержка IV квартал"), - ("corrected_development_q2", "Корректировка развитие II квартал"), - ("corrected_development_q3", "Корректировка развитие III квартал"), - ("corrected_development_q4", "Корректировка развитие IV квартал"), + ("plan_support_q1", "План поддержка I квартал, тыс. руб."), + ("plan_support_q2", "План поддержка II квартал, тыс. руб."), + ("plan_support_q3", "План поддержка III квартал, тыс. руб."), + ("plan_support_q4", "План поддержка IV квартал, тыс. руб."), + ("plan_support_year", "План поддержка Год, тыс. руб."), + ("plan_development_q1", "План развитие I квартал, тыс. руб."), + ("plan_development_q2", "План развитие II квартал, тыс. руб."), + ("plan_development_q3", "План развитие III квартал, тыс. руб."), + ("plan_development_q4", "План развитие IV квартал, тыс. руб."), + ("plan_development_year", "План развитие Год, тыс. руб."), + ("plan_total_year", "План ИТОГО Год, тыс. руб."), + ("approved_support_q1", "Утверждено поддержка I квартал, тыс. руб."), + ("approved_support_q2", "Утверждено поддержка II квартал, тыс. руб."), + ("approved_support_q3", "Утверждено поддержка III квартал, тыс. руб."), + ("approved_support_q4", "Утверждено поддержка IV квартал, тыс. руб."), + ("approved_support_year", "Утверждено поддержка Год, тыс. руб."), + ("approved_development_q1", "Утверждено развитие I квартал, тыс. руб."), + ("approved_development_q2", "Утверждено развитие II квартал, тыс. руб."), + ("approved_development_q3", "Утверждено развитие III квартал, тыс. руб."), + ("approved_development_q4", "Утверждено развитие IV квартал, тыс. руб."), + ("approved_development_year", "Утверждено развитие Год, тыс. руб."), + ("approved_total_year", "Утверждено ИТОГО Год, тыс. руб."), + ("fact_support_q1", "Факт поддержка I квартал, тыс. руб."), + ("fact_support_q2", "Факт поддержка II квартал, тыс. руб."), + ("fact_support_q3", "Факт поддержка III квартал, тыс. руб."), + ("fact_support_q4", "Факт поддержка IV квартал, тыс. руб."), + ("fact_support_year", "Факт поддержка Год, тыс. руб."), + ("fact_development_q1", "Факт развитие I квартал, тыс. руб."), + ("fact_development_q2", "Факт развитие II квартал, тыс. руб."), + ("fact_development_q3", "Факт развитие III квартал, тыс. руб."), + ("fact_development_q4", "Факт развитие IV квартал, тыс. руб."), + ("fact_development_year", "Факт развитие Год, тыс. руб."), + ("fact_total_year", "Факт ИТОГО Год, тыс. руб."), + ("corrected_support_q2", "Корректировка поддержка II квартал, тыс. руб."), + ("corrected_support_q3", "Корректировка поддержка III квартал, тыс. руб."), + ("corrected_support_q4", "Корректировка поддержка IV квартал, тыс. руб."), + ("corrected_development_q2", "Корректировка развитие II квартал, тыс. руб."), + ("corrected_development_q3", "Корректировка развитие III квартал, тыс. руб."), + ("corrected_development_q4", "Корректировка развитие IV квартал, тыс. руб."), ] SMETA_FORM2_COLUMNS: list[tuple[str, str]] = [ ("section_code", "Код раздела"), @@ -4066,8 +4066,14 @@ def _replace_column_year_placeholders(columns: dict, year_values: dict[str, str] _replace_column_year_placeholders(column["children"], year_values) -def render_column_years(columns: dict, year: int) -> dict: - """Resolve year placeholders in header names without changing shared templates.""" +def render_column_years(columns: dict, year: int, extra: dict[str, str] | None = None) -> dict: + """Resolve year (и, опционально, прочие) плейсхолдеры в заголовках без изменения + общих шаблонов (FORM1_DEPTH_COLUMNS и производные от него делят один и тот же + словарь между листами Ф.1/Ф.4 — рендерить нужно отдельную копию на каждый лист). + + `extra` — дополнительные плейсхолдеры (например {vat}/{vat_plan} для текста НДС, + AURORA-1900), которые для разных листов резолвятся в разный текст. + """ rendered = copy.deepcopy(columns) values = { "year": str(year), @@ -4075,6 +4081,8 @@ def render_column_years(columns: dict, year: int) -> dict: "next_year": str(year + 1), "next_year_short": f"{(year + 1) % 100:02d}", } + if extra: + values.update(extra) _replace_column_year_placeholders(rendered, values) return rendered diff --git a/api/src/services/export_service/export_service.py b/api/src/services/export_service/export_service.py index 0284cab..cb98a3e 100644 --- a/api/src/services/export_service/export_service.py +++ b/api/src/services/export_service/export_service.py @@ -80,6 +80,19 @@ SHEET_NAMES = { 'CURRENT_EXPENSES': 'Текущие расходы', } SKIP_SHEETS = ('OTCH9F',) +# AURORA-1900: текст НДС в экспорте должен совпадать с экраном (вместо текстовой +# опечатки «с учетом НДC» — Latin C). Ф.1 AHR и все листы Ф.4 показывают суммы без НДС, +# Ф.1 OPER/CAP — с учётом НДС (см. render_column_years(..., extra=...) ниже). +FORM1_SHEET_VAT_WORDING = { + "OPER": "с учётом НДС", + "CAP": "с учётом НДС", + "AHR": "без НДС", +} +FORM4_SHEET_VAT_WORDING = "без НДС" + + +def _vat_placeholders(vat_phrase: str) -> dict[str, str]: + return {"vat": vat_phrase, "vat_plan": vat_phrase} BULK_EXPORT_CONCURRENCY = 2 EXPORT_TMPDIR = os.getenv("EXPORT_TMPDIR") or tempfile.gettempdir() @@ -252,7 +265,7 @@ class ExportService: stream = await self._export_summary_rows( rows=rows, columns=columns, - metadata=(("Свод", summary_number), ("Лист", sheet), ("Год", year)), + metadata=(("Свод", summary_number), ("Лист", sheet), ("Год", year), ("Единица", "тыс. руб.")), worksheet_name=f"Свод {summary_number} {sheet}", summary_number=summary_number, year=year, @@ -906,7 +919,9 @@ class ExportService: ) -> dict[str, Any]: default_writer = XlsxDepthSheetWriter( workbook=workbook, - columns_dict=render_column_years(FORM1_DEPTH_COLUMNS, year), + columns_dict=render_column_years( + FORM1_DEPTH_COLUMNS, year, _vat_placeholders(FORM1_SHEET_VAT_WORDING["OPER"]) + ), row_normalizer=self.form1_row_normalizer.normalize, value_serializer=self.value_serializer.to_excel_value, ) @@ -921,25 +936,33 @@ class ExportService: } if form_type_code == FormTypeEnum.FORM_4.value: writer_configs = { - "OPER": (FORM4_OPER_DEPTH_COLUMNS, FORM4_OPER_COLORS), - "AHR": (FORM4_DEPTH_COLUMNS, FORM4_COLORS["AHR"]), - "CAP": (FORM4_DEPTH_COLUMNS, FORM4_COLORS["CAP"]), - "STRUCTURE": (FORM4_STRUCTURE_DEPTH_COLUMNS, FORM4_STRUCTURE_COLORS), + "OPER": (FORM4_OPER_DEPTH_COLUMNS, FORM4_OPER_COLORS, _vat_placeholders(FORM4_SHEET_VAT_WORDING)), + "AHR": (FORM4_DEPTH_COLUMNS, FORM4_COLORS["AHR"], _vat_placeholders(FORM4_SHEET_VAT_WORDING)), + "CAP": (FORM4_DEPTH_COLUMNS, FORM4_COLORS["CAP"], _vat_placeholders(FORM4_SHEET_VAT_WORDING)), + "STRUCTURE": ( + FORM4_STRUCTURE_DEPTH_COLUMNS, + FORM4_STRUCTURE_COLORS, + _vat_placeholders(FORM4_SHEET_VAT_WORDING), + ), } else: writer_configs = { - "OPER": (FORM1_DEPTH_COLUMNS, FORM1_COLORS["OPER"]), - "AHR": (FORM1_DEPTH_COLUMNS, FORM1_COLORS["AHR"]), - "CAP": (FORM1_DEPTH_COLUMNS, FORM1_COLORS["CAP"]), - "AHR_RENT": (FORM2_DEPTH_AHR_SUB_COLUMNS, None), - "AHR_UTILITY": (FORM2_DEPTH_AHR_SUB_COLUMNS, None), - "AHR_SECURITY": (FORM2_DEPTH_AHR_SUB_COLUMNS, None), - "STRUCTURE": (FORM4_STRUCTURE_DEPTH_COLUMNS, FORM4_STRUCTURE_COLORS), + "OPER": (FORM1_DEPTH_COLUMNS, FORM1_COLORS["OPER"], _vat_placeholders(FORM1_SHEET_VAT_WORDING["OPER"])), + "AHR": (FORM1_DEPTH_COLUMNS, FORM1_COLORS["AHR"], _vat_placeholders(FORM1_SHEET_VAT_WORDING["AHR"])), + "CAP": (FORM1_DEPTH_COLUMNS, FORM1_COLORS["CAP"], _vat_placeholders(FORM1_SHEET_VAT_WORDING["CAP"])), + "AHR_RENT": (FORM2_DEPTH_AHR_SUB_COLUMNS, None, None), + "AHR_UTILITY": (FORM2_DEPTH_AHR_SUB_COLUMNS, None, None), + "AHR_SECURITY": (FORM2_DEPTH_AHR_SUB_COLUMNS, None, None), + "STRUCTURE": ( + FORM4_STRUCTURE_DEPTH_COLUMNS, + FORM4_STRUCTURE_COLORS, + _vat_placeholders(FORM4_SHEET_VAT_WORDING), + ), } - for sheet_name, (columns, colors) in writer_configs.items(): + for sheet_name, (columns, colors, extra) in writer_configs.items(): writers[sheet_name] = XlsxDepthSheetWriter( workbook=workbook, - columns_dict=render_column_years(columns, year), + columns_dict=render_column_years(columns, year, extra), row_normalizer=self.form1_row_normalizer.normalize, value_serializer=self.value_serializer.to_excel_value, colors_config=colors, diff --git a/api/tests/unit/test_export_mappings_labels.py b/api/tests/unit/test_export_mappings_labels.py new file mode 100644 index 0000000..e1f2b2e --- /dev/null +++ b/api/tests/unit/test_export_mappings_labels.py @@ -0,0 +1,112 @@ +"""AURORA-1900: единые подписи «тыс. руб.» и НДС в выгрузке Excel. + +Проверяет только текст меток (name) в FORM1_DEPTH_COLUMNS-производных мапах и в +SMETA_COLUMNS — набор и порядок колонок эта задача не трогает (AURORA-1902/1903/ +1904/1905). +""" + +import re + +import pytest + +from src.services.export_service.export_mappings import ( + FORM1_DEPTH_COLUMNS, + FORM4_DEPTH_COLUMNS, + FORM4_OPER_DEPTH_COLUMNS, + FORM4_STRUCTURE_DEPTH_COLUMNS, + SMETA_COLUMNS, + render_column_years, +) + +# Латинская C/c в «НДС» — опечатка AURORA-1900 (п.4 тикета), должна быть устранена везде. +LATIN_C_IN_NDS = re.compile(r"НД[Cc]\b|НД[Cc][^\wа-яё]", re.IGNORECASE) + +FORM1_SHEET_VAT = { + "OPER": "с учётом НДС", + "CAP": "с учётом НДС", + "AHR": "без НДС", +} +FORM4_SHEET_VAT = "без НДС" + +DEPTH_COLUMN_MAPPINGS = [ + FORM1_DEPTH_COLUMNS, + FORM4_DEPTH_COLUMNS, + FORM4_STRUCTURE_DEPTH_COLUMNS, + FORM4_OPER_DEPTH_COLUMNS, +] + + +def _collect_names(columns: dict) -> list[str]: + names = [] + for column in columns.values(): + if "name" in column: + names.append(column["name"]) + if "children" in column: + names.extend(_collect_names(column["children"])) + return names + + +def _rendered_names(columns: dict, vat_phrase: str) -> list[str]: + rendered = render_column_years(columns, 2026, {"vat": vat_phrase, "vat_plan": vat_phrase}) + return _collect_names(rendered) + + +def test_raw_templates_use_a_vat_placeholder_not_a_hardcoded_phrase(): + # Санити-чек: убедились, что типовой текст НДС стал плейсхолдером, а не был + # просто вычищен/захардкожен в другую фразу. + names = _collect_names(FORM1_DEPTH_COLUMNS) + assert any("{vat}" in name for name in names) + assert any("{vat_plan}" in name for name in names) + + +@pytest.mark.parametrize("columns", DEPTH_COLUMN_MAPPINGS) +def test_no_latin_c_typo_in_nds_for_any_sheet_vat_wording(columns): + for vat_phrase in (*FORM1_SHEET_VAT.values(), FORM4_SHEET_VAT): + for name in _rendered_names(columns, vat_phrase): + assert not LATIN_C_IN_NDS.search(name), f"Latin C in НДС: {name!r}" + + +@pytest.mark.parametrize("columns", DEPTH_COLUMN_MAPPINGS) +def test_no_leftover_placeholders_after_rendering(columns): + for vat_phrase in (*FORM1_SHEET_VAT.values(), FORM4_SHEET_VAT): + for name in _rendered_names(columns, vat_phrase): + assert "{vat}" not in name + assert "{vat_plan}" not in name + assert "{unit}" not in name + + +def test_form1_ahr_labels_say_without_vat_matching_screen(): + names = _rendered_names(FORM1_DEPTH_COLUMNS, FORM1_SHEET_VAT["AHR"]) + assert any("без НДС" in name for name in names) + assert not any("с учётом НДС" in name for name in names) + + +def test_form1_oper_labels_say_with_vat(): + names = _rendered_names(FORM1_DEPTH_COLUMNS, FORM1_SHEET_VAT["OPER"]) + assert any("с учётом НДС" in name for name in names) + assert not any(name == "без НДС" or "(без НДС)" in name for name in names) + + +def test_form1_cap_labels_say_with_vat(): + names = _rendered_names(FORM1_DEPTH_COLUMNS, FORM1_SHEET_VAT["CAP"]) + assert any("с учётом НДС" in name for name in names) + + +def test_form4_sheets_say_without_vat(): + for columns in (FORM4_DEPTH_COLUMNS, FORM4_STRUCTURE_DEPTH_COLUMNS, FORM4_OPER_DEPTH_COLUMNS): + names = _rendered_names(columns, FORM4_SHEET_VAT) + assert any("без НДС" in name for name in names) + + +def test_smeta_columns_have_thousand_rub_suffix_on_sum_labels(): + non_money_keys = {"section_code", "name"} + for key, label in SMETA_COLUMNS: + if key in non_money_keys: + assert "тыс. руб." not in label + continue + assert "тыс. руб." in label, f"{key} label missing тыс. руб.: {label!r}" + + +def test_smeta_columns_have_no_nds_typo(): + for _key, label in SMETA_COLUMNS: + assert not LATIN_C_IN_NDS.search(label), f"Latin C in НДС: {label!r}" diff --git a/web/src/components/RealtimeTable/RealtimeTable.jsx b/web/src/components/RealtimeTable/RealtimeTable.jsx index 1d88ba2..fd7a244 100644 --- a/web/src/components/RealtimeTable/RealtimeTable.jsx +++ b/web/src/components/RealtimeTable/RealtimeTable.jsx @@ -805,6 +805,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => { createPortal( { const pinningPosition = column.getIsPinned(); @@ -102,7 +102,7 @@ const getColorBrightness = (hexColor) => { return 0.299 * r + 0.587 * g + 0.114 * b; }; -const HeaderCell = ({ header, table, pinningPosition, onClick, onChangeWidth, budgetYear }) => { +const HeaderCell = ({ header, table, pinningPosition, onClick, onChangeWidth, budgetYear, denomination }) => { const column = header.column; const headerSize = header.getSize(); const isPinned = Boolean(pinningPosition); @@ -172,7 +172,7 @@ const HeaderCell = ({ header, table, pinningPosition, onClick, onChangeWidth, bu maxWidth: 'calc(100% - 1rem)', boxSizing: 'border-box', }}> - {header.isPlaceholder ? null : formatHeaderYear(column.columnDef.header, budgetYear)} + {header.isPlaceholder ? null : formatHeaderUnit(formatHeaderYear(column.columnDef.header, budgetYear), denomination)} @@ -317,7 +317,7 @@ const FilterCell = ({ column }) => { ); }; -const TableHeadComponent = ({ table, selectedColumnId, onColumnSelect, onChangeWidth, isLoadingData, budgetYear }) => { +const TableHeadComponent = ({ table, selectedColumnId, onColumnSelect, onChangeWidth, isLoadingData, budgetYear, denomination }) => { const handleHeaderClick = (header) => { if (!header.subHeaders?.length && header.column?.id) { onColumnSelect?.(header.column.id); @@ -355,6 +355,7 @@ const TableHeadComponent = ({ table, selectedColumnId, onColumnSelect, onChangeW (groups[rowIndex]?.headers || []).map((header) => ( { + if (typeof header !== 'string') return header; + if (!header.includes('{unit}')) return header; + const resolved = resolveDenomination(denomination); + const label = UNIT_LABELS[resolved] ?? UNIT_LABELS.thousand; + return header.replaceAll('{unit}', label); +}; + // {year}, {year+1}, {year+2}; :short keeps the two-digit year format. export const parseBudgetYear = (value) => { const year = Number(value); diff --git a/web/src/components/RealtimeTable/utils/headerYearUtils.test.js b/web/src/components/RealtimeTable/utils/headerYearUtils.test.js index deb5b2b..119519c 100644 --- a/web/src/components/RealtimeTable/utils/headerYearUtils.test.js +++ b/web/src/components/RealtimeTable/utils/headerYearUtils.test.js @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { formatHeaderYear, parseBudgetYear } from './headerYearUtils.js'; +import { formatHeaderUnit, formatHeaderYear, parseBudgetYear } from './headerYearUtils.js'; test('headers follow the estimate year and retain relative payment years', () => { const header = 'План {year}; платежи {year+1} и {year+2}'; @@ -24,3 +24,22 @@ test('ordinary labels and non-string headers are preserved', () => { assert.equal(formatHeaderYear('', 2026), ''); assert.equal(formatHeaderYear(null, 2026), null); }); + +test('formatHeaderUnit substitutes the {unit} placeholder for the selected denomination', () => { + assert.equal(formatHeaderUnit('Сумма, {unit} (без НДС)', 'million'), 'Сумма, млн руб. (без НДС)'); + assert.equal(formatHeaderUnit('План {year} ({unit}) с учётом НДС', 'billion'), 'План {year} (млрд руб.) с учётом НДС'); + assert.equal(formatHeaderUnit('{unit}', 'rub'), 'руб.'); + assert.equal(formatHeaderUnit('{unit}', 'thousand'), 'тыс. руб.'); +}); + +test('formatHeaderUnit leaves headers without the placeholder unchanged', () => { + assert.equal(formatHeaderUnit('Наименование', 'million'), 'Наименование'); + assert.equal(formatHeaderUnit('', 'million'), ''); + assert.equal(formatHeaderUnit(null, 'million'), null); +}); + +test('formatHeaderUnit defaults to thousand (literal "тыс. руб.") when no denomination is given', () => { + assert.equal(formatHeaderUnit('Сумма, {unit}', undefined), 'Сумма, тыс. руб.'); + assert.equal(formatHeaderUnit('Сумма, {unit}', null), 'Сумма, тыс. руб.'); + assert.equal(formatHeaderUnit('Сумма, {unit}', ''), 'Сумма, тыс. руб.'); +}); diff --git a/web/src/components/common/CollapsibleTree.jsx b/web/src/components/common/CollapsibleTree.jsx index 93ae504..339627f 100644 --- a/web/src/components/common/CollapsibleTree.jsx +++ b/web/src/components/common/CollapsibleTree.jsx @@ -4,7 +4,7 @@ import { Box, Checkbox, InputAdornment, Popover, TextField, Typography } from '@ import { SimpleTreeView, TreeItem } from '@mui/x-tree-view'; import { memo, useMemo, useState } from 'react'; import { filterColumnTree, getColumnKey, getColumnTreeLeafKeys } from '../RealtimeTable/utils/columnUtils'; -import { formatHeaderYear } from '../RealtimeTable/utils/headerYearUtils'; +import { formatHeaderUnit, formatHeaderYear } from '../RealtimeTable/utils/headerYearUtils'; const EMPTY_IDS = []; @@ -114,7 +114,9 @@ const CollapsibleTree = ({ checkedIcon={} indeterminateIcon={} /> - {formatHeaderYear(node.columnDef?.header || node.name || node.header || 'Без названия', budgetYear)} + + {formatHeaderUnit(formatHeaderYear(node.columnDef?.header || node.name || node.header || 'Без названия', budgetYear))} + }> {node.columns && node.columns.length > 0 && renderTree(node.columns)} diff --git a/web/src/pages/AdminPanel/PhaseTemplatesPage/utils/templateColumns.js b/web/src/pages/AdminPanel/PhaseTemplatesPage/utils/templateColumns.js index 5910d66..7a66571 100644 --- a/web/src/pages/AdminPanel/PhaseTemplatesPage/utils/templateColumns.js +++ b/web/src/pages/AdminPanel/PhaseTemplatesPage/utils/templateColumns.js @@ -1,5 +1,5 @@ import { filterColumnTree } from '../../../../components/RealtimeTable/utils/columnUtils'; -import { formatHeaderYear } from '../../../../components/RealtimeTable/utils/headerYearUtils'; +import { formatHeaderUnit, formatHeaderYear } from '../../../../components/RealtimeTable/utils/headerYearUtils'; export async function loadTemplateColumnTree(formType, sheet) { const configForm = formType === 'FORM_3' ? 'PROJECT' : formType; @@ -12,7 +12,7 @@ export async function loadTemplateColumns(formType, sheet, excludedKeys = []) { const options = []; const collect = (nodes, parents = []) => { for (const node of nodes) { - const header = typeof node.header === 'string' ? formatHeaderYear(node.header) : ''; + const header = typeof node.header === 'string' ? formatHeaderUnit(formatHeaderYear(node.header)) : ''; const path = [...parents, header].filter(Boolean); if (node.columns?.length) collect(node.columns, path); else if (node.accessorKey?.startsWith('data.')) diff --git a/web/src/pages/Svod2Page/Svod2Page.jsx b/web/src/pages/Svod2Page/Svod2Page.jsx index e4551f2..6870758 100644 --- a/web/src/pages/Svod2Page/Svod2Page.jsx +++ b/web/src/pages/Svod2Page/Svod2Page.jsx @@ -6,11 +6,12 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch'; +import { formatHeaderUnit } from '../../components/RealtimeTable/utils/headerYearUtils'; +import { getDisplayFactor } from '../../components/RealtimeTable/utils/moneyUtils'; +import { createFixedRowVirtualizerOptions, getRootFontSizePx } from '../../components/RealtimeTable/utils/virtualizerOptions'; import { PrimaryButton } from '../../components/common/Buttons/Buttons'; import DenominationSelect from '../../components/common/DenominationSelect'; import useDenomination from '../../components/common/useDenomination'; -import { getDisplayFactor } from '../../components/RealtimeTable/utils/moneyUtils'; -import { createFixedRowVirtualizerOptions, getRootFontSizePx } from '../../components/RealtimeTable/utils/virtualizerOptions'; import { useSvod } from '../SvodPage/SvodContext'; import { SvodFilters } from '../SvodPage/SvodFilters'; @@ -99,7 +100,7 @@ const createPaymentColumns = (quarter) => ({ header: 'Платеж и предоставление акта', columns: [ textColumn(`q${quarter}.payment_date`, 'Дата платежа', [`q${quarter}`, 'payment_date'], 9), - numericColumn(`q${quarter}.payment_amount`, 'Сумма, тыс. руб. (без НДС)', [`q${quarter}`, 'payment_amount'], 12), + numericColumn(`q${quarter}.payment_amount`, 'Сумма, {unit} (без НДС)', [`q${quarter}`, 'payment_amount'], 12), numericColumn(`q${quarter}.payment_amount_ho`, 'в т.ч. сумма (без НДС) ГО', [`q${quarter}`, 'payment_amount_ho'], 12), numericColumn(`q${quarter}.payment_amount_rf`, 'в т.ч. сумма (без НДС) РФ', [`q${quarter}`, 'payment_amount_rf'], 12), textColumn(`q${quarter}.payment_act`, 'Предоставление акта (др. подтверждения)', [`q${quarter}`, 'payment_act'], 16), @@ -269,11 +270,11 @@ const createColumns = (sheet) => [ textColumn('contract.reference', 'Договор (реквизиты)', ['contract_detail', 'reference'], 12), textColumn('contract.subject', 'Предмет', ['contract_detail', 'subject'], 18), textColumn('contract.currency', 'Валюта договора', ['contract_detail', 'currency'], 9), - numericColumn('contract.ceiling', 'Предельная ст-ть, тыс. руб. (без НДС)', ['contract_detail', 'ceiling_amount'], 14), + numericColumn('contract.ceiling', 'Предельная ст-ть, {unit} (без НДС)', ['contract_detail', 'ceiling_amount'], 14), ...QUARTERS.map((quarter) => numericColumn( `contract.expenses_q${quarter}`, - `Расходы ${quarter} кв., тыс. руб. (без НДС)`, + `Расходы ${quarter} кв., {unit} (без НДС)`, ['contract_detail', `expenses_q${quarter}`], 13, ), @@ -348,12 +349,14 @@ const getColumnConfig = (sheet) => { return COLUMN_CONFIG_CACHE.get(sheet); }; -const scaleNumericColumns = (columns, factor) => columns.map((column) => { - const children = column.columns ? scaleNumericColumns(column.columns, factor) : undefined; - if (children) return { ...column, columns: children }; - if (!column.meta?.money) return column; - return { ...column, Cell: ({ cell }) => formatValue(cell.getValue(), factor) }; -}); +const scaleNumericColumns = (columns, factor, denomination) => + columns.map((column) => { + const children = column.columns ? scaleNumericColumns(column.columns, factor, denomination) : undefined; + const header = formatHeaderUnit(column.header, denomination); + if (children) return { ...column, header, columns: children }; + if (!column.meta?.money) return { ...column, header }; + return { ...column, header, Cell: ({ cell }) => formatValue(cell.getValue(), factor) }; + }); const matchesSearch = (row, query) => { const searchableData = { @@ -466,7 +469,7 @@ export default function Svod2Page() { return normalizedSearch ? rows.filter((row) => matchesSearch(row, normalizedSearch)) : rows; }, [hasCurrentData, rows, search]); const { columns: rawColumns, columnBands, columnGroupEnds } = useMemo(() => getColumnConfig(sheet), [sheet]); - const columns = useMemo(() => scaleNumericColumns(rawColumns, factor), [rawColumns, factor]); + const columns = useMemo(() => scaleNumericColumns(rawColumns, factor, denomination), [rawColumns, factor, denomination]); const table = useMaterialReactTable({ columns, data: filteredRows, @@ -601,7 +604,12 @@ export default function Svod2Page() { onChange={(_event, value) => setSheet(value)} sx={{ px: '1rem', minHeight: '3rem', borderBottom: '0.0625rem solid #edf0f2' }}> {SHEETS.map((item) => ( - + ))} rem * 16; // Высота строки задана в rem явно (строка и ячейка), виртуализатор layout не читает. @@ -63,30 +64,36 @@ export const countSummaryTree = (tree) => tree.reduce((count, row) => count + 1 const denominationKey = (tableKey) => `summary_${tableKey}_denomination_v2`; -const scaleColumns = (columns, factor) => columns.map((column) => { - const children = column.columns ? scaleColumns(column.columns, factor) : undefined; - const originalCell = column.Cell; - const isMoney = Boolean(column.meta?.money); - return { - ...column, - ...(children ? { columns: children } : {}), - ...(isMoney ? { Cell: ({ cell }) => { - const value = cell.getValue(); - if (value === null || value === undefined || value === '') return originalCell ? originalCell({ cell }) : '—'; - const numeric = Number(value); - if (!Number.isFinite(numeric)) return originalCell ? originalCell({ cell }) : value; - if (numeric === 0) return '-'; - return new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 2 }).format(numeric * factor); - } } : {}), - }; -}); +const scaleColumns = (columns, factor, denomination) => + columns.map((column) => { + const children = column.columns ? scaleColumns(column.columns, factor, denomination) : undefined; + const originalCell = column.Cell; + const isMoney = Boolean(column.meta?.money); + return { + ...column, + header: formatHeaderUnit(column.header, denomination), + ...(children ? { columns: children } : {}), + ...(isMoney + ? { + Cell: ({ cell }) => { + const value = cell.getValue(); + if (value === null || value === undefined || value === '') return originalCell ? originalCell({ cell }) : '—'; + const numeric = Number(value); + if (!Number.isFinite(numeric)) return originalCell ? originalCell({ cell }) : value; + if (numeric === 0) return '-'; + return new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 2 }).format(numeric * factor); + }, + } + : {}), + }; + }); export const SummaryTable = memo(function SummaryTable({ columns, data, loading, colorBySource = false, tableKey = 'default' }) { const storageKey = denominationKey(tableKey); const { denomination } = useDenomination(storageKey); const factor = getDisplayFactor('thousand', denomination); - const scaledColumns = useMemo(() => scaleColumns(columns, factor), [columns, factor]); + const scaledColumns = useMemo(() => scaleColumns(columns, factor, denomination), [columns, factor, denomination]); const table = useMaterialReactTable({ columns: scaledColumns, data, diff --git a/web/src/pages/SvodPage/SvodPage.jsx b/web/src/pages/SvodPage/SvodPage.jsx index ce375f7..3b692c5 100644 --- a/web/src/pages/SvodPage/SvodPage.jsx +++ b/web/src/pages/SvodPage/SvodPage.jsx @@ -16,16 +16,16 @@ const SHEETS = [ { value: 'FORM_4', label: 'Проектная деятельность' }, ]; const METRICS = [ - { key: 'plan', label: 'План' }, - { key: 'approved', label: 'Утверждено' }, - { key: 'fact', label: 'Факт' }, - { key: 'corrected', label: 'Скорректированный план' }, + { key: 'plan', label: 'План, {unit}' }, + { key: 'approved', label: 'Утверждено, {unit}' }, + { key: 'fact', label: 'Факт, {unit}' }, + { key: 'corrected', label: 'Скорректированный план, {unit}' }, ]; const FORM_3_METRIC_LABELS = { - plan: 'Расходы, планируемые РФ', - approved: 'Утвержденные базовые расходы', - fact: 'Фактические расходы', - corrected: 'Скорректированная смета расходов', + plan: 'Расходы, планируемые РФ, {unit}', + approved: 'Утвержденные базовые расходы, {unit}', + fact: 'Фактические расходы, {unit}', + corrected: 'Скорректированная смета расходов, {unit}', }; const DIRECTIONS = [ { key: 'support', label: 'Поддержка' },