fix: ОКВЭД импорт/DaData/словарь+интернет, доменное имя, вкладка ОКИИ → вложенные вкладки, словарики, СЗИ разбивка, адрес отдельно
- ОКВЭД: resolve_okved (словарь okved.json + DaData suggest okved2), применяется при импорте и DaData; галочки «ОКВЭД осн./доп.» в «что применять» - DaData: показ и подстановка доп. ОКВЭД - доменное имя: поле во вкладке «Организация» + импорт - вкладка «Объекты КИИ»: сверху Наименование/Описание/Категория, остальное вкладками: Основное (назначение, сфера, тип, архитектура, типовой отраслевой объект — со словариками и выпадающими списками), Субъект, Сети и ПО, Безопасность (236), СЗИ, Пользователи ОКИИ - новые словари: spheres.json, object_types.json, architectures.json, typical_objects.json - адрес объекта — в отдельное поле (не в описание) - СЗИ: разбивка слипшихся названий (Kaspersky...)
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
"одноранговая сеть",
|
||||||
|
"клиент-серверная система",
|
||||||
|
"технология \"тонкий клиент\"",
|
||||||
|
"сеть передачи данных",
|
||||||
|
"система диспетчерского управления и контроля",
|
||||||
|
"распределенная система управления",
|
||||||
|
"иная архитектура"
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
"Информационная система",
|
||||||
|
"Автоматизированная система управления",
|
||||||
|
"Информационно-телекоммуникационная сеть"
|
||||||
|
]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[
|
||||||
|
"Здравоохранение",
|
||||||
|
"Наука",
|
||||||
|
"Транспорт",
|
||||||
|
"Связь",
|
||||||
|
"Энергетика",
|
||||||
|
"Государственная регистрация прав",
|
||||||
|
"Банковская сфера и финансовый рынок",
|
||||||
|
"Топливно-энергетический комплекс",
|
||||||
|
"Атомная энергетика",
|
||||||
|
"Оборонная промышленность",
|
||||||
|
"Ракетно-космическая промышленность",
|
||||||
|
"Горнодобывающая промышленность",
|
||||||
|
"Металлургическая промышленность",
|
||||||
|
"Химическая промышленность",
|
||||||
|
"Иная сфера деятельности"
|
||||||
|
]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
"Информационная система управления",
|
||||||
|
"Автоматизированная система управления технологическим процессом",
|
||||||
|
"Информационно-телекоммуникационная сеть",
|
||||||
|
"Автоматизированная система управления производством",
|
||||||
|
"Система диспетчерского управления",
|
||||||
|
"Система управления базами данных",
|
||||||
|
"Автоматизированная система научных исследований",
|
||||||
|
"Система электронного документооборота",
|
||||||
|
"Информационная система расчетов",
|
||||||
|
"Система управления финансами",
|
||||||
|
"Иной типовой отраслевой объект КИИ"
|
||||||
|
]
|
||||||
+28
-2
@@ -279,7 +279,7 @@ def _import_187_is_list(wb, data, settings, log_fn):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
is_obj = {
|
is_obj = {
|
||||||
'name': '', 'description': '', 'usersList': [],
|
'name': '', 'description': '', 'address': '', 'usersList': [],
|
||||||
'isInternet': False, 'defense_tools': [], 'software': '',
|
'isInternet': False, 'defense_tools': [], 'software': '',
|
||||||
# 236 приказ
|
# 236 приказ
|
||||||
'sphere': '', 'purpose': '', 'object_type': '', 'architecture': '',
|
'sphere': '', 'purpose': '', 'object_type': '', 'architecture': '',
|
||||||
@@ -315,6 +315,25 @@ def _import_187_is_list(wb, data, settings, log_fn):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _split_entries(text):
|
||||||
|
"""Разбивает слипшиеся названия СЗИ: по переносам строк, ';' и по границе
|
||||||
|
'цифра + заглавная буква' (напр. '15.1.0.22239Kaspersky' → два названия)."""
|
||||||
|
if not text:
|
||||||
|
return []
|
||||||
|
parts = re.split(r'[\n;]+', text)
|
||||||
|
out = []
|
||||||
|
for p in parts:
|
||||||
|
p = p.strip()
|
||||||
|
if not p:
|
||||||
|
continue
|
||||||
|
# граница: цифра/точка → заглавная буква без пробела
|
||||||
|
sub = re.split(r'(?<=[0-9.])(?=[А-ЯЁA-Z])', p)
|
||||||
|
for s in sub:
|
||||||
|
s = s.strip()
|
||||||
|
if s and s not in out:
|
||||||
|
out.append(s)
|
||||||
|
return out
|
||||||
|
|
||||||
for vals in rows:
|
for vals in rows:
|
||||||
field = (vals[0] or '').strip()
|
field = (vals[0] or '').strip()
|
||||||
field_lower = field.lower()
|
field_lower = field.lower()
|
||||||
@@ -326,6 +345,11 @@ def _import_187_is_list(wb, data, settings, log_fn):
|
|||||||
is_obj['name'] = val_b
|
is_obj['name'] = val_b
|
||||||
log_fn(f" Объект КИИ: {val_b}")
|
log_fn(f" Объект КИИ: {val_b}")
|
||||||
continue
|
continue
|
||||||
|
# --- Адрес размещения объекта (в отдельное поле, не в описание) ---
|
||||||
|
if 'адрес размещения' in field_lower or 'адрес расположения' in field_lower or 'местонахождение объекта' in field_lower:
|
||||||
|
is_obj['address'] = val_b
|
||||||
|
log_fn(f" Адрес объекта: {val_b[:60]}")
|
||||||
|
continue
|
||||||
# --- Описание ---
|
# --- Описание ---
|
||||||
if 'описание окки' in field_lower or 'описание объекта' in field_lower:
|
if 'описание окки' in field_lower or 'описание объекта' in field_lower:
|
||||||
if val_b:
|
if val_b:
|
||||||
@@ -458,7 +482,9 @@ def _import_187_is_list(wb, data, settings, log_fn):
|
|||||||
for kw, label in defense_keywords.items():
|
for kw, label in defense_keywords.items():
|
||||||
if re.search(kw, field_lower):
|
if re.search(kw, field_lower):
|
||||||
if val_b and 'выбрать' not in field_lower:
|
if val_b and 'выбрать' not in field_lower:
|
||||||
is_obj['defense_tools'].append(val_b)
|
for tool in _split_entries(val_b):
|
||||||
|
if tool not in is_obj['defense_tools']:
|
||||||
|
is_obj['defense_tools'].append(tool)
|
||||||
matched = True
|
matched = True
|
||||||
break
|
break
|
||||||
if matched:
|
if matched:
|
||||||
|
|||||||
+122
-66
@@ -359,6 +359,8 @@ class DokoGenApp:
|
|||||||
'address': tk.BooleanVar(value=True),
|
'address': tk.BooleanVar(value=True),
|
||||||
'requisites': tk.BooleanVar(value=True),
|
'requisites': tk.BooleanVar(value=True),
|
||||||
'chief': tk.BooleanVar(value=True),
|
'chief': tk.BooleanVar(value=True),
|
||||||
|
'okved': tk.BooleanVar(value=True),
|
||||||
|
'okved_extra': tk.BooleanVar(value=True),
|
||||||
}
|
}
|
||||||
apply_row = ttk.Frame(right)
|
apply_row = ttk.Frame(right)
|
||||||
apply_row.pack(fill=tk.X, pady=(4, 0))
|
apply_row.pack(fill=tk.X, pady=(4, 0))
|
||||||
@@ -368,6 +370,11 @@ class DokoGenApp:
|
|||||||
ttk.Checkbutton(apply_row, text="адрес", variable=self._apply_flags['address']).pack(side=tk.LEFT)
|
ttk.Checkbutton(apply_row, text="адрес", variable=self._apply_flags['address']).pack(side=tk.LEFT)
|
||||||
ttk.Checkbutton(apply_row, text="ИНН/КПП/ОГРН", variable=self._apply_flags['requisites']).pack(side=tk.LEFT)
|
ttk.Checkbutton(apply_row, text="ИНН/КПП/ОГРН", variable=self._apply_flags['requisites']).pack(side=tk.LEFT)
|
||||||
ttk.Checkbutton(apply_row, text="руковод.", variable=self._apply_flags['chief']).pack(side=tk.LEFT)
|
ttk.Checkbutton(apply_row, text="руковод.", variable=self._apply_flags['chief']).pack(side=tk.LEFT)
|
||||||
|
apply_row2 = ttk.Frame(right)
|
||||||
|
apply_row2.pack(fill=tk.X, pady=(2, 0))
|
||||||
|
ttk.Label(apply_row2, text="", font=('', 8), width=10).pack(side=tk.LEFT)
|
||||||
|
ttk.Checkbutton(apply_row2, text="ОКВЭД осн.", variable=self._apply_flags['okved']).pack(side=tk.LEFT)
|
||||||
|
ttk.Checkbutton(apply_row2, text="ОКВЭД доп.", variable=self._apply_flags['okved_extra']).pack(side=tk.LEFT)
|
||||||
self._verify_result = None
|
self._verify_result = None
|
||||||
|
|
||||||
# ---------- ПРОВЕРКА ДАННЫХ (Морфер / DaData / ИИ) ----------
|
# ---------- ПРОВЕРКА ДАННЫХ (Морфер / DaData / ИИ) ----------
|
||||||
@@ -704,15 +711,18 @@ class DokoGenApp:
|
|||||||
if comp.get(data_key) and ui_key in self._company_entries:
|
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].delete(0, tk.END)
|
||||||
self._company_entries[ui_key].insert(0, comp[data_key])
|
self._company_entries[ui_key].insert(0, comp[data_key])
|
||||||
# ОКВЭД из DaData
|
# ОКВЭД из DaData (с названием из словаря/интернета)
|
||||||
if comp.get('okved') and 'okved' in self._company_entries:
|
from .verify import resolve_okved
|
||||||
|
from .api_settings import load_api_settings as _las3
|
||||||
|
_tok3 = (_las3().get('dadata_token') or '')
|
||||||
|
if want('okved') and comp.get('okved') and 'okved' in self._company_entries:
|
||||||
self._company_entries['okved'].delete(0, tk.END)
|
self._company_entries['okved'].delete(0, tk.END)
|
||||||
self._company_entries['okved'].insert(0, comp['okved'])
|
self._company_entries['okved'].insert(0, resolve_okved(comp['okved'], _tok3))
|
||||||
if comp.get('okved_extra') and hasattr(self, 'okved_extra_listbox'):
|
if want('okved_extra') and comp.get('okved_extra') and hasattr(self, 'okved_extra_listbox'):
|
||||||
self.okved_extra_listbox.delete(0, tk.END)
|
self.okved_extra_listbox.delete(0, tk.END)
|
||||||
for code in comp['okved_extra']:
|
for code in comp['okved_extra']:
|
||||||
if str(code).strip():
|
if str(code).strip():
|
||||||
self.okved_extra_listbox.insert(tk.END, str(code).strip())
|
self.okved_extra_listbox.insert(tk.END, resolve_okved(str(code).strip(), _tok3))
|
||||||
if want('chief'):
|
if want('chief'):
|
||||||
if comp.get('chief_position') and 'chief_position' in self._official_entries:
|
if comp.get('chief_position') and 'chief_position' in self._official_entries:
|
||||||
self._official_entries['chief_position'].delete(0, tk.END)
|
self._official_entries['chief_position'].delete(0, tk.END)
|
||||||
@@ -748,61 +758,87 @@ class DokoGenApp:
|
|||||||
fields_frame = ttk.Frame(self._is_edit_panel, padding=10)
|
fields_frame = ttk.Frame(self._is_edit_panel, padding=10)
|
||||||
fields_frame.pack(fill=tk.X)
|
fields_frame.pack(fill=tk.X)
|
||||||
|
|
||||||
# Основные поля
|
# Основные поля (сверху — только название, описание, категория)
|
||||||
ttk.Label(fields_frame, text="Наименование:").grid(row=0, column=0, sticky=tk.W, pady=2)
|
ttk.Label(fields_frame, text="Наименование:").grid(row=0, column=0, sticky=tk.W, pady=2)
|
||||||
self.is_name_entry = ttk.Entry(fields_frame, width=55)
|
self.is_name_entry = ttk.Entry(fields_frame, width=60)
|
||||||
self.is_name_entry.grid(row=0, column=1, padx=10, sticky=tk.EW)
|
self.is_name_entry.grid(row=0, column=1, padx=10, sticky=tk.EW)
|
||||||
|
|
||||||
ttk.Label(fields_frame, text="Описание:").grid(row=1, column=0, sticky=tk.W, pady=2)
|
ttk.Label(fields_frame, text="Описание:").grid(row=1, column=0, sticky=tk.W, pady=2)
|
||||||
self.is_description_entry = ttk.Entry(fields_frame, width=55)
|
self.is_description_entry = ttk.Entry(fields_frame, width=60)
|
||||||
self.is_description_entry.grid(row=1, column=1, padx=10, sticky=tk.EW)
|
self.is_description_entry.grid(row=1, column=1, padx=10, sticky=tk.EW)
|
||||||
|
|
||||||
# Чекбоксы
|
|
||||||
chk_frame = ttk.Frame(fields_frame)
|
|
||||||
chk_frame.grid(row=2, column=1, sticky=tk.W, pady=5)
|
|
||||||
self.is_lan_var = tk.BooleanVar()
|
|
||||||
ttk.Checkbutton(chk_frame, text="ЛВС", variable=self.is_lan_var).pack(side=tk.LEFT, padx=5)
|
|
||||||
self.is_internet_var = tk.BooleanVar()
|
|
||||||
ttk.Checkbutton(chk_frame, text="Интернет", variable=self.is_internet_var).pack(side=tk.LEFT, padx=5)
|
|
||||||
|
|
||||||
# Категория значимости объекта КИИ
|
# Категория значимости объекта КИИ
|
||||||
self.is_category_var = tk.StringVar(value="без категории")
|
self.is_category_var = tk.StringVar(value="без категории")
|
||||||
ttk.Label(fields_frame, text="Категория значимости:").grid(row=3, column=0, sticky=tk.W, pady=2)
|
ttk.Label(fields_frame, text="Категория значимости:").grid(row=2, column=0, sticky=tk.W, pady=2)
|
||||||
cat_frame = ttk.Frame(fields_frame)
|
cat_frame = ttk.Frame(fields_frame)
|
||||||
cat_frame.grid(row=3, column=1, sticky=tk.W, padx=10)
|
cat_frame.grid(row=2, column=1, sticky=tk.W, padx=10)
|
||||||
for val in ["1", "2", "3", "без категории"]:
|
for val in ["1", "2", "3", "без категории"]:
|
||||||
ttk.Radiobutton(cat_frame, text=val, variable=self.is_category_var,
|
ttk.Radiobutton(cat_frame, text=val, variable=self.is_category_var,
|
||||||
value=val).pack(side=tk.LEFT, padx=3)
|
value=val).pack(side=tk.LEFT, padx=3)
|
||||||
|
|
||||||
# Программное обеспечение
|
|
||||||
ttk.Label(fields_frame, text="Программное обеспечение:").grid(row=4, column=0, sticky=tk.W, pady=2)
|
|
||||||
self.is_software_entry = ttk.Entry(fields_frame, width=55)
|
|
||||||
self.is_software_entry.grid(row=4, column=1, padx=10, sticky=tk.EW)
|
|
||||||
|
|
||||||
fields_frame.columnconfigure(1, weight=1)
|
fields_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
# Вложенные списки
|
# ---- Вложенные вкладки ----
|
||||||
nb2 = ttk.Notebook(self._is_edit_panel)
|
nb2 = ttk.Notebook(self._is_edit_panel)
|
||||||
nb2.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
nb2.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||||||
|
|
||||||
# ===== Вкладка «Сведения (236 приказ)» =====
|
# ===== Вкладка «Основное» =====
|
||||||
info_tab = ttk.Frame(nb2)
|
main_tab = ttk.Frame(nb2)
|
||||||
nb2.add(info_tab, text="Сведения (236)")
|
nb2.add(main_tab, text="Основное")
|
||||||
info_frame = ttk.Frame(info_tab, padding=8)
|
main_frame = ttk.Frame(main_tab, padding=8)
|
||||||
info_frame.pack(fill=tk.BOTH, expand=True)
|
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
info_fields = [
|
|
||||||
("Назначение объекта:", "is_purpose_entry"),
|
# Назначение объекта
|
||||||
("Сфера деятельности:", "is_sphere_entry"),
|
ttk.Label(main_frame, text="Назначение объекта:").grid(row=0, column=0, sticky=tk.W, pady=2)
|
||||||
("Тип объекта:", "is_object_type_entry"),
|
self.is_purpose_entry = ttk.Entry(main_frame, width=70)
|
||||||
("Архитектура объекта:", "is_architecture_entry"),
|
self.is_purpose_entry.grid(row=0, column=1, padx=8, sticky=tk.EW, pady=1)
|
||||||
("Типовой отраслевой объект КИИ:", "is_typical_object_entry"),
|
|
||||||
]
|
# Сфера деятельности — словарик + выпадающий список
|
||||||
for i, (label, attr) in enumerate(info_fields):
|
ttk.Label(main_frame, text="Сфера деятельности:").grid(row=1, column=0, sticky=tk.W, pady=2)
|
||||||
ttk.Label(info_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
|
self.is_sphere_combo = ttk.Combobox(main_frame, width=68)
|
||||||
entry = ttk.Entry(info_frame, width=70)
|
self.is_sphere_combo.grid(row=1, column=1, padx=8, sticky=tk.EW, pady=1)
|
||||||
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
|
try:
|
||||||
setattr(self, attr, entry)
|
import json as _json
|
||||||
info_frame.columnconfigure(1, weight=1)
|
_sp = os.path.join(os.path.dirname(__file__), 'dictionaries', 'spheres.json')
|
||||||
|
with open(_sp, encoding='utf-8') as _f:
|
||||||
|
self.is_sphere_combo['values'] = _json.load(_f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Тип объекта — словарик + выпадающий список
|
||||||
|
ttk.Label(main_frame, text="Тип объекта:").grid(row=2, column=0, sticky=tk.W, pady=2)
|
||||||
|
self.is_object_type_combo = ttk.Combobox(main_frame, width=68)
|
||||||
|
self.is_object_type_combo.grid(row=2, column=1, padx=8, sticky=tk.EW, pady=1)
|
||||||
|
try:
|
||||||
|
_ot = os.path.join(os.path.dirname(__file__), 'dictionaries', 'object_types.json')
|
||||||
|
with open(_ot, encoding='utf-8') as _f:
|
||||||
|
self.is_object_type_combo['values'] = _json.load(_f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Архитектура объекта — словарик + выпадающий список
|
||||||
|
ttk.Label(main_frame, text="Архитектура объекта:").grid(row=3, column=0, sticky=tk.W, pady=2)
|
||||||
|
self.is_architecture_combo = ttk.Combobox(main_frame, width=68)
|
||||||
|
self.is_architecture_combo.grid(row=3, column=1, padx=8, sticky=tk.EW, pady=1)
|
||||||
|
try:
|
||||||
|
_ar = os.path.join(os.path.dirname(__file__), 'dictionaries', 'architectures.json')
|
||||||
|
with open(_ar, encoding='utf-8') as _f:
|
||||||
|
self.is_architecture_combo['values'] = _json.load(_f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Типовой отраслевой объект КИИ — словарик + выпадающий список
|
||||||
|
ttk.Label(main_frame, text="Типовой отраслевой объект КИИ:").grid(row=4, column=0, sticky=tk.W, pady=2)
|
||||||
|
self.is_typical_object_combo = ttk.Combobox(main_frame, width=68)
|
||||||
|
self.is_typical_object_combo.grid(row=4, column=1, padx=8, sticky=tk.EW, pady=1)
|
||||||
|
try:
|
||||||
|
_to = os.path.join(os.path.dirname(__file__), 'dictionaries', 'typical_objects.json')
|
||||||
|
with open(_to, encoding='utf-8') as _f:
|
||||||
|
self.is_typical_object_combo['values'] = _json.load(_f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
main_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
# ===== Вкладка «Субъект» =====
|
# ===== Вкладка «Субъект» =====
|
||||||
subj_tab = ttk.Frame(nb2)
|
subj_tab = ttk.Frame(nb2)
|
||||||
@@ -835,19 +871,29 @@ class DokoGenApp:
|
|||||||
nb2.add(net_tab, text="Сети и ПО")
|
nb2.add(net_tab, text="Сети и ПО")
|
||||||
net_frame = ttk.Frame(net_tab, padding=8)
|
net_frame = ttk.Frame(net_tab, padding=8)
|
||||||
net_frame.pack(fill=tk.BOTH, expand=True)
|
net_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# ЛВС / Интернет
|
||||||
|
chk = ttk.Frame(net_frame)
|
||||||
|
chk.grid(row=0, column=0, columnspan=2, sticky=tk.W, pady=2)
|
||||||
|
self.is_lan_var = tk.BooleanVar()
|
||||||
|
ttk.Checkbutton(chk, text="ЛВС", variable=self.is_lan_var).pack(side=tk.LEFT, padx=5)
|
||||||
|
self.is_internet_var = tk.BooleanVar()
|
||||||
|
ttk.Checkbutton(chk, text="Интернет", variable=self.is_internet_var).pack(side=tk.LEFT, padx=5)
|
||||||
|
|
||||||
net_fields = [
|
net_fields = [
|
||||||
("Категория сети электросвязи:", "is_net_category_entry"),
|
("Категория сети электросвязи:", "is_net_category_entry", 1),
|
||||||
("Оператор связи/провайдер хостинга:", "is_net_operator_entry"),
|
("Оператор связи/провайдер хостинга:", "is_net_operator_entry", 2),
|
||||||
("Цель взаимодействия с сетью:", "is_net_purpose_entry"),
|
("Цель взаимодействия с сетью:", "is_net_purpose_entry", 3),
|
||||||
("Способ взаимодействия/тип доступа:", "is_net_method_entry"),
|
("Способ взаимодействия/тип доступа:", "is_net_method_entry", 4),
|
||||||
("ПО и аппаратные средства:", "is_hw_sw_entry"),
|
("ПО и аппаратные средства:", "is_hw_sw_entry", 5),
|
||||||
("Общесистемное ПО (ОС, виртуализация):", "is_os_sw_entry"),
|
("Общесистемное ПО (ОС, виртуализация):", "is_os_sw_entry", 6),
|
||||||
("Прикладные программы:", "is_app_sw_entry"),
|
("Прикладные программы:", "is_app_sw_entry", 7),
|
||||||
|
("Программное обеспечение:", "is_software_entry", 8),
|
||||||
]
|
]
|
||||||
for i, (label, attr) in enumerate(net_fields):
|
for label, attr, row in net_fields:
|
||||||
ttk.Label(net_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=2)
|
ttk.Label(net_frame, text=label).grid(row=row, column=0, sticky=tk.W, pady=2)
|
||||||
entry = ttk.Entry(net_frame, width=70)
|
entry = ttk.Entry(net_frame, width=70)
|
||||||
entry.grid(row=i, column=1, padx=8, sticky=tk.EW, pady=1)
|
entry.grid(row=row, column=1, padx=8, sticky=tk.EW, pady=1)
|
||||||
setattr(self, attr, entry)
|
setattr(self, attr, entry)
|
||||||
net_frame.columnconfigure(1, weight=1)
|
net_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
@@ -872,7 +918,7 @@ class DokoGenApp:
|
|||||||
setattr(self, attr, entry)
|
setattr(self, attr, entry)
|
||||||
sec_frame.columnconfigure(1, weight=1)
|
sec_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
# СЗИ
|
# ===== Вкладка «Средства защиты» =====
|
||||||
def_tab = ttk.Frame(nb2)
|
def_tab = ttk.Frame(nb2)
|
||||||
nb2.add(def_tab, text="Средства защиты")
|
nb2.add(def_tab, text="Средства защиты")
|
||||||
def_btn_frame = ttk.Frame(def_tab)
|
def_btn_frame = ttk.Frame(def_tab)
|
||||||
@@ -883,7 +929,7 @@ class DokoGenApp:
|
|||||||
self.defense_tools_listbox = tk.Listbox(def_tab, height=6)
|
self.defense_tools_listbox = tk.Listbox(def_tab, height=6)
|
||||||
self.defense_tools_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
self.defense_tools_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
# Пользователи ОКИИ
|
# ===== Вкладка «Пользователи ОКИИ» =====
|
||||||
user_tab = ttk.Frame(nb2)
|
user_tab = ttk.Frame(nb2)
|
||||||
nb2.add(user_tab, text="Пользователи ОКИИ")
|
nb2.add(user_tab, text="Пользователи ОКИИ")
|
||||||
self.users_listbox = tk.Listbox(user_tab, height=6)
|
self.users_listbox = tk.Listbox(user_tab, height=6)
|
||||||
@@ -1124,10 +1170,10 @@ class DokoGenApp:
|
|||||||
# Поля 236 приказа
|
# Поля 236 приказа
|
||||||
for attr, model_field in [
|
for attr, model_field in [
|
||||||
('is_purpose_entry', 'purpose'),
|
('is_purpose_entry', 'purpose'),
|
||||||
('is_sphere_entry', 'sphere'),
|
('is_sphere_combo', 'sphere'),
|
||||||
('is_object_type_entry', 'object_type'),
|
('is_object_type_combo', 'object_type'),
|
||||||
('is_architecture_entry', 'architecture'),
|
('is_architecture_combo', 'architecture'),
|
||||||
('is_typical_object_entry', 'typical_object'),
|
('is_typical_object_combo', 'typical_object'),
|
||||||
('is_subject_name_entry', 'subject_name'),
|
('is_subject_name_entry', 'subject_name'),
|
||||||
('is_subject_address_entry', 'subject_address'),
|
('is_subject_address_entry', 'subject_address'),
|
||||||
('is_subject_chief_position_entry', 'subject_chief_position'),
|
('is_subject_chief_position_entry', 'subject_chief_position'),
|
||||||
@@ -1364,10 +1410,10 @@ class DokoGenApp:
|
|||||||
# Поля 236 приказа
|
# Поля 236 приказа
|
||||||
for attr, model_field in [
|
for attr, model_field in [
|
||||||
('is_purpose_entry', 'purpose'),
|
('is_purpose_entry', 'purpose'),
|
||||||
('is_sphere_entry', 'sphere'),
|
('is_sphere_combo', 'sphere'),
|
||||||
('is_object_type_entry', 'object_type'),
|
('is_object_type_combo', 'object_type'),
|
||||||
('is_architecture_entry', 'architecture'),
|
('is_architecture_combo', 'architecture'),
|
||||||
('is_typical_object_entry', 'typical_object'),
|
('is_typical_object_combo', 'typical_object'),
|
||||||
('is_subject_name_entry', 'subject_name'),
|
('is_subject_name_entry', 'subject_name'),
|
||||||
('is_subject_address_entry', 'subject_address'),
|
('is_subject_address_entry', 'subject_address'),
|
||||||
('is_subject_chief_position_entry', 'subject_chief_position'),
|
('is_subject_chief_position_entry', 'subject_chief_position'),
|
||||||
@@ -1397,8 +1443,12 @@ class DokoGenApp:
|
|||||||
]:
|
]:
|
||||||
w = getattr(self, attr, None)
|
w = getattr(self, attr, None)
|
||||||
if w is not None:
|
if w is not None:
|
||||||
w.delete(0, tk.END)
|
val = getattr(isys, model_field, '') or ''
|
||||||
w.insert(0, getattr(isys, model_field, '') or '')
|
if isinstance(w, ttk.Combobox):
|
||||||
|
w.set(val)
|
||||||
|
else:
|
||||||
|
w.delete(0, tk.END)
|
||||||
|
w.insert(0, val)
|
||||||
|
|
||||||
# Списки
|
# Списки
|
||||||
for lb, items in [
|
for lb, items in [
|
||||||
@@ -1970,10 +2020,16 @@ class DokoGenApp:
|
|||||||
if data.get('okved'):
|
if data.get('okved'):
|
||||||
entry = self._company_entries.get('okved')
|
entry = self._company_entries.get('okved')
|
||||||
if entry:
|
if entry:
|
||||||
|
from .verify import resolve_okved
|
||||||
|
from .api_settings import load_api_settings as _las
|
||||||
|
_tok = (_las().get('dadata_token') or '')
|
||||||
entry.delete(0, tk.END)
|
entry.delete(0, tk.END)
|
||||||
entry.insert(0, data['okved'])
|
entry.insert(0, resolve_okved(data['okved'], _tok))
|
||||||
if data.get('okvedExtra'):
|
if data.get('okvedExtra'):
|
||||||
if hasattr(self, 'okved_extra_listbox'):
|
if hasattr(self, 'okved_extra_listbox'):
|
||||||
|
from .verify import resolve_okved
|
||||||
|
from .api_settings import load_api_settings as _las2
|
||||||
|
_tok2 = (_las2().get('dadata_token') or '')
|
||||||
self.okved_extra_listbox.delete(0, tk.END)
|
self.okved_extra_listbox.delete(0, tk.END)
|
||||||
extra = data['okvedExtra']
|
extra = data['okvedExtra']
|
||||||
if isinstance(extra, str):
|
if isinstance(extra, str):
|
||||||
@@ -1982,7 +2038,7 @@ class DokoGenApp:
|
|||||||
else:
|
else:
|
||||||
parts = [str(p).strip() for p in extra if str(p).strip()]
|
parts = [str(p).strip() for p in extra if str(p).strip()]
|
||||||
for p in parts:
|
for p in parts:
|
||||||
self.okved_extra_listbox.insert(tk.END, p)
|
self.okved_extra_listbox.insert(tk.END, resolve_okved(p, _tok2))
|
||||||
|
|
||||||
# Объекты КИИ
|
# Объекты КИИ
|
||||||
if data.get('informationSystems'):
|
if data.get('informationSystems'):
|
||||||
|
|||||||
@@ -148,6 +148,49 @@ def normalize_address(text):
|
|||||||
return ' '.join(fixed)
|
return ' '.join(fixed)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_okved(code, dadata_token=None):
|
||||||
|
"""Код ОКВЭД → «код - название».
|
||||||
|
|
||||||
|
1) Ищем в словаре dictionaries/okved.json (строки вида «27.32.2 Название»).
|
||||||
|
2) Если не нашли — запрашиваем DaData suggest okved2 (если есть токен).
|
||||||
|
3) Иначе возвращаем код как есть.
|
||||||
|
"""
|
||||||
|
code = (code or '').strip()
|
||||||
|
if not code:
|
||||||
|
return ''
|
||||||
|
# 1) Словарь
|
||||||
|
try:
|
||||||
|
import os, json
|
||||||
|
dict_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'dictionaries', 'okved.json')
|
||||||
|
with open(dict_path, encoding='utf-8') as f:
|
||||||
|
items = json.load(f)
|
||||||
|
for item in items:
|
||||||
|
item = str(item).strip()
|
||||||
|
# совпадение по началу: «27.32.2» или «27.32.2 - ...» / «27.32.2 ...»
|
||||||
|
if item.split()[0].rstrip('.') == code.rstrip('.'):
|
||||||
|
# нормализуем: «код - название»
|
||||||
|
rest = item[len(item.split()[0]):].strip().lstrip('- ').strip()
|
||||||
|
if rest:
|
||||||
|
return f"{code} - {rest}"
|
||||||
|
return item
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# 2) DaData suggest okved2
|
||||||
|
if dadata_token:
|
||||||
|
try:
|
||||||
|
js, err = _http_json('https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/okved2',
|
||||||
|
data={'query': code, 'count': 1},
|
||||||
|
headers={'Content-Type': 'application/json',
|
||||||
|
'Authorization': f'Token {dadata_token}'})
|
||||||
|
if not err and js:
|
||||||
|
sugg = (js.get('suggestions') or [])
|
||||||
|
if sugg and sugg[0].get('value'):
|
||||||
|
return sugg[0]['value']
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
def _fmt_date(value):
|
def _fmt_date(value):
|
||||||
"""Дата: '2005-02-09' → '09.02.2005'; миллисекунды 1107907200000 → дата."""
|
"""Дата: '2005-02-09' → '09.02.2005'; миллисекунды 1107907200000 → дата."""
|
||||||
if not value:
|
if not value:
|
||||||
|
|||||||
Reference in New Issue
Block a user