fix errors
This commit is contained in:
parent
7aeca7a45a
commit
2e570fb386
@ -50,6 +50,7 @@ COL_TERRITORY_CODE_CARD = _index(96)
|
||||
COL_CARD_HOLDER_INFO = _index(103)
|
||||
COL_EMPLOYEE_SIGN = _index(104)
|
||||
COL_FOREIGN_BANK_NAME = _index(105)
|
||||
COL_OPERATION_DOCUMENTS = _index(107)
|
||||
|
||||
# Участник.
|
||||
COL_PARTICIPANT_TYPE = _index(109)
|
||||
|
||||
@ -39,6 +39,7 @@ from .column_constants import (
|
||||
COL_METAL_CODE,
|
||||
COL_METAL_NAME,
|
||||
COL_OPERATION_CODE,
|
||||
COL_OPERATION_DOCUMENTS,
|
||||
COL_OPERATION_SIGN,
|
||||
COL_OPERATOR_TYPE,
|
||||
COL_PARTICIPANT_TYPE,
|
||||
@ -133,6 +134,17 @@ class StructuredGroupRule:
|
||||
|
||||
_INVALID_TAGS = {"", "-", "Источник", "путь", "подразумеваются", "тэга", "нашла"}
|
||||
_INDEXED_PATH_SEGMENT = re.compile(r"\[\d+\]")
|
||||
_OPERATION_DOCUMENT_FIELDS = (
|
||||
"КодДок",
|
||||
"ИноеНаимДок",
|
||||
"ДатаДок",
|
||||
"НомДок",
|
||||
"СодДок",
|
||||
)
|
||||
_OPERATION_DOCUMENT_FIELD = re.compile(
|
||||
r"(?:^|\.)ОснованиеОп(?:\[(?P<index>\d+)\])?\."
|
||||
r"(?P<field>КодДок|ИноеНаимДок|ДатаДок|НомДок|СодДок)$"
|
||||
)
|
||||
_EIO_BLOCK_NAMES = (
|
||||
"СведЕИО",
|
||||
"БенефициарЮЛ",
|
||||
@ -453,6 +465,11 @@ def build_fixed_row_by_index(
|
||||
rule.compiled_candidates,
|
||||
allow_short_lookup=allow_short_lookup,
|
||||
)
|
||||
_set(
|
||||
row,
|
||||
COL_OPERATION_DOCUMENTS,
|
||||
_format_operation_documents(operation_lookup),
|
||||
)
|
||||
if not is_continuation:
|
||||
_apply_participant_identity_rules(row, participant_lookup)
|
||||
# Сначала убираем запрещённые однострочные адреса, чтобы структурная
|
||||
@ -629,6 +646,35 @@ def _lookup_pick_direct_value(lookup: _PayloadLookup, field_name: str) -> str:
|
||||
return str(value).strip() if value else ""
|
||||
|
||||
|
||||
def _format_operation_documents(lookup: _PayloadLookup) -> str:
|
||||
indexed_documents: dict[int, dict[str, str]] = {}
|
||||
single_document: dict[str, str] = {}
|
||||
for entry in lookup.entries:
|
||||
match = _OPERATION_DOCUMENT_FIELD.search(entry.raw_path)
|
||||
if match is None:
|
||||
continue
|
||||
field_name = match.group("field")
|
||||
value = str(entry.value).strip()
|
||||
document_index = match.group("index")
|
||||
if document_index is None:
|
||||
single_document[field_name] = value
|
||||
continue
|
||||
indexed_documents.setdefault(int(document_index), {})[field_name] = value
|
||||
|
||||
documents = (
|
||||
[indexed_documents[index] for index in sorted(indexed_documents)]
|
||||
if indexed_documents
|
||||
else [single_document] if single_document else []
|
||||
)
|
||||
formatted_documents = []
|
||||
for position, document in enumerate(documents, start=1):
|
||||
fields = [
|
||||
document.get(field_name, "") for field_name in _OPERATION_DOCUMENT_FIELDS
|
||||
]
|
||||
formatted_documents.append(f"{position}. {', '.join(fields)}")
|
||||
return "; ".join(formatted_documents)
|
||||
|
||||
|
||||
def _apply_participant_identity_rules(
|
||||
row: dict[int, str], participant_lookup: _PayloadLookup
|
||||
) -> None:
|
||||
|
||||
@ -2125,12 +2125,12 @@
|
||||
"column_name": "Сведения о документе, подтверждающем совершение операции",
|
||||
"block": "operation_basis",
|
||||
"report_group": "participant_base",
|
||||
"xml_tag": "СодДок",
|
||||
"xml_path": "СообщОперКО/ИнформЧасть/СведКО/Операция/ОснованиеОп/СодДок",
|
||||
"source_scope": "any",
|
||||
"allow_short_lookup": true,
|
||||
"xml_tag": "КодДок|ИноеНаимДок|ДатаДок|НомДок|СодДок",
|
||||
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/ОснованиеОп/",
|
||||
"source_scope": "operation",
|
||||
"allow_short_lookup": false,
|
||||
"allow_direct_mapping": true,
|
||||
"structured_value": false,
|
||||
"structured_value": true,
|
||||
"structured_group": "",
|
||||
"structured_role": "",
|
||||
"structured_order": 0,
|
||||
@ -3265,12 +3265,12 @@
|
||||
"column_name": "Иные сведения ЕИО/Бенефициара",
|
||||
"block": "eio",
|
||||
"report_group": "eio",
|
||||
"xml_tag": "",
|
||||
"xml_path": "",
|
||||
"source_scope": "any",
|
||||
"allow_short_lookup": true,
|
||||
"xml_tag": "СНИЛСФЛ|ПолисНомер|ТелефонНомер",
|
||||
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/СведЕИО/ФЛЕИО/СНИЛСФЛ | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/БенефициарЮЛ/ФЛБенефициар/СНИЛСФЛ | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/СведЕИО/ФЛЕИО/ПолисНомер | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/БенефициарЮЛ/ФЛБенефициар/ПолисНомер | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/СведЕИО/ФЛЕИО/ТелефонНомер | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/БенефициарЮЛ/ФЛБенефициар/ТелефонНомер",
|
||||
"source_scope": "participant",
|
||||
"allow_short_lookup": false,
|
||||
"allow_direct_mapping": true,
|
||||
"structured_value": false,
|
||||
"structured_value": true,
|
||||
"structured_group": "",
|
||||
"structured_role": "",
|
||||
"structured_order": 0,
|
||||
|
||||
@ -201,9 +201,13 @@ def _build_expanded_rows(
|
||||
def _collapse_indexed_fields(fields: dict[str, str]) -> dict[str, str]:
|
||||
"""Сохраняет все операционные повторы в одной строке без потери значений."""
|
||||
collapsed: dict[str, str] = {}
|
||||
indexed_operation_documents: dict[str, str] = {}
|
||||
for key, value in fields.items():
|
||||
if re.match(r"^ОснованиеОп\[\d+\]\.", key):
|
||||
indexed_operation_documents[key] = value
|
||||
deindexed_key = re.sub(r"\[\d+\]", "", key)
|
||||
_append_value(collapsed, deindexed_key, value)
|
||||
collapsed.update(indexed_operation_documents)
|
||||
return collapsed
|
||||
|
||||
|
||||
|
||||
@ -825,6 +825,35 @@ def test_col9_uses_operation_number_from_xml() -> None:
|
||||
assert row[9] == "ЦФТ-БАНК_1177326777530"
|
||||
|
||||
|
||||
def test_operation_documents_keep_positions_and_join_multiple_documents() -> None:
|
||||
row = build_fixed_row_by_index(
|
||||
file_name="f.xml",
|
||||
record_id="R1",
|
||||
operation_index=1,
|
||||
operation_fields={
|
||||
"ОснованиеОп[0].КодДок": "13",
|
||||
"ОснованиеОп[0].ДатаДок": "29/01/2026",
|
||||
"ОснованиеОп[0].НомДок": "253",
|
||||
"ОснованиеОп[0].СодДок": "Размещение денежных средств",
|
||||
"ОснованиеОп[1].КодДок": "99",
|
||||
"ОснованиеОп[1].ИноеНаимДок": "Депозитный договор",
|
||||
"ОснованиеОп[1].ДатаДок": "29/01/2026",
|
||||
"ОснованиеОп[1].НомДок": "Р202307/0001/93/Э",
|
||||
"ОснованиеОп[2].КодДок": "99",
|
||||
"ОснованиеОп[2].ИноеНаимДок": "Общие условия размещения депозитов",
|
||||
"ОснованиеОп[2].ДатаДок": "17/11/2020",
|
||||
"ОснованиеОп[2].НомДок": "Р202307/0001",
|
||||
},
|
||||
participant_fields={},
|
||||
)
|
||||
|
||||
assert row[107] == (
|
||||
"1. 13, , 29/01/2026, 253, Размещение денежных средств; "
|
||||
"2. 99, Депозитный договор, 29/01/2026, Р202307/0001/93/Э, ; "
|
||||
"3. 99, Общие условия размещения депозитов, 17/11/2020, Р202307/0001, "
|
||||
)
|
||||
|
||||
|
||||
def test_structured_cash_address_does_not_include_bank_fields() -> None:
|
||||
row = build_fixed_row_by_index(
|
||||
file_name="f.xml",
|
||||
@ -1090,6 +1119,21 @@ def test_eio_block_is_empty_when_eio_and_beneficiary_are_absent() -> None:
|
||||
assert row[index] == ""
|
||||
|
||||
|
||||
def test_eio_other_info_combines_snils_and_phone() -> None:
|
||||
row = build_fixed_row_by_index(
|
||||
file_name="f.xml",
|
||||
record_id="R1",
|
||||
operation_index=1,
|
||||
operation_fields={},
|
||||
participant_fields={
|
||||
"УчастникЮЛ.СведЕИО.ФЛЕИО.СНИЛСФЛ": "123-456-789 00",
|
||||
"УчастникЮЛ.СведЕИО.ФЛЕИО.ТелефонНомер": "+7 999 123-45-67",
|
||||
},
|
||||
)
|
||||
|
||||
assert row[164] == "123-456-789 00, +7 999 123-45-67"
|
||||
|
||||
|
||||
def test_participant_and_beneficiary_inn_are_scoped_regardless_of_field_order() -> None:
|
||||
own_inn = ("УчастникЮЛ.СведЮЛ.ИННЮЛ", "2820000210")
|
||||
beneficiary_fields = (
|
||||
|
||||
@ -324,6 +324,8 @@ def test_operation_repeats_are_collapsed_for_single_participant() -> None:
|
||||
|
||||
assert len(result.rows) == 1
|
||||
assert result.rows[0].operation_fields["ОснованиеОп.НомДок"] == "BASE-1; BASE-2"
|
||||
assert result.rows[0].operation_fields["ОснованиеОп[0].НомДок"] == "BASE-1"
|
||||
assert result.rows[0].operation_fields["ОснованиеОп[1].НомДок"] == "BASE-2"
|
||||
|
||||
|
||||
def test_mixed_operation_and_eio_repeats_are_additive_not_cartesian() -> None:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user