Changeset - ccc3a829da9e
[Not reviewed]
0 2 0
Brett Smith - 4 years ago 2020-06-15 14:38:26
brettcsmith@brettcsmith.org
reports: Add RelatedPostings.balance_at_cost_by_date() method.
2 files changed with 40 insertions and 0 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/reports/core.py
Show inline comments
...
 
@@ -359,24 +359,32 @@ class RelatedPostings(Sequence[data.Posting]):
 
    def iter_with_balance(self) -> Iterator[Tuple[data.Posting, Balance]]:
 
        balance = MutableBalance()
 
        for post in self:
 
            balance += post.units
 
            yield post, balance
 

	
 
    def balance(self) -> Balance:
 
        return Balance(post.units for post in self)
 

	
 
    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,
 
    ) -> Set[Optional[MetaValue]]:
 
        return {post.meta.get(key, default) for post in self}
 

	
 

	
 
class BaseSpreadsheet(Generic[RT, ST], metaclass=abc.ABCMeta):
 
    """Abstract base class to help write spreadsheets
 

	
 
    This class provides the very core logic to write an arbitrary set of data
 
    rows to arbitrary output. It calls hooks when it starts writing the
tests/test_reports_related_postings.py
Show inline comments
...
 
@@ -188,24 +188,56 @@ def test_balance_at_cost_singleton_without_cost():
 
        ('Assets:Receivable:Accounts', '20'),
 
    ])
 
    related = core.RelatedPostings(data.Posting.from_txn(txn))
 
    balance = related.balance_at_cost()
 
    amounts = set(balance.values())
 
    assert amounts == {testutil.Amount(20)}
 

	
 
def test_balance_at_cost_empty():
 
    related = core.RelatedPostings()
 
    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()
 

	
 
def test_meta_values_no_match():
 
    related = core.RelatedPostings([
 
        testutil.Posting('Income:Donations', -1, metakey='metavalue'),
 
    ])
 
    assert related.meta_values('key') == {None}
 

	
 
def test_meta_values_no_match_default_given():
 
    related = core.RelatedPostings([
0 comments (0 inline, 0 general)