예제 #1
0
    def test_compute_balance(self):
        real_root = create_real([('Assets:US:Bank:Checking', '100 USD'),
                                 ('Assets:US:Bank:Savings', '200 USD'),
                                 ('Assets:US:Bank', '10 USD'),
                                 ('Liabilities:Bank:CreditCard', '-500 USD')])
        balance = realization.compute_balance(real_root)
        self.assertEqual(inventory.from_string('-190 USD'), balance)

        balance = realization.compute_balance(realization.get(real_root, 'Assets:US:Bank'))
        self.assertEqual(inventory.from_string('310 USD'), balance)
def asset_allocation(
        filename,
        accounts:
    'Regex patterns of accounts to include in asset allocation.' = '',
        base_currency='USD',
        dump_balances_tree=False,
        skip_tax_adjustment=False,
        debug=False):

    if not accounts:
        accounts = ['.*']
    global argsmap
    argsmap = locals()
    init_entries(filename, argsmap)

    realacc = build_interesting_realacc(entries, accounts)
    if not skip_tax_adjustment:
        tax_adjust(realacc)
    balance = realization.compute_balance(realacc)
    vbalance = balance.reduce(convert.get_units)
    asset_buckets = bucketize(vbalance, base_currency, entries)

    # print output
    print(tabulate_asset_buckets(asset_buckets))
    if dump_balances_tree:
        print_balances_tree(realacc)
예제 #3
0
 def _total_balance(self, names, begin_date, end_date):
     totals = [realization.compute_balance(
         self._real_account(account_name, self.entries, begin_date,
                            end_date))
               for account_name in names]
     return serialize_inventory(sum(totals, inventory.Inventory()),
                                at_cost=True)
예제 #4
0
파일: __init__.py 프로젝트: cgrinds/fava
 def _total_balance(self, names, begin_date, end_date):
     totals = [realization.compute_balance(
         self._real_account(account_name, self.entries, begin_date,
                            end_date))
               for account_name in names]
     return serialize_inventory(sum(totals, inventory.Inventory()),
                                at_cost=True)
예제 #5
0
def test_tree_from_entries(example_ledger):
    tree = Tree(example_ledger.entries)
    real_account = realization.realize(example_ledger.entries)

    for account in realization.iter_children(real_account):
        name = account.account
        node = tree[name]
        _compare_inv_and_counter(account.balance, node.balance)
        _compare_inv_and_counter(realization.compute_balance(account),
                                 node.balance_children)
예제 #6
0
def _serialize_real_account(real_account):
    return {
        'account': real_account.account,
        'balance_children':
            _serialize_inventory(realization.compute_balance(real_account),
                                 at_cost=True),
        'balance': _serialize_inventory(real_account.balance, at_cost=True),
        'children': [_serialize_real_account(a)
                     for n, a in sorted(real_account.items())],
    }
예제 #7
0
파일: charts.py 프로젝트: yagebu/fava
def _serialize_real_account(real_account):
    return {
        'account': real_account.account,
        'balance_children':
            _serialize_inventory(realization.compute_balance(real_account),
                                 at_cost=True),
        'balance': _serialize_inventory(real_account.balance, at_cost=True),
        'children': [_serialize_real_account(a)
                     for n, a in sorted(real_account.items())],
    }
예제 #8
0
파일: api.py 프로젝트: ghmajx/beancount-web
    def _table_totals(self, real_account):
        """
            Renders the total balances for root_acccounts and their children.

            Returns:
                {
                    'USD': 123.45,
                    ...
                }
        """
        return self._inventory_to_json(realization.compute_balance(real_account), at_cost=True)
예제 #9
0
    def _table_totals(self, real_account):
        """
            Renders the total balances for root_acccounts and their children.

            Returns:
                {
                    'USD': 123.45,
                    ...
                }
        """
        return self._inventory_to_json(
            realization.compute_balance(real_account), at_cost=True)
