From 14f7d5aa21c4c73411433fe9c9b499a812eac9ce Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 15:43:27 -0800 Subject: [PATCH 1/7] Add Transaction.cleared field --- src/budge/transaction.py | 6 ++++-- src/budge/transfer.py | 24 ++++++++++++++++++++---- tests/budge/test_transfer.py | 6 ++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/budge/transaction.py b/src/budge/transaction.py index fd06d00..645717a 100644 --- a/src/budge/transaction.py +++ b/src/budge/transaction.py @@ -17,8 +17,9 @@ class Transaction: description: str amount: IntoMoney = IntoMoney() date: _date = field(default_factory=_date.today) - account: "account.Account | None" = field(default=None, kw_only=True) - parent: Self | None = field(default=None, kw_only=True) + account: "account.Account | None" = None + parent: Self | None = None + cleared: bool = False def __hash__(self): return hash((self.amount, self.description, self.date)) @@ -53,6 +54,7 @@ def __iter__(self): date=next.date(), account=self.account, parent=self, + cleared=True, ) for next in self.schedule ) diff --git a/src/budge/transfer.py b/src/budge/transfer.py index b45b364..1d4078c 100644 --- a/src/budge/transfer.py +++ b/src/budge/transfer.py @@ -18,8 +18,18 @@ def __post_init__(self, from_account: Account, to_account: Account): Create the from and to transactions, add them to the respective accounts, and set their parent to this transfer. """ - self.from_transaction = Transaction(self.description, -self.amount, self.date) - self.to_transaction = Transaction(self.description, self.amount, self.date) + self.from_transaction = Transaction( + self.description, + -self.amount, + self.date, + cleared=self.cleared, + ) + self.to_transaction = Transaction( + self.description, + self.amount, + self.date, + cleared=self.cleared, + ) self.from_transaction.parent = self.to_transaction.parent = self @@ -40,10 +50,16 @@ def __post_init__(self, from_account: Account, to_account: Account): respective accounts, and set their parent to this repeating transfer. """ self.from_transaction = RepeatingTransaction( - self.description, -self.amount, schedule=self.schedule + self.description, + -self.amount, + schedule=self.schedule, + cleared=True, ) self.to_transaction = RepeatingTransaction( - self.description, self.amount, schedule=self.schedule + self.description, + self.amount, + schedule=self.schedule, + cleared=True, ) self.from_transaction.parent = self.to_transaction.parent = self diff --git a/tests/budge/test_transfer.py b/tests/budge/test_transfer.py index 366f37b..8b50063 100644 --- a/tests/budge/test_transfer.py +++ b/tests/budge/test_transfer.py @@ -48,6 +48,9 @@ def test_transfer( assert transfer.from_transaction.amount == Money(-100) assert transfer.to_transaction.amount == Money(100) + assert transfer.from_transaction.cleared is False + assert transfer.to_transaction.cleared is False + assert from_account.balance(today) == Money(-100) assert to_account.balance(today) == Money(100) @@ -61,6 +64,9 @@ def test_repeating_transfer( assert repeating_transfer.from_transaction.amount == Money(-100) assert repeating_transfer.to_transaction.amount == Money(100) + assert repeating_transfer.from_transaction.cleared is True + assert repeating_transfer.to_transaction.cleared is True + as_of = today + relativedelta(months=6) assert from_account.balance(as_of) == Money(-600) From 08570cbd4b958aa5a5986251ea4d200d7f474ab9 Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 16:01:09 -0800 Subject: [PATCH 2/7] Add cleared transactions filter to account methods --- src/budge/account.py | 44 +++++++++++++++------- tests/budge/test_account.py | 75 +++++++++++++++++++++++++++++-------- 2 files changed, 90 insertions(+), 29 deletions(-) diff --git a/src/budge/account.py b/src/budge/account.py index 062bf48..3ed3fd0 100644 --- a/src/budge/account.py +++ b/src/budge/account.py @@ -56,7 +56,10 @@ def __iter__(self): ) def transactions_range( - self, start_date: date | None = None, end_date: date | None = None + self, + start_date: date | None = None, + end_date: date | None = None, + cleared: bool | None = None, ) -> Generator[Transaction]: """Iterate over transactions in the account over the given range.""" for transaction in self: @@ -64,15 +67,20 @@ def transactions_range( continue if end_date and transaction.date > end_date: break - yield transaction + + if cleared is None or transaction.cleared == cleared: + yield transaction def running_balance( - self, start_date: date | None = None, end_date: date | None = None + self, + start_date: date | None = None, + end_date: date | None = None, + cleared: bool | None = None, ) -> Generator[RunningBalance]: """Iterate over transactions in the account over the given range with a running account balance.""" balance = ( - self.balance(start_date + relativedelta(days=-1)) + self.balance(start_date + relativedelta(days=-1), cleared) if start_date is not None else Money(0) ) @@ -81,17 +89,20 @@ def running_balance( balance += transaction.amount yield RunningBalance(transaction, balance) - def balance(self, as_of: date | None = None): + def balance(self, as_of: date | None = None, cleared: bool | None = None): """Calculate the account balance as of the given date.""" as_of = as_of or date.today() return Money.sum( transaction.amount - for transaction in self.transactions_range(end_date=as_of) + for transaction in self.transactions_range(end_date=as_of, cleared=cleared) ) def daily_balance( - self, start_date: date | None = None, end_date: date | None = None + self, + start_date: date | None = None, + end_date: date | None = None, + cleared: bool | None = None, ) -> Generator[DailyBalance]: """ Iterate over the daily balance of the account, yielding tuples of date @@ -105,17 +116,20 @@ def daily_balance( start_date = start_date or next(self.transactions_range()).date end_date = end_date or date.today() - balance = self.balance(start_date) + balance = self.balance(start_date, cleared) yield DailyBalance(start_date, balance) for _date, delta in self._daily_balance_delta( - start_date + timedelta(days=1), end_date + start_date + timedelta(days=1), end_date, cleared ): balance += delta yield DailyBalance(_date, balance) def _deltas_by_date( - self, start_date: date, end_date: date + self, + start_date: date, + end_date: date, + cleared: bool | None = None, ) -> Generator[DailyBalance]: """ Iterate over the deltas in the account balance for each date in the @@ -129,12 +143,16 @@ def _deltas_by_date( _date, Money.sum(transaction.amount for transaction in transactions) ) for _date, transactions in groupby( - self.transactions_range(start_date, end_date), key=lambda t: t.date + self.transactions_range(start_date, end_date, cleared), + key=lambda t: t.date, ) ) def _daily_balance_delta( - self, start_date: date, end_date: date + self, + start_date: date, + end_date: date, + cleared: bool | None = None, ) -> Generator[DailyBalance]: """ Calculate the daily change in account balance over the specified date range. @@ -148,7 +166,7 @@ def _daily_balance_delta( DailyBalance(_date, Money.sum(delta.balance for delta in deltas)) for _date, deltas in groupby( merge( - self._deltas_by_date(start_date, end_date), + self._deltas_by_date(start_date, end_date, cleared), ( DailyBalance(_date, Money(0)) for _date in daterange(start_date, end_date) diff --git a/tests/budge/test_account.py b/tests/budge/test_account.py index 61b4ff4..d8f2f14 100644 --- a/tests/budge/test_account.py +++ b/tests/budge/test_account.py @@ -9,9 +9,10 @@ from budge.rrule import rruleset -@fixture(scope="session") +@fixture def account( transaction: Transaction, + cleared_transaction: Transaction, repeating_transaction_rrule: RepeatingTransaction, repeating_transaction_rruleset: RepeatingTransaction, ): @@ -26,18 +27,25 @@ def account( acct.repeating_transactions.add( repeating_transaction_rrule, repeating_transaction_rruleset ) - acct.transactions.add(transaction, manual_transaction) + acct.transactions.add(transaction, cleared_transaction, manual_transaction) return acct -@fixture(scope="session") +@fixture def transaction(): return Transaction("test transaction", Money(1), date(2022, 12, 1)) -@fixture(scope="session") -def repeating_transaction_rrule(today: date, rrule: dateutil.rrule.rrule): +@fixture +def cleared_transaction(): + return Transaction( + "test cleared transaction", Money(1), date(2022, 12, 1), cleared=True + ) + + +@fixture +def repeating_transaction_rrule(rrule: dateutil.rrule.rrule): return RepeatingTransaction( "test repeating transaction with rrule", Money(1), @@ -45,7 +53,7 @@ def repeating_transaction_rrule(today: date, rrule: dateutil.rrule.rrule): ) -@fixture(scope="session") +@fixture def repeating_transaction_rruleset(rruleset: rruleset): return RepeatingTransaction( "test repeating transaction with rruleset", Money(2), schedule=rruleset @@ -53,8 +61,18 @@ def repeating_transaction_rruleset(rruleset: rruleset): def test_account_balance(account: Account, today: date): - assert account.balance(today) == Money(1) - assert account.balance(today + relativedelta(years=1)) == Money(37) + assert account.balance(today) == Money(2) + assert account.balance(today + relativedelta(years=1)) == Money(38) + + +def test_account_balance_cleared_true(account: Account, today: date): + assert account.balance(today, cleared=True) == Money(1) + assert account.balance(today + relativedelta(years=1), cleared=True) == Money(36) + + +def test_account_balance_cleared_false(account: Account, today: date): + assert account.balance(today, cleared=False) == Money(1) + assert account.balance(today + relativedelta(years=1), cleared=False) == Money(2) def test_account_transactions_range(account: Account, today: date): @@ -73,14 +91,39 @@ def test_account_transactions_range(account: Account, today: date): next_date = transaction.date +def test_account_transactions_range_cleared_true(account: Account, today: date): + end_date = today + relativedelta(months=3) + transactions = list(account.transactions_range(today, end_date, cleared=True)) + + assert len(transactions) == 5 + assert transactions[0].description == "test repeating transaction with rruleset" + assert transactions[0].date == date(2022, 12, 17) + + assert transactions[-1].date == date(2023, 3, 1) + + next_date = transactions[0].date + for transaction in transactions: + assert transaction.date >= next_date + next_date = transaction.date + + +def test_account_transactions_range_cleared_false(account: Account, today: date): + end_date = today + relativedelta(months=3) + transactions = list(account.transactions_range(today, end_date, cleared=False)) + + assert len(transactions) == 1 + assert transactions[0].description == "test repeating transaction with rrule" + assert transactions[0].date == date(2023, 1, 1) + + def test_account_running_balance(account: Account, today: date): end_date = today + relativedelta(months=3) balances = list(account.running_balance(today, end_date)) assert len(balances) == 6 - assert balances[0].balance == Money(3) - assert balances[1].balance == Money(4) - assert balances[-1].balance == Money(10) + assert balances[0].balance == Money(4) + assert balances[1].balance == Money(5) + assert balances[-1].balance == Money(11) def test_account_daily_balance_past(account: Account, today: date): @@ -89,7 +132,7 @@ def test_account_daily_balance_past(account: Account, today: date): assert len(balances) == 31 assert balances[0] == (start_date, Money(0)) - assert balances[-1] == (today, Money(1)) + assert balances[-1] == (today, Money(2)) def test_account_daily_balance_future(account: Account, today: date): @@ -97,7 +140,7 @@ def test_account_daily_balance_future(account: Account, today: date): balances = list(account.daily_balance(today, end_date)) assert len(balances) == 32 - assert balances[0] == (today, Money(1)) - assert balances[9] == (date(2022, 12, 15), Money(1)) - assert balances[11] == (date(2022, 12, 17), Money(3)) - assert balances[-1] == (end_date, Money(4)) + assert balances[0] == (today, Money(2)) + assert balances[9] == (date(2022, 12, 15), Money(2)) + assert balances[11] == (date(2022, 12, 17), Money(4)) + assert balances[-1] == (end_date, Money(5)) From 674bd6b8e491eacc71a2c4aeeb849c0f1042b9ec Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 16:04:12 -0800 Subject: [PATCH 3/7] Fix Account.running_balance cleared filter --- src/budge/account.py | 2 +- tests/budge/test_account.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/budge/account.py b/src/budge/account.py index 3ed3fd0..27409f8 100644 --- a/src/budge/account.py +++ b/src/budge/account.py @@ -85,7 +85,7 @@ def running_balance( else Money(0) ) - for transaction in self.transactions_range(start_date, end_date): + for transaction in self.transactions_range(start_date, end_date, cleared): balance += transaction.amount yield RunningBalance(transaction, balance) diff --git a/tests/budge/test_account.py b/tests/budge/test_account.py index d8f2f14..c34099d 100644 --- a/tests/budge/test_account.py +++ b/tests/budge/test_account.py @@ -126,6 +126,24 @@ def test_account_running_balance(account: Account, today: date): assert balances[-1].balance == Money(11) +def test_account_running_balance_cleared_true(account: Account, today: date): + end_date = today + relativedelta(months=3) + balances = list(account.running_balance(today, end_date, cleared=True)) + + assert len(balances) == 5 + assert balances[0].balance == Money(3) + assert balances[1].balance == Money(5) + assert balances[-1].balance == Money(9) + + +def test_account_running_balance_cleared_false(account: Account, today: date): + end_date = today + relativedelta(months=3) + balances = list(account.running_balance(today, end_date, cleared=False)) + + assert len(balances) == 1 + assert balances[0].balance == Money(2) + + def test_account_daily_balance_past(account: Account, today: date): start_date = today + relativedelta(months=-1) balances = list(account.daily_balance(start_date, today)) From c4e5e738ebac64a3ddce85edbf8770b19a0ebb26 Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 16:08:37 -0800 Subject: [PATCH 4/7] Fix Account.daily_balance cleared filter --- src/budge/account.py | 2 +- tests/budge/test_account.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/budge/account.py b/src/budge/account.py index 27409f8..c563ed1 100644 --- a/src/budge/account.py +++ b/src/budge/account.py @@ -113,7 +113,7 @@ def daily_balance( given, the date of the first transaction is used. If the end date is not given, today's date is used. """ - start_date = start_date or next(self.transactions_range()).date + start_date = start_date or next(self.transactions_range(cleared=cleared)).date end_date = end_date or date.today() balance = self.balance(start_date, cleared) diff --git a/tests/budge/test_account.py b/tests/budge/test_account.py index c34099d..0b0dcb3 100644 --- a/tests/budge/test_account.py +++ b/tests/budge/test_account.py @@ -162,3 +162,25 @@ def test_account_daily_balance_future(account: Account, today: date): assert balances[9] == (date(2022, 12, 15), Money(2)) assert balances[11] == (date(2022, 12, 17), Money(4)) assert balances[-1] == (end_date, Money(5)) + + +def test_account_daily_balance_cleared_true(account: Account, today: date): + end_date = today + relativedelta(months=1) + balances = list(account.daily_balance(today, end_date, cleared=True)) + + assert len(balances) == 32 + assert balances[0] == (today, Money(1)) + assert balances[9] == (date(2022, 12, 15), Money(1)) + assert balances[11] == (date(2022, 12, 17), Money(3)) + assert balances[-1] == (end_date, Money(3)) + + +def test_account_daily_balance_cleared_false(account: Account, today: date): + end_date = today + relativedelta(months=1) + balances = list(account.daily_balance(today, end_date, cleared=False)) + + assert len(balances) == 32 + assert balances[0] == (today, Money(1)) + assert balances[9] == (date(2022, 12, 15), Money(1)) + assert balances[11] == (date(2022, 12, 17), Money(1)) + assert balances[-1] == (end_date, Money(2)) From 39eb51458f533a2e53f0c57b81f3a9ffcfd5d0e4 Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 16:44:26 -0800 Subject: [PATCH 5/7] Add RepeatingTransaction.last_cleared property --- src/budge/transaction.py | 19 ++++++++++++++++++- src/budge/transfer.py | 19 ++++++++++++++++--- tests/budge/test_account.py | 33 +++++++++++++++------------------ tests/budge/test_transfer.py | 9 +++++++-- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/budge/transaction.py b/src/budge/transaction.py index 645717a..c9e6a50 100644 --- a/src/budge/transaction.py +++ b/src/budge/transaction.py @@ -1,5 +1,6 @@ from dataclasses import dataclass, field from datetime import date as _date +from datetime import datetime from typing import Self from dateutil.rrule import rrule @@ -37,6 +38,22 @@ class RepeatingTransaction(Transaction): """ schedule: rrule | rruleset + _last_cleared: _date | None = None + + @property + def last_cleared(self) -> _date | None: + if self._last_cleared is None: + return None + + return ( + self._last_cleared + if isinstance(self._last_cleared, datetime) + else datetime.combine(self._last_cleared, datetime.max.time()) + ) + + @last_cleared.setter + def last_cleared(self, date: _date | None): + self._last_cleared = date def __hash__(self): return hash((self.amount, self.description, self.schedule)) @@ -54,7 +71,7 @@ def __iter__(self): date=next.date(), account=self.account, parent=self, - cleared=True, + cleared=(next <= self.last_cleared if self.last_cleared else False), ) for next in self.schedule ) diff --git a/src/budge/transfer.py b/src/budge/transfer.py index 1d4078c..e4ecacb 100644 --- a/src/budge/transfer.py +++ b/src/budge/transfer.py @@ -1,4 +1,5 @@ from dataclasses import InitVar, dataclass, field +from datetime import date from .account import Account from .transaction import RepeatingTransaction, Transaction @@ -44,6 +45,15 @@ class RepeatingTransfer(Transfer, RepeatingTransaction): `dateutil.rrule.rrule` or `dateutil.rrule.rruleset`. """ + @property + def last_cleared(self) -> date | None: + return super().last_cleared + + @last_cleared.setter + def last_cleared(self, date: date | None): + self._last_cleared = date + self.from_transaction.last_cleared = self.to_transaction.last_cleared = date # type: ignore + def __post_init__(self, from_account: Account, to_account: Account): """ Create the from and to repeating transactions, add them to the @@ -52,17 +62,20 @@ def __post_init__(self, from_account: Account, to_account: Account): self.from_transaction = RepeatingTransaction( self.description, -self.amount, + parent=self, schedule=self.schedule, - cleared=True, ) + self.to_transaction = RepeatingTransaction( self.description, self.amount, + parent=self, schedule=self.schedule, - cleared=True, ) - self.from_transaction.parent = self.to_transaction.parent = self + self.from_transaction.last_cleared = self.to_transaction.last_cleared = ( + self.last_cleared + ) from_account.repeating_transactions.add(self.from_transaction) to_account.repeating_transactions.add(self.to_transaction) diff --git a/tests/budge/test_account.py b/tests/budge/test_account.py index 0b0dcb3..ffd3a21 100644 --- a/tests/budge/test_account.py +++ b/tests/budge/test_account.py @@ -45,18 +45,22 @@ def cleared_transaction(): @fixture -def repeating_transaction_rrule(rrule: dateutil.rrule.rrule): +def repeating_transaction_rrule(today: date, rrule: dateutil.rrule.rrule): return RepeatingTransaction( "test repeating transaction with rrule", Money(1), schedule=rrule, + _last_cleared=today + relativedelta(months=1), ) @fixture -def repeating_transaction_rruleset(rruleset: rruleset): +def repeating_transaction_rruleset(today: date, rruleset: rruleset): return RepeatingTransaction( - "test repeating transaction with rruleset", Money(2), schedule=rruleset + "test repeating transaction with rruleset", + Money(2), + schedule=rruleset, + _last_cleared=today + relativedelta(months=1), ) @@ -67,12 +71,12 @@ def test_account_balance(account: Account, today: date): def test_account_balance_cleared_true(account: Account, today: date): assert account.balance(today, cleared=True) == Money(1) - assert account.balance(today + relativedelta(years=1), cleared=True) == Money(36) + assert account.balance(today + relativedelta(years=1), cleared=True) == Money(3) def test_account_balance_cleared_false(account: Account, today: date): assert account.balance(today, cleared=False) == Money(1) - assert account.balance(today + relativedelta(years=1), cleared=False) == Money(2) + assert account.balance(today + relativedelta(years=1), cleared=False) == Money(35) def test_account_transactions_range(account: Account, today: date): @@ -95,23 +99,16 @@ def test_account_transactions_range_cleared_true(account: Account, today: date): end_date = today + relativedelta(months=3) transactions = list(account.transactions_range(today, end_date, cleared=True)) - assert len(transactions) == 5 + assert len(transactions) == 1 assert transactions[0].description == "test repeating transaction with rruleset" assert transactions[0].date == date(2022, 12, 17) - assert transactions[-1].date == date(2023, 3, 1) - - next_date = transactions[0].date - for transaction in transactions: - assert transaction.date >= next_date - next_date = transaction.date - def test_account_transactions_range_cleared_false(account: Account, today: date): end_date = today + relativedelta(months=3) transactions = list(account.transactions_range(today, end_date, cleared=False)) - assert len(transactions) == 1 + assert len(transactions) == 5 assert transactions[0].description == "test repeating transaction with rrule" assert transactions[0].date == date(2023, 1, 1) @@ -130,18 +127,18 @@ def test_account_running_balance_cleared_true(account: Account, today: date): end_date = today + relativedelta(months=3) balances = list(account.running_balance(today, end_date, cleared=True)) - assert len(balances) == 5 + assert len(balances) == 1 assert balances[0].balance == Money(3) - assert balances[1].balance == Money(5) - assert balances[-1].balance == Money(9) def test_account_running_balance_cleared_false(account: Account, today: date): end_date = today + relativedelta(months=3) balances = list(account.running_balance(today, end_date, cleared=False)) - assert len(balances) == 1 + assert len(balances) == 5 assert balances[0].balance == Money(2) + assert balances[1].balance == Money(4) + assert balances[-1].balance == Money(8) def test_account_daily_balance_past(account: Account, today: date): diff --git a/tests/budge/test_transfer.py b/tests/budge/test_transfer.py index 8b50063..3a46554 100644 --- a/tests/budge/test_transfer.py +++ b/tests/budge/test_transfer.py @@ -61,13 +61,18 @@ def test_repeating_transfer( from_account: Account, to_account: Account, ): + repeating_transfer.last_cleared = today + relativedelta(months=3) + assert repeating_transfer.from_transaction.amount == Money(-100) assert repeating_transfer.to_transaction.amount == Money(100) - assert repeating_transfer.from_transaction.cleared is True - assert repeating_transfer.to_transaction.cleared is True + assert repeating_transfer.from_transaction.cleared is False + assert repeating_transfer.to_transaction.cleared is False as_of = today + relativedelta(months=6) assert from_account.balance(as_of) == Money(-600) assert to_account.balance(as_of) == Money(600) + + assert from_account.balance(as_of, cleared=True) == Money(-300) + assert to_account.balance(as_of, cleared=True) == Money(300) From 615bd00a7200857bad895efde9755b7c3550ac98 Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 16:51:09 -0800 Subject: [PATCH 6/7] Track account test transactions by digits places --- tests/budge/test_account.py | 52 +++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/tests/budge/test_account.py b/tests/budge/test_account.py index ffd3a21..fcf9b4a 100644 --- a/tests/budge/test_account.py +++ b/tests/budge/test_account.py @@ -40,7 +40,7 @@ def transaction(): @fixture def cleared_transaction(): return Transaction( - "test cleared transaction", Money(1), date(2022, 12, 1), cleared=True + "test cleared transaction", Money(10), date(2022, 12, 1), cleared=True ) @@ -48,7 +48,7 @@ def cleared_transaction(): def repeating_transaction_rrule(today: date, rrule: dateutil.rrule.rrule): return RepeatingTransaction( "test repeating transaction with rrule", - Money(1), + Money(100), schedule=rrule, _last_cleared=today + relativedelta(months=1), ) @@ -58,25 +58,27 @@ def repeating_transaction_rrule(today: date, rrule: dateutil.rrule.rrule): def repeating_transaction_rruleset(today: date, rruleset: rruleset): return RepeatingTransaction( "test repeating transaction with rruleset", - Money(2), + Money(1000), schedule=rruleset, _last_cleared=today + relativedelta(months=1), ) def test_account_balance(account: Account, today: date): - assert account.balance(today) == Money(2) - assert account.balance(today + relativedelta(years=1)) == Money(38) + assert account.balance(today) == Money(11) + assert account.balance(today + relativedelta(years=1)) == Money(13211) def test_account_balance_cleared_true(account: Account, today: date): - assert account.balance(today, cleared=True) == Money(1) - assert account.balance(today + relativedelta(years=1), cleared=True) == Money(3) + assert account.balance(today, cleared=True) == Money(10) + assert account.balance(today + relativedelta(years=1), cleared=True) == Money(1010) def test_account_balance_cleared_false(account: Account, today: date): assert account.balance(today, cleared=False) == Money(1) - assert account.balance(today + relativedelta(years=1), cleared=False) == Money(35) + assert account.balance(today + relativedelta(years=1), cleared=False) == Money( + 12201 + ) def test_account_transactions_range(account: Account, today: date): @@ -118,9 +120,9 @@ def test_account_running_balance(account: Account, today: date): balances = list(account.running_balance(today, end_date)) assert len(balances) == 6 - assert balances[0].balance == Money(4) - assert balances[1].balance == Money(5) - assert balances[-1].balance == Money(11) + assert balances[0].balance == Money(1011) + assert balances[1].balance == Money(1111) + assert balances[-1].balance == Money(3311) def test_account_running_balance_cleared_true(account: Account, today: date): @@ -128,7 +130,7 @@ def test_account_running_balance_cleared_true(account: Account, today: date): balances = list(account.running_balance(today, end_date, cleared=True)) assert len(balances) == 1 - assert balances[0].balance == Money(3) + assert balances[0].balance == Money(1010) def test_account_running_balance_cleared_false(account: Account, today: date): @@ -136,9 +138,9 @@ def test_account_running_balance_cleared_false(account: Account, today: date): balances = list(account.running_balance(today, end_date, cleared=False)) assert len(balances) == 5 - assert balances[0].balance == Money(2) - assert balances[1].balance == Money(4) - assert balances[-1].balance == Money(8) + assert balances[0].balance == Money(101) + assert balances[1].balance == Money(1101) + assert balances[-1].balance == Money(2301) def test_account_daily_balance_past(account: Account, today: date): @@ -147,7 +149,7 @@ def test_account_daily_balance_past(account: Account, today: date): assert len(balances) == 31 assert balances[0] == (start_date, Money(0)) - assert balances[-1] == (today, Money(2)) + assert balances[-1] == (today, Money(11)) def test_account_daily_balance_future(account: Account, today: date): @@ -155,10 +157,10 @@ def test_account_daily_balance_future(account: Account, today: date): balances = list(account.daily_balance(today, end_date)) assert len(balances) == 32 - assert balances[0] == (today, Money(2)) - assert balances[9] == (date(2022, 12, 15), Money(2)) - assert balances[11] == (date(2022, 12, 17), Money(4)) - assert balances[-1] == (end_date, Money(5)) + assert balances[0] == (today, Money(11)) + assert balances[9] == (date(2022, 12, 15), Money(11)) + assert balances[11] == (date(2022, 12, 17), Money(1011)) + assert balances[-1] == (end_date, Money(1111)) def test_account_daily_balance_cleared_true(account: Account, today: date): @@ -166,10 +168,10 @@ def test_account_daily_balance_cleared_true(account: Account, today: date): balances = list(account.daily_balance(today, end_date, cleared=True)) assert len(balances) == 32 - assert balances[0] == (today, Money(1)) - assert balances[9] == (date(2022, 12, 15), Money(1)) - assert balances[11] == (date(2022, 12, 17), Money(3)) - assert balances[-1] == (end_date, Money(3)) + assert balances[0] == (today, Money(10)) + assert balances[9] == (date(2022, 12, 15), Money(10)) + assert balances[11] == (date(2022, 12, 17), Money(1010)) + assert balances[-1] == (end_date, Money(1010)) def test_account_daily_balance_cleared_false(account: Account, today: date): @@ -180,4 +182,4 @@ def test_account_daily_balance_cleared_false(account: Account, today: date): assert balances[0] == (today, Money(1)) assert balances[9] == (date(2022, 12, 15), Money(1)) assert balances[11] == (date(2022, 12, 17), Money(1)) - assert balances[-1] == (end_date, Money(2)) + assert balances[-1] == (end_date, Money(101)) From 166b44afbf85efec309f668b932f78a97e44bc47 Mon Sep 17 00:00:00 2001 From: Jesse Brooklyn Hannah Date: Tue, 21 Jan 2025 16:54:03 -0800 Subject: [PATCH 7/7] Update CHANGELOG --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2836f8d..276eaca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v1.2.0 (unreleased) + +- Add `Transaction.cleared` boolean field. +- Add `RepeatingTransaction.last_cleared` date field. All `Transactions` yielded + will have their `cleared` field set to true if the date is before the value of + `last_cleared`. The same rule applies to `RepeatingTransfer`. +- Add `cleared: bool | None` parameters to `Account` methods, where a non-`None` + value filters account transactions by the given value for `cleared`. + ## v1.1.1 (2025-01-13) - Removed the ability to set a transaction's amount to a callback until I've