diff --git a/conservancy_beancount/data.py b/conservancy_beancount/data.py index 8e191dfbf6677cc57602ab4f1d21d09fdc621fdf..b16e60e8856a9fdf0cc18ea77a72d4178080eb1d 100644 --- a/conservancy_beancount/data.py +++ b/conservancy_beancount/data.py @@ -260,6 +260,31 @@ class Posting(BasePosting): return self.account.is_cash_equivalent() and self.is_debit(threshold, default) +def balance_of(txn: Transaction, + *accounts: str, + default: Optional[DecimalCompat]=None, +) -> Optional[decimal.Decimal]: + """Return the balance of specified postings in a transaction. + + Given a transaction and a series of account names, balance_of returns the + balance of the amounts of all postings under those account names. + + Account names are matched using Account.is_under. Refer to that docstring + for details about what matches. + + If any of the postings have no amount, returns default. + """ + if default is not None: + default = decimal.Decimal(default) + retval = decimal.Decimal(0) + for post in txn.postings: + if Account(post.account).is_under(*accounts): + if post.units.number is None: + return default + else: + retval += post.units.number + return retval + def iter_postings(txn: Transaction) -> Iterator[Posting]: """Yield an enhanced Posting object for every posting in the transaction""" for index, source in enumerate(txn.postings):