Импорт: доп. ОКВЭД нарезаются по кодам (переносы внутри названий больше не рвут записи), угрозы с переносом внутри названия склеиваются (УБИ.209 «памяти\r\nядра процессора» → одна строка)
This commit is contained in:
+10
-16
@@ -22,7 +22,7 @@ from . import (
|
|||||||
from .verify import (
|
from .verify import (
|
||||||
check_declension_morpher, check_company_dadata,
|
check_declension_morpher, check_company_dadata,
|
||||||
check_declension_ai, check_company_ai,
|
check_declension_ai, check_company_ai,
|
||||||
COMPANY_FIELDS, compare_company_values,
|
COMPANY_FIELDS, compare_company_values, normalize_threats,
|
||||||
)
|
)
|
||||||
from .api_settings import load_api_settings, save_api_settings
|
from .api_settings import load_api_settings, save_api_settings
|
||||||
|
|
||||||
@@ -761,8 +761,9 @@ class DokoGenApp:
|
|||||||
self._company_entries['okved'].insert(0, resolve_okved(comp['okved'], _tok3))
|
self._company_entries['okved'].insert(0, resolve_okved(comp['okved'], _tok3))
|
||||||
if want('okved_extra') and 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)
|
||||||
|
from .verify import split_okved_extra
|
||||||
_applied = 0
|
_applied = 0
|
||||||
for code in comp['okved_extra']:
|
for code in split_okved_extra(comp['okved_extra']):
|
||||||
if str(code).strip():
|
if str(code).strip():
|
||||||
self.okved_extra_listbox.insert(tk.END, resolve_okved(str(code).strip(), _tok3))
|
self.okved_extra_listbox.insert(tk.END, resolve_okved(str(code).strip(), _tok3))
|
||||||
_applied += 1
|
_applied += 1
|
||||||
@@ -4661,21 +4662,14 @@ class DokoGenApp:
|
|||||||
entry.insert(0, resolve_okved(data['okved'], _tok))
|
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 .verify import resolve_okved, split_okved_extra
|
||||||
from .api_settings import load_api_settings as _las2
|
from .api_settings import load_api_settings as _las2
|
||||||
_tok2 = (_las2().get('dadata_token') or '')
|
_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']
|
# Доп. ОКВЭД могут быть склеены с переносами внутри названий
|
||||||
if isinstance(extra, str):
|
# («25.93 — Производство изделий из проволоки\nцепей и пружин 32.12.1 — …») —
|
||||||
import re as _re
|
# нарезаем по кодам ОКВЭД, затем нормализуем каждый в «код название».
|
||||||
# Перенос строки внутри одной записи («27.32.2 Производство\nсиловых кабелей»)
|
for p in split_okved_extra(data['okvedExtra']):
|
||||||
# не должен создавать вторую запись — сначала склеиваем переносы в пробел,
|
|
||||||
# затем режем только по запятой / точке с запятой.
|
|
||||||
extra = _re.sub(r'\s*[\n\r]+\s*', ' ', extra)
|
|
||||||
parts = [p.strip() for p in _re.split(r'[;]+|\s*,\s*', extra) if p.strip()]
|
|
||||||
else:
|
|
||||||
parts = [str(p).strip() for p in extra if str(p).strip()]
|
|
||||||
for p in parts:
|
|
||||||
self.okved_extra_listbox.insert(tk.END, resolve_okved(p, _tok2))
|
self.okved_extra_listbox.insert(tk.END, resolve_okved(p, _tok2))
|
||||||
|
|
||||||
# Объекты КИИ
|
# Объекты КИИ
|
||||||
@@ -4713,8 +4707,8 @@ class DokoGenApp:
|
|||||||
attacker_category=is_data.get('attacker_category', ''),
|
attacker_category=is_data.get('attacker_category', ''),
|
||||||
attacker_level=is_data.get('attacker_level', ''),
|
attacker_level=is_data.get('attacker_level', ''),
|
||||||
attacker_types=is_data.get('attacker_types', ''),
|
attacker_types=is_data.get('attacker_types', ''),
|
||||||
threats=is_data.get('threats', ''),
|
threats=normalize_threats(is_data.get('threats', '')),
|
||||||
incidents=is_data.get('incidents', ''),
|
incidents=normalize_threats(is_data.get('incidents', '')),
|
||||||
criteria_values=is_data.get('criteria_values', ''),
|
criteria_values=is_data.get('criteria_values', ''),
|
||||||
criteria_justification=is_data.get('criteria_justification', ''),
|
criteria_justification=is_data.get('criteria_justification', ''),
|
||||||
org_measures=is_data.get('org_measures', ''),
|
org_measures=is_data.get('org_measures', ''),
|
||||||
|
|||||||
@@ -544,6 +544,51 @@ def _norm_threat_text(text):
|
|||||||
return s.lower()
|
return s.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_threats(text):
|
||||||
|
"""Склеить переносы внутри названий угроз.
|
||||||
|
|
||||||
|
В опросниках встречается «УБИ.209 Угроза … памяти\r\nядра процессора» —
|
||||||
|
перенос строки внутри одного названия. Строка, не начинающаяся с «УБИ.»,
|
||||||
|
считается продолжением предыдущей угрозы.
|
||||||
|
"""
|
||||||
|
if not text:
|
||||||
|
return ''
|
||||||
|
lines = [ln.strip() for ln in str(text).split('\n') if ln.strip()]
|
||||||
|
out = []
|
||||||
|
for ln in lines:
|
||||||
|
if re.match(r'^уби\.?\s*\d+', ln, re.IGNORECASE):
|
||||||
|
out.append(ln)
|
||||||
|
elif out:
|
||||||
|
out[-1] = out[-1] + ' ' + ln
|
||||||
|
else:
|
||||||
|
out.append(ln)
|
||||||
|
return '\n'.join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def split_okved_extra(value):
|
||||||
|
"""Разбить okvedExtra (строка или список строк с переносами) на записи «код название».
|
||||||
|
|
||||||
|
В опросниках доп. ОКВЭД часто идут склеенными:
|
||||||
|
«25.93 — Производство изделий из проволоки\nцепей и пружин 32.12.1 — …»
|
||||||
|
Здесь «цепей и пружин» — продолжение названия 25.93, а 32.12.1 — новый код.
|
||||||
|
Нарезаем по кодам ОКВЭД (двузначный код с точками в начале записи).
|
||||||
|
"""
|
||||||
|
if isinstance(value, (list, tuple)):
|
||||||
|
text = ' '.join(str(x) for x in value)
|
||||||
|
else:
|
||||||
|
text = str(value or '')
|
||||||
|
text = text.replace('\r', ' ').replace('\n', ' ')
|
||||||
|
# Нарезаем по началу кода ОКВЭД: «25.93», «32.12.1», «43.2» …
|
||||||
|
# Перед кодом не должно быть цифры или точки (чтобы не разрезать «25.93» на «25» и «93»)
|
||||||
|
parts = re.split(r'(?<!\d)(?<!\.)(?=\d{2}(?:\.\d+)*\b)', text)
|
||||||
|
out = []
|
||||||
|
for p in parts:
|
||||||
|
p = p.strip().strip('-—– ').strip()
|
||||||
|
if p and re.match(r'^\d{2}(?:\.\d+)*', p):
|
||||||
|
out.append(p)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def filter_threats_by_dict(lines, threats_full=None):
|
def filter_threats_by_dict(lines, threats_full=None):
|
||||||
"""Приводит строки угроз (от ИИ или оператора) к каноническому виду по словарю УБИ.
|
"""Приводит строки угроз (от ИИ или оператора) к каноническому виду по словарю УБИ.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user