예제 #10
0
    def render_real_htmldiv(self, real_root, options_map, file):
        text = tree_table.table_of_balances(real_root,
                                            options_map['operating_currency'],
                                            self.formatter,
                                            classes=['trial'])

        balance_cost = realization.compute_balance(real_root).cost()
        if not balance_cost.is_empty():
            text += """
              Total Balance: <span class="num">{}</span>
            """.format(balance_cost)

        file.write(text)
예제 #11
0
파일: __init__.py 프로젝트: miaoluda/fava
 def _table_tree(self, real_account):
     """
     Renders real_account and it's children as a flat list to be used
     in rendering tables.
     """
     return [{
         'account': ra.account,
         'balances_children':
             serialize_inventory(realization.compute_balance(ra),
                                 at_cost=True),
         'balances': serialize_inventory(ra.balance, at_cost=True),
         'is_leaf': len(ra) == 0 or bool(ra.txn_postings),
         'postings_count': len(ra.txn_postings)
     } for ra in realization.iter_children(real_account)]
예제 #12
0
파일: charts.py 프로젝트: mhansen/fava
def _serialize_real_account(real_account, date):
    return {
        'account':
        real_account.account,
        'balance_children':
        _inventory_cost_or_value(realization.compute_balance(real_account),
                                 date),
        'balance':
        _inventory_cost_or_value(real_account.balance, date),
        'children': [
            _serialize_real_account(account, date)
            for _, account in sorted(real_account.items())
        ],
    }
예제 #13
0
def assetalloc(accapi, config={}):
    realacc = build_interesting_realacc(
        accapi, config.get('accounts_patterns', ['.*']))
    # print(realization.compute_balance(realacc).reduce(convert.get_units))

    if config.get('skip_tax_adjustment', False) is False:
        tax_adjust(realacc, accapi)
    # print(realization.compute_balance(realacc).reduce(convert.get_units))

    balance = realization.compute_balance(realacc)
    vbalance = balance.reduce(convert.get_units)
    asset_buckets = bucketize(vbalance, accapi)

    return treeify(asset_buckets, accapi), realacc
예제 #14
0
def serialize_real_account(ra):
    return {
        'account': ra.account,
        'balance_children':
            serialize_inventory(realization.compute_balance(ra),
                                at_cost=True),
        'balance': serialize_inventory(ra.balance, at_cost=True),
        'is_leaf': len(ra) == 0 or bool(ra.txn_postings),
        'is_closed': isinstance(realization.find_last_active_posting(
            ra.txn_postings), Close),
        'has_transactions': any(isinstance(t, TxnPosting)
                                for t in ra.txn_postings),
        'children': [serialize_real_account(a) for n, a in sorted(ra.items())],
    }
예제 #15
0
def zip_real_accounts(ra_list):
    if not ra_list:
        return
    first = ra_list[0]
    return {
        'account': first.account,
        'balance_and_balance_children':
            [(serialize_inventory(ra.balance, at_cost=True),
              serialize_inventory(realization.compute_balance(ra),
                                  at_cost=True))
             for ra in ra_list],
        'children': [zip_real_accounts([realization.get(ra, n)
                                        for ra in ra_list])
                     for n, a in sorted(first.items())],
    }
예제 #16
0
def zip_real_accounts(ra_list):
    if not ra_list:
        return
    first = ra_list[0]
    return {
        'account':
        first.account,
        'balance_and_balance_children':
        [(serialize_inventory(ra.balance, at_cost=True),
          serialize_inventory(realization.compute_balance(ra), at_cost=True))
         for ra in ra_list],
        'children': [
            zip_real_accounts([realization.get(ra, n) for ra in ra_list])
            for n, a in sorted(first.items())
        ],
    }
