from datetime import timedelta from factories import make_account, make_category, make_cbr_rate, make_txn, refresh from fintracker.analytics import today_local async def test_pagination_filters_and_string_money(client, auth_headers): card = await make_account(name="Карта", balance="0") other = await make_account(name="Вклад", balance="0") food = await make_category("Еда") t = today_local() await make_cbr_rate(t - timedelta(days=10), "USD", "90") for i in range(1, 6): await make_txn( t - timedelta(days=i), outcome=f"{i}00.55", outcome_account_id=card, payee=f"Магазин {i}", primary_category_id=food if i == 1 else None, ) await make_txn( t - timedelta(days=6), income="1000", income_account_id=other, payee="Зарплата", comment="аванс", ) await make_txn( t - timedelta(days=7), outcome="10", outcome_currency="USD", outcome_account_id=card ) await make_txn(t - timedelta(days=8), outcome="1", outcome_account_id=card, deleted=True) await refresh() r = await client.get( "/api/v1/transactions", headers=auth_headers, params={"page_size": 3, "page": 1} ) assert r.status_code == 200 body = r.json() assert body["total"] == 7 # the deleted one is excluded assert body["page"] == 1 and body["page_size"] == 3 assert len(body["items"]) == 3 dates = [i["date"] for i in body["items"]] assert dates == sorted(dates, reverse=True) first = body["items"][0] assert isinstance(first["outcome"], str) assert first["outcome"].startswith("100.55") assert first["outcome_rub"].startswith("100.55") assert first["flow_type"] == "expense" page2 = await client.get( "/api/v1/transactions", headers=auth_headers, params={"page_size": 3, "page": 2} ) assert len(page2.json()["items"]) == 3 assert {i["id"] for i in page2.json()["items"]} & {i["id"] for i in body["items"]} == set() # filters r = await client.get("/api/v1/transactions", headers=auth_headers, params={"account_id": other}) assert [i["payee"] for i in r.json()["items"]] == ["Зарплата"] r = await client.get("/api/v1/transactions", headers=auth_headers, params={"q": "аванс"}) assert r.json()["total"] == 1 r = await client.get("/api/v1/transactions", headers=auth_headers, params={"q": "магазин"}) assert r.json()["total"] == 5 # ILIKE, case-insensitive r = await client.get( "/api/v1/transactions", headers=auth_headers, params={"flow_type": "income"} ) assert r.json()["total"] == 1 r = await client.get("/api/v1/transactions", headers=auth_headers, params={"category_id": food}) assert r.json()["total"] == 1 assert r.json()["items"][0]["tags"] == [food] r = await client.get( "/api/v1/transactions", headers=auth_headers, params={"from": str(t - timedelta(days=2)), "to": str(t)}, ) assert r.json()["total"] == 2 r = await client.get( "/api/v1/transactions", headers=auth_headers, params={"include_deleted": True} ) assert r.json()["total"] == 8 # the USD purchase converts at its own date's rate, and never silently at another r = await client.get( "/api/v1/transactions", headers=auth_headers, params={"q": "", "page_size": 100} ) usd = next(i for i in r.json()["items"] if i["outcome_currency"] == "USD") assert usd["outcome_rub"].startswith("900") async def test_unquoted_currency_gives_null_rub(client, auth_headers): card = await make_account(balance="0") await make_txn( today_local() - timedelta(days=1), outcome="2", outcome_currency="XBT", outcome_account_id=card, ) await refresh() r = await client.get("/api/v1/transactions", headers=auth_headers) (item,) = r.json()["items"] assert item["outcome"] == "2.0000000000" assert item["outcome_rub"] is None