SFM/tests/unit/test_mapping.py
2026-08-28 10:30:20 +03:00

1605 lines
60 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from app.pipeline import mapping
from app.pipeline.mapping import (
FIXED_REPORT_COLUMNS,
_extract_tag_candidate_keys,
build_fixed_row,
build_fixed_row_by_index,
)
def _column_with(prefix: str) -> str:
for column in FIXED_REPORT_COLUMNS:
if column.startswith(prefix):
return column
raise AssertionError(f"Колонка с префиксом '{prefix}' не найдена")
def test_build_fixed_row_maps_known_fields() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=2,
operation_fields={
"ИдФайл": "FILE_01",
"НомерОперация": "OP_2",
"КодОперации": "5007",
"СумОперации": "100.55",
},
participant_fields={
"ИННФЛ": "123456789012",
"Тип": "01",
},
)
assert row["Имя XML файла"] == "f.xml"
assert row["Идентификатор записи"] == "R1"
assert row["Уникальный номер операции"] == "OP_2"
assert row["Код вида операции"] == "5007"
assert row["Сумма в валюте проведения"] == "100.55"
assert row[_column_with("ИНН")] == "123456789012"
assert row["Тип участника"] == "01"
def test_build_fixed_row_keeps_missing_values_empty() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={},
)
for column in FIXED_REPORT_COLUMNS:
assert column in row
assert row["Код вида операции"] == ""
assert row[_column_with("ИНН")] == ""
def test_build_fixed_row_does_not_take_operation_inn_for_participant() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ИНН": "0000000000",
"Тип": "99",
},
participant_fields={
"ИННФЛ": "111111111111",
"Тип": "01",
},
)
assert row[_column_with("ИНН")] == "111111111111"
assert row["Тип участника"] == "01"
def test_fixed_report_columns_over_200() -> None:
assert len(FIXED_REPORT_COLUMNS) == 204
assert FIXED_REPORT_COLUMNS[126] == "Признак принадлежности к публичным лицам"
def test_build_fixed_row_uses_alternative_path_leaf_for_emitent_name() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"СведЦП.Эмитент.НаимЭмитентЦП.ФизЛицо.ФИОСтрока": "Эмитент ФЛ",
},
participant_fields={},
)
assert row["Наименование/ ФИО эмитента ЦП"] == "Эмитент ФЛ"
def test_build_fixed_row_maps_dotted_participant_keys() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.ИННФЛИП": "123456789012",
"УчастникФЛИП.СведФЛИП.СведДокУдЛичн.НомДок": "451099",
},
)
assert row[_column_with("ИНН")] == "123456789012"
assert row["Номер"] == "451099"
def test_build_fixed_row_splits_pipe_separated_xml_tag_values() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.АдрРег.Индекс": "674500",
},
)
assert row["Адрес по структуре (целый)"] == "674500, , , , , , , , "
def test_extract_tag_candidate_keys_supports_comma_separator() -> None:
candidates = _extract_tag_candidate_keys(
"КППЮЛ, ИдентификацияФЛ, ПризнакОргФормаИНБОЮЛ"
)
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"
def test_mapping_normalizes_each_payload_path_only_constant_times(monkeypatch) -> None:
calls = 0
original = mapping._normalize_indexed_path
def counted(path: str) -> str:
nonlocal calls
calls += 1
return original(path)
monkeypatch.setattr(mapping, "_normalize_indexed_path", counted)
operation_fields = {
"НомерОперация": "OP1",
"КодОперации": "6001",
}
participant_fields = {
"УчастникЮЛ.СведЮЛ.НаимЮЛ": "АО СИРИУС",
"УчастникЮЛ.СведЮЛ.ИННЮЛ": "2820000210",
"УчастникЮЛ.СведЕИО[0].ФЛЕИО.ФИОФЛИП.Фам": "Музалёв",
"УчастникЮЛ.СведЕИО[0].ФЛЕИО.ИННФЛИП": "410116812922",
}
build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields=operation_fields,
participant_fields=participant_fields,
)
assert calls == 2 * (len(operation_fields) + len(participant_fields))
def test_structured_address_is_built_from_right_columns() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.АдрРег.Индекс": "674500",
"УчастникФЛИП.СведФЛИП.АдрРег.КодОКСМ": "643",
"УчастникФЛИП.СведФЛИП.АдрРег.Пункт": "Москва",
"УчастникФЛИП.СведФЛИП.АдрРег.Улица": "Тверская",
"УчастникФЛИП.СведФЛИП.АдрРег.Дом": "1",
},
)
assert (
row["Адрес по структуре (целый)"] == "674500, 643, , , Москва, Тверская, 1, , "
)
def test_one_line_address_clears_structured_and_component_columns() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"АдресСтрока": "г. Москва, Тверская, 1",
"Индекс": "674500",
"КодОКСМ": "643",
"Улица": "Тверская",
"Дом": "1",
},
)
assert row["Адрес в одной строке"] == "г. Москва, Тверская, 1"
assert row["Адрес по структуре (целый)"] == ""
assert row["Индекс"] == ""
assert row["Код страны"] == ""
assert row["Улица"] == ""
assert row["Дом"] == ""
def test_fio_columns_prefer_participant_fields_over_operation_common_fields() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"Фам": "Кузнецов",
"Имя": "Сергей",
"Отч": "Владимирович",
},
participant_fields={
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Фам": "Азимов",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Имя": "Ислом",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Отч": "Каримович",
},
)
assert row["Фамилия"] == "Азимов"
assert row["Имя"] == "Ислом"
assert row["Отчество"] == "Каримович"
assert row["ФИО (по структуре полностью)"] == "Азимов Ислом Каримович"
def test_one_line_fio_clears_structured_and_component_fio_columns() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ФИОСтрока": "Азимов Ислом Каримович",
"Фам": "Азимов",
"Имя": "Ислом",
"Отч": "Каримович",
},
)
assert row["ФИО (в одной строке)"] == "Азимов Ислом Каримович"
assert row["ФИО (по структуре полностью)"] == ""
assert row["Фамилия"] == ""
assert row["Имя"] == ""
assert row["Отчество"] == ""
assert row["Наименование ЮЛ/ФИО ( по структуре полный)"] == ""
def test_structured_column_is_not_filled_directly_from_single_line_tag() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"АдресСтрока": "г. Москва, ул. Пример, д. 1",
},
)
assert row["Адрес в одной строке"] == "г. Москва, ул. Пример, д. 1"
assert (
row[
"Адрес ЮЛ/ Адрес места жительства (места нахождения) "
"ЕИО/Бенефициара (одной строкой)"
]
== ""
)
def test_structured_column_without_component_block_joins_candidate_values() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.Индекс": "121467",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.КодОКСМ": "643",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.Пункт": "Москва",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.Улица": "Молодогвардейская",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.Дом": "8",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.Корп": "1",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРег.Оф": "28",
},
)
assert (
row["Место государственной регистрации ЕИО/Бенефициара (структура полностью)"]
== "121467, 643, Москва, Молодогвардейская, 8, 1, 28"
)
def test_structured_column_uses_non_one_line_candidate_when_mixed_tags() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.АдрРег.АдрУчредитель": (
"г. Москва, ул. Пушкина, д. 1"
),
},
)
assert row["Адрес в одной строке"] == ""
assert row[
"Адрес ЮЛ/ Адрес места жительства (места нахождения) "
"ЕИО/Бенефициара (одной строкой)"
] == ("г. Москва, ул. Пушкина, д. 1")
assert (
row[
"Адрес ЮЛ/ Адрес места жительства (места нахождения) "
"ЕИО/Бенефициара (структура полностью)"
]
== ""
)
def test_digital_rights_operation_clears_currency_amount_fields() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодПризнОперации": "8",
"КодВал": "643",
"СумОперации": "100.00",
"СумРуб": "100.00",
},
participant_fields={},
)
assert row["Валюта"] == ""
assert row["Сумма в валюте проведения"] == ""
assert row["Сумма в рубл. эквиваленте"] == ""
def test_abnormal_operation_codes_only_for_6001() -> None:
row_without_6001 = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодОперации": "5007",
"ПризнНеобОперации": "1101",
},
participant_fields={},
)
assert row_without_6001["Коды призн. необычной операции"] == ""
row_with_6001 = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодОперации": "6001",
"ПризнНеобОперации": "1101",
},
participant_fields={},
)
assert row_with_6001["Коды призн. необычной операции"] == "1101"
def test_transfer_accounts_get_placeholder_when_required() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ВидПереводДС": "1",
"ТипОператорДС": "4",
},
participant_fields={},
)
assert row["Номер счета плательщика"] == "00000000000000000000"
assert row["Номер счета банка плательщика"] == "00000000000000000000"
assert row["Номер счета банка получателя"] == "00000000000000000000"
assert row["Номер счета получателя"] == "00000000000000000000"
def test_transfer_accounts_stay_empty_without_transfer_block() -> None:
row = build_fixed_row_by_index(
file_name="SKO115FZ_01_044525111_20260810_000001.xml",
record_id="R1",
operation_index=1,
operation_fields={
"НомерОперация": "ЦФТ-БАНК_1361233603059",
"ПризнакОперации": "5",
"СведенияВнесениеПолучениеНалДС.СуммаНал": "1000.00",
},
participant_fields={},
)
assert row[38] == ""
assert row[44] == ""
assert row[45] == ""
assert row[46] == ""
def test_operator_type_conditions_clear_irrelevant_bank_fields() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ТипОператорДС": "3",
"НаимКО": "Банк плательщика",
"СведБанкПолучатель.НаимКО": "Банк получателя",
"СведБанкПолучатель.БИККО": "044525225",
"СчетБанкПлательщик": "30101810000000000001",
"СчетБанкПолучатель": "30101810000000000002",
},
participant_fields={},
)
assert row["Наименование банка плательщика"] == ""
assert row["Наименование банка получателя"] == ""
assert row["БИК банка получателя"] == ""
assert row["Номер счета банка плательщика"] == ""
assert row["Номер счета банка получателя"] == ""
def test_col96_territory_code_cleared_when_operation_is_not_5016() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодОперации": "5007",
"КодТерИнГос": "840",
},
participant_fields={},
)
assert row["Код территории"] == ""
def test_col103_and_105_fill_info_absent_when_no_employee_and_empty() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ПризнакСотрудник": "0",
},
participant_fields={},
)
assert row["Сведения о держателе платежной карты"] == "Информация отсутствует"
assert row["Наименование иностранного банка"] == "Информация отсутствует"
def test_col103_and_105_keep_original_values_when_present() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ПризнакСотрудник": "0",
"СведДержательКарты": "Иванов И.И.",
"НаимИнБанк": "FOREIGN BANK",
},
participant_fields={},
)
assert row["Сведения о держателе платежной карты"] == "Иванов И.И."
assert row["Наименование иностранного банка"] == "FOREIGN BANK"
def test_patronymic_supports_typo_tag_ocht() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Фам": "Азимов",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Имя": "Ислом",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Очт": "Каримович",
},
)
assert row["Отчество"] == "Каримович"
def test_col124_cleared_for_physical_person_and_ip() -> None:
row_fl = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ТипФЛЧастнаяПрактика": "1"},
participant_fields={"ТипУчастника": "2"},
)
assert row_fl["Признак филиала: / Тип ФЛЧП"] == ""
row_ip = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ТипФЛЧастнаяПрактика": "1"},
participant_fields={"ТипУчастника": "3"},
)
assert row_ip["Признак филиала: / Тип ФЛЧП"] == ""
def test_col125_snils_cleared_for_ip() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={"ТипУчастника": "3", "СНИЛСФЛ": "123-456-789 00"},
)
assert row["ОМС/СНИЛС/Номер телефона"] == ""
def test_one_line_address_columns_cleared_when_participant_is_resident_client() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ПризнУчастника": "1",
"ПризнКлиент": "1",
"АдресСтрока": "г. Москва, ул. Тестовая, д. 1",
},
participant_fields={},
)
assert row["Адрес в одной строке"] == ""
assert row["Место государственной регистрации ( в одной строке)"] == ""
assert (
row["Место государственной регистрации ЕИО/Бенефициара (одной строкой)"] == ""
)
def test_eio_one_line_address_obeys_participant_residency_rule() -> None:
participant_fields = {
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.АдресСтрока": "г. Москва, ул. Тестовая",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.Индекс": "101000",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.КодОКСМ": "643",
}
resident_client = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ПризнУчастника": "1", "ПризнКлиент": "1"},
participant_fields=participant_fields,
)
nonresident = build_fixed_row_by_index(
file_name="f.xml",
record_id="R2",
operation_index=2,
operation_fields={"ПризнУчастника": "0", "ПризнКлиент": "1"},
participant_fields=participant_fields,
)
assert resident_client[167] == ""
assert resident_client[169] == "101000"
assert resident_client[170] == "643"
assert nonresident[167] == "г. Москва, ул. Тестовая"
def test_foreign_structure_founder_address_populates_eio_address_block() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникИНБОЮЛ.СведИНБОЮЛ.Учредитель.АдрУчредитель.Индекс": "101000",
"УчастникИНБОЮЛ.СведИНБОЮЛ.Учредитель.АдрУчредитель.КодОКСМ": "643",
"УчастникИНБОЮЛ.СведИНБОЮЛ.Учредитель.АдрУчредитель.Пункт": "Москва",
},
)
assert row[167] == ""
assert row[168] == "101000, 643, , , Москва, , , , "
assert row[169] == "101000"
assert row[170] == "643"
assert row[173] == "Москва"
def test_foreign_structure_founder_one_line_address_activates_eio_block() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ПризнУчастника": "0"},
participant_fields={
"УчастникИНБОЮЛ.СведИНБОЮЛ.Учредитель.АдрУчредитель.АдресСтрока": (
"г. Москва, ул. Пушкина, д. 1"
),
},
)
assert row[167] == "г. Москва, ул. Пушкина, д. 1"
assert row[168] == ""
def test_okato_cleared_when_country_code_is_not_russia() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодОКСМ": "840",
"КодСубъектаПоОКАТО": "45",
},
participant_fields={},
)
assert row["Код ОКАТО"] == ""
assert row["ОКАТО"] == ""
def test_col163_ogrn_eio_benef_cleared_for_physical_person() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ОГРНИП": "123456789012345"},
participant_fields={"ТипУчастника": "2"},
)
assert row["ОГРН ЕИО/Бенефициара"] == ""
def test_dul_sign_for_legal_entity_does_not_use_operation_doc_fields() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ДокУдЛичн": "451099", "ТипУчастника": "1"},
participant_fields={},
)
assert row["Признак ДУЛ"] == ""
def test_dul_columns_128_134_keep_expected_positions() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ВидДокКод": "21",
"СерияДок": "0104",
"НомДок": "476635",
"КемВыданДок": "ОВД",
"КодПодр": "222-022",
"ДатВыдачиДок": "23/08/2005",
"ДокУдЛичн": "1",
},
)
assert row["ДУЛ (структура полностью)"] == "1, 21, 0104, 476635, ОВД, 222-022"
assert row["Признак ДУЛ"] == "1"
assert row["Код вида документа/Наименование"] == "21"
assert row["Серия"] == "0104"
assert row["Номер"] == "476635"
assert row["Орган, выдавший документ"] == "ОВД"
assert row["КП"] == "222-022"
def test_col136_does_not_use_identity_document_type_without_stay_document() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.СведДокУдЛичн.ВидДокКод": "21",
},
)
assert row[136] == ""
def test_col136_uses_stay_document_type_instead_of_identity_document_type() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.СведДокУдЛичн.ВидДокКод": "21",
"УчастникФЛИП.СведФЛИП.СведДокПреб.ВидДокКод": "10",
},
)
assert row[136] == "10"
def test_col136_rejects_stay_document_type_from_unrelated_participant_path() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ДругойБлок.СведДокПреб.ВидДокКод": "99",
},
)
assert row[136] == ""
def test_bank_bik_columns_use_transfer_bank_paths_instead_of_common_bikko() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"БИККО": "044525111",
"ТипОператорДС": "4",
"СвединияПереводыДС.СведБанкПлательщик.БИККО": "011012100",
"СвединияПереводыДС.СведБанкПолучатель.БИККО": "022202220",
},
participant_fields={},
)
assert row["БИК банка плательщика"] == "011012100"
assert row["БИК банка получателя"] == "022202220"
def test_transfer_bank_fields_do_not_leak_into_unrelated_bank_blocks() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ТипОператорДС": "2",
"ВидПереводДС": "1",
"СведенияПереводыДС.СведБанкПлательщик.НаимКО": "ПАО Сбербанк",
"СведенияПереводыДС.СведБанкПлательщик.БИККО": "044525225",
},
participant_fields={},
)
assert row[40] == "ПАО Сбербанк"
assert row[41] == "044525225"
for column_index in (60, 61, 75, 76, 94, 95, 100, 101):
assert row[column_index] == ""
def test_cash_bank_fields_fill_only_their_own_block() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"СведенияВнесениеПолучениеНалДС.СведПриемВыдача.НаимКО": "АО Наличный банк",
"СведенияВнесениеПолучениеНалДС.СведПриемВыдача.БИККО": "040407777",
"СведенияВнесениеПолучениеНалДС.СведПриемВыдача.КодОКСМ": "643",
},
participant_fields={},
)
assert row[94] == "АО Наличный банк"
assert row[95] == "040407777"
for column_index in (40, 41, 42, 43, 60, 61, 75, 76, 98, 100, 101):
assert row[column_index] == ""
def test_citizenship_country_code_uses_only_direct_svedflip_value() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.АдрРег.КодОКСМ": "643",
"УчастникФЛИП.СведФЛИП.КодОКСМ": "762",
},
)
assert row["Код страны гражданства"] == "762"
def test_citizenship_country_code_is_empty_when_only_address_code_exists() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={"УчастникФЛИП.СведФЛИП.АдрРег.КодОКСМ": "643"},
)
assert row["Код страны гражданства"] == ""
def test_okato_column_4_uses_branch_okatofl_and_not_bank_okatoko() -> None:
row = build_fixed_row(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ОКАТОКО": "45",
"ОКАТОФл": "10",
"АдресСтрока": "г. Москва",
},
participant_fields={},
)
assert FIXED_REPORT_COLUMNS[3] == "ОКАТО"
assert row["ОКАТО"] == "10"
def test_col9_uses_operation_number_from_xml() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=7,
operation_fields={"НомерОперация": "ЦФТ-БАНК_1177326777530"},
participant_fields={},
)
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, Размещение денежных средств;\n"
"2. 99, , Депозитный договор, 29/01/2026, Р202307/0001/93/Э, ;\n"
"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",
record_id="R1",
operation_index=1,
operation_fields={
"СведенияПереводыДс.СведПриемНалДС.АдрМестоПриемаВыдача.Индекс": "675520",
"СведенияПереводыДс.СведПриемНалДС.АдрМестоПриемаВыдача.КодОКСМ": "643",
"СведенияПереводыДс.СведПриемНалДС.АдрМестоПриемаВыдача.КодСубъектаПоОКАТО": "10",
"СведенияПереводыДс.СведПриемНалДС.АдрМестоПриемаВыдача.Пункт": "Чигири с",
"СведенияПереводыДс.СведПриемНалДС.АдрМестоПриемаВыдача.Улица": "Зеленая ул",
"СведенияПереводыДс.СведПриемНалДС.АдрМестоПриемаВыдача.Дом": "1",
"СведенияПереводыДс.СведПриемНалДС.БИККО": "044525111",
"СведенияПереводыДс.СведПриемНалДС.НаимКО": "АО РСХБ",
},
participant_fields={},
)
assert row[50] == "675520, 643, 10, , Чигири с, Зеленая ул, 1, , "
assert "044525111" not in row[50]
assert "АО РСХБ" not in row[50]
def test_participant_structured_address_stays_in_142_and_components_143_plus() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.АдрРег.Индекс": "123456",
"УчастникФЛИП.СведФЛИП.АдрРег.КодОКСМ": "643",
"УчастникФЛИП.СведФЛИП.АдрРег.КодСубъектаПоОКАТО": "45",
"УчастникФЛИП.СведФЛИП.АдрРег.Пункт": "Москва",
"УчастникФЛИП.СведФЛИП.АдрРег.Улица": "Тверская",
"УчастникФЛИП.СведФЛИП.АдрРег.Дом": "1",
},
)
assert row[141] == ""
assert row[142] == "123456, 643, 45, , Москва, Тверская, 1, , "
assert row[143] == "123456"
assert row[144] == "643"
def test_shagidova_address_keeps_missing_component_positions() -> None:
row = build_fixed_row_by_index(
file_name="SKO115FZ_01_044525111_20260810_000001.xml",
record_id="R1",
operation_index=1,
operation_fields={"НомерОперация": "ЦФТ-БАНК_1361449333033"},
participant_fields={
"УчастникФЛИП.СведФЛИП.АдрРег.Индекс": "367014",
"УчастникФЛИП.СведФЛИП.АдрРег.КодОКСМ": "643",
"УчастникФЛИП.СведФЛИП.АдрРег.КодСубъектаПоОКАТО": "82",
"УчастникФЛИП.СведФЛИП.АдрРег.Пункт": "Махачкала г.",
"УчастникФЛИП.СведФЛИП.АдрРег.Улица": "Гаджиева А ул",
"УчастникФЛИП.СведФЛИП.АдрРег.Дом": "12 Ж",
"УчастникФЛИП.СведФЛИП.АдрРег.Оф": "29",
},
)
assert row[142] == ("367014, 643, 82, , Махачкала г., Гаджиева А ул, 12 Ж, , 29")
assert tuple(row[index] for index in range(143, 152)) == (
"367014",
"643",
"82",
"",
"Махачкала г.",
"Гаджиева А ул",
"12 Ж",
"",
"29",
)
def test_participant_full_address_keeps_all_nine_components() -> None:
components = {
"Индекс": "367014",
"КодОКСМ": "643",
"КодСубъектаПоОКАТО": "82",
"Район": "Советский р",
"Пункт": "Махачкала г.",
"Улица": "Гаджиева А ул",
"Дом": "12 Ж",
"Корп": "2",
"Оф": "29",
}
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
f"УчастникФЛИП.СведФЛИП.АдрРег.{tag}": value
for tag, value in components.items()
},
)
assert row[142] == ", ".join(components.values())
assert tuple(row[index] for index in range(143, 152)) == tuple(components.values())
def test_eio_address_keeps_missing_component_positions() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.Индекс": "367014",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.КодОКСМ": "643",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.КодСубъектаПоОКАТО": "82",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.Пункт": "Махачкала г.",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.Улица": "Гаджиева А ул",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.Дом": "12 Ж",
"УчастникЮЛ.СведЕИО.ФЛЕИО.АдрРег.Оф": "29",
},
)
assert row[168] == ("367014, 643, 82, , Махачкала г., Гаджиева А ул, 12 Ж, , 29")
assert tuple(row[index] for index in range(169, 178)) == (
"367014",
"643",
"82",
"",
"Махачкала г.",
"Гаджиева А ул",
"12 Ж",
"",
"29",
)
def test_participant_address_does_not_use_citizenship_without_address_block() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "3",
"УчастникФЛИП.СведФЛИП.КодОКСМ": "643",
},
)
assert row[126] == "643"
assert row[142] == ""
assert row[144] == ""
def test_participant_address_country_is_isolated_from_citizenship() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "2",
"УчастникФЛИП.СведФЛИП.КодОКСМ": "762",
"УчастникФЛИП.СведФЛИП.АдрРег.Индекс": "123456",
"УчастникФЛИП.СведФЛИП.АдрРег.КодОКСМ": "643",
"УчастникФЛИП.СведФЛИП.АдрРег.Пункт": "Москва",
},
)
assert row[126] == "762"
assert row[142] == "123456, 643, , , Москва, , , , "
assert row[144] == "643"
def test_participant_address_components_reject_unrelated_address_fields() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ДругойАдрес.Индекс": "999999",
"ДругойАдрес.Район": "Чужой район",
"ДругойАдрес.Дом": "9",
},
participant_fields={
"ТипУчастника": "3",
"УчастникФЛИП.СведФЛИП.КодОКСМ": "643",
},
)
assert row[142] == ""
assert row[143] == ""
assert row[144] == ""
assert row[146] == ""
assert row[149] == ""
def test_col153_uses_only_legal_entity_registration_address_components() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"КодОКСМ": "643", "Индекс": "999999"},
participant_fields={
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Индекс": "675520",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.КодОКСМ": "643",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.КодСубъектаПоОКАТО": "10",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Район": "Благовещенский р",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Пункт": "Чигири с",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Улица": "Зеленая ул",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Дом": "1",
},
)
assert row[153] == "675520, 643, 10, Благовещенский р-н, Чигири с, Зеленая ул, 1"
def test_col153_is_cleared_when_registration_address_one_line_exists() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.АдресСтрока": "Москва, Тверская, 1",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Индекс": "123456",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.КодОКСМ": "643",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Пункт": "Москва",
},
)
assert row[152] == "Москва, Тверская, 1"
assert row[153] == ""
def test_col179_is_cleared_when_eio_registration_one_line_exists() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдресСтрока": "Москва, Арбат, 1",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРегЮЛ.Индекс": "123456",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРегЮЛ.КодОКСМ": "643",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРегЮЛ.Пункт": "Москва",
},
)
assert row[178] == "Москва, Арбат, 1"
assert row[179] == ""
def test_col179_keeps_structured_eio_registration_without_one_line() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРегЮЛ.Индекс": "123456",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРегЮЛ.КодОКСМ": "643",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.АдрРегЮЛ.Пункт": "Москва",
},
)
assert row[178] == ""
assert row[179] == "123456, 643, Москва"
def test_cash_columns_cleared_for_cashless_transfer_type_1() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ВидПереводДС": "1",
"КодОперации": "4006",
"БИККО": "044525111",
"СведенияПереводыДс.СведПриемНалДС.БИККО": "044525111",
},
participant_fields={},
)
for index in (50, 61, 65, 76, 84, 95, 99, 101):
assert row[index] == ""
def test_col119_is_empty_for_legal_entity_and_uses_flip_identifier() -> None:
row_ul = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={"ТипУчастника": "1", "ИдентификацияФЛ": "1"},
)
assert row_ul[119] == ""
row_flip = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "3",
"УчастникФЛИП.ИдентификацияФЛ": "1",
},
)
assert row_flip[119] == "1"
def test_physical_person_type_2_does_not_fill_cols_119_and_122() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"СтатусУчастника": "3",
"ТипУчастника": "2",
"УчастникФЛИП.ИдентификацияФЛ": "1",
"УчастникФЛИП.СведФЛИП.ИННФЛИП": "410116812922",
},
)
assert row[119] == ""
assert row[120] == "410116812922"
assert row[122] == ""
def test_col123_uses_registration_date_for_legal_entity() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "1",
"УчастникЮЛ.СведЮЛ.ДатаРегЮЛ": "23/08/2005",
"УчастникФЛИП.СведФЛИП.ДатаРождения": "01/01/1990",
},
)
assert row[123] == "23/08/2005"
def test_eio_block_is_empty_when_eio_and_beneficiary_are_absent() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "1",
"УчастникЮЛ.СведЮЛ.ИННЮЛ": "2820000210",
"УчастникЮЛ.СведЮЛ.ОГРНЮЛ": "1022801198573",
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.КодСубъектаПоОКАТО": "45",
},
)
for index in (157, 162, 163, 168, 171):
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",
"УчастникЮЛ.СведЕИО.ФЛЕИО.ДатаРождения": "03/07/1984",
"УчастникЮЛ.СведЕИО.ФЛЕИО.ТипФЛЧастнаяПрактика": "2",
"УчастникЮЛ.СведЕИО.ФЛЕИО.РегнНомер": "77-12345",
},
)
assert row[164] == (
"СНИЛС: 123-456-789 00\n"
"ОМС: \n"
"Номер телефона: +7 999 123-45-67\n"
"Дата рождения: 03/07/1984\n"
"Тип ФЛ, занимающегося частной практикой: 2\n"
"Регистрационный номер: 77-12345\n"
"Дата регистрации: "
)
def test_eio_other_info_stays_empty_for_beneficiary_only_fields() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.СНИЛСФЛ": "074-115-177 38",
"УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.ДатаРождения": "18/02/1981",
},
)
assert row[164] == ""
def test_participant_and_beneficiary_inn_are_scoped_regardless_of_field_order() -> None:
own_inn = ("УчастникЮЛ.СведЮЛ.ИННЮЛ", "2820000210")
beneficiary_fields = (
("УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.ФИОФЛИП.Фам", "Иванов"),
("УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.ФИОФЛИП.Имя", "Иван"),
("УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.ФИОФЛИП.Отч", "Иванович"),
("УчастникЮЛ.БенефициарЮЛ.ФЛБенефициар.ИННФЛИП", "111111111111"),
)
for items in (
(own_inn, *beneficiary_fields),
(*reversed(beneficiary_fields), own_inn),
):
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields=dict(items),
)
assert row[120] == "2820000210"
assert row[157] == "Иванов Иван Иванович"
assert row[162] == "111111111111"
assert "111111111111" not in row[157]
def test_legal_entity_and_eio_representative_inn_remain_strictly_scoped() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЮЛ.НаимЮЛ": "АО СИРИУС",
"УчастникЮЛ.СведЮЛ.ИННЮЛ": "2820000210",
"УчастникЮЛ.СведЕИО[0].ФЛЕИО.ФИОФЛИП.Фам": "Музалёв",
"УчастникЮЛ.СведЕИО[0].ФЛЕИО.ФИОФЛИП.Имя": "Александр",
"УчастникЮЛ.СведЕИО[0].ФЛЕИО.ФИОФЛИП.Отч": "Сергеевич",
"УчастникЮЛ.СведЕИО[0].ФЛЕИО.ИННФЛИП": "410116812922",
},
)
assert row[120] == "2820000210"
assert row[157] == "Музалёв Александр Сергеевич"
assert row[162] == "410116812922"
def test_flip_beneficiary_is_scoped_to_eio_columns() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникФЛИП.СведФЛИП.ИННФЛИП": "222222222222",
"УчастникФЛИП.БенефициарФЛИП.ФЛБенефициар.ИННФЛИП": "111111111111",
},
)
assert row[120] == "222222222222"
assert row[162] == "111111111111"
def test_legal_entity_eio_name_is_preserved_in_structured_column() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"УчастникЮЛ.СведЕИО.ЮЛЕИО.НаимЮЛ": "ООО Управляющая компания",
"УчастникЮЛ.СведЕИО.ЮЛЕИО.ИННЮЛ": "7707083893",
},
)
assert row[157] == "ООО Управляющая компания"
assert row[162] == "7707083893"
def test_continuation_row_validates_local_codes_without_filling_defaults() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"ПризнФТр": "9"},
participant_fields={},
is_continuation=True,
)
assert row[10] == ""
assert row[44] == ""
assert row[45] == ""
def test_cp_block_is_empty_without_sved_cp_and_uses_emitent_inn_when_present() -> None:
row_without_cp = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={"ИННЮЛ": "2820000210"},
)
assert row_without_cp[202] == ""
row_with_cp = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"СведЦП.Эмитент.ИННЭмитентЦП": "7707083893"},
participant_fields={"ИННЮЛ": "2820000210"},
)
assert row_with_cp[202] == "7707083893"
def test_currency_sign_is_preserved_independently_of_operation_code() -> None:
non_conversion = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодОперации": "6001",
"СумКонверсия": "0.00",
"ПризнВалОперации": "VO",
},
participant_fields={},
)
assert non_conversion[26] == ""
assert non_conversion[27] == "VO"
conversion = build_fixed_row_by_index(
file_name="f.xml",
record_id="R2",
operation_index=2,
operation_fields={
"КодОперации": "6101",
"КодВалКонверсия": "978",
"СумКонверсия": "100.50",
"ПризнВалОперации": "VO",
},
participant_fields={},
)
assert conversion[26] == "100.50"
assert conversion[27] == "VO"
zero_conversion = build_fixed_row_by_index(
file_name="f.xml",
record_id="R3",
operation_index=3,
operation_fields={
"КодОперации": "6126",
"КодВалКонверсия": "840",
"СумКонверсия": "0.00",
"ПризнВалОперации": "VO",
},
participant_fields={},
)
assert zero_conversion[26] == ""
assert zero_conversion[27] == "VO"
for operation_code in ("6100", "6127"):
boundary_row = build_fixed_row_by_index(
file_name="f.xml",
record_id=operation_code,
operation_index=4,
operation_fields={
"КодОперации": operation_code,
"ПризнВалОперации": "VO",
},
participant_fields={},
)
assert boundary_row[27] == "VO"
def test_extra_info_uses_operation_comment() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"КодОперации": "9003", "Коммент": "Комментарий операции"},
participant_fields={},
)
assert row[34] == "Комментарий операции"
def test_extra_info_ignores_nested_operation_comment() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"КодОперации": "9003",
"СведенияПереводыДС.Коммент": "Комментарий вложенного блока",
},
participant_fields={},
)
assert row[34] == ""
def test_extra_info_rejects_participant_comment_outside_allowed_codes() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"КодОперации": "9003"},
participant_fields={"КомментУчастник": "Посторонний комментарий"},
)
assert row[34] == ""
def test_extra_info_is_not_directly_mapped_on_continuation_row() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"КодОперации": "9003"},
participant_fields={"КомментУчастник": "Посторонний комментарий"},
is_continuation=True,
)
assert row[34] == ""
def test_extra_info_accepts_participant_comment_for_main_or_extra_code() -> None:
for operation_fields in (
{"КодОперации": "6102"},
{"КодОперации": "9003", "ДопКодОперации": "6126"},
):
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields=operation_fields,
participant_fields={"КомментУчастник": "Комментарий участника"},
)
assert row[34] == "Комментарий участника"
def test_extra_info_joins_distinct_allowed_comments_without_duplicates() -> None:
combined = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={"КодОперации": "6102", "Коммент": "Общий комментарий"},
participant_fields={"КомментУчастник": "Комментарий участника"},
)
duplicate = build_fixed_row_by_index(
file_name="f.xml",
record_id="R2",
operation_index=2,
operation_fields={"КодОперации": "6102", "Коммент": "Одинаковый текст"},
participant_fields={"КомментУчастник": "Одинаковый текст"},
)
assert combined[34] == "Общий комментарий; Комментарий участника"
assert duplicate[34] == "Одинаковый текст"
def test_bank_bik_columns_accept_canonical_transfer_block_spelling() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={
"ТипОператорДС": "4",
"СведенияПереводыДС.СведБанкПлательщик.БИККО": "011012100",
"СведенияПереводыДС.СведБанкПолучатель.БИККО": "022202220",
},
participant_fields={},
)
assert row[41] == "011012100"
assert row[43] == "022202220"
def test_legal_entity_blocks_do_not_use_physical_person_identification() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "4",
"УчастникЮЛ.СведЮЛ.НаимЮЛ": "ООО Тест",
"ИдентификацияФЛ": "1",
},
)
assert row[119] == ""
assert row[122] == ""
def test_col124_is_empty_for_private_practice_participant_type_4() -> None:
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields={
"ТипУчастника": "4",
"УчастникФЛИП.СведФЛИП.ТипФЛЧастнаяПрактика": "1",
},
)
assert row[124] == ""
padded_type_row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R2",
operation_index=2,
operation_fields={},
participant_fields={
"ТипУчастника": "04",
"УчастникФЛИП.СведФЛИП.ТипФЛЧастнаяПрактика": "1",
},
)
assert padded_type_row[124] == ""
def test_col119_is_not_included_in_structured_fio_or_cleared_by_one_line_fio() -> None:
participant_fields = {
"ТипУчастника": "2",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Фам": "Азимов",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Имя": "Ислом",
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.Отч": "Каримович",
"УчастникФЛИП.ИдентификацияФЛ": "1",
}
row = build_fixed_row_by_index(
file_name="f.xml",
record_id="R1",
operation_index=1,
operation_fields={},
participant_fields=participant_fields,
)
assert row[114] == "Азимов Ислом Каримович"
assert row[119] == ""
assert row[122] == ""
row_with_one_line_fio = build_fixed_row_by_index(
file_name="f.xml",
record_id="R2",
operation_index=2,
operation_fields={},
participant_fields={
**participant_fields,
"УчастникФЛИП.СведФЛИП.ФИОФЛИП.ФИОСтрока": ("Азимов Ислом Каримович"),
},
)
assert row_with_one_line_fio[119] == ""
assert row_with_one_line_fio[122] == ""