optimization

This commit is contained in:
Raykov-MS 2026-07-07 10:04:09 +03:00
parent b9d4ba6573
commit 4482179e82
3 changed files with 71 additions and 10 deletions

View File

@ -153,11 +153,20 @@ def build_fixed_row(
"Уникальный номер операции": str(operation_index), "Уникальный номер операции": str(operation_index),
} }
merged = _merge_fields(operation_fields, participant_fields) merged = _merge_fields(operation_fields, participant_fields)
merged_suffix_index = _build_suffix_index(merged)
participant_suffix_index = _build_suffix_index(participant_fields)
for rule in REPORT_MAPPING_RULES: for rule in REPORT_MAPPING_RULES:
if row.get(rule.column_name): if row.get(rule.column_name):
continue continue
source_payload = participant_fields if rule.source == "participant" else merged if rule.source == "participant":
row[rule.column_name] = _pick_value(source_payload, rule.candidate_keys) source_payload = participant_fields
suffix_index = participant_suffix_index
else:
source_payload = merged
suffix_index = merged_suffix_index
row[rule.column_name] = _pick_value(
source_payload, suffix_index, rule.candidate_keys
)
for column in FIXED_REPORT_COLUMNS: for column in FIXED_REPORT_COLUMNS:
row.setdefault(column, "") row.setdefault(column, "")
return row return row
@ -173,17 +182,27 @@ def _merge_fields(
return merged return merged
def _pick_value(payload: dict[str, str], candidates: tuple[str, ...]) -> str: def _build_suffix_index(payload: dict[str, str]) -> dict[str, str]:
index: dict[str, str] = {}
for key, value in payload.items():
if not value:
continue
short = key.rsplit(".", maxsplit=1)[-1]
index.setdefault(short, value)
return index
def _pick_value(
payload: dict[str, str],
suffix_index: dict[str, str],
candidates: tuple[str, ...],
) -> str:
for key in candidates: for key in candidates:
if key in payload and payload[key]: if key in payload and payload[key]:
return payload[key] return payload[key]
short = key.split(".")[-1] short = key.rsplit(".", maxsplit=1)[-1]
if short in payload and payload[short]: if short in payload and payload[short]:
return payload[short] return payload[short]
dotted_suffix = f".{short}" if short in suffix_index:
for payload_key, payload_value in payload.items(): return suffix_index[short]
if not payload_value:
continue
if payload_key.endswith(dotted_suffix):
return payload_value
return "" return ""

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import tempfile import tempfile
import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@ -39,6 +40,7 @@ class BatchResult:
protocol_path: str protocol_path: str
log_path: str log_path: str
messages: list[str] = field(default_factory=list) messages: list[str] = field(default_factory=list)
duration_seconds: float = 0.0
def run_batch( def run_batch(
@ -48,6 +50,7 @@ def run_batch(
samba_password: str, samba_password: str,
launcher: str, launcher: str,
) -> BatchResult: ) -> BatchResult:
started_at = time.perf_counter()
messages: list[str] = [] messages: list[str] = []
if not samba_user: if not samba_user:
return BatchResult( return BatchResult(
@ -195,6 +198,8 @@ def run_batch(
status=status, processed=processed, partial=partial, errors=errors status=status, processed=processed, partial=partial, errors=errors
) )
) )
duration_seconds = round(time.perf_counter() - started_at, 2)
messages.append(f"Время выполнения: {_format_duration(duration_seconds)}.")
messages.extend(log_lines[-5:]) messages.extend(log_lines[-5:])
return BatchResult( return BatchResult(
status=status, status=status,
@ -205,6 +210,7 @@ def run_batch(
protocol_path=protocol_path, protocol_path=protocol_path,
log_path=log_path, log_path=log_path,
messages=messages, messages=messages,
duration_seconds=duration_seconds,
) )
@ -362,3 +368,11 @@ def _build_result_message(
f"успешно={processed}, частично={partial}, с ошибками={errors}." f"успешно={processed}, частично={partial}, с ошибками={errors}."
) )
return f"Ошибка обработки: успешно={processed}, частично={partial}, с ошибками={errors}." return f"Ошибка обработки: успешно={processed}, частично={partial}, с ошибками={errors}."
def _format_duration(duration_seconds: float) -> str:
total_seconds = max(0, int(round(duration_seconds)))
minutes, seconds = divmod(total_seconds, 60)
if minutes:
return f"{minutes} мин {seconds} сек"
return f"{seconds} сек"

View File

@ -121,3 +121,31 @@ def test_extract_tag_candidate_keys_supports_comma_separator() -> None:
"КППЮЛ, ИдентификацияФЛ, ПризнакОргФормаИНБОЮЛ" "КППЮЛ, ИдентификацияФЛ, ПризнакОргФормаИНБОЮЛ"
) )
assert candidates == ("КППЮЛ", "ИдентификацияФЛ", "ПризнакОргФормаИНБОЮЛ") assert candidates == ("КППЮЛ", "ИдентификацияФЛ", "ПризнакОргФормаИНБОЮЛ")
def test_build_fixed_row_uses_first_suffix_value_from_index() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.Первый.ИННФЛИП": "111111111111",
"УчастникФЛИП.Второй.ИННФЛИП": "222222222222",
},
)
assert row[_column_with("ИНН ")] == "111111111111"
def test_build_fixed_row_skips_empty_suffix_values_in_index() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.Первый.ИННФЛИП": "",
"УчастникФЛИП.Второй.ИННФЛИП": "222222222222",
},
)
assert row[_column_with("ИНН ")] == "222222222222"