"""HTTP-route tests for the finance-flux report import. The unit tests in ``test_report_import.py`` exercise ``parse_report`` / ``import_report`` directly. These cover the *route* the browser actually hits: ``multipart/form-data`` upload → RBAC gate → audit → commit. A regression guard after a user-reported "import failed" where everything below the HTTP layer worked in isolation. """ from __future__ import annotations import os from pathlib import Path import pytest from httpx import AsyncClient from sqlalchemy import select from app.domains.finance_flux import constants as c from app.domains.finance_flux.models import FinanceFluxPeriod pytestmark = pytest.mark.asyncio _XLS_CT = "application/vnd.ms-excel" def _ss(rows: list[list[str]]) -> bytes: """Minimal SpreadsheetML workbook mirroring a NetSuite export.""" def cells(r: list[str]) -> str: return "".join( f'{v}' for v in r) body = "".join(f"{cells(r)}" for r in rows) return ( '' '' f'{body}
' ).encode() BS_FIXTURE = _ss([ ["PingCAP"], ["虚拟母公司 : PingCap Ltd. (已合并)"], ["Consolidated Balance Sheet_no comparatives"], ["May,2026 末"], [], ["Finance:line", " "], ["ASSETS", ""], ["Current assets", ""], ["Cash and cash equivalents", ""], ["1002 - 银行存款", ""], ["总计 - 1002 - 银行存款", "24353092.92"], ["Cash and cash equivalents", "32228212.53"], ["Financial assets at fair value", "138066640.78"], ["Elim-5001 - Elim-生产成本", "0.00"], ["Current assets", "185841193.91"], ["Non-current assets", ""], ["Right-of-use assets", "264219.92"], ["Non-current assets", "1513555.35"], ["Total assets", "187354749.25"], ]) def _headers(finance_user) -> dict[str, str]: _, token = finance_user return {"Authorization": f"Bearer {token}"} async def test_import_endpoint_multipart_ok( client: AsyncClient, finance_user, db_session ): """A real multipart upload through the route creates the period.""" resp = await client.post( "/api/v1/finance-flux/import", files={"file": ("ConsolidatedBalanceSheet.xls", BS_FIXTURE, _XLS_CT)}, headers=_headers(finance_user), ) assert resp.status_code == 200, resp.text body = resp.json() assert body["success"] is True assert body["data"]["period_key"] == "2026-05" assert body["data"]["statement"] == c.STATEMENT_BS assert body["data"]["line_count"] == 6 period = (await db_session.execute( select(FinanceFluxPeriod).where(FinanceFluxPeriod.period_key == "2026-05") )).scalar_one() assert period.sync_status == c.SYNC_SYNCED async def test_import_endpoint_requires_finance( client: AsyncClient, employee_user ): """A non-finance/non-admin caller is rejected (403), not 500.""" _, token = employee_user resp = await client.post( "/api/v1/finance-flux/import", files={"file": ("x.xls", BS_FIXTURE, _XLS_CT)}, headers={"Authorization": f"Bearer {token}"}, ) assert resp.status_code == 403, resp.text async def test_import_endpoint_rejects_empty(client: AsyncClient, finance_user): resp = await client.post( "/api/v1/finance-flux/import", files={"file": ("empty.xls", b"", _XLS_CT)}, headers=_headers(finance_user), ) assert resp.status_code == 422, resp.text # --- Local diagnostic: the user's real export. Auto-skips in CI / when the # file isn't present so no real financial data is ever committed or required. --- _REAL = Path(os.path.expanduser( "~/Downloads/ConsolidatedBalanceSheet_nocomparatives-227.xls")) @pytest.mark.skipif(not _REAL.exists(), reason="real NetSuite export not present") async def test_import_endpoint_real_export( client: AsyncClient, finance_user, db_session ): resp = await client.post( "/api/v1/finance-flux/import", files={"file": (_REAL.name, _REAL.read_bytes(), _XLS_CT)}, headers=_headers(finance_user), ) assert resp.status_code == 200, resp.text assert resp.json()["data"]["statement"] == c.STATEMENT_BS