Changeset - aa1f2ea35aed
[Not reviewed]
0 2 0
Brett Smith - 4 years ago 2020-08-18 05:28:37
brettcsmith@brettcsmith.org
balance_sheet: Balance.total() accepts multiple account names.

This simplifies the code to total all equity.
2 files changed with 13 insertions and 13 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/reports/balance_sheet.py
Show inline comments
...
 
@@ -18,35 +18,37 @@ import argparse
 
import collections
 
import datetime
 
import enum
 
import logging
 
import os
 
import sys
 

	
 
from decimal import Decimal
 
from pathlib import Path
 

	
 
from typing import (
 
    Any,
 
    Collection,
 
    Dict,
 
    Hashable,
 
    Iterable,
 
    Iterator,
 
    List,
 
    Mapping,
 
    NamedTuple,
 
    Optional,
 
    Sequence,
 
    TextIO,
 
    Tuple,
 
    Union,
 
)
 

	
 
import odf.table  # type:ignore[import]
 

	
 
from beancount.parser import printer as bc_printer
 

	
 
from . import core
 
from .. import books
 
from .. import cliutil
 
from .. import config as configmod
 
from .. import data
 
from .. import ranges
...
 
@@ -118,33 +120,35 @@ class Balances:
 
                else:
 
                    raise TypeError()
 
            except (KeyError, TypeError):
 
                classification = account
 
            if account.root_part() == 'Expenses':
 
                post_type = post.meta.get('expense-type')
 
            else:
 
                post_type = None
 
            key = BalanceKey(account, classification, period, fund, post_type)
 
            self.balances[key] += post.at_cost()
 

	
 
    def total(self,
 
              account: Optional[str]=None,
 
              account: Union[None, str, Collection[str]]=None,
 
              classification: Optional[str]=None,
 
              period: int=Period.ANY,
 
              fund: int=Fund.ANY,
 
              post_type: Optional[str]=None,
 
    ) -> core.Balance:
 
        if isinstance(account, str):
 
            account = (account,)
 
        retval = core.MutableBalance()
 
        for key, balance in self.balances.items():
 
            if not (account is None or key.account.is_under(account)):
 
            if not (account is None or key.account.is_under(*account)):
 
                pass
 
            elif not (classification is None
 
                      or key.classification.is_under(classification)):
 
                pass
 
            elif not period & key.period:
 
                pass
 
            elif not fund & key.fund:
 
                pass
 
            elif not (post_type is None or post_type == key.post_type):
 
                pass
 
            else:
 
                retval += balance
...
 