예제 #17
0
def serialize_real_account(ra):
    return {
        'account':
        ra.account,
        'balance_children':
        serialize_inventory(realization.compute_balance(ra), at_cost=True),
        'balance':
        serialize_inventory(ra.balance, at_cost=True),
        'is_leaf':
        len(ra) == 0 or bool(ra.txn_postings),
        'is_closed':
        isinstance(realization.find_last_active_posting(ra.txn_postings),
                   Close),
        'has_transactions':
        any(isinstance(t, TxnPosting) for t in ra.txn_postings),
        'children': [serialize_real_account(a) for n, a in sorted(ra.items())],
    }
예제 #18
0
def get_balance(account, currency, real_root):
    real_account = realization.get(real_root, account)
    subtree_balance = realization.compute_balance(real_account,
                                                  leaf_only=False)
    return subtree_balance.get_currency_units(currency)
예제 #19
0
def read_assets(filename, currency, reduce_accounts, quantization):
    """Read a Beancount file and produce a list of assets.

    Args:
      filename: A string, the path to the Beancount file to read.
      currency: A string, the currency to convert all the contents to.
      reduce_accounts: A set of account names to be aggregated.
      quantization: A Decimal instance, to quantize all the resulting amounts.
    Returns:
      A list of (account-name, number-balance), numbers being assumed to be in
      the requested currency.
    """

    # Read the Beancount input file.
    entries, _, options_map = loader.load_file(filename,
                                               log_errors=logging.error)
    acctypes = options.get_account_types(options_map)
    price_map = prices.build_price_map(entries)
    ocmap = getters.get_account_open_close(entries)

    # Compute aggregations.
    real_root = realization.realize(entries, compute_balance=True)

    # Reduce accounts which have been found in details (mutate the tree in-place).
    for account in reduce_accounts:
        real_acc = realization.get(real_root, account)
        real_acc.balance = realization.compute_balance(real_acc)
        real_acc.clear()

    # Prune all the closed accounts and their parents.
    real_root = prune_closed_accounts(real_root, ocmap)

    # Produce a list of accounts and their balances reduced to a single currency.
    acceptable_types = (acctypes.assets, acctypes.liabilities)
    accounts = []
    for real_acc in realization.iter_children(real_root):
        atype = account_types.get_account_type(real_acc.account)
        if atype not in acceptable_types:
            continue

        try:
            _, close = ocmap[real_acc.account]
            if close is not None:
                continue
        except KeyError:
            #logging.info("Account not there: {}".format(real_acc.account))
            if real_acc.account not in reduce_accounts and real_acc.balance.is_empty(
            ):
                continue

        value_inv = real_acc.balance.reduce(
            lambda x: convert.get_value(x, price_map))
        currency_inv = value_inv.reduce(convert.convert_position, currency,
                                        price_map)
        amount = currency_inv.get_currency_units(currency)
        accounts.append(
            (real_acc.account, amount.number.quantize(quantization)))

    # Reduce this list of (account-name, balance-number) sorted by reverse amount order.
    accounts.sort(key=lambda x: x[1], reverse=True)
    return accounts
예제 #20
0
def balance_children(account):
    """Compute the total balance of an account."""
    return realization.compute_balance(account)
예제 #21
0
def balance_children(account):
    return realization.compute_balance(account)
예제 #22
0
def balance_children(account: realization.RealAccount) -> Inventory:
    """Compute the total balance of an account."""
    return realization.compute_balance(account)
예제 #23
0
def balance_children(account):
    """Compute the total balance of an account."""
    return realization.compute_balance(account)
