120 lines
7.2 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.

"""Суммы из OCR-ячеек (§11.1 п. 7): перенос `_parse_amount`/`_is_blank` старого ядра."""
from decimal import Decimal
import pytest
from src.normalizer.ocr.amounts import ParsedAmount, is_blank, parse_amount
@pytest.mark.parametrize(
("raw", "amount", "verified"),
[
("13 070", Decimal("13070"), True),
("(6032409)", Decimal("-6032409"), True),
("(7744536}", Decimal("7744536"), False), # закрывающая скобка не распознана: минус не ставится (решение №12)
("1 234,56", Decimal("1234.56"), True),
("1.234.567", Decimal("1234567"), True), # точки строго через три цифры — разделители тысяч (AURORA-1405, #37)
("30127", Decimal("30127"), True),
("211(1 |", Decimal("2111"), False),
("не ****", None, False),
("", None, True),
("--", None, True), # прочерк: ничего не отброшено, суммы нет (NULL)
(":", None, False),
# несколько точек: удаляются ВСЕ точки, десятичная часть теряется (`1.234,56` — не 1234.56), всегда не verified
("1.234,56", Decimal("123456"), False),
("1,234.56", Decimal("123456"), False),
# запятая-разделитель тысяч (AURORA-1405, scan-gateway#35): удаляется до замены запятой на точку, verified=True
("1,234", Decimal("1234"), True),
("4,200", Decimal("4200"), True),
("(4,200)", Decimal("-4200"), True),
("1,234,567", Decimal("1234567"), True),
("-4,200", Decimal("-4200"), True),
("+4,200", Decimal("4200"), True),
("(-4,200)", Decimal("-4200"), True),
("4,2", Decimal("4.2"), True),
("12,34", Decimal("12.34"), True),
("1,23", Decimal("1.23"), True),
# не тысячи: больше двух знаков после запятой остаётся десятичным — `Money` отсекает `document._value` (№30)
("0,125", Decimal("0.125"), True),
("12,3456", Decimal("12.3456"), True),
("4,200,", Decimal("4200"), False), # хвостовая запятая: правило не применяется (две точки удалены, как раньше)
("(4,200}", Decimal("4.200"), False), # нет пары скобок: правило не применяется, минус не ставится
# скобки не на всю строку — правило тысяч не применяется, прежний разбор (запятая → точка)
("(4,200) руб", Decimal("-4.200"), False),
("abc(4,200)", Decimal("-4.200"), False),
("(4,200)x", Decimal("-4.200"), False),
("(4,200)(1,000)", Decimal("-4.200"), False),
("1,234(5,678)", Decimal("-5.678"), False),
("((4,200))", Decimal("-4.200"), True),
("1234,567", Decimal("1234.567"), True), # запятая НЕ расширена (R-7): четыре цифры до неё — не тысячи
("1 234,567", Decimal("1234.567"), True),
("01,234", Decimal("1.234"), True), # ведущий ноль — не тысячи
("4,2000", Decimal("4.2000"), True),
("1, 234", Decimal("1234"), True), # пробелы убираются первыми
# точка-разделитель тысяч (AURORA-1405, scan-gateway#37): то же правило, что для запятой, verified=True
("4.200", Decimal("4200"), True),
("837.994", Decimal("837994"), True),
("(4.200)", Decimal("-4200"), True),
("-4.200", Decimal("-4200"), True),
("+4.200", Decimal("4200"), True),
("(-4.200)", Decimal("-4200"), True),
("1.234", Decimal("1234"), True),
("100.000", Decimal("100000"), True),
("1. 234", Decimal("1234"), True), # пробелы убираются первыми
# ровно три цифры после точки — тысячи независимо от числа цифр до неё (R-3, решение владельца 16.10.2026)
("1 234.567", Decimal("1234567"), True),
("1234.567", Decimal("1234567"), True),
("12345.678", Decimal("12345678"), True),
("(1 234.567)", Decimal("-1234567"), True),
("-1234.567", Decimal("-1234567"), True),
("1234.567.890", Decimal("1234567890"), True),
# не тысячи: не три цифры после точки — десятичная дробь, как раньше
("4.2", Decimal("4.2"), True),
("4.20", Decimal("4.20"), True),
("12.34", Decimal("12.34"), True),
("1.2345", Decimal("1.2345"), True),
("0.125", Decimal("0.125"), True), # ведущий ноль — не тысячи
("01.234", Decimal("1.234"), True),
("1234.56", Decimal("1234.56"), True), # дробная часть не из трёх цифр — дробь
("1234.5678", Decimal("1234.5678"), True),
# смешанные разделители и прочий мусор — правило не применяется (R-1): прежний разбор
("1.234,567", Decimal("1234567"), False),
("1,234.567", Decimal("1234567"), False),
("1.234.56", Decimal("123456"), False),
("4.200.", Decimal("4200"), False), # хвостовая точка
("(4.200}", Decimal("4.200"), False), # нет пары скобок: правило не применяется, минус не ставится
("(4.200) руб", Decimal("-4.200"), False),
("abc(4.200)", Decimal("-4.200"), False),
("(4.200)(1.000)", Decimal("-4.200"), False),
("1.234(5.678)", Decimal("-5.678"), False),
# пробел внутри суммы допустим только как разделитель тысяч (AURORA-1511/1519): иначе догадка, verified=False
("42831 1", Decimal("428311"), False),
("1 2", Decimal("12"), False),
("1234 567", Decimal("1234567"), False),
("12 34", Decimal("1234"), False),
("1 2345", Decimal("12345"), False),
("(42831 1)", Decimal("-428311"), False),
("1 234,5 6", Decimal("1234.56"), False),
("12 345 678", Decimal("12345678"), True),
("(12 345)", Decimal("-12345"), True),
("-1 234", Decimal("-1234"), True),
("123 456", Decimal("123456"), True),
# №13: скобки без содержимого — не сумма, но и не «неразобранный текст»
("()", None, True),
("( )", None, True),
("(.)", None, True),
("(+5)", Decimal("-5"), True), # в скобках знак заменяется минусом
],
)
def test_parse_amount(raw: str, amount: Decimal | None, verified: bool) -> None:
assert parse_amount(raw) == ParsedAmount(amount, verified)
@pytest.mark.parametrize(
("raw", "expected"),
[("", True), ("-", True), ("—", True), (" – ", True), ("0", False), ("x", False)],
)
def test_is_blank(raw: str, expected: bool) -> None:
assert is_blank(raw) is expected