You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

106 lines
3.8 KiB

from datetime import date
from decimal import Decimal
import pytest
from django.urls import reverse
from django.utils import timezone
from finance.models import Account, Category, Transaction
pytestmark = pytest.mark.django_db
def make_account(name="Synthetic Bank", *, currency="BRL"):
return Account.objects.create(name=name, kind=Account.Kind.BANK, currency=currency)
def post(account, amount, kind, posting_date, *, category=None):
return Transaction.objects.create(
account=account,
amount=Decimal(amount),
kind=kind,
posting_date=posting_date,
category=category,
)
def test_monthly_report_renders_exact_totals_category_rows_and_account_balances(client):
bank = make_account()
savings = make_account("Synthetic Savings")
food = Category.objects.create(name="Synthetic Food", kind=Category.Kind.EXPENSE)
post(bank, "500.00", Transaction.Kind.OPENING, date(2025, 12, 31))
post(bank, "1000.00", Transaction.Kind.INCOME, date(2026, 1, 2))
post(bank, "-300.00", Transaction.Kind.EXPENSE, date(2026, 1, 3), category=food)
post(bank, "50.00", Transaction.Kind.REFUND, date(2026, 1, 25), category=food)
post(bank, "-20.00", Transaction.Kind.EXPENSE, date(2026, 1, 26))
post(bank, "-200.00", Transaction.Kind.TRANSFER, date(2026, 1, 27))
post(savings, "200.00", Transaction.Kind.TRANSFER, date(2026, 1, 27))
response = client.get(reverse("monthly-report"), {"month": "2026-01", "currency": "BRL"})
assert response.status_code == 200
body = response.content.decode()
assert "Monthly report" in body
assert "1,000.00" in body
assert "320.00" in body
assert "50.00" in body
assert "270.00" in body
assert "730.00" in body
assert "Synthetic Food" in body
assert "Uncategorized" in body
assert "Synthetic Bank" in body and "1,030.00" in body
assert "Synthetic Savings" in body and "200.00" in body
@pytest.mark.parametrize(
("parameters", "expected_error"),
[
({"month": "01/2026", "currency": "BRL"}, "invalid_month"),
({"month": "2026-01", "currency": "brl"}, "invalid_currency"),
],
)
def test_invalid_report_selection_is_visible_and_not_silently_replaced(client, parameters, expected_error):
response = client.get(reverse("monthly-report"), parameters)
assert response.status_code == 400
assert expected_error in response.content.decode()
def test_home_defaults_to_local_month_and_first_available_currency(client, monkeypatch):
make_account("Synthetic USD", currency="USD")
make_account("Synthetic BRL", currency="BRL")
monkeypatch.setattr(timezone, "localdate", lambda: date(2026, 4, 17))
response = client.get(reverse("home"))
assert response.status_code == 200
body = response.content.decode()
assert "Dashboard" in body
assert 'value="2026-04"' in body
assert '<option value="BRL" selected>BRL</option>' in body
assert "Transactions" in body
def test_home_uses_brl_when_no_account_currency_exists(client, monkeypatch):
monkeypatch.setattr(timezone, "localdate", lambda: date(2026, 4, 17))
response = client.get(reverse("home"))
assert response.status_code == 200
assert '<option value="BRL" selected>BRL</option>' in response.content.decode()
def test_negative_spending_and_balance_keep_their_sign_and_are_labeled(client):
bank = make_account()
post(bank, "-100.00", Transaction.Kind.OPENING, date(2025, 12, 31))
post(bank, "25.00", Transaction.Kind.REFUND, date(2026, 1, 3))
response = client.get(reverse("monthly-report"), {"month": "2026-01", "currency": "BRL"})
body = response.content.decode()
assert response.status_code == 200
assert "Net spending (negative)" in body
assert "-25.00" in body
assert "Balance (negative)" in body
assert "-75.00" in body