"""Проверка ввода строки до обращения к хранилищу.""" from decimal import Decimal from http import HTTPStatus import pytest from sqlalchemy import func, select from src.api.dependencies.audit import RequestAudit from src.common.exceptions import ConflictError, DomainValidationError from src.models.audit_ex import AuditEvent from src.models.enums import AuditAction from src.models.kfo import Goodwill, KfoResult from src.models.osv import OsvEntry from src.models.statements import FinancialStatementValue from src.schemas.goodwill import GoodwillRowIn from src.services.goodwill import validate_decision from tests.test_api_consolidated_osv import KA_RF from tests.test_api_goodwill import goodwill_world @pytest.mark.parametrize( "value", ["-1", "100.01", "100.0001", "80.123", "80,123", "12.3456", "1e2", "NaN", "Infinity", "abc", ""] ) def test_invalid_share(value): with pytest.raises(DomainValidationError) as error: validate_decision(GoodwillRowIn(ownership_share=value, include_in_kfo=False)) assert error.value.code == "INVALID_SHARE" @pytest.mark.parametrize("value", ["0", "100", "7.5", "80.12", "80,12"]) def test_valid_share(value): result = validate_decision(GoodwillRowIn(ownership_share=value, include_in_kfo=True, comment=" Обоснование ")) assert str(result.ownership_share) == value.replace(",", ".") assert result.comment == "Обоснование" def test_required_fields(): assert validate_decision(GoodwillRowIn(ownership_share=None, include_in_kfo=False)).ownership_share is None with pytest.raises(DomainValidationError) as error: validate_decision(GoodwillRowIn(ownership_share=None, include_in_kfo=True, comment="Да")) assert error.value.code == "INVALID_SHARE" with pytest.raises(DomainValidationError) as error: validate_decision(GoodwillRowIn(ownership_share="100", include_in_kfo=True, comment=" ")) assert error.value.code == "COMMENT_REQUIRED" @pytest.mark.integration @pytest.mark.fixtures async def test_save_settings_and_disappearing_pair(db_session, auth_client, fixtures_dir): w = await goodwill_world(db_session, fixtures_dir) client = await auth_client(KA_RF) base = f"/consolidations/versions/{w.version.id}" path = base + f"/goodwill/{w.a.id}/{w.b.id}" body = dict(ownership_share="80.12", include_in_kfo=True, comment="Подтверждено") response = await client.put(path, json=body) assert response.status_code == HTTPStatus.CONFLICT and response.json()["detail"]["code"] == "LOCK_REQUIRED" assert (await client.post(base + "/lock")).status_code == HTTPStatus.CREATED other = await auth_client("rka@armka.local") rejected = await other.put(path, json=body) assert rejected.status_code == HTTPStatus.CONFLICT assert rejected.json()["detail"]["code"] == "LOCKED_BY_OTHER" response = await client.put(path, json=body) assert response.status_code == HTTPStatus.OK, response.text row = response.json() assert row["ownership_share"] == "80.12" assert row["participation_amount"] == "80120000.00" assert row["goodwill_amount"] == "189877300.00" again = await client.put(path, json=body) assert again.status_code == HTTPStatus.OK assert await db_session.scalar(select(func.count()).select_from(Goodwill)) == 1 on = await client.put(base + "/goodwill-settings", json=dict(goodwill_enabled=True)) assert on.status_code == HTTPStatus.OK assert on.json()["totals"]["goodwill_in_kfo_amount"] == "189877300.00" audit_count = await db_session.scalar( select(func.count()).select_from(AuditEvent).where(AuditEvent.action == AuditAction.GOODWILL_EDIT) ) assert ( await client.put(base + "/goodwill-settings", json=dict(goodwill_enabled=True)) ).status_code == HTTPStatus.OK assert audit_count == await db_session.scalar( select(func.count()).select_from(AuditEvent).where(AuditEvent.action == AuditAction.GOODWILL_EDIT) ) off = await client.put(base + "/goodwill-settings", json=dict(goodwill_enabled=False)) assert off.json()["totals"]["goodwill_in_kfo_amount"] == "0.00" assert off.json()["rows"][0]["ownership_share"] == "80.12" body["include_in_kfo"] = False assert (await client.put(path, json=body)).status_code == HTTPStatus.OK assert (await client.get(base + "/goodwill")).json()["totals"]["goodwill_amount"] == "0.00" entries = list( ( await db_session.scalars( select(OsvEntry).where(OsvEntry.account_code == "58.01", OsvEntry.owner_legal_entity_id == w.a.id) ) ).all() ) for entry in entries: entry.closing_debit = 0 await db_session.flush() row = (await client.get(base + "/goodwill")).json()["rows"][0] assert not row["has_investments"] and row["goodwill_amount"] is None assert row["comment"] == "Подтверждено" assert (await client.put(path, json=body)).status_code == HTTPStatus.OK body["include_in_kfo"] = True response = await client.put(path, json=body) assert response.status_code == HTTPStatus.OK assert response.json()["financial_investment_amount"] is None assert response.json()["goodwill_amount"] is None assert await db_session.scalar(select(func.count()).select_from(KfoResult)) == 0 @pytest.mark.integration @pytest.mark.fixtures async def test_mutation_validation_and_rollback(db_session, auth_client, fixtures_dir, monkeypatch): w = await goodwill_world(db_session, fixtures_dir) client = await auth_client(KA_RF) base = f"/consolidations/versions/{w.version.id}" path = base + f"/goodwill/{w.a.id}/{w.b.id}" assert (await client.post(base + "/lock")).status_code == HTTPStatus.CREATED body = dict(ownership_share="100", include_in_kfo=True, comment="") response = await client.put(path, json=body) assert ( response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY and response.json()["detail"]["code"] == "COMMENT_REQUIRED" ) body.update(ownership_share="100.00001", comment="Да") assert (await client.put(path, json=body)).json()["detail"]["code"] == "INVALID_SHARE" assert await db_session.scalar(select(func.count()).select_from(Goodwill)) == 0 async def reject_audit(*args, **kwargs): raise ConflictError("TEST_AUDIT_FAILURE", "Ошибка тестового аудита") monkeypatch.setattr(RequestAudit, "record", reject_audit) body["ownership_share"] = "100" response = await client.put(path, json=body) assert response.status_code == HTTPStatus.CONFLICT assert await db_session.scalar(select(func.count()).select_from(Goodwill)) == 0 @pytest.mark.integration @pytest.mark.fixtures async def test_money_overflow_keeps_database_unchanged(db_session, auth_client, fixtures_dir): w = await goodwill_world(db_session, fixtures_dir) client = await auth_client(KA_RF) base = f"/consolidations/versions/{w.version.id}" assert (await client.post(base + "/lock")).status_code == HTTPStatus.CREATED value = (await db_session.scalars(select(FinancialStatementValue))).one() value.amount = Decimal("9999999999999999.99") await db_session.flush() response = await client.put( base + f"/goodwill/{w.a.id}/{w.b.id}", json=dict(ownership_share="100", include_in_kfo=True, comment="Проверка") ) assert response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY assert response.json()["detail"]["code"] == "MONEY_OUT_OF_RANGE" assert await db_session.scalar(select(func.count()).select_from(Goodwill)) == 0