def net_worth(self, interval): """Compute net worth. Args: interval: A string for the interval. Returns: A list of dicts for all ends of the given interval containing the net worth (Assets + Liabilities) separately converted to all operating currencies. """ transactions = (entry for entry in self.ledger.entries if (isinstance(entry, Transaction) and entry.flag != flags.FLAG_UNREALIZED)) types = ( self.ledger.options["name_assets"], self.ledger.options["name_liabilities"], ) txn = next(transactions, None) inventory = CounterInventory() for end_date_exclusive in self.ledger.interval_ends(interval): end_date_inclusive = end_date_exclusive - datetime.timedelta( days=1) while txn and txn.date < end_date_exclusive: for posting in filter(lambda p: p.account.startswith(types), txn.postings): inventory.add_position(posting) txn = next(transactions, None) yield { "date": end_date_exclusive, "balance": cost_or_value(inventory, end_date_inclusive), }
def __init__(self, name): #: str: Account name. self.name = name #: A list of :class:`.TreeNode`, its children. self.children = [] #: :class:`.CounterInventory`: The cumulative account balance. self.balance_children = CounterInventory() #: :class:`.CounterInventory`: The account balance. self.balance = CounterInventory() #: bool: True if the account has any transactions. self.has_txns = False
def __init__(self, name: str) -> None: #: Account name. self.name: str = name #: A list of :class:`.TreeNode`, its children. self.children: List["TreeNode"] = [] #: The cumulative account balance. self.balance_children = CounterInventory() #: The account balance. self.balance = CounterInventory() #: Whether the account has any transactions. self.has_txns = False
def test_render_diff_and_number(app, snapshot) -> None: with app.test_request_context("/long-example/"): app.preprocess_request() macro = get_template_attribute(TREE_TABLE_PATH, "render_diff_and_number") for invert in [False, True]: balance = CounterInventory({"EUR": Decimal(12)}) cost = CounterInventory({"EUR": Decimal(10)}) snapshot(macro(balance, cost, "EUR", invert)) for invert in [False, True]: balance = CounterInventory({"EUR": Decimal(10)}) cost = CounterInventory({"EUR": Decimal(12)}) snapshot(macro(balance, cost, "EUR", invert))
def net_worth(self, interval): """Compute net worth. Args: interval: A string for the interval. Returns: A list of dicts for all ends of the given interval containing the net worth (Assets + Liabilities) separately converted to all operating currencies. """ transactions = (entry for entry in self.ledger.entries if (isinstance(entry, Transaction) and entry.flag != flags.FLAG_UNREALIZED)) types = ( self.ledger.options['name_assets'], self.ledger.options['name_liabilities'], ) txn = next(transactions, None) inventory = CounterInventory() for date in self.ledger.interval_ends(interval): while txn and txn.date < date: for posting in filter(lambda p: p.account.startswith(types), txn.postings): # Since we will be reducing the inventory to the operating # currencies, pre-aggregate the positions to reduce the # number of elements in the inventory. inventory.add_amount( posting.units, Cost(ZERO, posting.cost.currency, None, None) if posting.cost else None, ) txn = next(transactions, None) yield { 'date': date, 'balance': { currency: inventory.reduce( convert.convert_position, currency, self.ledger.price_map, date, ).get(currency) for currency in self.ledger.options['operating_currency'] }, }
def cap(self, options, unrealized_account): """Transfer Income and Expenses, add conversions and unrealized gains. Args: options: The Beancount options. unrealized_account: The name of the account to post unrealized gains to (as a subaccount of Equity). """ equity = options['name_equity'] conversions = CounterInventory({ (currency, None): -number for currency, number in self.get('').balance_children.reduce( convert.get_cost).items() }) # Add conversions self.insert(equity + ':' + options['account_current_conversions'], conversions) # Insert unrealized gains. self.insert(equity + ':' + unrealized_account, -self.get('').balance_children) # Transfer Income and Expenses self.insert(equity + ':' + options['account_current_earnings'], self.get(options['name_income']).balance_children) self.insert(equity + ':' + options['account_current_earnings'], self.get(options['name_expenses']).balance_children)
def test_add() -> None: inv = CounterInventory() key = ("KEY", None) inv.add(key, D(10)) assert len(inv) == 1 inv.add(key, D(-10)) assert inv.is_empty()
def test_add(): inv = CounterInventory() key = "KEY" inv.add(key, 10) assert len(inv) == 1 inv.add(key, -10) assert inv.is_empty()
def net_worth(self, interval): """Compute net worth. Args: interval: A string for the interval. Returns: A list of dicts for all ends of the given interval containing the net worth (Assets + Liabilities) separately converted to all operating currencies. """ transactions = (entry for entry in self.ledger.entries if (isinstance(entry, Transaction) and entry.flag != flags.FLAG_UNREALIZED)) types = (self.ledger.options['name_assets'], self.ledger.options['name_liabilities']) txn = next(transactions, None) inventory = CounterInventory() for date in self.ledger.interval_ends(interval): while txn and txn.date < date: for posting in filter(lambda p: p.account.startswith(types), txn.postings): # Since we will be reducing the inventory to the operating # currencies, pre-aggregate the positions to reduce the # number of elements in the inventory. inventory.add_amount( posting.units, Cost(ZERO, posting.cost.currency, None, None) if posting.cost else None) txn = next(transactions, None) yield { 'date': date, 'balance': { currency: inventory.reduce(convert.convert_position, currency, self.ledger.price_map, date).get(currency) for currency in self.ledger.options['operating_currency'] } }
def interval_totals(self, interval, accounts): """Renders totals for account (or accounts) in the intervals. Args: interval: An interval. accounts: A single account (str) or a tuple of accounts. """ for begin, end in pairwise(self.ledger.interval_ends(interval)): inventory = CounterInventory() entries = iter_entry_dates(self.ledger.entries, begin, end) for entry in filter_type(entries, Transaction): for posting in entry.postings: if posting.account.startswith(accounts): inventory.add_position(posting) yield { 'date': begin, 'balance': cost_or_value(inventory, end), 'budgets': self.ledger.budgets.calculate_children(accounts, begin, end), }
def test_add(): inv = CounterInventory() key = 'KEY' inv.add(key, 10) assert len(inv) == 1 inv.add(key, -10) assert inv.is_empty()
def interval_totals(self, interval, accounts): """Renders totals for account (or accounts) in the intervals. Args: interval: An interval. accounts: A single account (str) or a tuple of accounts. """ for begin, end in pairwise(self.ledger.interval_ends(interval)): inventory = CounterInventory() entries = iter_entry_dates(self.ledger.entries, begin, end) for entry in filter_type(entries, Transaction): for posting in entry.postings: if posting.account.startswith(accounts): inventory.add_position(posting) yield { "date": begin, "balance": cost_or_value(inventory, end), "budgets": self.ledger.budgets.calculate_children( accounts, begin, end ), }
def test_should_show(app: Flask) -> None: with app.test_request_context("/long-example/"): app.preprocess_request() assert should_show(g.filtered.root_tree.get("")) is True assert should_show(g.filtered.root_tree.get("Expenses")) is True account = TreeNode("name") assert should_show(account) is False account.balance_children = CounterInventory({("USD", None): D("9")}) assert should_show(account) is True with app.test_request_context("/long-example/income_statement/?time=2100"): app.preprocess_request() assert not g.ledger.fava_options.show_accounts_with_zero_balance assert should_show(g.filtered.root_tree.get("")) is True assert should_show(g.filtered.root_tree.get("Expenses")) is False
def test_should_show(app): with app.test_request_context("/long-example/"): app.preprocess_request() assert should_show(g.ledger.root_tree.get("")) is True assert should_show(g.ledger.root_tree.get("Expenses")) is True account = TreeNode("name") assert should_show(account) is False account.balance_children = CounterInventory({("USD", None): 9}) assert should_show(account) is True with app.test_request_context("/long-example/income_statement/?time=2100"): app.preprocess_request() assert not g.ledger.fava_options["show-accounts-with-zero-balance"] assert should_show(g.ledger.root_tree.get("")) is True assert should_show(g.ledger.root_tree.get("Expenses")) is False
def test_should_show(app): with app.test_request_context('/'): app.preprocess_request() assert should_show(g.ledger.root_tree.get('')) is True assert should_show(g.ledger.root_tree.get('Expenses')) is True account = TreeNode('name') assert should_show(account) is False account.balance_children = CounterInventory({('USD', None): 9}) assert should_show(account) is True with app.test_request_context('/?time=2100'): app.preprocess_request() assert not g.ledger.fava_options['show-accounts-with-zero-balance'] assert should_show(g.ledger.root_tree.get('')) is True assert should_show(g.ledger.root_tree.get('Expenses')) is False
def test_CounterInventory_add_inventory(): inv = CounterInventory() inv2 = CounterInventory() inv3 = CounterInventory() inv.add_amount(A('10 USD')) inv2.add_amount(A('30 USD')) inv3.add_amount(A('-40 USD')) inv.add_inventory(inv2) assert len(inv) == 1 inv.add_inventory(inv3) assert inv.is_empty() inv = CounterInventory() inv.add_inventory(inv2) assert len(inv) == 1
def test_add_inventory(): inv = CounterInventory() inv2 = CounterInventory() inv3 = CounterInventory() inv.add_amount(A("10 USD")) inv2.add_amount(A("30 USD")) inv3.add_amount(A("-40 USD")) inv.add_inventory(inv2) assert len(inv) == 1 inv.add_inventory(inv3) assert inv.is_empty() inv = CounterInventory() inv.add_inventory(inv2) assert len(inv) == 1
def test_add_amount(): inv = CounterInventory() inv.add_amount(A("10 USD")) inv.add_amount(A("30 USD")) assert len(inv) == 1 inv.add_amount(A("-40 USD")) assert inv.is_empty() inv.add_amount(A("10 USD")) inv.add_amount(A("20 CAD")) inv.add_amount(A("10 USD")) assert len(inv) == 2 inv.add_amount(A("-20 CAD")) assert len(inv) == 1
def test_add_amount(): inv = CounterInventory() inv.add_amount(A('10 USD')) inv.add_amount(A('30 USD')) assert len(inv) == 1 inv.add_amount(A('-40 USD')) assert inv.is_empty() inv.add_amount(A('10 USD')) inv.add_amount(A('20 CAD')) inv.add_amount(A('10 USD')) assert len(inv) == 2 inv.add_amount(A('-20 CAD')) assert len(inv) == 1
def test_add_inventory(): inv = CounterInventory() inv2 = CounterInventory() inv3 = CounterInventory() inv.add_amount(A('10 USD')) inv2.add_amount(A('30 USD')) inv3.add_amount(A('-40 USD')) inv.add_inventory(inv2) assert len(inv) == 1 inv.add_inventory(inv3) assert inv.is_empty() inv = CounterInventory() inv.add_inventory(inv2) assert len(inv) == 1