- domain/inn.py: нормализация и проверка ИНН (ЮЛ — 10, ИП — 12 цифр 0–9), ASSUMPTION(OQ-88)
- репозиторий: список ЮЛ с видимостью и фильтрами (company_group_id, outside_group, inn точно, q по name/inn),
карточка, история (по убыванию valid_from), текущие членства, close_memberships (SCD2), алиасы
- LegalEntityService: create (INN_EXISTS, CRM_ID_EXISTS, ГК через scope → 404, филиал по умолчанию — филиал ГК),
update (no-op без истории; снимок UPDATE), move (MOVE_TO_GROUP, закрытие членств, MEMBERSHIP_CHANGE),
withdraw (CLOSE / REMOVE_FROM_GROUP), effective_date ≥ сегодня — ASSUMPTION(OQ-21)
- эндпоинты /directories/legal-entities: GET/POST, GET/PATCH /{id}, /{id}/move, /{id}/withdraw, /{id}/history
- тесты: unit ИНН, интеграционные сценарии спеки, Review Focus 1–3, откат мутации
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
50 lines
1.9 KiB
Python
50 lines
1.9 KiB
Python
"""ИНН: нормализация и проверка длины по типу (spec directories-api; ASSUMPTION(OQ-88) — только длина)."""
|
||
|
||
import pytest
|
||
|
||
from src.common.exceptions import DomainValidationError
|
||
from src.domain.inn import INN_LENGTH, normalize_inn, validate_inn
|
||
from src.models.enums import EntityType
|
||
|
||
|
||
def test_legal_entity_inn_has_ten_digits() -> None:
|
||
assert validate_inn("3528052718", EntityType.ЮЛ) == "3528052718"
|
||
|
||
|
||
def test_sole_proprietor_inn_has_twelve_digits() -> None:
|
||
assert validate_inn("352805271812", EntityType.ИП) == "352805271812"
|
||
|
||
|
||
def test_leading_zero_is_valid_and_kept() -> None:
|
||
"""Review Focus 2: ИНН — строка, ведущий ноль не теряется."""
|
||
assert validate_inn("0123456789", EntityType.ЮЛ) == "0123456789"
|
||
|
||
|
||
def test_ten_digits_for_sole_proprietor_is_invalid() -> None:
|
||
with pytest.raises(DomainValidationError) as error:
|
||
validate_inn("3528052718", EntityType.ИП)
|
||
assert error.value.code == "INVALID_INN"
|
||
assert error.value.message == "ИНН ИП — ровно 12 цифр"
|
||
|
||
|
||
@pytest.mark.parametrize("raw", ["35280527AB", "LV12345678", "нерез.", "", "35280527181"])
|
||
def test_non_digits_or_wrong_length_is_invalid(raw: str) -> None:
|
||
with pytest.raises(DomainValidationError) as error:
|
||
validate_inn(raw, EntityType.ЮЛ)
|
||
assert error.value.code == "INVALID_INN"
|
||
|
||
|
||
def test_non_ascii_digits_are_invalid() -> None:
|
||
"""Арабско-индийские цифры проходят `str.isdigit`, но ИНН — только 0–9."""
|
||
with pytest.raises(DomainValidationError):
|
||
validate_inn("٣٥٢٨٠٥٢٧١٨", EntityType.ЮЛ)
|
||
|
||
|
||
def test_spaces_inside_are_removed() -> None:
|
||
assert normalize_inn(" 3528 052\t718 ") == "3528052718"
|
||
assert validate_inn("35 28 05 27 18", EntityType.ЮЛ) == "3528052718"
|
||
|
||
|
||
def test_lengths_by_entity_type() -> None:
|
||
assert INN_LENGTH == {EntityType.ЮЛ: 10, EntityType.ИП: 12}
|