def serialise( self, conversion: str, ledger: "FavaLedger", end: Optional[datetime.date], ) -> SerialisedTreeNode: """Serialise the account. Args: end: A date to use for cost conversions. """ price_map = ledger.price_map children = [ child.serialise(conversion, ledger, end) for child in self.children ] return { "account": self.name, "label": self.label_or_name(ledger), "balance_children": cost_or_value( self.balance_children, conversion, price_map, end ), "balance": cost_or_value(self.balance, conversion, price_map, end), "children": children, }
def serialise( self, conversion: str, price_map: PriceMap, end: Optional[datetime.date], ) -> SerialisedTreeNode: """Serialise the account. Args: end: A date to use for cost conversions. """ children = [ child.serialise(conversion, price_map, end) for child in self.children ] return { "account": self.name, "balance_children": cost_or_value(self.balance_children, conversion, price_map, end), "balance": cost_or_value(self.balance, conversion, price_map, end), "children": children, }
def interval_totals( self, filtered: FilteredLedger, interval: Interval, accounts: str | tuple[str], conversion: str, invert: bool = False, ) -> Generator[DateAndBalanceWithBudget, None, None]: """Renders totals for account (or accounts) in the intervals. Args: interval: An interval. accounts: A single account (str) or a tuple of accounts. conversion: The conversion to use. invert: invert all numbers. """ # pylint: disable=too-many-locals price_map = self.ledger.price_map for begin, end in pairwise(filtered.interval_ends(interval)): inventory = Inventory() entries = iter_entry_dates(filtered.entries, begin, end) account_inventories = {} for entry in (e for e in entries if isinstance(e, Transaction)): for posting in entry.postings: if posting.account.startswith(accounts): if posting.account not in account_inventories: account_inventories[posting.account] = Inventory() account_inventories[posting.account].add_position( posting) inventory.add_position(posting) balance = cost_or_value(inventory, conversion, price_map, end - ONE_DAY) account_balances = {} for account, acct_value in account_inventories.items(): account_balances[account] = cost_or_value( acct_value, conversion, price_map, end - ONE_DAY, ) budgets = {} if isinstance(accounts, str): budgets = self.ledger.budgets.calculate_children( accounts, begin, end) if invert: # pylint: disable=invalid-unary-operand-type balance = -balance budgets = {k: -v for k, v in budgets.items()} account_balances = {k: -v for k, v in account_balances.items()} yield DateAndBalanceWithBudget( begin, balance, account_balances, budgets, )
def interval_totals( self, interval: Interval, accounts: Union[str, Tuple[str]], conversion: str, ): """Renders totals for account (or accounts) in the intervals. Args: interval: An interval. accounts: A single account (str) or a tuple of accounts. conversion: The conversion to use. """ price_map = self.ledger.price_map for begin, end in pairwise(self.ledger.interval_ends(interval)): inventory = Inventory() entries = iter_entry_dates(self.ledger.entries, begin, end) for entry in (e for e in entries if isinstance(e, Transaction)): for posting in entry.postings: if posting.account.startswith(accounts): inventory.add_position(posting) yield { "date": begin, "balance": cost_or_value(inventory, conversion, price_map, end - ONE_DAY), "budgets": self.ledger.budgets.calculate_children(accounts, begin, end), }
def serialise(self, conversion, price_map, end: datetime.date): """Serialise the account. Args: end: A date to use for cost conversions. """ children = [ child.serialise(conversion, price_map, end) for child in self.children ] return { "account": self.name, "balance_children": cost_or_value(self.balance_children, conversion, price_map, end), "balance": cost_or_value(self.balance, conversion, price_map, end), "children": children, }
def serialise( self, conversion: str, price_map: PriceMap, end: datetime.date | None, ) -> SerialisedTreeNode: """Serialise the account. Args: end: A date to use for cost conversions. """ children = [ child.serialise(conversion, price_map, end) for child in self.children ] return SerialisedTreeNode( self.name, cost_or_value(self.balance, conversion, price_map, end), cost_or_value(self.balance_children, conversion, price_map, end), children, )
def net_worth( self, interval: Interval, conversion: str ) -> Generator[DateAndBalance, None, None]: """Compute net worth. Args: interval: A string for the interval. conversion: The conversion to use. 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 != FLAG_UNREALIZED ) ) types = ( self.ledger.options["name_assets"], self.ledger.options["name_liabilities"], ) txn = next(transactions, None) inventory = Inventory() price_map = self.ledger.price_map for end_date in self.ledger.interval_ends(interval): while txn and txn.date < end_date: for posting in txn.postings: if posting.account.startswith(types): inventory.add_position(posting) txn = next(transactions, None) yield { "date": end_date, "balance": cost_or_value( inventory, conversion, price_map, end_date - ONE_DAY ), }
def linechart( self, account_name: str, conversion: str ) -> Generator[DateAndBalance, None, None]: """The balance of an account. Args: account_name: A string. conversion: The conversion to use. Returns: A list of dicts for all dates on which the balance of the given account has changed containing the balance (in units) of the account at that date. """ real_account = realization.get_or_create( self.ledger.root_account, account_name ) postings = realization.get_postings(real_account) journal = realization.iterate_with_balance(postings) # When the balance for a commodity just went to zero, it will be # missing from the 'balance' so keep track of currencies that last had # a balance. last_currencies = None price_map = self.ledger.price_map for entry, _, change, balance_inventory in journal: if change.is_empty(): continue balance = inv_to_dict( cost_or_value( balance_inventory, conversion, price_map, entry.date ) ) currencies = set(balance.keys()) if last_currencies: for currency in last_currencies - currencies: balance[currency] = 0 last_currencies = currencies yield {"date": entry.date, "balance": balance}
def interval_totals( self, interval: Interval, accounts: Union[str, Tuple[str]], conversion: str, invert: bool = False, ) -> Generator[DateAndBalanceWithBudget, None, None]: """Renders totals for account (or accounts) in the intervals. Args: interval: An interval. accounts: A single account (str) or a tuple of accounts. conversion: The conversion to use. """ price_map = self.ledger.price_map for begin, end in pairwise(self.ledger.interval_ends(interval)): inventory = Inventory() entries = iter_entry_dates(self.ledger.entries, begin, end) for entry in (e for e in entries if isinstance(e, Transaction)): for posting in entry.postings: if posting.account.startswith(accounts): inventory.add_position(posting) balance = cost_or_value( inventory, conversion, price_map, end - ONE_DAY ) budgets = {} if isinstance(accounts, str): budgets = self.ledger.budgets.calculate_children( accounts, begin, end ) if invert: # pylint: disable=invalid-unary-operand-type balance = -balance budgets = {k: -v for k, v in budgets.items()} yield { "date": begin, "balance": balance, "budgets": budgets, }