from factories import make_account from fintracker.models import AccountRole async def test_auth_is_required(client): for method, url in ( ("get", "/api/v1/accounts"), ("get", "/api/v1/categories"), ("get", "/api/v1/transactions"), ("get", "/api/v1/rules"), ("get", "/api/v1/networth/series"), ("get", "/api/v1/cashflow/monthly"), ("get", "/api/v1/runway"), ("get", "/api/v1/data-quality"), ("get", "/api/v1/metrics/status"), ("post", "/api/v1/metrics/refresh"), ): r = await getattr(client, method)(url) assert r.status_code == 401, (url, r.status_code) assert r.headers["content-type"].startswith("application/problem+json") async def test_list_accounts_exposes_balance_as_string(client, auth_headers): await make_account(name="Карта", balance="1234.56") r = await client.get("/api/v1/accounts", headers=auth_headers) assert r.status_code == 200 (row,) = r.json() assert row["name"] == "Карта" assert isinstance(row["balance"], str) assert row["balance"].startswith("1234.56") assert row["role"] == "liquid" assert row["include_in_net_worth"] is True async def test_patch_account(client, auth_headers): broker = await make_account(name="Брокер", role=AccountRole.investment) zm = await make_account(name="Зеркало") r = await client.patch( f"/api/v1/accounts/{zm}", headers=auth_headers, json={"include_in_net_worth": False, "mirror_of_account_id": broker, "role": "investment"}, ) assert r.status_code == 200 assert r.json()["include_in_net_worth"] is False assert r.json()["mirror_of_account_id"] == broker assert r.json()["role"] == "investment" # unset fields are untouched r = await client.patch( f"/api/v1/accounts/{zm}", headers=auth_headers, json={"name": "Зеркало+"} ) assert r.json()["mirror_of_account_id"] == broker assert r.json()["name"] == "Зеркало+" async def test_patch_account_validation(client, auth_headers): account_id = await make_account() r = await client.patch("/api/v1/accounts/999999", headers=auth_headers, json={"name": "x"}) assert r.status_code == 404 r = await client.patch( f"/api/v1/accounts/{account_id}", headers=auth_headers, json={"mirror_of_account_id": account_id}, ) assert r.status_code == 400 r = await client.patch( f"/api/v1/accounts/{account_id}", headers=auth_headers, json={"mirror_of_account_id": 4242} ) assert r.status_code == 400 r = await client.patch( f"/api/v1/accounts/{account_id}", headers=auth_headers, json={"role": "nonsense"} ) assert r.status_code == 422 r = await client.patch( f"/api/v1/accounts/{account_id}", headers=auth_headers, json={"currency": "USD"} ) assert r.status_code == 422 # extra="forbid": source-owned fields are not patchable r = await client.patch( f"/api/v1/accounts/{account_id}", headers=auth_headers, json={"name": " "} ) assert r.status_code == 400 async def test_categories_are_flat_with_parent_ids(client, auth_headers): from factories import make_category food = await make_category("Еда") await make_category("Продукты", parent_id=food) r = await client.get("/api/v1/categories", headers=auth_headers) assert r.status_code == 200 by_name = {c["name"]: c for c in r.json()} assert by_name["Еда"]["parent_id"] is None assert by_name["Продукты"]["parent_id"] == food