105 lines
4.3 KiB
Python
105 lines
4.3 KiB
Python
"""Плоский справочник счетов: все уровни и порядок кодов."""
|
|
|
|
import uuid
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
from src.api.endpoints.directories import accounts as accounts_endpoint
|
|
from src.api.endpoints.directories.accounts import list_accounts
|
|
from src.app import app
|
|
from src.models.enums import AccountKind, AccountRowType
|
|
from src.repositories.directories import list_accounts as query_accounts
|
|
from src.schemas.directories import AccountFilter
|
|
|
|
|
|
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,
|
|
),
|
|
SimpleNamespace(
|
|
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,
|
|
),
|
|
]
|
|
session = SimpleNamespace(scalars=AsyncMock(return_value=SimpleNamespace(all=lambda: rows)))
|
|
|
|
assert [item.code for item in await query_accounts(session)] == ["60", "60.2", "60.10"]
|
|
response = await list_accounts(session, AccountFilter())
|
|
assert [item.code for item in response] == ["60", "60.2", "60.10"]
|
|
assert response[0].parent_id is None
|
|
assert response[2].parent_id == root_id
|
|
assert response[2].id == sub_id
|
|
assert [item.model_dump(mode="json")["is_debit"] for item in response] == [True, False, True]
|
|
assert [item.model_dump(mode="json")["is_credit"] for item in response] == [True, True, False]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("filters", "expected_columns"),
|
|
[
|
|
({}, set()),
|
|
({"kind": [AccountKind.A]}, {"kind"}),
|
|
({"kind": [AccountKind.A, AccountKind.AP]}, {"kind"}),
|
|
({"row_type": AccountRowType.analytic}, {"row_type"}),
|
|
({"is_off_balance": False}, {"is_off_balance"}),
|
|
(
|
|
{"kind": [AccountKind.AP, AccountKind.P], "row_type": AccountRowType.account, "is_off_balance": True},
|
|
{"kind", "row_type", "is_off_balance"},
|
|
),
|
|
],
|
|
)
|
|
async def test_account_filters_apply_only_when_supplied(filters: dict, expected_columns: set[str]) -> None:
|
|
session = SimpleNamespace(scalars=AsyncMock(return_value=SimpleNamespace(all=list)))
|
|
|
|
assert await query_accounts(session, **filters) == []
|
|
statement = session.scalars.await_args.args[0]
|
|
where_clause = str(statement.whereclause) if statement.whereclause is not None else ""
|
|
for column in ("kind", "row_type", "is_off_balance"):
|
|
assert (f"chart_of_account.{column} " in where_clause) == (column in expected_columns)
|
|
if "kind" in filters:
|
|
assert "chart_of_account.kind IN" in where_clause
|
|
assert statement.compile().params["kind_1"] == filters["kind"]
|
|
|
|
|
|
async def test_account_endpoint_forwards_all_filters(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
query = AsyncMock(return_value=[])
|
|
monkeypatch.setattr(accounts_endpoint.repo, "list_accounts", query)
|
|
session = SimpleNamespace()
|
|
|
|
filters = AccountFilter(kind=[AccountKind.AP, AccountKind.P], row_type=AccountRowType.account, is_off_balance=False)
|
|
assert await list_accounts(session, filters) == []
|
|
query.assert_awaited_once_with(
|
|
session, kind=[AccountKind.AP, AccountKind.P], row_type=AccountRowType.account, is_off_balance=False
|
|
)
|
|
|
|
|
|
def test_account_filters_are_optional_query_parameters() -> None:
|
|
parameters = app.openapi()["paths"]["/api/v1/directories/accounts"]["get"]["parameters"]
|
|
assert {item["name"] for item in parameters} == {"kind", "row_type", "is_off_balance"}
|
|
assert all(item["in"] == "query" and item["required"] is False for item in parameters)
|
|
kind = next(item for item in parameters if item["name"] == "kind")
|
|
assert kind["schema"]["anyOf"][0]["type"] == "array"
|