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_CARD_HOLDER_INFO = _index(103)
|
||||||
COL_EMPLOYEE_SIGN = _index(104)
|
COL_EMPLOYEE_SIGN = _index(104)
|
||||||
COL_FOREIGN_BANK_NAME = _index(105)
|
COL_FOREIGN_BANK_NAME = _index(105)
|
||||||
|
COL_OPERATION_DOCUMENTS = _index(107)
|
||||||
|
|
||||||
# Участник.
|
# Участник.
|
||||||
COL_PARTICIPANT_TYPE = _index(109)
|
COL_PARTICIPANT_TYPE = _index(109)
|
||||||
|
|||||||
@ -39,6 +39,7 @@ from .column_constants import (
|
|||||||
COL_METAL_CODE,
|
COL_METAL_CODE,
|
||||||
COL_METAL_NAME,
|
COL_METAL_NAME,
|
||||||
COL_OPERATION_CODE,
|
COL_OPERATION_CODE,
|
||||||
|
COL_OPERATION_DOCUMENTS,
|
||||||
COL_OPERATION_SIGN,
|
COL_OPERATION_SIGN,
|
||||||
COL_OPERATOR_TYPE,
|
COL_OPERATOR_TYPE,
|
||||||
COL_PARTICIPANT_TYPE,
|
COL_PARTICIPANT_TYPE,
|
||||||
@ -133,6 +134,17 @@ class StructuredGroupRule:
|
|||||||
|
|
||||||
_INVALID_TAGS = {"", "-", "Источник", "путь", "подразумеваются", "тэга", "нашла"}
|
_INVALID_TAGS = {"", "-", "Источник", "путь", "подразумеваются", "тэга", "нашла"}
|
||||||
_INDEXED_PATH_SEGMENT = re.compile(r"\[\d+\]")
|
_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 = (
|
_EIO_BLOCK_NAMES = (
|
||||||
"СведЕИО",
|
"СведЕИО",
|
||||||
"БенефициарЮЛ",
|
"БенефициарЮЛ",
|
||||||
@ -453,6 +465,11 @@ def build_fixed_row_by_index(
|
|||||||
rule.compiled_candidates,
|
rule.compiled_candidates,
|
||||||
allow_short_lookup=allow_short_lookup,
|
allow_short_lookup=allow_short_lookup,
|
||||||
)
|
)
|
||||||
|
_set(
|
||||||
|
row,
|
||||||
|
COL_OPERATION_DOCUMENTS,
|
||||||
|
_format_operation_documents(operation_lookup),
|
||||||
|
)
|
||||||
if not is_continuation:
|
if not is_continuation:
|
||||||
_apply_participant_identity_rules(row, participant_lookup)
|
_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 ""
|
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(
|
def _apply_participant_identity_rules(
|
||||||
row: dict[int, str], participant_lookup: _PayloadLookup
|
row: dict[int, str], participant_lookup: _PayloadLookup
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@ -2125,12 +2125,12 @@
|
|||||||
"column_name": "Сведения о документе, подтверждающем совершение операции",
|
"column_name": "Сведения о документе, подтверждающем совершение операции",
|
||||||
"block": "operation_basis",
|
"block": "operation_basis",
|
||||||
"report_group": "participant_base",
|
"report_group": "participant_base",
|
||||||
"xml_tag": "СодДок",
|
"xml_tag": "КодДок|ИноеНаимДок|ДатаДок|НомДок|СодДок",
|
||||||
"xml_path": "СообщОперКО/ИнформЧасть/СведКО/Операция/ОснованиеОп/СодДок",
|
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/ОснованиеОп/",
|
||||||
"source_scope": "any",
|
"source_scope": "operation",
|
||||||
"allow_short_lookup": true,
|
"allow_short_lookup": false,
|
||||||
"allow_direct_mapping": true,
|
"allow_direct_mapping": true,
|
||||||
"structured_value": false,
|
"structured_value": true,
|
||||||
"structured_group": "",
|
"structured_group": "",
|
||||||
"structured_role": "",
|
"structured_role": "",
|
||||||
"structured_order": 0,
|
"structured_order": 0,
|
||||||
@ -3265,12 +3265,12 @@
|
|||||||
"column_name": "Иные сведения ЕИО/Бенефициара",
|
"column_name": "Иные сведения ЕИО/Бенефициара",
|
||||||
"block": "eio",
|
"block": "eio",
|
||||||
"report_group": "eio",
|
"report_group": "eio",
|
||||||
"xml_tag": "",
|
"xml_tag": "СНИЛСФЛ|ПолисНомер|ТелефонНомер",
|
||||||
"xml_path": "",
|
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/СведЕИО/ФЛЕИО/СНИЛСФЛ | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/БенефициарЮЛ/ФЛБенефициар/СНИЛСФЛ | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/СведЕИО/ФЛЕИО/ПолисНомер | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/БенефициарЮЛ/ФЛБенефициар/ПолисНомер | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/СведЕИО/ФЛЕИО/ТелефонНомер | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОП/УчастникЮЛ/БенефициарЮЛ/ФЛБенефициар/ТелефонНомер",
|
||||||
"source_scope": "any",
|
"source_scope": "participant",
|
||||||
"allow_short_lookup": true,
|
"allow_short_lookup": false,
|
||||||
"allow_direct_mapping": true,
|
"allow_direct_mapping": true,
|
||||||
"structured_value": false,
|
"structured_value": true,
|
||||||
"structured_group": "",
|
"structured_group": "",
|
||||||
"structured_role": "",
|
"structured_role": "",
|
||||||
"structured_order": 0,
|
"structured_order": 0,
|
||||||
|
|||||||
@ -201,9 +201,13 @@ def _build_expanded_rows(
|
|||||||
def _collapse_indexed_fields(fields: dict[str, str]) -> dict[str, str]:
|
def _collapse_indexed_fields(fields: dict[str, str]) -> dict[str, str]:
|
||||||
"""Сохраняет все операционные повторы в одной строке без потери значений."""
|
"""Сохраняет все операционные повторы в одной строке без потери значений."""
|
||||||
collapsed: dict[str, str] = {}
|
collapsed: dict[str, str] = {}
|
||||||
|
indexed_operation_documents: dict[str, str] = {}
|
||||||
for key, value in fields.items():
|
for key, value in fields.items():
|
||||||
|
if re.match(r"^ОснованиеОп\[\d+\]\.", key):
|
||||||
|
indexed_operation_documents[key] = value
|
||||||
deindexed_key = re.sub(r"\[\d+\]", "", key)
|
deindexed_key = re.sub(r"\[\d+\]", "", key)
|
||||||
_append_value(collapsed, deindexed_key, value)
|
_append_value(collapsed, deindexed_key, value)
|
||||||
|
collapsed.update(indexed_operation_documents)
|
||||||
return collapsed
|
return collapsed
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -825,6 +825,35 @@ def test_col9_uses_operation_number_from_xml() -> None:
|
|||||||
assert row[9] == "ЦФТ-БАНК_1177326777530"
|
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:
|
def test_structured_cash_address_does_not_include_bank_fields() -> None:
|
||||||
row = build_fixed_row_by_index(
|
row = build_fixed_row_by_index(
|
||||||
file_name="f.xml",
|
file_name="f.xml",
|
||||||
@ -1090,6 +1119,21 @@ def test_eio_block_is_empty_when_eio_and_beneficiary_are_absent() -> None:
|
|||||||
assert row[index] == ""
|
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:
|
def test_participant_and_beneficiary_inn_are_scoped_regardless_of_field_order() -> None:
|
||||||
own_inn = ("УчастникЮЛ.СведЮЛ.ИННЮЛ", "2820000210")
|
own_inn = ("УчастникЮЛ.СведЮЛ.ИННЮЛ", "2820000210")
|
||||||
beneficiary_fields = (
|
beneficiary_fields = (
|
||||||
|
|||||||
@ -324,6 +324,8 @@ def test_operation_repeats_are_collapsed_for_single_participant() -> None:
|
|||||||
|
|
||||||
assert len(result.rows) == 1
|
assert len(result.rows) == 1
|
||||||
assert result.rows[0].operation_fields["ОснованиеОп.НомДок"] == "BASE-1; BASE-2"
|
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:
|
def test_mixed_operation_and_eio_repeats_are_additive_not_cartesian() -> None:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user