@@ -319,31 +323,27 @@ class Report(core.BaseODS[Sequence[None], None]):
 
            self.balance_cell(period_liabilities, stylename=self.style_totline),
 
            self.balance_cell(prior_liabilities, stylename=self.style_totline),
 
        )
 
        self.add_row()
 
        self.add_row()
 

	
 
        prior_net = core.MutableBalance()
 
        period_net = core.MutableBalance()
 
        self.add_row(self.string_cell("Net Assets", stylename=self.style_bold))
 
        self.add_row()
 
        for fund in [Fund.UNRESTRICTED, Fund.RESTRICTED]:
 
            preposition = "Without" if fund is Fund.UNRESTRICTED else "With"
 
            period_bal = -sum(
 
                (self.balances.total(account=account, fund=fund)
 
                 for account in EQUITY_ACCOUNTS), core.MutableBalance(),
 
            )
 
            prior_bal = period_bal + sum(
 
                (self.balances.total(account=account, fund=fund, period=Period.PERIOD)
 
                 for account in EQUITY_ACCOUNTS), core.MutableBalance(),
 
            period_bal = -self.balances.total(account=EQUITY_ACCOUNTS, fund=fund)
 
            prior_bal = period_bal + self.balances.total(
 
                account=EQUITY_ACCOUNTS, fund=fund, period=Period.PERIOD,
 
            )
 
            self.add_row(
 
                self.string_cell(f"{preposition} donor restrictions"),
 
                self.balance_cell(period_bal),
 
                self.balance_cell(prior_bal),
 
            )
 
            prior_net += prior_bal
 
            period_net += period_bal
 
        self.add_row(
 
            self.string_cell("Total Net Assets"),
 
            self.balance_cell(period_net, stylename=self.style_subtotline),
 
            self.balance_cell(prior_net, stylename=self.style_subtotline),
...
 
@@ -487,26 +487,25 @@ class Report(core.BaseODS[Sequence[None], None]):
 
        self.add_row()
 
        self.add_row(
 
            self.string_cell("Change in Net Assets"),
 
            *(self.balance_cell(total) for total in totals),
 
        )
 

	
 
        for kwargs in bal_kwargs:
 
            if kwargs['period'] is Period.PERIOD:
 
                kwargs['period'] = Period.BEFORE_PERIOD
 
            else:
 
                kwargs['period'] = Period.OPENING
 
        beginnings = [
 
            -sum((self.balances.total(account=account, **kwargs)
 
                  for account in EQUITY_ACCOUNTS), core.MutableBalance())
 
            -self.balances.total(account=EQUITY_ACCOUNTS, **kwargs)
 
            for kwargs in bal_kwargs
 
        ]
 
        self.add_row()
 
        self.add_row(
 
            self.string_cell("Beginning Net Assets"),
 
            *(self.balance_cell(beg_bal) for beg_bal in beginnings),
 
        )
 

	
 
        self.add_row()
 
        self.add_row(
 
            self.string_cell("Ending Net Assets"),
 
            *(self.balance_cell(beg_bal + tot_bal, stylename=self.style_bottomline)
...
 
@@ -598,26 +597,25 @@ class Report(core.BaseODS[Sequence[None], None]):
 
        self.add_row(
 
            odf.table.TableCell(),
 
            self.string_cell(self.period_name, stylename=self.style_huline),
 
            self.string_cell(self.opening_name, stylename=self.style_huline),
 
        )
 
        self.add_row(self.string_cell(
 
            "Cash Flows from Operating Activities",
 
            stylename=self.style_bold,
 
        ))
 
        self.add_row()
 

	
 
        totals = [
 
            -sum((self.balances.total(account=account, **kwargs)
 
                  for account in EQUITY_ACCOUNTS), core.MutableBalance())
 
            -self.balances.total(account=EQUITY_ACCOUNTS, **kwargs)
 
            for kwargs in bal_kwargs
 
        ]
 
        self.add_row(
 
            self.string_cell("Change in Net Assets"),
 
            *(self.balance_cell(bal) for bal in totals),
 
        )
 
        self.add_row(self.string_cell(
 
            "(Increase) decrease in operating assets:",
 
        ))
 
        for text, classification in self.walk_classifications_by_account('Assets'):
 
            text_cell = self.string_cell(self.SPACE + text)
 
            if classification is None:
tests/test_reports_balance_sheet.py
Show inline comments
...
 
@@ -85,24 +85,26 @@ def income_expense_balances():
 
    ({'classification': 'Nonexistent'}, None),
 
    ({'period': Period.PRIOR, 'account': 'Income'}, '-9.60'),
 
    ({'period': Period.PERIOD, 'account': 'Expenses'}, 26),
 
    ({'fund': Fund.RESTRICTED, 'account': 'Income'}, -10),
 
    ({'fund': Fund.UNRESTRICTED, 'account': 'Expenses'}, 25),
 
    ({'post_type': 'fundraising'}, 20),
 
    ({'post_type': 'management'}, 10),
 
    ({'post_type': 'Nonexistent'}, None),
 
    ({'period': Period.PRIOR, 'post_type': 'fundraising'}, '9.60'),
 
    ({'fund': Fund.RESTRICTED, 'post_type': 'program'}, 10),
 
    ({'period': Period.PRIOR, 'fund': Fund.RESTRICTED, 'post_type': 'program'}, '4.80'),
 
    ({'period': Period.PERIOD, 'fund': Fund.RESTRICTED, 'post_type': 'ΓΈ'}, None),
 
    ({'account': ('Income', 'Expenses')}, 30),
 
    ({'account': ('Income', 'Expenses'), 'fund': Fund.UNRESTRICTED}, 15),
 
])
 
def test_balance_total(income_expense_balances, kwargs, expected):
 
    actual = income_expense_balances.total(**kwargs)
 
    if expected is None:
 
        assert not actual
 
    else:
 
        assert actual == {'USD': testutil.Amount(expected)}
 

	
 
def run_main(arglist=[], config=None):
 
    if config is None:
 
        config = testutil.TestConfig(books_path=testutil.test_path('books/fund.beancount'))
 
    stdout = io.BytesIO()
0 comments (0 inline, 0 general)