Compare commits
No commits in common. "bf3d3f12e9d14e12b27558e3576256c81b08f686" and "1d46f8cc6d8dcd1ed7b68a6afa1dbb98fa6c227e" have entirely different histories.
bf3d3f12e9
...
1d46f8cc6d
@ -47,7 +47,6 @@ COL_TRANSFER_STATUS = _index(62)
|
|||||||
|
|
||||||
# Карты и место операции.
|
# Карты и место операции.
|
||||||
COL_TERRITORY_CODE_CARD = _index(96)
|
COL_TERRITORY_CODE_CARD = _index(96)
|
||||||
COL_FOREIGN_CARD_ADDRESS_STRUCTURED = _index(99)
|
|
||||||
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)
|
||||||
|
|||||||
@ -31,7 +31,6 @@ from .column_constants import (
|
|||||||
COL_EXTRA_INFO,
|
COL_EXTRA_INFO,
|
||||||
COL_FILE_NAME,
|
COL_FILE_NAME,
|
||||||
COL_FOREIGN_BANK_NAME,
|
COL_FOREIGN_BANK_NAME,
|
||||||
COL_FOREIGN_CARD_ADDRESS_STRUCTURED,
|
|
||||||
COL_FTR_SIGN,
|
COL_FTR_SIGN,
|
||||||
COL_IDENT_FL,
|
COL_IDENT_FL,
|
||||||
COL_INN,
|
COL_INN,
|
||||||
@ -291,32 +290,6 @@ def _build_rules(mapping_data: tuple[ColumnMeta, ...]) -> tuple[MappingRule, ...
|
|||||||
candidates = [
|
candidates = [
|
||||||
f"{base_path}.{tag}" for base_path in base_paths for tag in address_tags
|
f"{base_path}.{tag}" for base_path in base_paths for tag in address_tags
|
||||||
]
|
]
|
||||||
elif index == COL_FOREIGN_CARD_ADDRESS_STRUCTURED:
|
|
||||||
# legacy_099: адрес места приёма/выдачи по карте иностранного
|
|
||||||
# банка (код 1009) приходит в XML разложенным по тем же тегам
|
|
||||||
# АдрМестаПриемаВыдача, что и другие адресные блоки (см.
|
|
||||||
# COL_REG_PLACE_STRUCTURED выше) — АдресСтрока как единого поля
|
|
||||||
# для этого блока в схеме нет, поэтому колонку нужно собирать
|
|
||||||
# из компонентов, а не мапить напрямую на несуществующий тег.
|
|
||||||
base_paths = (
|
|
||||||
"СведенияКартаИнБанк.СведМестоОперация.АдрМестаПриемаВыдача",
|
|
||||||
"СообщОперКО.ИнформЧасть.СведКО.Операция.СведенияКартаИнБанк."
|
|
||||||
"СведМестоОперация.АдрМестаПриемаВыдача",
|
|
||||||
)
|
|
||||||
address_tags = (
|
|
||||||
"Индекс",
|
|
||||||
"КодОКСМ",
|
|
||||||
"КодСубъектаПоОКАТО",
|
|
||||||
"Район",
|
|
||||||
"Пункт",
|
|
||||||
"Улица",
|
|
||||||
"Дом",
|
|
||||||
"Корп",
|
|
||||||
"Оф",
|
|
||||||
)
|
|
||||||
candidates = [
|
|
||||||
f"{base_path}.{tag}" for base_path in base_paths for tag in address_tags
|
|
||||||
]
|
|
||||||
elif index == COL_CP_ISSUER_INN:
|
elif index == COL_CP_ISSUER_INN:
|
||||||
candidates = [
|
candidates = [
|
||||||
candidate
|
candidate
|
||||||
|
|||||||
@ -1965,10 +1965,10 @@
|
|||||||
"column_name": "Адрес места приема (выдачи) наличных денежных средств (по структуре полный)",
|
"column_name": "Адрес места приема (выдачи) наличных денежных средств (по структуре полный)",
|
||||||
"block": "foreign_card",
|
"block": "foreign_card",
|
||||||
"report_group": "foreign_card_operation",
|
"report_group": "foreign_card_operation",
|
||||||
"xml_tag": "Индекс|КодОКСМ|КодСубъектаПоОКАТО|Район|Пункт|Улица|Дом|Корп|Оф",
|
"xml_tag": "АдрМестаПриемаВыдача",
|
||||||
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/СведенияКартаИнБанк/СведМестоОперация/АдрМестаПриемаВыдача/",
|
"xml_path": "СообщОперКО/ИнформЧасть/СведКО/Операция/СведенияКартаИнБанк/СведМестоОперация/АдрМестаПриемаВыдача/АдресСтрока",
|
||||||
"source_scope": "any",
|
"source_scope": "any",
|
||||||
"allow_short_lookup": false,
|
"allow_short_lookup": true,
|
||||||
"allow_direct_mapping": true,
|
"allow_direct_mapping": true,
|
||||||
"structured_value": true,
|
"structured_value": true,
|
||||||
"structured_group": "",
|
"structured_group": "",
|
||||||
@ -1977,7 +1977,7 @@
|
|||||||
"join_with_space": false,
|
"join_with_space": false,
|
||||||
"multiplies": "нет",
|
"multiplies": "нет",
|
||||||
"required": "необязательно",
|
"required": "необязательно",
|
||||||
"comment": "У блока АдрМестаПриемаВыдача в СведенияКартаИнБанк нет единого тега АдресСтрока (в отличие от одноимённого блока в СведенияВнесениеПолучениеНалДС) — значение собирается из компонентов адреса (см. COL_FOREIGN_CARD_ADDRESS_STRUCTURED в mapping.py), поле может остаться пустым"
|
"comment": "текстовый показатель, поле может остаться пустым и не передаваться в XML"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"index": 100,
|
"index": 100,
|
||||||
|
|||||||
@ -28,7 +28,7 @@ def test_registry_covers_all_report_columns_without_gaps() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_registry_assigns_card_columns_missing_from_original_plan() -> None:
|
def test_registry_assigns_card_columns_missing_from_original_plan() -> None:
|
||||||
assert COLUMNS.block("foreign_card") == tuple(range(96, 107))
|
assert COLUMNS.block("foreign_card") == tuple(range(97, 107))
|
||||||
|
|
||||||
|
|
||||||
def test_registry_explicitly_preserves_structured_lookup_compatibility() -> None:
|
def test_registry_explicitly_preserves_structured_lookup_compatibility() -> None:
|
||||||
@ -75,14 +75,14 @@ def test_registry_splits_money_and_participant_header_groups() -> None:
|
|||||||
(
|
(
|
||||||
"own_account_cash",
|
"own_account_cash",
|
||||||
79,
|
79,
|
||||||
95,
|
96,
|
||||||
"Сведения о внесении наличных денежных средств на свой банковский счет "
|
"Сведения о внесении наличных денежных средств на свой банковский счет "
|
||||||
"или о получении наличных денежных средств со своего банковского счета "
|
"или о получении наличных денежных средств со своего банковского счета "
|
||||||
"у одного оператора по переводу денежных средств",
|
"у одного оператора по переводу денежных средств",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"foreign_card_operation",
|
"foreign_card_operation",
|
||||||
96,
|
97,
|
||||||
106,
|
106,
|
||||||
"Сведения об операции с использованием платежной карты иностранного банка",
|
"Сведения об операции с использованием платежной карты иностранного банка",
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1720,48 +1720,6 @@ def test_col99_foreign_card_address_header_renamed() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_col99_foreign_card_address_assembled_from_structured_components() -> None:
|
|
||||||
"""Регрессия: у блока АдрМестаПриемаВыдача в СведенияКартаИнБанк (код
|
|
||||||
1009) нет единого тега АдресСтрока, в отличие от одноимённого блока в
|
|
||||||
СведенияВнесениеПолучениеНалДС — колонка 99 раньше мапилась напрямую на
|
|
||||||
несуществующий АдресСтрока и оставалась пустой. Значение должно
|
|
||||||
собираться из компонентов адреса, разложенных в XML по структуре."""
|
|
||||||
row = build_fixed_row_by_index(
|
|
||||||
file_name="f.xml",
|
|
||||||
record_id="R1",
|
|
||||||
operation_index=1,
|
|
||||||
operation_fields={
|
|
||||||
"КодОперации": "1009",
|
|
||||||
"СведенияКартаИнБанк.СведМестоОперация.АдрМестаПриемаВыдача.КодОКСМ": "840",
|
|
||||||
"СведенияКартаИнБанк.СведМестоОперация.АдрМестаПриемаВыдача.Пункт": "Нью-Йорк",
|
|
||||||
"СведенияКартаИнБанк.СведМестоОперация.АдрМестаПриемаВыдача.Улица": "Уолл-стрит",
|
|
||||||
"СведенияКартаИнБанк.СведМестоОперация.АдрМестаПриемаВыдача.Дом": "11",
|
|
||||||
},
|
|
||||||
participant_fields={},
|
|
||||||
)
|
|
||||||
|
|
||||||
assert row[99] == "840, Нью-Йорк, Уолл-стрит, 11"
|
|
||||||
|
|
||||||
|
|
||||||
def test_col99_foreign_card_address_not_leaked_from_participant_address() -> None:
|
|
||||||
"""Регрессия: allow_short_lookup для колонки 99 должен быть выключен —
|
|
||||||
иначе адрес участника операции (другой блок, тот же тег 'Улица') может
|
|
||||||
случайно попасть в адрес места приёма/выдачи по карте ин. банка."""
|
|
||||||
row = build_fixed_row_by_index(
|
|
||||||
file_name="f.xml",
|
|
||||||
record_id="R1",
|
|
||||||
operation_index=1,
|
|
||||||
operation_fields={
|
|
||||||
"КодОперации": "1009",
|
|
||||||
},
|
|
||||||
participant_fields={
|
|
||||||
"УчастникЮЛ.СведЮЛ.АдрРегЮЛ.Улица": "Совсем другая улица",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
assert row[99] == ""
|
|
||||||
|
|
||||||
|
|
||||||
def test_col96_territory_code_card_belongs_to_foreign_card_group() -> None:
|
def test_col96_territory_code_card_belongs_to_foreign_card_group() -> None:
|
||||||
"""Регрессия: колонка 96 раньше входила в группу заголовков блока
|
"""Регрессия: колонка 96 раньше входила в группу заголовков блока
|
||||||
'своих' кассовых операций (cash_operation/own_account_cash), из-за чего
|
'своих' кассовых операций (cash_operation/own_account_cash), из-за чего
|
||||||
|
|||||||
@ -2,7 +2,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from app.pipeline.mapping import build_fixed_row_by_index
|
|
||||||
from app.pipeline.parser import _extract_direct_fields, parse_xml_content
|
from app.pipeline.parser import _extract_direct_fields, parse_xml_content
|
||||||
|
|
||||||
|
|
||||||
@ -359,65 +358,6 @@ def test_mixed_operation_and_eio_repeats_are_additive_not_cartesian() -> None:
|
|||||||
assert result.rows[0].operation_fields["ОснованиеОп.НомДок"] == "BASE-1; BASE-2"
|
assert result.rows[0].operation_fields["ОснованиеОп.НомДок"] == "BASE-1; BASE-2"
|
||||||
|
|
||||||
|
|
||||||
def test_1009_foreign_card_address_survives_full_pipeline() -> None:
|
|
||||||
"""Сквозная проверка на синтетическом файле: реальный XML -> parse_xml_content
|
|
||||||
-> build_fixed_row_by_index. Адрес места приёма/выдачи по карте
|
|
||||||
иностранного банка (код 1009) должен собраться из компонентов
|
|
||||||
АдрМестаПриемаВыдача в колонку 99, а не потеряться и не подхватить
|
|
||||||
чужой адрес участника операции (тот же тег 'Улица' в другом блоке)."""
|
|
||||||
xml = _base_xml(
|
|
||||||
"""
|
|
||||||
<Операция>
|
|
||||||
<ИдентификаторЗаписи>OP1</ИдентификаторЗаписи>
|
|
||||||
<КодОперации>1009</КодОперации>
|
|
||||||
<СведенияКартаИнБанк>
|
|
||||||
<НомерКарта>5536********1234</НомерКарта>
|
|
||||||
<НаимИнБанк>Bank of Testland</НаимИнБанк>
|
|
||||||
<СведМестоОперация>
|
|
||||||
<ИдТерминал>ATM00042</ИдТерминал>
|
|
||||||
<НаимКО>First Test Bank</НаимКО>
|
|
||||||
<АдрМестаПриемаВыдача>
|
|
||||||
<Индекс>10001</Индекс>
|
|
||||||
<КодОКСМ>840</КодОКСМ>
|
|
||||||
<Пункт>Нью-Йорк</Пункт>
|
|
||||||
<Улица>Уолл-стрит</Улица>
|
|
||||||
<Дом>11</Дом>
|
|
||||||
</АдрМестаПриемаВыдача>
|
|
||||||
</СведМестоОперация>
|
|
||||||
</СведенияКартаИнБанк>
|
|
||||||
<УчастникОп>
|
|
||||||
<Тип>01</Тип>
|
|
||||||
<УчастникЮЛ>
|
|
||||||
<СведЮЛ>
|
|
||||||
<АдрРегЮЛ>
|
|
||||||
<Улица>Совсем другая улица участника</Улица>
|
|
||||||
</АдрРегЮЛ>
|
|
||||||
</СведЮЛ>
|
|
||||||
</УчастникЮЛ>
|
|
||||||
</УчастникОп>
|
|
||||||
</Операция>
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
result = parse_xml_content("SKO115FZ_01_123456789_20260616_X00001.xml", xml)
|
|
||||||
assert not result.is_fatal
|
|
||||||
assert len(result.rows) == 1
|
|
||||||
|
|
||||||
row = result.rows[0]
|
|
||||||
fixed_row = build_fixed_row_by_index(
|
|
||||||
file_name="SKO115FZ_01_123456789_20260616_X00001.xml",
|
|
||||||
record_id=row.record_id,
|
|
||||||
operation_index=1,
|
|
||||||
operation_fields=row.operation_fields,
|
|
||||||
participant_fields=row.participant_fields,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert fixed_row[97] == "ATM00042"
|
|
||||||
assert fixed_row[98] == "840"
|
|
||||||
assert fixed_row[99] == "10001, 840, Нью-Йорк, Уолл-стрит, 11"
|
|
||||||
assert fixed_row[100] == "First Test Bank"
|
|
||||||
|
|
||||||
|
|
||||||
def test_repeated_scalar_leaves_are_joined_without_continuation_rows() -> None:
|
def test_repeated_scalar_leaves_are_joined_without_continuation_rows() -> None:
|
||||||
operation = ET.fromstring(
|
operation = ET.fromstring(
|
||||||
"""
|
"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user