Отраслевые ПП: применимость показателей + формулы ОПК
- criteria_applicability.json: Атомная (ПП-4: без 4, 10-10.7, 14; +6), Связь (ПП-402: +6, 8, 9), Оборонная (ПП-796: 1-4, 6-13.1, без 5/10/14), Транспорт (+8, 9, 13, 14), Наука (1, 7-9, 11, 13) - variables.py: _calc_criterion_8_opk (U8=(C+A+X)/Rгод*100%, ПП-796 п.18-20), _calc_criterion_13_opk (13а: V=(1-(Vmax-Vинц)/VГОЗ)*100%, 13б: T=(1-tнорм/tненорм)*100%) - ui.py: ОПК-поля в окне авторасчёта (C/A/X, Vmax/Vинц/VГОЗ, tнорм/tненорм), сохранение в criterion_input
This commit is contained in:
+129
-1
@@ -523,6 +523,113 @@ def _calc_criterion_8_9(company, isys, num):
|
||||
return text, cat
|
||||
|
||||
|
||||
def _calc_criterion_8_opk(company, isys):
|
||||
"""Показатель 8 (ущерб субъекту КИИ) по отраслевым особенностям ОПК
|
||||
(ПП РФ № 796 от 27.06.2026, п. 18–20):
|
||||
|
||||
U_8 = U_у8 / R_год × 100%,
|
||||
U_у8 = C + A + X,
|
||||
|
||||
где C — суммарные затраты на объект КИИ;
|
||||
A — затраты на возмещение ущерба потерпевшим и их имуществу (если инцидент
|
||||
не влечёт ущерба, A = 0);
|
||||
X — ущерб от ранее произошедших компьютерных инцидентов (если инцидентов
|
||||
не было или нет данных, X = 0);
|
||||
R_год — усреднённый объём годового дохода за прошедший 5-летний период.
|
||||
|
||||
Значения C/A/X берутся из criterion_input (ключи 8_c, 8_a, 8_x);
|
||||
если C не заполнен — используется балансовая стоимость объекта КИИ.
|
||||
Возвращает (текст_обоснования, категория или None).
|
||||
"""
|
||||
crit = dict(getattr(isys, 'criterion_input', None) or {}) if isys else {}
|
||||
c_val = _num(crit.get('8_c', '') or '') or _num(getattr(isys, 'balance_value', '') or '')
|
||||
a_val = _num(crit.get('8_a', '') or '') or 0.0
|
||||
x_val = _num(crit.get('8_x', '') or '') or 0.0
|
||||
|
||||
inc5 = _num(getattr(company, 'income_5y', '') or '')
|
||||
if inc5:
|
||||
r_avg = inc5 / 5.0
|
||||
else:
|
||||
incs = [_num(getattr(company, f'income_year_{i}', '') or '') for i in range(1, 6)]
|
||||
incs = [x for x in incs if x is not None]
|
||||
r_avg = (sum(incs) / len(incs)) if incs else None
|
||||
|
||||
if c_val is None or not r_avg:
|
||||
return ("Показатель применим (отраслевые особенности ОПК, ПП РФ № 796). "
|
||||
"Для расчёта заполните суммарные затраты на объект КИИ (C) и доходы за 5 лет "
|
||||
"(или балансовую стоимость объекта КИИ).", None)
|
||||
|
||||
u_y8 = c_val + a_val + x_val
|
||||
val_pct = u_y8 / r_avg * 100
|
||||
if val_pct > 20:
|
||||
cat = 'I'
|
||||
elif val_pct > 10:
|
||||
cat = 'II'
|
||||
elif val_pct >= 1:
|
||||
cat = 'III'
|
||||
else:
|
||||
cat = None
|
||||
|
||||
text = (f"Показатель 8 рассчитывается по отраслевым особенностям ОПК "
|
||||
f"(ПП РФ № 796 от 27.06.2026): U_8 = U_у8 / R_год × 100%, U_у8 = C + A + X. "
|
||||
f"Суммарные затраты на объект КИИ: C = {c_val:,.2f} руб. "
|
||||
f"Затраты на возмещение ущерба потерпевшим: A = {a_val:,.2f} руб. "
|
||||
f"Ущерб от ранее произошедших компьютерных инцидентов: X = {x_val:,.2f} руб. "
|
||||
f"Ущерб субъекту КИИ: U_у8 = {c_val:,.2f} + {a_val:,.2f} + {x_val:,.2f} "
|
||||
f"= {u_y8:,.2f} руб. "
|
||||
f"Усреднённый годовой доход за 5-летний период: R_год = {r_avg:,.2f} руб. "
|
||||
f"Показатель ущерба: U_8 = {u_y8:,.2f} / {r_avg:,.2f} × 100% = {val_pct:.6f} %.")
|
||||
if cat:
|
||||
text += (f" Так как {val_pct:.6f} % более 1% (пороговое значение для 3-й категории "
|
||||
f"значимости), по данному показателю объекту присваивается {cat}-я категория значимости.")
|
||||
else:
|
||||
text += (f" Так как {val_pct:.6f} % менее 1% (пороговое значение для 3-й категории "
|
||||
f"значимости), по данному показателю объекту категория значимости не присваивается.")
|
||||
return text, cat
|
||||
|
||||
|
||||
def _calc_criterion_13_opk(company, isys, num):
|
||||
"""Показатели 13а/13б по отраслевым особенностям ОПК (ПП РФ № 796, п. 34, 38):
|
||||
|
||||
13а: V = (1 − (V_max − V_инц) / V_ГОЗ) × 100% (снижение объёма продукции ГОЗ)
|
||||
13б: T = (1 − (t_норм / t_ненорм)) × 100% (увеличение времени изготовления)
|
||||
|
||||
Значения берутся из criterion_input: 13a_vmax, 13a_vinc, 13a_vgoz;
|
||||
13b_tnorm, 13b_tnonorm. Категория — по порогам ПП-127 (CRITERION_QUANT_THRESHOLDS).
|
||||
Возвращает (текст_обоснования, категория или None).
|
||||
"""
|
||||
crit = dict(getattr(isys, 'criterion_input', None) or {}) if isys else {}
|
||||
num = str(num)
|
||||
if num == '13а':
|
||||
vmax = _num(crit.get('13a_vmax', '') or '')
|
||||
vinc = _num(crit.get('13a_vinc', '') or '')
|
||||
vgoz = _num(crit.get('13a_vgoz', '') or '')
|
||||
if vmax is None or vinc is None or not vgoz:
|
||||
return ("Показатель 13а рассчитывается по отраслевым особенностям ОПК "
|
||||
"(ПП РФ № 796): V = (1 − (V_max − V_инц) / V_ГОЗ) × 100%. "
|
||||
"Заполните V_max, V_инц, V_ГОЗ (объёмы продукции ГОЗ).", None)
|
||||
val = (1 - (vmax - vinc) / vgoz) * 100
|
||||
formula = (f"V = (1 − ({vmax:,.2f} − {vinc:,.2f}) / {vgoz:,.2f}) × 100% = {val:.6f} %")
|
||||
else: # 13б
|
||||
tnorm = _num(crit.get('13b_tnorm', '') or '')
|
||||
tnon = _num(crit.get('13b_tnonorm', '') or '')
|
||||
if tnorm is None or tnon is None or tnon <= 0:
|
||||
return ("Показатель 13б рассчитывается по отраслевым особенностям ОПК "
|
||||
"(ПП РФ № 796): T = (1 − (t_норм / t_ненорм)) × 100%. "
|
||||
"Заполните t_норм и t_ненорм (время операций по ГОЗ).", None)
|
||||
val = (1 - tnorm / tnon) * 100
|
||||
formula = (f"T = (1 − ({tnorm:,.2f} / {tnon:,.2f})) × 100% = {val:.6f} %")
|
||||
|
||||
cat = _criterion_other_cat(num, val)
|
||||
text = (f"Показатель {num} рассчитывается по отраслевым особенностям ОПК "
|
||||
f"(ПП РФ № 796 от 27.06.2026): {formula}.")
|
||||
if cat:
|
||||
text += (f" По порогам ПП-127 это соответствует {cat}-й категории значимости.")
|
||||
else:
|
||||
text += " По порогам ПП-127 категория значимости не присваивается."
|
||||
return text, cat
|
||||
|
||||
|
||||
# Пороги показателя 10 и подпоказателей 10.1–10.7 (ПП-127, «Значение показателя»)
|
||||
CRITERION_10_THRESHOLDS = {
|
||||
# num: (категория → (нижняя граница, верхняя граница)), границы «включительно»
|
||||
@@ -800,7 +907,11 @@ def _build_categorization_indicators(company, is_list):
|
||||
justification = (just.get(num) or just.get(grp_num)
|
||||
or f"Показатель не применим к объекту КИИ организации сферы «{sphere or '—'}».")
|
||||
elif grp_num in ('8', '9'):
|
||||
text, cat = _calc_criterion_8_9(company, isys, grp_num)
|
||||
if grp_num == '8' and sphere == 'Оборонная промышленность':
|
||||
# ОПК: U_8 = (C+A+X)/R_год×100% (ПП РФ № 796, п. 18–20)
|
||||
text, cat = _calc_criterion_8_opk(company, isys)
|
||||
else:
|
||||
text, cat = _calc_criterion_8_9(company, isys, grp_num)
|
||||
if text:
|
||||
value = text
|
||||
if cat:
|
||||
@@ -815,6 +926,23 @@ def _build_categorization_indicators(company, is_list):
|
||||
category = f"{cat}-я категория"
|
||||
else:
|
||||
category = '—'
|
||||
elif num in ('13а', '13б') and sphere == 'Оборонная промышленность':
|
||||
# ОПК: V = (1−(V_max−V_инц)/V_ГОЗ)×100%, T = (1−(t_норм/t_ненорм))×100%
|
||||
# (ПП РФ № 796, п. 34, 38) — при наличии введённых составляющих
|
||||
_opk_crit = dict(getattr(isys, 'criterion_input', None) or {}) if isys else {}
|
||||
_opk_ready = bool(_opk_crit.get('13a_vmax', '') or _opk_crit.get('13a_vinc', '') or _opk_crit.get('13a_vgoz', '') or _opk_crit.get('13b_tnorm', '') or _opk_crit.get('13b_tnonorm', ''))
|
||||
if _opk_ready:
|
||||
text, cat = _calc_criterion_13_opk(company, isys, num)
|
||||
if text:
|
||||
value = text
|
||||
if cat:
|
||||
category = f"{cat}-я категория"
|
||||
else:
|
||||
category = '—'
|
||||
else:
|
||||
value = '—'
|
||||
justification = (just.get(num) or just.get(grp_num)
|
||||
or 'Показатель применим к объекту КИИ; значение определяется по данным объекта (для ОПК — по формулам ПП РФ № 796: V = (1−(V_max−V_инц)/V_ГОЗ)×100%, T = (1−(t_норм/t_ненорм))×100%).')
|
||||
else:
|
||||
# Применимый показатель без формульного авторасчёта (1–7, 11–14):
|
||||
# если значение введено (опросник/окно авторасчёта) — считаем категорию по порогам
|
||||
|
||||
Reference in New Issue
Block a user