fix(matrix): ограничить PRESET правилами ББ
This commit is contained in:
parent
e9dc67b2e9
commit
38c8eefa18
@ -16,7 +16,7 @@ from src.domain.policy import VisibilityScope
|
||||
from src.models.accounting import ChartOfAccount, EliminationRule
|
||||
from src.models.consolidation import Consolidation, ConsolidationVersion
|
||||
from src.models.directories import CompanyGroup
|
||||
from src.models.enums import AccountKind, PeriodQuarter
|
||||
from src.models.enums import AccountKind, PeriodQuarter, StatementType
|
||||
from src.repositories import directories as directory_repo
|
||||
from src.repositories import elimination_rules as elimination_rules_repo
|
||||
from src.schemas.consolidations import (
|
||||
@ -419,6 +419,8 @@ class IntercompanyMatrixService:
|
||||
rule, rule_accounts = await elimination_rules_repo.rule_with_account(self._session, rule_id)
|
||||
if rule is None or not elimination_rules_repo.is_valid_for_version(rule, version.elimination_rules_version):
|
||||
raise NotFoundError("правило-пресет не найдено для версии консолидации")
|
||||
if rule.statement_type != StatementType.balance:
|
||||
raise DomainValidationError("INVALID_RULE", "Шахматка PRESET поддерживает только правила ББ")
|
||||
if rule.side_1 not in ("D", "K") or rule.measure not in ("closing", "turnover"):
|
||||
raise DomainValidationError("INVALID_RULE", "Неверное направление или показатель правила-пресета")
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ from src.models.accounting import ChartOfAccount, EliminationRule
|
||||
from src.models.audit_ex import AuditEvent
|
||||
from src.models.consolidation import ConsolidationDocument, ConsolidationVersion
|
||||
from src.models.directories import CompanyGroup, LegalEntity, RegionalOffice
|
||||
from src.models.enums import AuditAction, AuditSection, CounterpartyMatchKind, PeriodQuarter
|
||||
from src.models.enums import AuditAction, AuditSection, CounterpartyMatchKind, PeriodQuarter, StatementType
|
||||
from src.models.osv import OsvEntry
|
||||
from src.repositories import consolidations as consolidation_repo
|
||||
from src.repositories import directories as directory_repo
|
||||
@ -179,6 +179,23 @@ async def test_preset_uses_rule_sides_and_exclusions(auth_client: AuthClientFact
|
||||
assert audit.after_value["rule_id"] == str(rule.id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("suffix", ["", "/export"])
|
||||
async def test_preset_rejects_income_rule(auth_client: AuthClientFactory, seeded: AsyncSession, suffix: str) -> None:
|
||||
world = await _world(seeded)
|
||||
rule = (
|
||||
await seeded.scalars(select(EliminationRule).where(EliminationRule.rule_no == RECEIVABLES_PAYABLES_RULE_NO))
|
||||
).one()
|
||||
rule.statement_type = StatementType.income
|
||||
await seeded.flush()
|
||||
|
||||
client = await auth_client(KA_RF)
|
||||
response = await client.get(
|
||||
f"/consolidations/versions/{world.version.id}/intercompany-matrix/preset/{rule.id}{suffix}"
|
||||
)
|
||||
assert response.status_code == UNPROCESSABLE, response.text
|
||||
assert response.json()["detail"]["code"] == "INVALID_RULE"
|
||||
|
||||
|
||||
async def test_preset_unpaired_osv_returns_rows_and_total(auth_client: AuthClientFactory, seeded: AsyncSession) -> None:
|
||||
world = await _world(seeded)
|
||||
rule = (
|
||||
|
||||
@ -7,9 +7,10 @@ from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
from fastapi import status as http_status
|
||||
|
||||
from src.api.endpoints.consolidations.intercompany_matrix import router
|
||||
from src.models.enums import AccountKind
|
||||
from src.models.enums import AccountKind, StatementType
|
||||
from src.schemas.consolidations import (
|
||||
IntercompanyMatrixCellOut,
|
||||
IntercompanyMatrixCompanyOut,
|
||||
@ -128,6 +129,7 @@ async def test_preset_applies_exclusions_to_its_own_side_and_rule_measure(monkey
|
||||
monkeypatch.setattr(matrix.directory_repo, "list_accounts", AsyncMock(return_value=[parent, child]))
|
||||
rule = SimpleNamespace(
|
||||
id=uuid.uuid4(),
|
||||
statement_type=StatementType.balance,
|
||||
version_no=1,
|
||||
side_1="D",
|
||||
measure="turnover",
|
||||
@ -162,6 +164,22 @@ async def test_preset_applies_exclusions_to_its_own_side_and_rule_measure(monkey
|
||||
assert info.measure == "turnover"
|
||||
|
||||
|
||||
async def test_preset_rejects_income_rule_before_selecting_accounts(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
rule = SimpleNamespace(
|
||||
statement_type=StatementType.income,
|
||||
version_no=1,
|
||||
valid_to=None,
|
||||
)
|
||||
monkeypatch.setattr(matrix.elimination_rules_repo, "rule_with_account", AsyncMock(return_value=(rule, [])))
|
||||
service = matrix.IntercompanyMatrixService(object(), None, object())
|
||||
|
||||
with pytest.raises(matrix.DomainValidationError) as error:
|
||||
await service._resolve_preset_selection(uuid.uuid4(), SimpleNamespace(elimination_rules_version=1), {}, {})
|
||||
|
||||
assert error.value.status == http_status.HTTP_422_UNPROCESSABLE_CONTENT
|
||||
assert error.value.code == "INVALID_RULE"
|
||||
|
||||
|
||||
def test_one_sided_reflects_osv_sources_even_when_amount_is_zero() -> None:
|
||||
company_a, company_b = uuid.uuid4(), uuid.uuid4()
|
||||
debit_account, credit_account = uuid.uuid4(), uuid.uuid4()
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
`closing` — конечное сальдо (`closing_debit`/`closing_credit`), `turnover` — обороты (`turnover_debit`/`turnover_credit`).
|
||||
Правило SHALL быть действительным для версии консолидации: при заданном `elimination_rules_version` — с тем же
|
||||
`version_no`, иначе — без `valid_to`; несуществующее или недействительное правило SHALL давать 404. Ошибки 422:
|
||||
`RULE_REQUIRED` — правило не выбрано, `INVALID_RULE` — неверные `side_1`, `measure` или сторона счёта правила,
|
||||
`RULE_REQUIRED` — правило не выбрано, `INVALID_RULE` — правило ОФР либо неверные `side_1`, `measure` или сторона счёта правила,
|
||||
`ACCOUNTS_REQUIRED` — у одной из сторон нет счетов. Невидимая и несуществующая версия SHALL отвечать 404 `NOT_FOUND`.
|
||||
|
||||
#### Scenario: Пресет по сальдо
|
||||
@ -28,6 +28,10 @@
|
||||
- **WHEN** `rule_id` не существует
|
||||
- **THEN** 404
|
||||
|
||||
#### Scenario: Правило ОФР
|
||||
- **WHEN** у правила `statement_type = income`
|
||||
- **THEN** расчёт и выгрузка возвращают 422 `INVALID_RULE`
|
||||
|
||||
### Requirement: Строки сводной ОСВ без пары по пресету
|
||||
`GET /api/v1/consolidations/versions/{version_id}/intercompany-matrix/preset/{rule_id}/unpaired-osv`
|
||||
(`CONSOLIDATION_VIEW`, policy) SHALL возвращать `{items, total}`: все строки сводной ОСВ версии, чьи записи ОСВ
|
||||
|
||||
@ -9,6 +9,6 @@
|
||||
`correction_ids_*`) вместе с тестами; код выделен в `AURORA-1747`.
|
||||
- [ ] 2.1a Убрать ручку `unpaired-osv` (`get_unpaired_rows`, `UnpairedOsvOut`, маршрут) вместе с тестами;
|
||||
код сохранён в `wip/shahmatka-corrections-unpaired`.
|
||||
- [ ] 2.2 PRESET — только правила `statement_type = balance`; правило ОФР — 422 `INVALID_RULE`, тест.
|
||||
- [x] 2.2 PRESET — только правила `statement_type = balance`; правило ОФР — 422 `INVALID_RULE`, тест.
|
||||
- [ ] 2.3 Несколько открытых `version_no` — одна версия (max) или явная ошибка, тест.
|
||||
- [ ] 2.4 Ревьюер: убрать из дельты `consolidated-osv` требования про корректировки и `unpaired-osv`, обновить README.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user