예제 #1
0
파일: will.py 프로젝트: redstreet/beanlabs
def group_accounts_by_metadata(accounts_map, meta_name):
    """Group accounts by the value of a metadata field on its corresponding Open
    entry or in one of its parent accounts.

    Args:
      accounts_map: A mapping of account name to its Open entry.
      meta_name: A string, the name of a metadata key to extract to figure out the
        group name.
    Returns:
      A dict of group names (the values of the metadata field) to a list of account
      name strings, and a list of ignored accounts.
    """
    groups = collections.defaultdict(list)
    ignored_accounts = set()
    for account_ in accounts_map:
        # Find the group of this account; the group is defined as the first
        # parent account that has a particular metadata field. If an account is
        # not covered by a parent with the metadata, it defines its own group.
        for parent_account in account.parents(account_):
            open_entry = accounts_map.get(parent_account, None)
            if (open_entry and open_entry.meta and meta_name in open_entry.meta):
                group = open_entry.meta[meta_name]
                groups[group].append(account_)
                break
        else:
            ignored_accounts.add(account_)
    for group in groups.values():
        group.sort()
    return dict(groups), ignored_accounts
예제 #2
0
def create_report(entries, options_map):
    real_root = realization.realize(entries)

    # Find the institutions from the data.
    groups, ignored_accounts = find_institutions(entries, options_map)

    # List all the asset accounts which aren't included in the report.
    oc_map = getters.get_account_open_close(entries)
    open_map = {acc: open_entry for acc, (open_entry, _) in oc_map.items()}
    for acc in sorted(ignored_accounts):
        logging.info("Ignored account: %s", acc)

    # Gather missing fields and create a report object.
    institutions = []
    for name, accounts in sorted(groups.items()):
        # Get the institution fields, which is the union of the fields for all
        # the accounts with the institution fields.
        institution_accounts = [
            acc for acc in accounts if 'institution' in open_map[acc].meta
        ]

        institution_fields = {}
        for acc in institution_accounts:
            for key, value in open_map[acc].meta.items():
                institution_fields.setdefault(key, value)
        institution_fields.pop('filename', None)
        institution_fields.pop('lineno', None)

        # Create infos for each account in this institution.
        account_reports = []
        for acc in accounts:
            account_fields = {}
            for subacc in account.parents(acc):
                open_entry = open_map[subacc]
                if 'institution' in open_entry.meta:
                    break
                account_fields.update(open_entry.meta)
            account_fields.pop('filename', None)
            account_fields.pop('lineno', None)
            for field in institution_fields:
                account_fields.pop(field, None)

            real_node = realization.get(real_root, acc)
            account_reports.append(
                AccountReport(
                    acc, open_entry.date, real_node.balance,
                    sum(1 for posting in real_node.txn_postings
                        if isinstance(posting, data.TxnPosting)),
                    account_fields))

        # Create the institution report.
        institution = InstitutionReport(name, institution_fields,
                                        account_reports)
        institutions.append(institution)

    return Report(options_map['title'], institutions)
예제 #3
0
 def test_parents(self):
     iterator = account.parents('Assets:Bank:Checking')
     self.assertIsInstance(iterator, types.GeneratorType)
     self.assertEqual(['Assets:Bank:Checking', 'Assets:Bank', 'Assets'],
                      list(iterator))