From ccc3a829da9ef7a994d3935696f19563ba37af51 Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Mon, 15 Jun 2020 10:38:26 -0400 Subject: [PATCH] reports: Add RelatedPostings.balance_at_cost_by_date() method. --- conservancy_beancount/reports/core.py | 8 +++++++ tests/test_reports_related_postings.py | 32 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/conservancy_beancount/reports/core.py b/conservancy_beancount/reports/core.py index dbf602d..d2cc864 100644 --- a/conservancy_beancount/reports/core.py +++ b/conservancy_beancount/reports/core.py @@ -368,6 +368,14 @@ class RelatedPostings(Sequence[data.Posting]): def balance_at_cost(self) -> Balance: return Balance(post.at_cost() for post in self) + def balance_at_cost_by_date(self, date: datetime.date) -> Balance: + for index, post in enumerate(self): + if post.meta.date >= date: + break + else: + index += 1 + return Balance(post.at_cost() for post in self._postings[:index]) + def meta_values(self, key: MetaKey, default: Optional[MetaValue]=None, diff --git a/tests/test_reports_related_postings.py b/tests/test_reports_related_postings.py index f58a7f5..49f0534 100644 --- a/tests/test_reports_related_postings.py +++ b/tests/test_reports_related_postings.py @@ -197,6 +197,38 @@ def test_balance_at_cost_empty(): balance = related.balance_at_cost() assert balance.is_zero() +@pytest.mark.parametrize('date,expected', [ + (testutil.FY_MID_DATE - datetime.timedelta(days=1), 0), + (testutil.FY_MID_DATE, 0), + (testutil.FY_MID_DATE + datetime.timedelta(days=1), 25), + (testutil.FY_MID_DATE + datetime.timedelta(days=2), 70), + (testutil.FY_MID_DATE + datetime.timedelta(days=3), 135), + (testutil.FY_MID_DATE + datetime.timedelta(days=4), 135), +]) +def test_balance_at_cost_by_date(date, expected): + dates = testutil.date_seq() + jpy_cost = ('0.01', 'USD') + entries = [ + testutil.Transaction(date=next(dates), postings=[ + ('Assets:Cash', 1000, 'JPY', jpy_cost), + ('Assets:Cash', 15), + ]), + testutil.Transaction(date=next(dates), postings=[ + ('Assets:Cash', 2000, 'JPY', jpy_cost), + ('Assets:Cash', 25), + ]), + testutil.Transaction(date=next(dates), postings=[ + ('Assets:Cash', 3000, 'JPY', jpy_cost), + ('Assets:Cash', 35), + ]), + ] + related = core.RelatedPostings(data.Posting.from_entries(entries)) + actual = related.balance_at_cost_by_date(date) + if not expected: + assert actual.is_zero() + else: + assert actual == {'USD': testutil.Amount(expected)} + def test_meta_values_empty(): related = core.RelatedPostings() assert related.meta_values('key') == set()