fix
This commit is contained in:
parent
bef38dedd8
commit
510d668ab8
@ -27,6 +27,7 @@ COL_SUSPICIOUS_ID = _index(28)
|
|||||||
COL_METAL_CODE = _index(29)
|
COL_METAL_CODE = _index(29)
|
||||||
COL_METAL_NAME = _index(30)
|
COL_METAL_NAME = _index(30)
|
||||||
COL_ITEM_TYPE = _index(31)
|
COL_ITEM_TYPE = _index(31)
|
||||||
|
COL_EXTRA_INFO = _index(34)
|
||||||
|
|
||||||
# Перевод.
|
# Перевод.
|
||||||
COL_TRANSFER_TYPE = _index(35)
|
COL_TRANSFER_TYPE = _index(35)
|
||||||
@ -101,7 +102,7 @@ PARTICIPANT_ADDRESS_OUTPUT_SOURCES: dict[int, int] = {
|
|||||||
|
|
||||||
# Бизнес-константы.
|
# Бизнес-константы.
|
||||||
ACCOUNT_PLACEHOLDER = "00000000000000000000"
|
ACCOUNT_PLACEHOLDER = "00000000000000000000"
|
||||||
CURRENCY_OPERATION_CODES = frozenset(str(code) for code in range(6101, 6127))
|
EXPORT_SUBSIDIARY_COMMENT_CODES = frozenset(str(code) for code in range(6102, 6127))
|
||||||
CASHLESS_TRANSFER_TYPES = frozenset(
|
CASHLESS_TRANSFER_TYPES = frozenset(
|
||||||
{"1", "2", "3", "4", "7", "10", "11", "12", "13", "14"}
|
{"1", "2", "3", "4", "7", "10", "11", "12", "13", "14"}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -19,13 +19,13 @@ from .column_constants import (
|
|||||||
COL_COUNTRY_CODE,
|
COL_COUNTRY_CODE,
|
||||||
COL_CP_ISSUER_INN,
|
COL_CP_ISSUER_INN,
|
||||||
COL_CURRENCY,
|
COL_CURRENCY,
|
||||||
COL_CURRENCY_SIGN,
|
|
||||||
COL_EIO_ADDRESS_ONE_LINE,
|
COL_EIO_ADDRESS_ONE_LINE,
|
||||||
COL_EIO_INN,
|
COL_EIO_INN,
|
||||||
COL_EIO_REG_PLACE_ONE_LINE,
|
COL_EIO_REG_PLACE_ONE_LINE,
|
||||||
COL_EMPLOYEE_SIGN,
|
COL_EMPLOYEE_SIGN,
|
||||||
COL_ESP_SIGN,
|
COL_ESP_SIGN,
|
||||||
COL_EXTRA_CODES,
|
COL_EXTRA_CODES,
|
||||||
|
COL_EXTRA_INFO,
|
||||||
COL_FILE_NAME,
|
COL_FILE_NAME,
|
||||||
COL_FOREIGN_BANK_NAME,
|
COL_FOREIGN_BANK_NAME,
|
||||||
COL_FTR_SIGN,
|
COL_FTR_SIGN,
|
||||||
@ -63,8 +63,8 @@ from .column_constants import (
|
|||||||
COL_TRANSFER_STATUS,
|
COL_TRANSFER_STATUS,
|
||||||
COL_TRANSFER_TYPE,
|
COL_TRANSFER_TYPE,
|
||||||
COL_UNUSUAL_CODES,
|
COL_UNUSUAL_CODES,
|
||||||
CURRENCY_OPERATION_CODES,
|
|
||||||
EMPLOYEE_ABSENT_CODE,
|
EMPLOYEE_ABSENT_CODE,
|
||||||
|
EXPORT_SUBSIDIARY_COMMENT_CODES,
|
||||||
OKATO_COUNTRY_PAIRS,
|
OKATO_COUNTRY_PAIRS,
|
||||||
PARTICIPANT_TYPE_FL,
|
PARTICIPANT_TYPE_FL,
|
||||||
PARTICIPANT_TYPE_FLCHP,
|
PARTICIPANT_TYPE_FLCHP,
|
||||||
@ -389,6 +389,8 @@ def build_fixed_row_by_index(
|
|||||||
row,
|
row,
|
||||||
has_eio_block=has_eio_block,
|
has_eio_block=has_eio_block,
|
||||||
has_cp_block=has_cp_block,
|
has_cp_block=has_cp_block,
|
||||||
|
operation_fields=operation_fields,
|
||||||
|
participant_fields=participant_fields,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
_apply_continuation_validation_rules(row)
|
_apply_continuation_validation_rules(row)
|
||||||
@ -472,6 +474,14 @@ def _pick_scoped_payload_value(payload: dict[str, str], scoped_path: str) -> str
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def _pick_direct_payload_value(payload: dict[str, str], field_name: str) -> str:
|
||||||
|
"""Возвращает только прямое поле текущего XML-блока без suffix-поиска."""
|
||||||
|
for key, value in payload.items():
|
||||||
|
if value and _normalize_indexed_path(key) == field_name:
|
||||||
|
return str(value).strip()
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def _apply_participant_identity_rules(
|
def _apply_participant_identity_rules(
|
||||||
row: dict[int, str], participant_fields: dict[str, str]
|
row: dict[int, str], participant_fields: dict[str, str]
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -633,6 +643,8 @@ def _apply_business_rules(
|
|||||||
*,
|
*,
|
||||||
has_eio_block: bool,
|
has_eio_block: bool,
|
||||||
has_cp_block: bool,
|
has_cp_block: bool,
|
||||||
|
operation_fields: dict[str, str],
|
||||||
|
participant_fields: dict[str, str],
|
||||||
) -> None:
|
) -> None:
|
||||||
codes = _operation_codes(row)
|
codes = _operation_codes(row)
|
||||||
operation_sign = _get(row, COL_OPERATION_SIGN)
|
operation_sign = _get(row, COL_OPERATION_SIGN)
|
||||||
@ -646,7 +658,7 @@ def _apply_business_rules(
|
|||||||
_rule_unusual_codes(row, codes)
|
_rule_unusual_codes(row, codes)
|
||||||
_rule_digital_rights_currency(row, operation_sign)
|
_rule_digital_rights_currency(row, operation_sign)
|
||||||
_rule_sale_currency(row)
|
_rule_sale_currency(row)
|
||||||
_rule_currency_sign(row, codes)
|
_rule_extra_info(row, codes, operation_fields, participant_fields)
|
||||||
_rule_suspicious_activity(row, codes)
|
_rule_suspicious_activity(row, codes)
|
||||||
_rule_metal_name(row)
|
_rule_metal_name(row)
|
||||||
_rule_item_type(row, codes)
|
_rule_item_type(row, codes)
|
||||||
@ -725,10 +737,26 @@ def _rule_sale_currency(row: dict[int, str]) -> None:
|
|||||||
_set(row, COL_SALE_AMOUNT, "")
|
_set(row, COL_SALE_AMOUNT, "")
|
||||||
|
|
||||||
|
|
||||||
def _rule_currency_sign(row: dict[int, str], codes: set[str]) -> None:
|
def _rule_extra_info(
|
||||||
"""Правило 27: признак VO только для валютных операций 6101-6126."""
|
row: dict[int, str],
|
||||||
if not codes & CURRENCY_OPERATION_CODES:
|
codes: set[str],
|
||||||
_set(row, COL_CURRENCY_SIGN, "")
|
operation_fields: dict[str, str],
|
||||||
|
participant_fields: dict[str, str],
|
||||||
|
) -> None:
|
||||||
|
"""Правило 34: объединяет допустимые комментарии операции и участника."""
|
||||||
|
operation_comment = _pick_direct_payload_value(operation_fields, "Коммент")
|
||||||
|
participant_comment = ""
|
||||||
|
if codes & EXPORT_SUBSIDIARY_COMMENT_CODES:
|
||||||
|
participant_comment = _pick_direct_payload_value(
|
||||||
|
participant_fields, "КомментУчастник"
|
||||||
|
)
|
||||||
|
|
||||||
|
values = list(
|
||||||
|
dict.fromkeys(
|
||||||
|
value for value in (operation_comment, participant_comment) if value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
_set(row, COL_EXTRA_INFO, "; ".join(values))
|
||||||
|
|
||||||
|
|
||||||
def _rule_suspicious_activity(row: dict[int, str], codes: set[str]) -> None:
|
def _rule_suspicious_activity(row: dict[int, str], codes: set[str]) -> None:
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
"xml_path": "/ММ/ГГГГ",
|
"xml_path": "/ММ/ГГГГ",
|
||||||
"source_scope": "any",
|
"source_scope": "any",
|
||||||
"allow_short_lookup": true,
|
"allow_short_lookup": true,
|
||||||
"allow_direct_mapping": true,
|
"allow_direct_mapping": false,
|
||||||
"structured_value": false,
|
"structured_value": false,
|
||||||
"structured_group": "",
|
"structured_group": "",
|
||||||
"structured_role": "",
|
"structured_role": "",
|
||||||
@ -665,11 +665,11 @@
|
|||||||
"column_name": "Доп. сведения",
|
"column_name": "Доп. сведения",
|
||||||
"block": "operation_base",
|
"block": "operation_base",
|
||||||
"report_group": "operation_parameters",
|
"report_group": "operation_parameters",
|
||||||
"xml_tag": "КомментУчастник",
|
"xml_tag": "Коммент | КомментУчастник",
|
||||||
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОп/КомментУчастник",
|
"xml_path": "/СообщОперКО/ИнформЧасть/СведКО/Операция/Коммент | /СообщОперКО/ИнформЧасть/СведКО/Операция/УчастникОп/КомментУчастник",
|
||||||
"source_scope": "any",
|
"source_scope": "any",
|
||||||
"allow_short_lookup": true,
|
"allow_short_lookup": true,
|
||||||
"allow_direct_mapping": true,
|
"allow_direct_mapping": false,
|
||||||
"structured_value": false,
|
"structured_value": false,
|
||||||
"structured_group": "",
|
"structured_group": "",
|
||||||
"structured_role": "",
|
"structured_role": "",
|
||||||
|
|||||||
@ -937,7 +937,7 @@ def test_cp_block_is_empty_without_sved_cp_and_uses_emitent_inn_when_present() -
|
|||||||
assert row_with_cp[202] == "7707083893"
|
assert row_with_cp[202] == "7707083893"
|
||||||
|
|
||||||
|
|
||||||
def test_currency_columns_apply_only_to_conversion_and_currency_operations() -> None:
|
def test_currency_sign_is_preserved_independently_of_operation_code() -> None:
|
||||||
non_conversion = build_fixed_row_by_index(
|
non_conversion = build_fixed_row_by_index(
|
||||||
file_name="f.xml",
|
file_name="f.xml",
|
||||||
record_id="R1",
|
record_id="R1",
|
||||||
@ -950,7 +950,7 @@ def test_currency_columns_apply_only_to_conversion_and_currency_operations() ->
|
|||||||
participant_fields={},
|
participant_fields={},
|
||||||
)
|
)
|
||||||
assert non_conversion[26] == ""
|
assert non_conversion[26] == ""
|
||||||
assert non_conversion[27] == ""
|
assert non_conversion[27] == "VO"
|
||||||
|
|
||||||
conversion = build_fixed_row_by_index(
|
conversion = build_fixed_row_by_index(
|
||||||
file_name="f.xml",
|
file_name="f.xml",
|
||||||
@ -993,7 +993,95 @@ def test_currency_columns_apply_only_to_conversion_and_currency_operations() ->
|
|||||||
},
|
},
|
||||||
participant_fields={},
|
participant_fields={},
|
||||||
)
|
)
|
||||||
assert boundary_row[27] == ""
|
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:
|
def test_bank_bik_columns_accept_canonical_transfer_block_spelling() -> None:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user