Enum counterparty_match_kind (INN, NAME, ALIAS, MANUAL, PROPAGATED) и nullable-колонка osv_entry.counterparty_match_kind (NULL <=> counterparty_id NULL). Миграция 0004_dbml_v5_16: enum, колонка, backfill тремя UPDATE по уже смапленным строкам (ИНН без пробелов -> INN, trim(имя) -> NAME, остальные -> ALIAS), откат удаляет колонку и тип. CounterpartyIndex.resolve возвращает Resolution(entity_id, kind) (определение в domain/osv_mapping, R-4); маппинг пишет kind; EntryOut.match_kind. DBML_VERSION 5.16, Makefile/dbml_parity/CLAUDE/README/config.yaml. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
68 lines
2.4 KiB
Python
68 lines
2.4 KiB
Python
"""Enum'ы ORM против блоков `Enum {}` DBML v5.16: имена, значения и их порядок (без БД)."""
|
|
|
|
import enum
|
|
import re
|
|
|
|
import pytest
|
|
from sqlalchemy import Enum as SAEnum
|
|
|
|
from src.models import DBML_VERSION
|
|
from src.models.enums import ENUMS, pg_enum
|
|
from tests.dbml_helpers import dbml_path, load_dbml
|
|
|
|
EXPECTED_ENUM_COUNT = 28
|
|
|
|
|
|
def test_dbml_version_format() -> None:
|
|
assert re.fullmatch(r"\d+\.\d+", DBML_VERSION)
|
|
assert DBML_VERSION == "5.16"
|
|
assert f"v{DBML_VERSION}" in dbml_path().name
|
|
|
|
|
|
def test_osv_data_type_has_nu_after_bu() -> None:
|
|
"""v5.15: налоговый учёт (`NU`) идёт сразу после `BU` — порядок DBML."""
|
|
assert [m.value for m in ENUMS["osv_data_type"]] == ["BU", "NU", "CURRENCY", "QUANTITY", "SUM"]
|
|
|
|
|
|
def test_counterparty_match_kind_values() -> None:
|
|
"""v5.16: способ сопоставления контрагента — пять значений в порядке DBML."""
|
|
assert [m.value for m in ENUMS["counterparty_match_kind"]] == ["INN", "NAME", "ALIAS", "MANUAL", "PROPAGATED"]
|
|
|
|
|
|
def test_enums_count_and_names_match_dbml() -> None:
|
|
dbml_enums = {e.name for e in load_dbml().enums}
|
|
assert len(dbml_enums) == EXPECTED_ENUM_COUNT
|
|
assert set(ENUMS) == dbml_enums
|
|
|
|
|
|
def test_enum_values_match_dbml_in_order() -> None:
|
|
for dbml_enum in load_dbml().enums:
|
|
expected = [item.name for item in dbml_enum.items]
|
|
actual = [m.value for m in ENUMS[dbml_enum.name]]
|
|
assert actual == expected, f"enum {dbml_enum.name}: ожидалось {expected}, фактически {actual}"
|
|
|
|
|
|
def test_enum_classes_are_str_enums_with_member_name_equal_value() -> None:
|
|
for name, cls in ENUMS.items():
|
|
assert issubclass(cls, enum.Enum) and issubclass(cls, str), name
|
|
assert [m.name for m in cls] == [m.value for m in cls], name
|
|
|
|
|
|
def test_cyrillic_values_kept_verbatim() -> None:
|
|
assert [m.value for m in ENUMS["entity_type"]] == ["ЮЛ", "ИП"]
|
|
|
|
|
|
def test_pg_enum_factory_gives_dbml_named_type_in_dkb_schema() -> None:
|
|
for name, cls in ENUMS.items():
|
|
sa_enum = pg_enum(name)
|
|
assert isinstance(sa_enum, SAEnum)
|
|
assert sa_enum.name == name
|
|
assert sa_enum.schema == "dkb"
|
|
assert sa_enum.native_enum is True
|
|
assert sa_enum.enums == [m.value for m in cls], name
|
|
|
|
|
|
def test_pg_enum_unknown_name_fails() -> None:
|
|
with pytest.raises(KeyError):
|
|
pg_enum("no_such_enum")
|