feat: ОКИИ — ОКВЭД (импорт+DaData), доменное имя, поля 236 приказа ФСТЭК

- ОКВЭД: починен импорт (split по запятым/точкам с запятой), добавлен okvedExtra и domainName в DEFAULT_SETTINGS + merge полей по var в load_settings (старый import_settings.json теперь дополняется)
- DaData: проверка и подстановка основного/доп. ОКВЭД
- Вкладка «Организация»: поле «Доменное имя и внешний IP» + импорт из опросника
- Вкладка «Объекты КИИ»: поля 236 приказа — сведения (назначение, сфера, тип, архитектура, типовой отраслевой объект), субъект (12 полей), сети и ПО (категория сети, оператор, цель/способ взаимодействия, ПО/аппаратные средства, ОС, прикладные), безопасность (нарушитель, угрозы, инциденты, показатели критериев, обоснование, орг./тех. меры)
- importer: распознавание полей 236 из опросника, variables: новые переменные шаблонов
This commit is contained in:
2026-08-04 14:42:33 +04:00
parent ce1b56066a
commit 2037925986
7 changed files with 502 additions and 14 deletions
+3 -3
View File
@@ -97,7 +97,7 @@ def _generate_variables_reference(path):
_bullet(doc, f'{var}{desc}')
_h(doc, 'Циклы', 12)
_bullet(doc, 'information_systems — объекты КИИ ({{item.name}}, {{item.description}}, {{item.category}}, {{item.defense_tools_list}}, {{item.users}}, {{item.software}} и др.).')
_bullet(doc, 'information_systems — объекты КИИ ({{item.name}}, {{item.description}}, {{item.category}}, {{item.purpose}}, {{item.sphere}}, {{item.object_type}}, {{item.architecture}}, {{item.net_category}}, {{item.hw_sw}}, {{item.os_sw}}, {{item.app_sw}}, {{item.defense_tools_list}}, {{item.users}} и др.).')
_bullet(doc, 'commission — комиссия ({{item.role}}, {{item.position}}, {{item.fio}}, {{item.fio_initials}}, {{item.fio_short}}, {{item.signature}}).')
_bullet(doc, 'employees_access — сотрудники с доступом ({{item.position}}, {{item.fio}}).')
@@ -140,7 +140,7 @@ def _generate_user_manual(path):
'сотрудника или объекта КИИ — используются маркеры цикла:')
_p(doc, '<!-- loop:information_systems --> ... {{item.name}} ... <!-- loop_end -->', bold=True)
_p(doc, 'Доступные циклы:')
_bullet(doc, 'information_systems — объекты КИИ ({{item.name}}, {{item.description}}, {{item.category}}, {{item.defense_tools_list}}, {{item.users}}, {{item.software}} и др.).')
_bullet(doc, 'information_systems — объекты КИИ ({{item.name}}, {{item.description}}, {{item.category}}, {{item.purpose}}, {{item.sphere}}, {{item.object_type}}, {{item.architecture}}, {{item.net_category}}, {{item.hw_sw}}, {{item.os_sw}}, {{item.app_sw}}, {{item.defense_tools_list}}, {{item.users}} и др.).')
_bullet(doc, 'commission — комиссия ({{item.role}}, {{item.position}}, {{item.fio}}, {{item.fio_initials}}, {{item.fio_short}}, {{item.signature}}).')
_bullet(doc, 'employees_access — сотрудники с доступом ({{item.position}}, {{item.fio}}).')
@@ -179,7 +179,7 @@ def _generate_admin_manual(path):
_h(doc, '1. Файлы настроек рядом с программой', 12)
_bullet(doc, 'api_settings.json — API-ключи (DaData, ИИ).')
_bullet(doc, 'import_settings.json — словарь импорта: что и откуда брать из опросника.')
_bullet(doc, 'dictionaries/ — справочники: defense_tools.json, okved.json.')
_bullet(doc, 'dictionaries/ — справочники: defense_tools.json, okved.json (словарь ОКВЭД).')
_bullet(doc, 'dokogen.log — журнал работы (пишется автоматически).')
_bullet(doc, 'docs/ — инструкции и пустой опросник (создаются автоматически).')
+9 -1
View File
@@ -67,6 +67,8 @@ DEFAULT_SETTINGS = {
_f('ОГРН', 'ogrn', keywords=r'огрн'),
_f('КПП', 'kpp', keywords=r'кпп'),
_f('Основной ОКВЭД', 'okved', keywords=r'основной оквэд'),
_f('Дополнительные ОКВЭД', 'okvedExtra', keywords=r'дополнительные оквэд'),
_f('Доменное имя и внешний сетевой адрес', 'domainName', keywords=r'доменное имя и внешний сетевой адрес'),
_f('Должность руководителя', 'chiefPosition', keywords=r'должность руководителя'),
_f('ФИО руководителя', 'chiefFio', keywords=r'фио руководителя'),
_f('Должность ответственного за ПДн', 'ispdnPosition', keywords=r'должность.*защит.*информ|должность.*администрат'),
@@ -117,7 +119,13 @@ def load_settings(path=None):
merged = dict(DEFAULT_SETTINGS)
for k, v in loaded.items():
if k == 'fields' and isinstance(v, list):
merged['fields'] = v
# Мержим поля по var: поля из файла + недостающие из дефолта
by_var = {f.get('var'): f for f in v}
for df in DEFAULT_SETTINGS.get('fields', []):
dv = df.get('var')
if dv and dv not in by_var:
by_var[dv] = df
merged['fields'] = list(by_var.values())
else:
merged[k] = v
return merged
+139 -7
View File
@@ -248,7 +248,11 @@ def _import_187_common(wb, data, settings, log_fn):
def _import_187_is_list(wb, data, settings, log_fn):
"""Импорт объектов КИИ из остальных листов (ОБЪЕКТ №1, №2, ...)."""
"""Импорт объектов КИИ из остальных листов (ОБЪЕКТ №1, №2, ...).
Заполняет поля 236 приказа ФСТЭК: сфера, назначение, тип, архитектура,
сети электросвязи, ПО, СЗИ, сведения о субъекте.
"""
exclude_kws = settings.get('is_sheet_exclude_keywords', ['общие сведения', 'сотрудники'])
is_sheets = []
for sn in wb.sheetnames:
@@ -277,6 +281,20 @@ def _import_187_is_list(wb, data, settings, log_fn):
is_obj = {
'name': '', 'description': '', 'usersList': [],
'isInternet': False, 'defense_tools': [], 'software': '',
# 236 приказ
'sphere': '', 'purpose': '', 'object_type': '', 'architecture': '',
'typical_object': '',
'subject_name': '', 'subject_address': '',
'subject_chief_position': '', 'subject_chief_fio': '',
'subject_security_position': '', 'subject_security_fio': '',
'subject_department': '', 'subject_department_chief': '',
'subject_phone': '', 'subject_email': '',
'subject_inn': '', 'subject_kpp': '',
'net_category': '', 'net_operator': '', 'net_purpose': '', 'net_method': '',
'hw_sw': '', 'os_sw': '', 'app_sw': '',
'attacker_category': '', 'threats': '', 'incidents': '',
'criteria_values': '', 'criteria_justification': '',
'org_measures': '', 'tech_measures': '',
}
defense_keywords = {
@@ -290,23 +308,137 @@ def _import_187_is_list(wb, data, settings, log_fn):
'гарантирован': 'Доверенная загрузка',
}
def _set(field_lower, key, val):
"""Записать значение, если ключевое слово найдено в вопросе."""
if val and 'выбрать' not in field_lower:
is_obj[key] = val
return True
return False
for vals in rows:
field = (vals[0] or '').strip()
field_lower = field.lower()
val_b = clean_value(vals[1]) if len(vals) > 1 else ''
is_checked = val_b.upper() in ('ДА', 'YES', '', '', '1', 'TRUE', 'ЕСТЬ')
# --- Наименование объекта ---
if 'наименование объекта' in field_lower or 'название объекта' in field_lower:
is_obj['name'] = val_b
log_fn(f" Объект КИИ: {val_b}")
continue
if 'описание объекта' in field_lower or 'описание окки' in field_lower:
# --- Описание ---
if 'описание окки' in field_lower or 'описание объекта' in field_lower:
if val_b:
is_obj['description'] = val_b
continue
if 'операционная' in field_lower or 'прикладные программы' in field_lower or 'наименования программно' in field_lower:
if val_b:
is_obj['software'] = (is_obj['software'] + '; ' + val_b) if is_obj['software'] else val_b
# --- Сфера деятельности ---
if 'сфера' in field_lower and 'деятельност' in field_lower:
if _set(field_lower, 'sphere', val_b):
log_fn(f" Сфера: {val_b[:60]}")
continue
# --- Назначение объекта ---
if 'назначение объекта' in field_lower:
if _set(field_lower, 'purpose', val_b):
log_fn(f" Назначение: {val_b[:60]}")
continue
# --- Тип объекта ---
if 'тип объекта' in field_lower:
if _set(field_lower, 'object_type', val_b):
log_fn(f" Тип объекта: {val_b[:60]}")
continue
# --- Архитектура ---
if 'архитектура' in field_lower:
if _set(field_lower, 'architecture', val_b):
log_fn(f" Архитектура: {val_b[:60]}")
continue
# --- Типовой отраслевой объект ---
if 'типового отраслевого' in field_lower or 'типовой отраслевой' in field_lower:
if _set(field_lower, 'typical_object', val_b):
log_fn(f" Типовой объект: {val_b[:60]}")
continue
# --- Субъект ---
if 'наименование организации эксплуатирующ' in field_lower or ('наименование субъекта' in field_lower):
if _set(field_lower, 'subject_name', val_b):
log_fn(f" Субъект: {val_b[:60]}")
continue
if 'адрес местонахождения' in field_lower:
if _set(field_lower, 'subject_address', val_b):
log_fn(f" Адрес субъекта: {val_b[:60]}")
continue
if 'инн лица, эксплуатирующего' in field_lower or 'инн субъекта' in field_lower:
if _set(field_lower, 'subject_inn', val_b):
log_fn(f" ИНН субъекта: {val_b[:60]}")
continue
if 'кпп его обособленных' in field_lower or 'кпп субъекта' in field_lower:
if _set(field_lower, 'subject_kpp', val_b):
log_fn(f" КПП субъекта: {val_b[:60]}")
continue
if 'элемент (компонент) объекта, который эксплуатируется' in field_lower:
if _set(field_lower, 'subject_department', val_b):
log_fn(f" Элемент объекта: {val_b[:60]}")
continue
# --- Сети электросвязи ---
if 'категория сети электросвязи' in field_lower:
if _set(field_lower, 'net_category', val_b):
log_fn(f" Категория сети: {val_b[:60]}")
continue
if 'наименование провайдера' in field_lower or 'оператор связи' in field_lower:
if _set(field_lower, 'net_operator', val_b):
log_fn(f" Оператор: {val_b[:60]}")
continue
if 'цель взаимодействия' in field_lower:
if _set(field_lower, 'net_purpose', val_b):
log_fn(f" Цель взаимодействия: {val_b[:60]}")
continue
if 'способ взаимодействия' in field_lower:
if _set(field_lower, 'net_method', val_b):
log_fn(f" Способ взаимодействия: {val_b[:60]}")
continue
# --- ПО и аппаратные средства ---
if 'наименования программно-аппаратных средств' in field_lower:
if _set(field_lower, 'hw_sw', val_b):
log_fn(f" ПО/аппаратные средства: {val_b[:60]}")
continue
if 'операционная' in field_lower and 'система' in field_lower:
if _set(field_lower, 'os_sw', val_b):
log_fn(f" ОС: {val_b[:60]}")
continue
if 'прикладные программы' in field_lower:
if _set(field_lower, 'app_sw', val_b):
log_fn(f" Прикладные программы: {val_b[:60]}")
continue
if 'общесистемн' in field_lower:
if _set(field_lower, 'os_sw', val_b):
log_fn(f" Общесистемное ПО: {val_b[:60]}")
continue
# --- Безопасность / 236 приказ ---
if 'категория нарушителя' in field_lower:
if _set(field_lower, 'attacker_category', val_b):
log_fn(f" Категория нарушителя: {val_b[:60]}")
continue
if 'основные угрозы' in field_lower or 'угрозы безопасности' in field_lower:
if _set(field_lower, 'threats', val_b):
log_fn(f" Угрозы: {val_b[:60]}")
continue
if 'компьютерных инцидентов' in field_lower or 'инцидент' in field_lower:
if _set(field_lower, 'incidents', val_b):
log_fn(f" Инциденты: {val_b[:60]}")
continue
if 'показателей критериев' in field_lower or 'показатели критериев' in field_lower:
if _set(field_lower, 'criteria_values', val_b):
log_fn(f" Показатели: {val_b[:60]}")
continue
if 'обоснование полученных' in field_lower or 'обоснование значений' in field_lower:
if _set(field_lower, 'criteria_justification', val_b):
log_fn(f" Обоснование: {val_b[:60]}")
continue
if 'организационные меры' in field_lower:
if _set(field_lower, 'org_measures', val_b):
log_fn(f" Орг. меры: {val_b[:60]}")
continue
if 'технические меры' in field_lower:
if _set(field_lower, 'tech_measures', val_b):
log_fn(f" Тех. меры: {val_b[:60]}")
continue
if 'интернет' in field_lower:
is_obj['isInternet'] = is_checked
@@ -321,7 +453,7 @@ def _import_187_is_list(wb, data, settings, log_fn):
if cleaned and cleaned not in is_obj['usersList']:
is_obj['usersList'].append(cleaned)
continue
# Средства защиты
# --- Средства защиты ---
matched = False
for kw, label in defense_keywords.items():
if re.search(kw, field_lower):
@@ -332,7 +464,7 @@ def _import_187_is_list(wb, data, settings, log_fn):
if matched:
continue
if val_b and 'выбрать' not in field_lower and field_lower not in ('значение', 'примечание'):
# Остальные заполненные поля — в описание (адрес, сфера, тип и т.д.)
# Остальные заполненные поля — в описание (адрес, балансовая стоимость и т.д.)
if not is_obj['description']:
is_obj['description'] = f"{field}: {val_b}"
else:
+42 -1
View File
@@ -23,10 +23,50 @@ class InformationSystem:
category: str = "" # Категория значимости объекта КИИ: 1 / 2 / 3 / без категории
users_list: List[str] = field(default_factory=list) # Пользователи ОКИИ
defense_tools_list: List[str] = field(default_factory=list) # Средства защиты
purpose: str = ""
purpose: str = "" # Назначение объекта (п. 236)
structure: str = "" # Структура объекта КИИ
software: str = "" # Программное обеспечение
# ---- 236 приказ ФСТЭК: сведения об объекте ----
sphere: str = "" # Сфера (область) деятельности
object_type: str = "" # Тип объекта (ИС, АСУ, ИТКС)
architecture: str = "" # Архитектура объекта
typical_object: str = "" # Наименование типового отраслевого объекта КИИ
# Субъект (владелец объекта)
subject_name: str = "" # Наименование субъекта
subject_address: str = "" # Адрес местонахождения субъекта
subject_chief_position: str = "" # Должность руководителя субъекта
subject_chief_fio: str = "" # ФИО руководителя субъекта
subject_security_position: str = "" # Должность ответственного за безопасность ЗОКИИ
subject_security_fio: str = "" # ФИО ответственного за безопасность ЗОКИИ
subject_department: str = "" # Структурное подразделение по безопасности
subject_department_chief: str = "" # Руководитель структурного подразделения
subject_phone: str = "" # Телефон
subject_email: str = "" # Адрес электронной почты
subject_inn: str = "" # ИНН субъекта
subject_kpp: str = "" # КПП обособленных подразделений
# Сети электросвязи
net_category: str = "" # Категория сети электросвязи
net_operator: str = "" # Оператор связи и (или) провайдер хостинга
net_purpose: str = "" # Цель взаимодействия с сетью электросвязи
net_method: str = "" # Способ взаимодействия с указанием типа доступа
# Программно-аппаратные средства
hw_sw: str = "" # Наименования программно-аппаратных средств и их количество
os_sw: str = "" # Общесистемное ПО (ОС, средства виртуализации)
app_sw: str = "" # Прикладные программы
# Безопасность (236 приказ)
attacker_category: str = "" # Категория нарушителя (внешний/внутренний)
threats: str = "" # Основные угрозы безопасности информации
incidents: str = "" # Типы компьютерных инцидентов
criteria_values: str = "" # Полученные значения по показателям критериев значимости
criteria_justification: str = "" # Обоснование полученных значений
org_measures: str = "" # Организационные меры
tech_measures: str = "" # Технические меры
@dataclass
class Company:
@@ -58,6 +98,7 @@ class Company:
kpp: str = ""
okved: str = "" # Основной ОКВЭД
okved_extra: List[str] = field(default_factory=list) # Дополнительные ОКВЭД
domain_name: str = "" # Доменное имя и внешний сетевой адрес
# Должностные лица
chief_position: str = ""
+254 -2
View File
@@ -255,6 +255,7 @@ class DokoGenApp:
("КПП:", "kpp"),
("ОГРН:", "ogrn"),
("Дата ОГРН:", "ogrn_date"),
("Доменное имя и внешний IP:", "domain_name"),
]
for i, (label, key) in enumerate(addr_fields):
ttk.Label(f2, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
@@ -589,9 +590,12 @@ class DokoGenApp:
for key, label in [('full_name', 'Наименование'), ('short_name', 'Краткое'),
('address', 'Адрес'), ('inn', 'ИНН'), ('kpp', 'КПП'),
('ogrn', 'ОГРН'), ('ogrn_date', 'Дата ОГРН'),
('okved', 'Основной ОКВЭД'),
('chief_position', 'Руководитель'), ('chief_fio', 'ФИО')]:
if d.get(key):
lines.append(f"{label}: {d[key]}")
if d.get('okved_extra'):
lines.append(f"Доп. ОКВЭД: {', '.join(d['okved_extra'])}")
else:
# ИИ-рецензия: показываем снимок полей (что ИИ увидел), замечания и предложения
lines.append(f"Оценка: {d.get('rating', '')}")
@@ -700,6 +704,15 @@ class DokoGenApp:
if comp.get(data_key) and ui_key in self._company_entries:
self._company_entries[ui_key].delete(0, tk.END)
self._company_entries[ui_key].insert(0, comp[data_key])
# ОКВЭД из DaData
if comp.get('okved') and 'okved' in self._company_entries:
self._company_entries['okved'].delete(0, tk.END)
self._company_entries['okved'].insert(0, comp['okved'])
if comp.get('okved_extra') and hasattr(self, 'okved_extra_listbox'):
self.okved_extra_listbox.delete(0, tk.END)
for code in comp['okved_extra']:
if str(code).strip():
self.okved_extra_listbox.insert(tk.END, str(code).strip())
if want('chief'):
if comp.get('chief_position') and 'chief_position' in self._official_entries:
self._official_entries['chief_position'].delete(0, tk.END)
@@ -772,6 +785,93 @@ class DokoGenApp:
nb2 = ttk.Notebook(self._is_edit_panel)
nb2.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# ===== Вкладка «Сведения (236 приказ)» =====
info_tab = ttk.Frame(nb2)
nb2.add(info_tab, text="Сведения (236)")
info_frame = ttk.Frame(info_tab, padding=8)
info_frame.pack(fill=tk.BOTH, expand=True)
info_fields = [
("Назначение объекта:", "is_purpose_entry"),
("Сфера деятельности:", "is_sphere_entry"),
("Тип объекта:", "is_object_type_entry"),
("Архитектура объекта:", "is_architecture_entry"),
("Типовой отраслевой объект КИИ:", "is_typical_object_entry"),
]
for i, (label, attr) in enumerate(info_fields):
ttk.Label(info_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
entry = ttk.Entry(info_frame, width=70)
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
setattr(self, attr, entry)
info_frame.columnconfigure(1, weight=1)
# ===== Вкладка «Субъект» =====
subj_tab = ttk.Frame(nb2)
nb2.add(subj_tab, text="Субъект")
subj_frame = ttk.Frame(subj_tab, padding=8)
subj_frame.pack(fill=tk.BOTH, expand=True)
subj_fields = [
("Наименование субъекта:", "is_subject_name_entry"),
("Адрес местонахождения:", "is_subject_address_entry"),
("Должность руководителя:", "is_subject_chief_position_entry"),
("ФИО руководителя:", "is_subject_chief_fio_entry"),
("Должность отв. за безопасность:", "is_subject_security_position_entry"),
("ФИО отв. за безопасность:", "is_subject_security_fio_entry"),
("Структурное подразделение:", "is_subject_department_entry"),
("Руководитель подразделения:", "is_subject_department_chief_entry"),
("Телефон:", "is_subject_phone_entry"),
("Эл. почта:", "is_subject_email_entry"),
("ИНН субъекта:", "is_subject_inn_entry"),
("КПП обособленных подразделений:", "is_subject_kpp_entry"),
]
for i, (label, attr) in enumerate(subj_fields):
ttk.Label(subj_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
entry = ttk.Entry(subj_frame, width=70)
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
setattr(self, attr, entry)
subj_frame.columnconfigure(1, weight=1)
# ===== Вкладка «Сети и ПО» =====
net_tab = ttk.Frame(nb2)
nb2.add(net_tab, text="Сети и ПО")
net_frame = ttk.Frame(net_tab, padding=8)
net_frame.pack(fill=tk.BOTH, expand=True)
net_fields = [
("Категория сети электросвязи:", "is_net_category_entry"),
("Оператор связи/провайдер хостинга:", "is_net_operator_entry"),
("Цель взаимодействия с сетью:", "is_net_purpose_entry"),
("Способ взаимодействия/тип доступа:", "is_net_method_entry"),
("ПО и аппаратные средства:", "is_hw_sw_entry"),
("Общесистемное ПО (ОС, виртуализация):", "is_os_sw_entry"),
("Прикладные программы:", "is_app_sw_entry"),
]
for i, (label, attr) in enumerate(net_fields):
ttk.Label(net_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
entry = ttk.Entry(net_frame, width=70)
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
setattr(self, attr, entry)
net_frame.columnconfigure(1, weight=1)
# ===== Вкладка «Безопасность (236)» =====
sec_tab = ttk.Frame(nb2)
nb2.add(sec_tab, text="Безопасность (236)")
sec_frame = ttk.Frame(sec_tab, padding=8)
sec_frame.pack(fill=tk.BOTH, expand=True)
sec_fields = [
("Категория нарушителя:", "is_attacker_category_entry"),
("Основные угрозы БИ:", "is_threats_entry"),
("Типы компьютерных инцидентов:", "is_incidents_entry"),
("Показатели критериев значимости:", "is_criteria_values_entry"),
("Обоснование значений показателей:", "is_criteria_justification_entry"),
("Организационные меры:", "is_org_measures_entry"),
("Технические меры:", "is_tech_measures_entry"),
]
for i, (label, attr) in enumerate(sec_fields):
ttk.Label(sec_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
entry = ttk.Entry(sec_frame, width=70)
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
setattr(self, attr, entry)
sec_frame.columnconfigure(1, weight=1)
# СЗИ
def_tab = ttk.Frame(nb2)
nb2.add(def_tab, text="Средства защиты")
@@ -1021,6 +1121,43 @@ class DokoGenApp:
isys.is_local_network = self.is_lan_var.get()
isys.is_internet = self.is_internet_var.get()
isys.category = self.is_category_var.get()
# Поля 236 приказа
for attr, model_field in [
('is_purpose_entry', 'purpose'),
('is_sphere_entry', 'sphere'),
('is_object_type_entry', 'object_type'),
('is_architecture_entry', 'architecture'),
('is_typical_object_entry', 'typical_object'),
('is_subject_name_entry', 'subject_name'),
('is_subject_address_entry', 'subject_address'),
('is_subject_chief_position_entry', 'subject_chief_position'),
('is_subject_chief_fio_entry', 'subject_chief_fio'),
('is_subject_security_position_entry', 'subject_security_position'),
('is_subject_security_fio_entry', 'subject_security_fio'),
('is_subject_department_entry', 'subject_department'),
('is_subject_department_chief_entry', 'subject_department_chief'),
('is_subject_phone_entry', 'subject_phone'),
('is_subject_email_entry', 'subject_email'),
('is_subject_inn_entry', 'subject_inn'),
('is_subject_kpp_entry', 'subject_kpp'),
('is_net_category_entry', 'net_category'),
('is_net_operator_entry', 'net_operator'),
('is_net_purpose_entry', 'net_purpose'),
('is_net_method_entry', 'net_method'),
('is_hw_sw_entry', 'hw_sw'),
('is_os_sw_entry', 'os_sw'),
('is_app_sw_entry', 'app_sw'),
('is_attacker_category_entry', 'attacker_category'),
('is_threats_entry', 'threats'),
('is_incidents_entry', 'incidents'),
('is_criteria_values_entry', 'criteria_values'),
('is_criteria_justification_entry', 'criteria_justification'),
('is_org_measures_entry', 'org_measures'),
('is_tech_measures_entry', 'tech_measures'),
]:
w = getattr(self, attr, None)
if w is not None:
setattr(isys, model_field, w.get().strip())
# Списки
isys.defense_tools_list = list(self.defense_tools_listbox.get(0, tk.END))
isys.users_list = list(self.users_listbox.get(0, tk.END))
@@ -1224,6 +1361,45 @@ class DokoGenApp:
self.is_internet_var.set(isys.is_internet)
self.is_category_var.set(isys.category or "без категории")
# Поля 236 приказа
for attr, model_field in [
('is_purpose_entry', 'purpose'),
('is_sphere_entry', 'sphere'),
('is_object_type_entry', 'object_type'),
('is_architecture_entry', 'architecture'),
('is_typical_object_entry', 'typical_object'),
('is_subject_name_entry', 'subject_name'),
('is_subject_address_entry', 'subject_address'),
('is_subject_chief_position_entry', 'subject_chief_position'),
('is_subject_chief_fio_entry', 'subject_chief_fio'),
('is_subject_security_position_entry', 'subject_security_position'),
('is_subject_security_fio_entry', 'subject_security_fio'),
('is_subject_department_entry', 'subject_department'),
('is_subject_department_chief_entry', 'subject_department_chief'),
('is_subject_phone_entry', 'subject_phone'),
('is_subject_email_entry', 'subject_email'),
('is_subject_inn_entry', 'subject_inn'),
('is_subject_kpp_entry', 'subject_kpp'),
('is_net_category_entry', 'net_category'),
('is_net_operator_entry', 'net_operator'),
('is_net_purpose_entry', 'net_purpose'),
('is_net_method_entry', 'net_method'),
('is_hw_sw_entry', 'hw_sw'),
('is_os_sw_entry', 'os_sw'),
('is_app_sw_entry', 'app_sw'),
('is_attacker_category_entry', 'attacker_category'),
('is_threats_entry', 'threats'),
('is_incidents_entry', 'incidents'),
('is_criteria_values_entry', 'criteria_values'),
('is_criteria_justification_entry', 'criteria_justification'),
('is_org_measures_entry', 'org_measures'),
('is_tech_measures_entry', 'tech_measures'),
]:
w = getattr(self, attr, None)
if w is not None:
w.delete(0, tk.END)
w.insert(0, getattr(isys, model_field, '') or '')
# Списки
for lb, items in [
(self.defense_tools_listbox, isys.defense_tools_list or []),
@@ -1257,6 +1433,37 @@ class DokoGenApp:
category=src.category,
defense_tools_list=list(src.defense_tools_list),
users_list=list(src.users_list),
purpose=src.purpose,
sphere=src.sphere,
object_type=src.object_type,
architecture=src.architecture,
typical_object=src.typical_object,
subject_name=src.subject_name,
subject_address=src.subject_address,
subject_chief_position=src.subject_chief_position,
subject_chief_fio=src.subject_chief_fio,
subject_security_position=src.subject_security_position,
subject_security_fio=src.subject_security_fio,
subject_department=src.subject_department,
subject_department_chief=src.subject_department_chief,
subject_phone=src.subject_phone,
subject_email=src.subject_email,
subject_inn=src.subject_inn,
subject_kpp=src.subject_kpp,
net_category=src.net_category,
net_operator=src.net_operator,
net_purpose=src.net_purpose,
net_method=src.net_method,
hw_sw=src.hw_sw,
os_sw=src.os_sw,
app_sw=src.app_sw,
attacker_category=src.attacker_category,
threats=src.threats,
incidents=src.incidents,
criteria_values=src.criteria_values,
criteria_justification=src.criteria_justification,
org_measures=src.org_measures,
tech_measures=src.tech_measures,
)
self.model.information_systems.append(copy)
self._refresh_is_listbox()
@@ -1745,6 +1952,20 @@ class DokoGenApp:
if data.get('ispdnDepartment'):
self.model.security_department = data['ispdnDepartment']
# Доменное имя и внешний сетевой адрес
if data.get('domainName'):
entry = self._company_entries.get('domain_name')
if entry:
entry.delete(0, tk.END)
entry.insert(0, data['domainName'])
# Доменное имя и внешний сетевой адрес
if data.get('domainName'):
entry = self._company_entries.get('domain_name')
if entry:
entry.delete(0, tk.END)
entry.insert(0, data['domainName'])
# ОКВЭД (основной и дополнительные)
if data.get('okved'):
entry = self._company_entries.get('okved')
@@ -1756,7 +1977,8 @@ class DokoGenApp:
self.okved_extra_listbox.delete(0, tk.END)
extra = data['okvedExtra']
if isinstance(extra, str):
parts = [p.strip() for p in extra.replace(';', '\n').split('\n') if p.strip()]
import re as _re
parts = [p.strip() for p in _re.split(r'[;,\n]+', extra) if p.strip()]
else:
parts = [str(p).strip() for p in extra if str(p).strip()]
for p in parts:
@@ -1774,9 +1996,39 @@ class DokoGenApp:
category=is_data.get('category', ''),
defense_tools_list=is_data.get('defense_tools', []),
users_list=is_data.get('usersList', []),
purpose=is_data.get('purpose', is_data.get('description', '')),
purpose=is_data.get('purpose', ''),
structure=is_data.get('structure', ''),
software=is_data.get('software', ''),
sphere=is_data.get('sphere', ''),
object_type=is_data.get('object_type', ''),
architecture=is_data.get('architecture', ''),
typical_object=is_data.get('typical_object', ''),
subject_name=is_data.get('subject_name', ''),
subject_address=is_data.get('subject_address', ''),
subject_chief_position=is_data.get('subject_chief_position', ''),
subject_chief_fio=is_data.get('subject_chief_fio', ''),
subject_security_position=is_data.get('subject_security_position', ''),
subject_security_fio=is_data.get('subject_security_fio', ''),
subject_department=is_data.get('subject_department', ''),
subject_department_chief=is_data.get('subject_department_chief', ''),
subject_phone=is_data.get('subject_phone', ''),
subject_email=is_data.get('subject_email', ''),
subject_inn=is_data.get('subject_inn', ''),
subject_kpp=is_data.get('subject_kpp', ''),
net_category=is_data.get('net_category', ''),
net_operator=is_data.get('net_operator', ''),
net_purpose=is_data.get('net_purpose', ''),
net_method=is_data.get('net_method', ''),
hw_sw=is_data.get('hw_sw', ''),
os_sw=is_data.get('os_sw', ''),
app_sw=is_data.get('app_sw', ''),
attacker_category=is_data.get('attacker_category', ''),
threats=is_data.get('threats', ''),
incidents=is_data.get('incidents', ''),
criteria_values=is_data.get('criteria_values', ''),
criteria_justification=is_data.get('criteria_justification', ''),
org_measures=is_data.get('org_measures', ''),
tech_measures=is_data.get('tech_measures', ''),
)
self.model.information_systems.append(isys)
self._refresh_is_listbox()
+43
View File
@@ -220,6 +220,17 @@ def _add_is_indexed_vars(replacements: Dict[str, str], isys, idx: int):
'is_purpose': isys.purpose or '',
'is_structure': getattr(isys, 'structure', '') or '',
'is_software': getattr(isys, 'software', '') or '',
'is_sphere': getattr(isys, 'sphere', '') or '',
'is_object_type': getattr(isys, 'object_type', '') or '',
'is_architecture': getattr(isys, 'architecture', '') or '',
'is_typical_object': getattr(isys, 'typical_object', '') or '',
'is_net_category': getattr(isys, 'net_category', '') or '',
'is_net_operator': getattr(isys, 'net_operator', '') or '',
'is_net_purpose': getattr(isys, 'net_purpose', '') or '',
'is_net_method': getattr(isys, 'net_method', '') or '',
'is_hw_sw': getattr(isys, 'hw_sw', '') or '',
'is_os_sw': getattr(isys, 'os_sw', '') or '',
'is_app_sw': getattr(isys, 'app_sw', '') or '',
}
for f, v in fields.items():
replacements[f'{{{{{f}_{idx}}}}}'] = str(v)
@@ -294,6 +305,38 @@ def _build_loop_data(company: Company, is_list: List) -> Dict[str, List[Dict]]:
'is_purpose': isys.purpose or '',
'structure': getattr(isys, 'structure', '') or '',
'software': getattr(isys, 'software', '') or '',
# 236 приказ
'purpose': isys.purpose or '',
'sphere': getattr(isys, 'sphere', '') or '',
'object_type': getattr(isys, 'object_type', '') or '',
'architecture': getattr(isys, 'architecture', '') or '',
'typical_object': getattr(isys, 'typical_object', '') or '',
'subject_name': getattr(isys, 'subject_name', '') or '',
'subject_address': getattr(isys, 'subject_address', '') or '',
'subject_chief_position': getattr(isys, 'subject_chief_position', '') or '',
'subject_chief_fio': getattr(isys, 'subject_chief_fio', '') or '',
'subject_security_position': getattr(isys, 'subject_security_position', '') or '',
'subject_security_fio': getattr(isys, 'subject_security_fio', '') or '',
'subject_department': getattr(isys, 'subject_department', '') or '',
'subject_department_chief': getattr(isys, 'subject_department_chief', '') or '',
'subject_phone': getattr(isys, 'subject_phone', '') or '',
'subject_email': getattr(isys, 'subject_email', '') or '',
'subject_inn': getattr(isys, 'subject_inn', '') or '',
'subject_kpp': getattr(isys, 'subject_kpp', '') or '',
'net_category': getattr(isys, 'net_category', '') or '',
'net_operator': getattr(isys, 'net_operator', '') or '',
'net_purpose': getattr(isys, 'net_purpose', '') or '',
'net_method': getattr(isys, 'net_method', '') or '',
'hw_sw': getattr(isys, 'hw_sw', '') or '',
'os_sw': getattr(isys, 'os_sw', '') or '',
'app_sw': getattr(isys, 'app_sw', '') or '',
'attacker_category': getattr(isys, 'attacker_category', '') or '',
'threats': getattr(isys, 'threats', '') or '',
'incidents': getattr(isys, 'incidents', '') or '',
'criteria_values': getattr(isys, 'criteria_values', '') or '',
'criteria_justification': getattr(isys, 'criteria_justification', '') or '',
'org_measures': getattr(isys, 'org_measures', '') or '',
'tech_measures': getattr(isys, 'tech_measures', '') or '',
})
loops['information_systems'] = items
+12
View File
@@ -250,6 +250,14 @@ def check_company_dadata(inn, token):
chief_fio = _normalize_text(management.get('name', ''))
ogrn_date = _fmt_date(d.get('ogrn_date') or '')
# ОКВЭД: основной (okved) и дополнительные (okveds — список словарей с 'code')
okved = d.get('okved', '') or ''
okved_extra = []
for ok in (d.get('okveds') or []):
code = (ok or {}).get('code') or ''
if code:
okved_extra.append(code)
return {
'source': 'DaData',
'source_url': 'https://dadata.ru',
@@ -266,6 +274,8 @@ def check_company_dadata(inn, token):
'chief_position': chief_position,
'chief_fio': chief_fio,
'inn': d.get('inn', inn),
'okved': okved,
'okved_extra': okved_extra,
},
'apply': {'company': {
'full_name': full_name,
@@ -276,6 +286,8 @@ def check_company_dadata(inn, token):
'ogrn_date': ogrn_date,
'chief_position': chief_position,
'chief_fio': chief_fio,
'okved': okved,
'okved_extra': okved_extra,
}},
}, None