filters: Add remove_opening_balance_txn.

This commit is contained in:
Brett Smith 2020-05-30 08:30:07 -04:00
parent 32b62df540
commit a008a09477
2 changed files with 54 additions and 0 deletions

View file

@ -16,17 +16,24 @@
import re import re
from beancount.core import data as bc_data
from . import data from . import data
from . import rtutil from . import rtutil
from typing import ( from typing import (
cast,
Iterable, Iterable,
Optional,
Pattern, Pattern,
Union, Union,
) )
from .beancount_types import ( from .beancount_types import (
Directive,
Entries,
MetaKey, MetaKey,
MetaValue, MetaValue,
Transaction,
) )
Postings = Iterable[data.Posting] Postings = Iterable[data.Posting]
@ -56,3 +63,29 @@ def filter_for_rt_id(postings: Postings, ticket_id: Union[int, str]) -> Postings
""" """
regexp = rtutil.RT.metadata_regexp(ticket_id, first_link_only=True) regexp = rtutil.RT.metadata_regexp(ticket_id, first_link_only=True)
return filter_meta_match(postings, 'rt-id', regexp) return filter_meta_match(postings, 'rt-id', regexp)
def remove_opening_balance_txn(entries: Entries) -> Optional[Transaction]:
"""Remove an opening balance transaction from entries returned by Beancount
Returns the removed transaction if found, or None if not.
Note that it modifies the ``entries`` argument in-place.
This function is useful for tools like accrual-report that are more
focused on finding and reporting related transactions than providing
total account balances, etc. Since the opening balance transaction does not
provide the same metadata documentation as typical transactions, it's
typically easiest to filter it out before cross-referencing transactions by
metadata.
Note that this function only removes a single transaction, because that's
fastest for the common case.
"""
for index, entry in enumerate(entries):
if isinstance(entry, bc_data.Transaction):
entry = cast(Transaction, entry)
if data.is_opening_balance_txn(entry):
break
else:
return None
del entries[index]
return entry

View file

@ -134,3 +134,24 @@ def test_filter_for_rt_id_uses_first_link_only():
postings = data.Posting.from_entries(entries) postings = data.Posting.from_entries(entries)
actual = filters.filter_for_rt_id(postings, 350) actual = filters.filter_for_rt_id(postings, 350)
check_filter(actual, entries, ()), check_filter(actual, entries, ()),
@pytest.mark.parametrize('opening_txn', [
testutil.OpeningBalance(),
None,
])
def test_remove_opening_balance_txn(opening_txn):
entries = [
testutil.Transaction(postings=[
(account, amount),
('Assets:Checking', -amount),
])
for account, amount in [
('Income:Donations', -50),
('Expenses:Other', 75),
]]
if opening_txn is not None:
entries.insert(1, opening_txn)
actual = filters.remove_opening_balance_txn(entries)
assert actual is opening_txn
assert len(entries) == 2
assert opening_txn not in entries