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.
 
 
 
 
 

126 lines
4.6 KiB

from datetime import date
import pytest
import finance.queries as queries
from finance.models import Account, Category, Payee, Transaction
from finance.queries import (
QueryInputError,
TransactionFilters,
filtered_transactions,
)
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 make_transaction(account, *, posting_date, amount="-10.00", **values):
return Transaction.objects.create(
account=account,
amount=amount,
posting_date=posting_date,
kind=values.pop("kind", Transaction.Kind.EXPENSE),
**values,
)
def test_filtered_transactions_combines_filters_and_orders_stably():
account = make_account()
category = Category.objects.create(name="Synthetic Food", kind=Category.Kind.EXPENSE)
older = make_transaction(account, posting_date=date(2026, 1, 5))
newer = make_transaction(account, posting_date=date(2026, 1, 20))
make_transaction(account, posting_date=date(2026, 1, 25), category=category)
make_transaction(account, posting_date=date(2026, 2, 1))
make_transaction(make_account("Synthetic USD", "USD"), posting_date=date(2026, 1, 22))
filters = TransactionFilters.from_mapping({
"date_from": "2026-01-01",
"date_to": "2026-01-31",
"currency": "BRL",
"uncategorized": "yes",
})
rows = list(filtered_transactions(filters))
assert [row.pk for row in rows] == [newer.pk, older.pk]
def test_filtered_transactions_supports_reference_kind_and_categorized_filters():
account = make_account()
other_account = make_account("Synthetic Other")
category = Category.objects.create(name="Synthetic Food", kind=Category.Kind.EXPENSE)
payee = Payee.objects.create(name="Synthetic Merchant")
expected = make_transaction(
account,
posting_date=date(2026, 1, 10),
category=category,
payee=payee,
)
make_transaction(account, posting_date=date(2026, 1, 11), category=category)
make_transaction(other_account, posting_date=date(2026, 1, 12), category=category, payee=payee)
filters = TransactionFilters.from_mapping({
"account": str(account.pk),
"category": str(category.pk),
"payee": str(payee.pk),
"kind": "EXPENSE",
"uncategorized": "no",
})
assert list(filtered_transactions(filters)) == [expected]
@pytest.mark.parametrize(
("mapping", "errors"),
[
({"date_from": "31/01/2026"}, {"date_from": "invalid_date"}),
({"date_to": "not-a-date"}, {"date_to": "invalid_date"}),
({"account": "bad"}, {"account": "invalid_uuid"}),
({"category": "bad"}, {"category": "invalid_uuid"}),
({"payee": "bad"}, {"payee": "invalid_uuid"}),
({"kind": "UNKNOWN"}, {"kind": "invalid_choice"}),
({"currency": "brl"}, {"currency": "invalid_currency"}),
({"uncategorized": "maybe"}, {"uncategorized": "invalid_choice"}),
],
)
def test_invalid_filter_is_explicit(mapping, errors):
with pytest.raises(QueryInputError) as caught:
TransactionFilters.from_mapping(mapping)
assert caught.value.errors == errors
def test_filter_errors_are_reported_together_and_date_order_is_checked():
with pytest.raises(QueryInputError) as caught:
TransactionFilters.from_mapping({
"date_from": "2026-02-01",
"date_to": "2026-01-01",
"account": "bad",
})
assert caught.value.errors == {
"account": "invalid_uuid",
"date_to": "before_date_from",
}
def test_reference_lists_include_history_after_active_rows_with_stable_names():
active_account = make_account("Synthetic Active")
archived_account = make_account("Synthetic Archived")
archived_account.archived = True
archived_account.save(update_fields=["archived"])
active_category = Category.objects.create(name="Synthetic Active", kind=Category.Kind.EXPENSE)
archived_category = Category.objects.create(name="Synthetic Archived", kind=Category.Kind.EXPENSE, archived=True)
active_payee = Payee.objects.create(name="Synthetic Active")
archived_payee = Payee.objects.create(name="Synthetic Archived", archived=True)
assert list(queries.listed_accounts()) == [active_account, archived_account]
assert list(queries.listed_categories()) == [active_category, archived_category]
assert list(queries.listed_payees()) == [active_payee, archived_payee]
assert list(queries.active_accounts()) == [active_account]
assert list(queries.active_categories()) == [active_category]
assert list(queries.active_payees()) == [active_payee]