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:
2026-08-04 15:33:36 +04:00
parent 2037925986
commit ed71343d92
7 changed files with 237 additions and 68 deletions
+9
View File
@@ -0,0 +1,9 @@
[
"одноранговая сеть",
"клиент-серверная система",
"технология \"тонкий клиент\"",
"сеть передачи данных",
"система диспетчерского управления и контроля",
"распределенная система управления",
"иная архитектура"
]
+5
View File
@@ -0,0 +1,5 @@
[
"Информационная система",
"Автоматизированная система управления",
"Информационно-телекоммуникационная сеть"
]
+17
View File
@@ -0,0 +1,17 @@
[
"Здравоохранение",
"Наука",
"Транспорт",
"Связь",
"Энергетика",
"Государственная регистрация прав",
"Банковская сфера и финансовый рынок",
"Топливно-энергетический комплекс",
"Атомная энергетика",
"Оборонная промышленность",
"Ракетно-космическая промышленность",
"Горнодобывающая промышленность",
"Металлургическая промышленность",
"Химическая промышленность",
"Иная сфера деятельности"
]
+13
View File
@@ -0,0 +1,13 @@
[
"Информационная система управления",
"Автоматизированная система управления технологическим процессом",
"Информационно-телекоммуникационная сеть",
"Автоматизированная система управления производством",
"Система диспетчерского управления",
"Система управления базами данных",
"Автоматизированная система научных исследований",
"Система электронного документооборота",
"Информационная система расчетов",
"Система управления финансами",
"Иной типовой отраслевой объект КИИ"
]
+28 -2
View File
@@ -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
View File
@@ -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'):
+43
View File
@@ -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: