Шахматка: зелёный make check (#114)

- Убраны отладочные print() в режиме MANUAL.
- mypy: computed_field у is_debit/is_credit — с type: ignore[prop-decorator],
  как у остальных схем; флаг is_more_5_percent без сравнения Decimal с None
  (поведение прежнее).
- ruff format по трём файлам.
- test_openapi_routes: новые маршруты шахматки и правил элиминации
  в EXPECTED_ROUTES.

make check: ruff, ruff format, mypy — чисто; pytest 1303 passed, 44 skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-15 18:37:23 +04:00
parent 4390ce8f27
commit 1ebd5b9997
6 changed files with 33 additions and 14 deletions

View File

@ -17,5 +17,5 @@ router = APIRouter()
summary="Список счетов плана счетов",
)
async def list_accounts(session: SessionDep) -> list[AccountOut]:
""" Все счета одним списком """
"""Все счета одним списком"""
return [AccountOut.model_validate(account) for account in await repo.list_accounts(session)]

View File

@ -51,13 +51,13 @@ class AccountOut(BaseModel):
row_type: AccountRowType
is_off_balance: bool
@computed_field
@computed_field # type: ignore[prop-decorator]
@property
def is_debit(self) -> bool:
"""Счёт можно выбрать для дебетовой стороны: активный или активно-пассивный."""
return self.kind in (AccountKind.A, AccountKind.AP)
@computed_field
@computed_field # type: ignore[prop-decorator]
@property
def is_credit(self) -> bool:
"""Счёт можно выбрать для кредитовой стороны: пассивный или активно-пассивный."""

View File

@ -129,7 +129,7 @@ def calculate_matrix(
variance_amount = abs(amount_a - amount_b)
base = min(amount_a, amount_b)
variance_percent = None if base == ZERO else variance_amount / base * 100
is_more_5_percent = False if base == ZERO else variance_percent > VARIANCE_THRESHOLD_PERCENT
is_more_5_percent = variance_percent is not None and variance_percent > VARIANCE_THRESHOLD_PERCENT
cells.append(
IntercompanyMatrixCellOut(
company_a_id=company_a,
@ -303,8 +303,6 @@ class IntercompanyMatrixService:
raise DomainValidationError("ACCOUNTS_REQUIRED", "Выберите дебетовые и кредитовые счета")
debit = _selected_accounts(debit_account_ids, (), "D", by_id, children)
credit = _selected_accounts(credit_account_ids, (), "K", by_id, children)
print(debit)
print(credit)
else:
raise DomainValidationError("INVALID_MODE", "Неизвестный режим выбора счетов")
selection = MatrixSelection(debit, credit, "closing")

View File

@ -13,16 +13,31 @@ async def test_accounts_are_flat_and_naturally_sorted() -> None:
root_id, sub_id = uuid.uuid4(), uuid.uuid4()
rows = [
SimpleNamespace(
id=sub_id, code="60.10", parent_id=root_id, name="Авансы", kind=AccountKind.A,
row_type=AccountRowType.subaccount, is_off_balance=False,
id=sub_id,
code="60.10",
parent_id=root_id,
name="Авансы",
kind=AccountKind.A,
row_type=AccountRowType.subaccount,
is_off_balance=False,
),
SimpleNamespace(
id=root_id, code="60", parent_id=None, name="Расчёты", kind=AccountKind.AP,
row_type=AccountRowType.account, is_off_balance=False,
id=root_id,
code="60",
parent_id=None,
name="Расчёты",
kind=AccountKind.AP,
row_type=AccountRowType.account,
is_off_balance=False,
),
SimpleNamespace(
id=uuid.uuid4(), code="60.2", parent_id=root_id, name="Поставщики", kind=AccountKind.P,
row_type=AccountRowType.subaccount, is_off_balance=False,
id=uuid.uuid4(),
code="60.2",
parent_id=root_id,
name="Поставщики",
kind=AccountKind.P,
row_type=AccountRowType.subaccount,
is_off_balance=False,
),
]
session = SimpleNamespace(scalars=AsyncMock(return_value=SimpleNamespace(all=lambda: rows)))

View File

@ -87,8 +87,7 @@ def test_matrix_export_has_three_rows_per_debit_company_and_highlights_threshold
assert middle.border.bottom.style is None
assert bottom.border.bottom.style == "thin"
assert all(
cell.border.left.style == "thin" and cell.border.right.style == "thin"
for cell in (top, middle, bottom)
cell.border.left.style == "thin" and cell.border.right.style == "thin" for cell in (top, middle, bottom)
)

View File

@ -73,6 +73,13 @@ EXPECTED_ROUTES: dict[str, set[str]] = {
"/api/v1/consolidations/versions/{version_id}/osv/export": {"get"},
"/api/v1/consolidations/versions/{version_id}/counterparty-candidates": {"get"},
"/api/v1/consolidations/versions/{version_id}/osv/entries/{entry_id}/counterparty": {"post"},
# шахматка ВГО и правила элиминации
"/api/v1/consolidations/versions/{version_id}/elimination-rules": {"get"},
"/api/v1/consolidations/versions/{version_id}/intercompany-matrix/all": {"get"},
"/api/v1/consolidations/versions/{version_id}/intercompany-matrix/all/export": {"get"},
"/api/v1/consolidations/versions/{version_id}/intercompany-matrix/manual": {"post"},
"/api/v1/consolidations/versions/{version_id}/intercompany-matrix/manual/export": {"post"},
"/api/v1/consolidations/versions/{version_id}/intercompany-matrix/result-table": {"get"},
}
# Префиксы, под которыми маршрутов сверх EXPECTED_ROUTES быть не должно