Example #1
0
def get_postings_table(
    entries: data.Entries,
    options_map: Dict,
    accounts_map: Dict[str, data.Open],
    threshold: Decimal = D('0.01')) -> Table:
    """Enumerate all the postings."""
    header = [
        'account', 'account_abbrev', 'number', 'currency', 'cost_number',
        'cost_currency', 'cost_date'
    ]
    balances, _ = summarize.balance_by_account(entries, compress_unbooked=True)
    acctypes = options.get_account_types(options_map)
    rows = []
    for acc, balance in sorted(balances.items()):
        # Keep only the balance sheet accounts.
        acctype = account_types.get_account_type(acc)
        if not acctype in (acctypes.assets, acctypes.liabilities):
            continue

        # Create a posting for each of the positions.
        for pos in balance:
            acc_abbrev = abbreviate_account(acc, accounts_map)
            row = [
                acc, acc_abbrev, pos.units.number, pos.units.currency,
                pos.cost.number if pos.cost else ONE,
                pos.cost.currency if pos.cost else pos.units.currency,
                pos.cost.date if pos.cost else None
            ]
            rows.append(row)

    return Table(header, rows)
Example #2
0
    def test_change_commodity_subaccount(self, entries, _, options_map):
        """
        2014-01-01 open Assets:Account1
        2014-01-01 open Income:Misc
        2014-01-01 open Income:Pnl

        2014-01-15 *
          Income:Misc           -1000 USD
          Assets:Account1       10 HOUSE {100 USD}

        2014-01-15 price HOUSE  100 USD
        2014-01-20 price HOUSE  125 USD
        2014-02-05 price HOUSE  150 USD

        2014-02-15 *
          Assets:Account1      -10 HOUSE {100 USD}
          Assets:Account1       30 CAR {50 USD}
          Income:Pnl           -500 USD
        2014-02-15 price CAR  50 USD
        2014-02-20 price CAR  100 USD
        """
        new_entries, _ = unrealized_periodic.add_unrealized_gains(
            entries, options_map, subaccount='Unrealized')
        unreal_entries = unrealized_periodic.get_unrealized_entries(
            new_entries)
        self.assertEqual(3, len(unreal_entries))
        self.assertEqual(2, len(unreal_entries[-2].postings)
                         )  # The second to last transaction zeroed the account
        self.assertEqual(
            2, len(unreal_entries[-1].postings
                   ))  # The last transaction added the new unrealized gain
        summary = summarize.balance_by_account(unreal_entries)
        self.assertEqual(summary[0]['Assets:Account1:Unrealized'],
                         inventory.Inventory.from_string("1500 USD"))
Example #3
0
 def test_balance_by_account__middle(self):
     # Test in the middle.
     balances, index = summarize.balance_by_account(
         self.entries, datetime.date(2014, 2, 10))
     self.assertEqual(4, index)
     self.assertEqual(
         {
             'Assets:AccountA': inventory.from_string('10 USD'),
             'Equity:Opening-Balances': inventory.from_string('-10 USD'),
         }, balances)
Example #4
0
 def test_balance_by_account__no_end_date(self):
     # Test with no end date.
     balances, index = summarize.balance_by_account(self.entries)
     self.assertEqual(len(self.entries), index)
     self.assertEqual(
         {
             'Assets:AccountA': inventory.from_string('11 USD'),
             'Equity:Opening-Balances': inventory.from_string('-23 USD'),
             'Assets:AccountB': inventory.from_string('12 USD')
         }, balances)
Example #5
0
def get_postings_table(entries: data.Entries, options_map: Dict,
                       accounts_map: Dict[str, data.Open],
                       threshold: Decimal = D('0.01')) -> Table:
    """Enumerate all the postings."""
    header = ['account',
              'account_abbrev',
              'number',
              'currency',
              'cost_number',
              'cost_currency',
              'cost_date']
    balances, _ = summarize.balance_by_account(entries)
    acctypes = options.get_account_types(options_map)
    rows = []
    for acc, balance in sorted(balances.items()):
        # Keep only the balance sheet accounts.
        acctype = account_types.get_account_type(acc)
        if not acctype in (acctypes.assets, acctypes.liabilities):
            continue

        # If the account has "NONE" booking method, merge all its postings
        # together in order to obtain an accurate cost basis and balance of
        # units.
        #
        # (This is a complex issue.) If you accrued positions without having them
        # booked properly against existing cost bases, you have not properly accounted
        # for the profit/loss to other postings. This means that the resulting
        # profit/loss is merged in the cost basis of the positive and negative
        # postings.
        dopen = accounts_map.get(acc, None)
        if dopen is not None and dopen.booking is data.Booking.NONE:
            average_balance = balance.average()
            balance = inventory.Inventory(pos
                                          for pos in average_balance
                                          if pos.units.number >= threshold)

        # Create a posting for each of the positions.
        for pos in balance:
            acc_abbrev = abbreviate_account(acc, accounts_map)
            row = [acc,
                   acc_abbrev,
                   pos.units.number,
                   pos.units.currency,
                   pos.cost.number if pos.cost else ONE,
                   pos.cost.currency if pos.cost else pos.units.currency,
                   pos.cost.date if pos.cost else None]
            rows.append(row)

    return Table(header, rows)
