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.
 
 
 
 
 

107 lines
3.5 KiB

from datetime import date
import pytest
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",
}