예제 #24
0
def check(entries, options_map):
    """Process the balance assertion directives.

    For each Balance directive, check that their expected balance corresponds to
    the actual balance computed at that time and replace failing ones by new
    ones with a flag that indicates failure.

    Args:
      entries: A list of directives.
      options_map: A dict of options, parsed from the input file.
    Returns:
      A pair of a list of directives and a list of balance check errors.
    """
    new_entries = []
    check_errors = []

    # This is similar to realization, but performed in a different order, and
    # where we only accumulate inventories for accounts that have balance
    # assertions in them (this saves on time). Here we process the entries one
    # by one along with the balance checks. We use a temporary realization in
    # order to hold the incremental tree of balances, so that we can easily get
    # the amounts of an account's subaccounts for making checks on parent
    # accounts.
    real_root = realization.RealAccount('')

    # Figure out the set of accounts for which we need to compute a running
    # inventory balance.
    asserted_accounts = {
        entry.account
        for entry in entries if isinstance(entry, Balance)
    }

    # Add all children accounts of an asserted account to be calculated as well,
    # and pre-create these accounts, and only those (we're just being tight to
    # make sure).
    asserted_match_list = [
        account.parent_matcher(account_) for account_ in asserted_accounts
    ]
    for account_ in getters.get_accounts(entries):
        if (account_ in asserted_accounts
                or any(match(account_) for match in asserted_match_list)):
            realization.get_or_create(real_root, account_)

    # Get the Open directives for each account.
    open_close_map = getters.get_account_open_close(entries)

    for entry in entries:
        if isinstance(entry, Transaction):
            # For each of the postings' accounts, update the balance inventory.
            for posting in entry.postings:
                real_account = realization.get(real_root, posting.account)

                # The account will have been created only if we're meant to track it.
                if real_account is not None:
                    # Note: Always allow negative lots for the purpose of balancing.
                    # This error should show up somewhere else than here.
                    real_account.balance.add_position(posting)

        elif isinstance(entry, Balance):
            # Check that the currency of the balance check is one of the allowed
            # currencies for that account.
            expected_amount = entry.amount
            try:
                open, _ = open_close_map[entry.account]
            except KeyError:
                check_errors.append(
                    BalanceError(
                        entry.meta,
                        "Invalid reference to unknown account '{}'".format(
                            entry.account), entry))
                continue

            if (expected_amount is not None and open and open.currencies
                    and expected_amount.currency not in open.currencies):
                check_errors.append(
                    BalanceError(
                        entry.meta,
                        "Invalid currency '{}' for Balance directive: ".format(
                            expected_amount.currency), entry))

            # Sum up the current balances for this account and its
            # sub-accounts. We want to support checks for parent accounts
            # for the total sum of their subaccounts.
            #
            # FIXME: Improve the performance further by computing the balance
            # for the desired currency only. This won't allow us to cache in
            # this way but may be faster, if we're not asserting all the
            # currencies. Furthermore, we could probably avoid recomputing the
            # balance if a subtree of positions hasn't been invalidated by a new
            # position added to the realization. Do this.
            real_account = realization.get(real_root, entry.account)
            assert real_account is not None, "Missing {}".format(entry.account)
            subtree_balance = realization.compute_balance(real_account,
                                                          leaf_only=False)

            # Get only the amount in the desired currency.
            balance_amount = subtree_balance.get_currency_units(
                expected_amount.currency)

            # Check if the amount is within bounds of the expected amount.
            diff_amount = amount.sub(balance_amount, expected_amount)

            # Use the specified tolerance or automatically infer it.
            tolerance = get_balance_tolerance(entry, options_map)

            if abs(diff_amount.number) > tolerance:
                check_errors.append(
                    BalanceError(
                        entry.meta,
                        ("Balance failed for '{}': "
                         "expected {} != accumulated {} ({} {})").format(
                             entry.account, expected_amount, balance_amount,
                             abs(diff_amount.number),
                             ('too much' if diff_amount.number > 0 else
                              'too little')), entry))

                # Substitute the entry by a failing entry, with the diff_amount
                # field set on it. I'm not entirely sure that this is the best
                # of ideas, maybe leaving the original check intact and insert a
                # new error entry might be more functional or easier to
                # understand.
                entry = entry._replace(meta=entry.meta.copy(),
                                       diff_amount=diff_amount)

        new_entries.append(entry)

    return new_entries, check_errors