Example #6
0
def find_balance_currencies(entries, date=None):
    """Return currencies relevant for the given date.

    This computes the account balances as of the date, and returns the union of:
    a) The currencies held at cost, and
    b) Currency pairs from previous conversions, but only for currencies with
       non-zero balances.

    This is intended to produce the list of currencies whose prices are relevant
    at a particular date, based on previous history.

    Args:
      entries: A list of directives.
      date: A datetime.date instance.
    Returns:
      A set of (base, quote) currencies.
    """
    # Compute the balances.
    currencies = set()
    currencies_on_books = set()
    balances, _ = summarize.balance_by_account(entries, date)
    for _, balance in balances.items():
        for pos in balance:
            if pos.cost is not None:
                # Add currencies held at cost.
                currencies.add((pos.units.currency, pos.cost.currency))
            else:
                # Add regular currencies.
                currencies_on_books.add(pos.units.currency)

    # Create currency pairs from the currencies which are on account balances.
    # In order to figure out the quote currencies, we use the list of price
    # conversions until this date.
    converted = (find_currencies_converted(entries, date)
                 | find_currencies_priced(entries, date))
    for cbase in currencies_on_books:
        for base_quote in converted:
            base, quote = base_quote
            if base == cbase:
                currencies.add(base_quote)

    return currencies
Example #7
0
def get_balance_sheet_balances(entries, options_map):
    """Enumerate all the assets and liabilities.

    Args:
      entries: A list of directives, as per the loader.
      options_map: An options map, as per the parser.
    Yields:
      Instances of Posting.
    """
    balances, _ = summarize.balance_by_account(entries)
    date = entries[-1].date
    acctypes = options.get_account_types(options_map)
    for account, balance in sorted(balances.items()):
        # Keep only the balance sheet accounts.
        acctype = account_types.get_account_type(account)
        if not acctype in (acctypes.assets, acctypes.liabilities):
            continue
        # Create a posting for each of the positions.
        for position in balance:
            yield data.Posting(account, position.units, position.cost, None, None, None)
def main():
    logging.basicConfig(level=logging.INFO, format='%(levelname)-8s: %(message)s')
    parser = argparse.ArgumentParser(description=__doc__.strip())
    parser.add_argument('filename', help='Beancount input filename')
    args = parser.parse_args()

    entries, errors, options_map = loader.load_file(args.filename)

    root_account = realization.realize(entries)
    balances, _ = summarize.balance_by_account(entries, compress_unbooked=True)

    realization_account_names = {
        real_account.account
        for real_account in realization.iter_children(root_account)
        if not real_account.balance.is_empty()}

    summarize_account_names = {
        account
        for account, balance in balances.items()
        if not balance.is_empty()}

    if (realization_account_names - summarize_account_names):
        pprint.pprint(realization_account_names - summarize_account_names)
    if (summarize_account_names - realization_account_names):
        pprint.pprint(summarize_account_names - realization_account_names)

    for real_account in sorted(list(realization.iter_children(root_account)),
                               key=lambda ra: ra.account):
        summarize_balance = balances.get(real_account.account, inventory.Inventory())

        if summarize_balance == real_account.balance:
            continue

        print(real_account.account)
        print("    realization")
        for pos in real_account.balance:
            print("      {}".format(pos))
        print("    summarization")
        for pos in summarize_balance:
            print("      {}".format(pos))
        print()
Example #9
0
 def test_balance_by_account__first_date(self):
     # Test on the first date (should be empty).
     balances, index = summarize.balance_by_account(
         self.entries, datetime.date(2014, 2, 1))
     self.assertEqual(3, index)
     self.assertEqual({}, balances)