The customer's ruling of 24.09.2026 is that every value present in the XML must reach the report, taking into account which block holds it. Two defects broke that for operation code 5016 with transfer types 4 and 5. Wrong paths in mapping_table.json. Columns 48-63 spelled the block as "СведенияПереводыДс" and columns 49-59 spelled the address as "АдрМестоПриемаВыдача"; the schema uses "СведенияПереводыДС" and "АдрМестаПриемаВыдача". Those columns carry allow_short_lookup=false, so they can only match on a fully scoped path and never matched at all: the whole cash receipt block (AV-BI) and the transfer status (BJ) stayed empty on every file. The existing test passed only because it fed the same misspellings. Rules that deleted data instead of filling it: - Rules 38, 44-45 and 46 wiped the account columns for code 5016. The XML of those records carries СчетБанкПолучатель = 00000000000000000000, which is exactly the value the customer asked for. The rules now only substitute the placeholder into an empty column, and never for 5016. - Rule 44 also wiped the correspondent accounts for operator types 3 and 5 even when the XML had them. - The cashless rule wiped columns 50, 61, 65, 76, 84, 95, 99 and 101 for transfer types 1-4, 7 and 10-14, although type 4 is by definition a transfer that accepts cash and must carry the receipt block. - Rule 62 limited the transfer status to types 2, 5 and 8. - Rule 30 limited the metal name to code C99, while the available exports only ever carry code A90. Verified on the sample exports: all 16 records with code 5016 now carry the zeros in column 45, the real account in column 46, and no invented placeholders in columns 38 and 44.
114 lines
3.3 KiB
Python
114 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from .column_registry import COLUMNS
|
|
|
|
|
|
def _index(legacy_position: int) -> int:
|
|
return COLUMNS.index_of(f"legacy_{legacy_position:03d}")
|
|
|
|
|
|
# Служебные поля и операция.
|
|
COL_FILE_NAME = _index(1)
|
|
COL_RECORD_ID = _index(7)
|
|
COL_FTR_SIGN = _index(10)
|
|
COL_SUSPENSION_BASIS = _index(11)
|
|
COL_OPERATION_SIGN = _index(14)
|
|
COL_ESP_SIGN = _index(15)
|
|
COL_OPERATION_CODE = _index(19)
|
|
COL_EXTRA_CODES = _index(20)
|
|
COL_UNUSUAL_CODES = _index(21)
|
|
COL_CURRENCY = _index(22)
|
|
COL_AMOUNT_CURRENCY = _index(23)
|
|
COL_AMOUNT_RUB = _index(24)
|
|
COL_SALE_CURRENCY = _index(25)
|
|
COL_SALE_AMOUNT = _index(26)
|
|
COL_CURRENCY_SIGN = _index(27)
|
|
COL_SUSPICIOUS_ID = _index(28)
|
|
COL_ITEM_TYPE = _index(31)
|
|
COL_EXTRA_INFO = _index(34)
|
|
|
|
# Перевод.
|
|
COL_TRANSFER_TYPE = _index(35)
|
|
COL_TERRITORY_CODE = _index(36)
|
|
COL_OPERATOR_TYPE = _index(37)
|
|
COL_PAYER_ACCOUNT = _index(38)
|
|
COL_PAYER_ESP = _index(39)
|
|
COL_PAYER_BANK_NAME = _index(40)
|
|
COL_PAYER_BANK_BIK = _index(41)
|
|
COL_RECIPIENT_BANK_NAME = _index(42)
|
|
COL_RECIPIENT_BANK_BIK = _index(43)
|
|
COL_PAYER_BANK_ACCOUNT = _index(44)
|
|
COL_RECIPIENT_BANK_ACCOUNT = _index(45)
|
|
COL_RECIPIENT_ACCOUNT = _index(46)
|
|
COL_RECIPIENT_ESP = _index(47)
|
|
|
|
# Карты и место операции.
|
|
COL_TERRITORY_CODE_CARD = _index(96)
|
|
COL_FOREIGN_CARD_ADDRESS_STRUCTURED = _index(99)
|
|
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)
|
|
COL_RESIDENT_SIGN = _index(110)
|
|
COL_CLIENT_SIGN = _index(111)
|
|
COL_IDENT_FL = _index(119)
|
|
COL_INN = _index(120)
|
|
COL_KPP = _index(122)
|
|
COL_BIRTH_REG_DATE = _index(123)
|
|
COL_BRANCH_SIGN = _index(124)
|
|
COL_INSURANCE_NUMBER = _index(125)
|
|
COL_COUNTRY_CODE = _index(126)
|
|
COL_STAY_DOCUMENT_TYPE = _index(136)
|
|
COL_ADDRESS_ONE_LINE = _index(141)
|
|
COL_ADDRESS_STRUCTURED = _index(142)
|
|
COL_REG_PLACE_ONE_LINE = _index(152)
|
|
COL_REG_PLACE_STRUCTURED = _index(153)
|
|
COL_EIO_ADDRESS_ONE_LINE = _index(167)
|
|
|
|
# ЕИО и ценные бумаги.
|
|
COL_EIO_INN = _index(163)
|
|
COL_EIO_OTHER_INFO = _index(164)
|
|
COL_EIO_REG_PLACE_ONE_LINE = _index(178)
|
|
COL_EIO_REG_PLACE_STRUCTURED = _index(179)
|
|
COL_CP_ISSUER_INN = _index(202)
|
|
|
|
# Блоки схемы.
|
|
BLOCK_EIO = COLUMNS.block("eio")
|
|
BLOCK_CP = COLUMNS.block("cp")
|
|
PARTICIPANT_ADDRESS_COMPONENT_COLUMNS = tuple(
|
|
column.index
|
|
for column in COLUMNS.ordered_columns()
|
|
if column.structured_group == "legacy_142" and column.structured_role == "component"
|
|
)
|
|
|
|
OKATO_COUNTRY_PAIRS: tuple[tuple[int, int], ...] = tuple(
|
|
(_index(country), _index(okato))
|
|
for country, okato in (
|
|
(52, 53),
|
|
(67, 68),
|
|
(86, 87),
|
|
(144, 145),
|
|
(170, 171),
|
|
)
|
|
)
|
|
|
|
# Бизнес-константы.
|
|
ACCOUNT_PLACEHOLDER = "00000000000000000000"
|
|
EXPORT_SUBSIDIARY_COMMENT_CODES = frozenset(str(code) for code in range(6102, 6127))
|
|
VALID_FTR_SIGNS = frozenset({"0", "1", "2", "3", "4", "5"})
|
|
VALID_SUSPENSION_BASES = frozenset({"1", "2", "3"})
|
|
VALID_ESP_SIGNS = frozenset({"1", "2", "3", "4"})
|
|
PRECIOUS_ITEM_CODES = frozenset({"5020", "5021", "5022", "5023"})
|
|
SUSPICIOUS_CODE = "6001"
|
|
TERRITORY_CODE = "5016"
|
|
EMPLOYEE_ABSENT_CODE = "0"
|
|
RUSSIA_COUNTRY_CODE = "643"
|
|
|
|
PARTICIPANT_TYPE_UL = "1"
|
|
PARTICIPANT_TYPE_FL = "2"
|
|
PARTICIPANT_TYPE_IP = "3"
|
|
PARTICIPANT_TYPE_FLCHP = "4"
|