fix: импорт одного человека в поле ФИО (старые опросники)

- если в ячейке ФИО несколько человек (через запятую/точку с запятой/
  перевод строки или просто подряд) — остаётся первое полное ФИО
- применяется к должностным лицам (chief/ответственный/админ),
  комиссии и сотрудникам при импорте из опросника
- то же при открытии сохранённого файла (from_dict):
  «Коростелев Павел Сергеевич Хрящев Сергей Владимирович …» → «Коростелев Павел Сергеевич»
This commit is contained in:
2026-08-04 17:34:17 +04:00
parent 42a243f7b6
commit b6f595fd32
2 changed files with 49 additions and 3 deletions
+27 -2
View File
@@ -179,6 +179,27 @@ def import_187fz(filepath: str, log_fn: Optional[Callable] = None, settings_path
return data return data
def _extract_single_fio(text):
"""Из строки, где может быть несколько ФИО (через запятую, точку с запятой,
перевод строки или просто подряд), выделяет одно первое полное ФИО.
Пример: «Коростелев Павел Сергеевич Хрящев Сергей Владимирович …» → «Коростелев Павел Сергеевич»
"""
if not text:
return text
text = str(text).strip()
# 1) Явные разделители — берём первую часть
for sep in (',', ';', '\n', '\r'):
if sep in text:
text = text.split(sep)[0].strip()
break
# 2) Если осталось больше 3 слов — это несколько ФИО подряд, оставляем первые 3
words = [w for w in text.split() if w]
if len(words) > 3:
text = ' '.join(words[:3])
return text.strip()
def _import_187_common(wb, data, settings, log_fn): def _import_187_common(wb, data, settings, log_fn):
"""Импорт общих сведений по словарю настроек. """Импорт общих сведений по словарю настроек.
@@ -228,6 +249,8 @@ def _import_187_common(wb, data, settings, log_fn):
break break
val = clean_value(cell_value(target_ws, coord)) val = clean_value(cell_value(target_ws, coord))
if val: if val:
if key in ('chiefFio', 'responsibleFio', 'ispdnFio', 'adminFio'):
val = _extract_single_fio(val)
data[key] = val data[key] = val
log_fn(f" {name} [ячейка {coord}]: {val}") log_fn(f" {name} [ячейка {coord}]: {val}")
continue continue
@@ -242,6 +265,8 @@ def _import_187_common(wb, data, settings, log_fn):
for field_lower, val in row_cache.items(): for field_lower, val in row_cache.items():
if rx.search(field_lower): if rx.search(field_lower):
if val: if val:
if key in ('chiefFio', 'responsibleFio', 'ispdnFio', 'adminFio'):
val = _extract_single_fio(val)
data[key] = val data[key] = val
log_fn(f" {name} [по ключу]: {val}") log_fn(f" {name} [по ключу]: {val}")
break break
@@ -619,7 +644,7 @@ def _import_187_employees(wb, data, settings, log_fn):
commission.append({ commission.append({
'role': role, 'role': role,
'position': col_b, 'position': col_b,
'fio': col_c.replace('\n', ' '), 'fio': _extract_single_fio(col_c.replace('\n', ' ')),
}) })
if in_employees: if in_employees:
@@ -628,7 +653,7 @@ def _import_187_employees(wb, data, settings, log_fn):
continue continue
employee = { employee = {
'position': col_b, 'position': col_b,
'fio': fio.replace('\n', ' '), 'fio': _extract_single_fio(fio.replace('\n', ' ')),
} }
if col_e: if col_e:
employee['is_list'] = [s.strip() for s in col_e.split('\n') if s.strip()] employee['is_list'] = [s.strip() for s in col_e.split('\n') if s.strip()]
+22 -1
View File
@@ -5,6 +5,21 @@ from dataclasses import dataclass, field, asdict
from typing import List, Dict, Any from typing import List, Dict, Any
def _clean_single_fio(value):
"""Оставить одно первое ФИО, если в строке их несколько."""
if not value:
return value
value = str(value).strip()
for sep in (',', ';', '\n', '\r'):
if sep in value:
value = value.split(sep)[0].strip()
break
words = [w for w in value.split() if w]
if len(words) > 3:
value = ' '.join(words[:3])
return value.strip()
@dataclass @dataclass
class CommissionMember: class CommissionMember:
"""Член комиссии по категорированию объектов КИИ""" """Член комиссии по категорированию объектов КИИ"""
@@ -171,7 +186,13 @@ class Company:
if "okved_extra" in d and not isinstance(d.get("okved_extra"), list): if "okved_extra" in d and not isinstance(d.get("okved_extra"), list):
d["okved_extra"] = [] d["okved_extra"] = []
valid = {f.name for f in cls.__dataclass_fields__.values()} valid = {f.name for f in cls.__dataclass_fields__.values()}
return cls(**{k: v for k, v in d.items() if k in valid}) obj = cls(**{k: v for k, v in d.items() if k in valid})
# Если в поле ФИО несколько человек — оставить одного (старые опросники)
for fio_field in ('chief_fio', 'responsible_fio', 'admin_fio'):
val = getattr(obj, fio_field, '')
if val:
setattr(obj, fio_field, _clean_single_fio(val))
return obj
def get_folder_name(self) -> str: def get_folder_name(self) -> str:
if self.short_name: if self.short_name: