I-1: сохранённая доля неактивной строки нормализуется (numeric(7,4) читается как 80.1200) и не даёт INVALID_SHARE при null в пакете; экспорт помечает строку «Нет вложений» (сценарий спеки); design/tasks/docstring без устаревшего «построчного» PUT, R-7/R-8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
4.7 KiB
Python
92 lines
4.7 KiB
Python
"""XLSX: пустые расчёты, группировка, итоги и аудит через настоящий API."""
|
||
|
||
from http import HTTPStatus
|
||
from io import BytesIO
|
||
|
||
import pytest
|
||
from openpyxl import load_workbook
|
||
from sqlalchemy import select, update
|
||
|
||
from src.models.audit_ex import AuditEvent
|
||
from src.models.enums import AuditAction
|
||
from src.models.osv import OsvEntry
|
||
from tests.test_api_consolidated_osv import KA_RF
|
||
from tests.test_api_goodwill import batch, goodwill_world
|
||
|
||
INVESTMENT_AMOUNT = 269997300
|
||
FRONTEND_COLUMN_COUNT = 8
|
||
EMPTY_EXPORT_ROW_COUNT = 2
|
||
|
||
pytestmark = [pytest.mark.integration, pytest.mark.fixtures]
|
||
|
||
|
||
async def test_export_matches_server_table(db_session, auth_client, fixtures_dir):
|
||
world = await goodwill_world(db_session, fixtures_dir)
|
||
client = await auth_client(KA_RF)
|
||
base = f"/consolidations/versions/{world.version.id}"
|
||
response = await client.get(base + "/goodwill/export")
|
||
assert response.status_code == HTTPStatus.OK, response.text
|
||
assert "filename*=" in response.headers["content-disposition"]
|
||
sheet = load_workbook(BytesIO(response.content)).active
|
||
assert sheet.max_column == FRONTEND_COLUMN_COUNT
|
||
assert sheet.cell(1, 1).value == "Учет в отчете"
|
||
assert sheet.cell(1, 2).value == "Наименование дочерней организации"
|
||
assert sheet.cell(2, 2).value == world.a.name
|
||
assert sheet.cell(3, 2).value == world.b.name
|
||
assert sheet.cell(3, 4).value == INVESTMENT_AMOUNT
|
||
assert sheet.cell(3, 5).value is None
|
||
assert sheet.cell(3, 7).value is None
|
||
assert sheet.cell(4, 2).value == "Всего"
|
||
assert sheet.cell(5, 2).value == "Итого по листу"
|
||
assert sheet.cell(5, 4).value == sheet.cell(4, 4).value == sheet.cell(3, 4).value
|
||
assert sheet.cell(5, 4).fill.patternType is None
|
||
event = (await db_session.scalars(select(AuditEvent).where(AuditEvent.action == AuditAction.EXPORT))).one()
|
||
assert event.after_value == {"report": "goodwill", "rows": 1}
|
||
# Нерассчитанные строки не считаются нулевыми; итоги фильтр не меняет (PDF §4).
|
||
filtered = await client.get(base + "/goodwill/export?sign=zero")
|
||
filtered_sheet = load_workbook(BytesIO(filtered.content)).active
|
||
assert filtered_sheet.max_row == EMPTY_EXPORT_ROW_COUNT
|
||
assert filtered_sheet.cell(2, 2).value == "Итого по листу"
|
||
assert filtered_sheet.cell(2, 4).value == INVESTMENT_AMOUNT
|
||
assert (await client.get(base + "/goodwill/export?sign=unknown")).status_code == HTTPStatus.UNPROCESSABLE_ENTITY
|
||
assert (await client.post(base + "/lock")).status_code == HTTPStatus.CREATED
|
||
body = dict(ownership_share="100", include_in_kfo=True, comment="=1+1")
|
||
assert (
|
||
await client.put(base + "/goodwill", json=batch(world.a.id, world.b.id, **body))
|
||
).status_code == HTTPStatus.OK
|
||
response = await client.get(base + "/goodwill/export")
|
||
sheet = load_workbook(BytesIO(response.content)).active
|
||
assert sheet.cell(3, 8).data_type == "s"
|
||
assert sheet.cell(3, 8).value == "=1+1"
|
||
assert sheet.cell(3, 7).value == sheet.cell(5, 7).value
|
||
filtered = await client.get(base + "/goodwill/export?sign=negative")
|
||
filtered_sheet = load_workbook(BytesIO(filtered.content)).active
|
||
assert filtered_sheet.max_row == EMPTY_EXPORT_ROW_COUNT
|
||
assert filtered_sheet.cell(2, 2).value == "Итого по листу"
|
||
assert filtered_sheet.cell(2, 4).value == INVESTMENT_AMOUNT
|
||
assert filtered_sheet.cell(2, 7).value == sheet.cell(5, 7).value
|
||
|
||
await db_session.execute(
|
||
update(OsvEntry)
|
||
.where(OsvEntry.owner_legal_entity_id == world.a.id, OsvEntry.account_code == "58.01")
|
||
.values(closing_debit=0)
|
||
)
|
||
response = await client.get(base + "/goodwill/export")
|
||
sheet = load_workbook(BytesIO(response.content)).active
|
||
assert sheet.cell(3, 4).value == "Нет вложений"
|
||
assert sheet.cell(3, 7).value is None
|
||
assert sheet.cell(5, 4).value == 0
|
||
assert sheet.cell(5, 7).value == 0
|
||
|
||
|
||
async def test_export_totals_come_from_table(db_session, auth_client, fixtures_dir):
|
||
world = await goodwill_world(db_session, fixtures_dir)
|
||
client = await auth_client(KA_RF)
|
||
base = f"/consolidations/versions/{world.version.id}"
|
||
table = (await client.get(base + "/goodwill")).json()
|
||
sheet = load_workbook(BytesIO((await client.get(base + "/goodwill/export")).content)).active
|
||
assert sheet.cell(4, 2).value == "Всего"
|
||
assert sheet.cell(4, 6).value == float(table["groups"][0]["totals"]["charter_capital_amount"])
|
||
assert sheet.cell(5, 2).value == "Итого по листу"
|
||
assert sheet.cell(5, 6).value == float(table["totals"]["charter_capital_amount"])
|