Ejemplo n.º 1
0
    def test_close(self):
        date = datetime.date(2012, 9, 1)
        closed_entries, index = self.do_close(self.entries, date, 'NOTHING',
                                              'Equity:Conversions:Current')

        self.assertEqualEntries(
            """

        2012-01-01 open Income:Salary
        2012-01-01 open Expenses:Taxes
        2012-01-01 open Assets:US:Checking
        2012-01-01 open Assets:CA:Checking

        2012-03-01 * "Some income and expense to be summarized"
          Income:Salary        10000 USD
          Expenses:Taxes        3600 USD
          Assets:US:Checking  -13600 USD

        2012-03-02 * "Some conversion to be summarized"
          Assets:US:Checking   -5000 USD @ 1.2 CAD
          Assets:CA:Checking    6000 CAD

        ;; 2012-06-01  BEGIN --------------------------------

        2012-08-01 * "Some income and expense to show"
          Income:Salary        11000 USD
          Expenses:Taxes        3200 USD
          Assets:US:Checking  -14200 USD

        2012-08-02 * "Some other conversion to be summarized"
          Assets:US:Checking   -3000 USD @ 1.25 CAD
          Assets:CA:Checking    3750 CAD

        ;; 2012-09-01  END   --------------------------------

        2012-08-31 C "Conversion for (-8000 USD, 9750 CAD)"
          Equity:Conversions:Current    8000 USD  @ 0 NOTHING
          Equity:Conversions:Current   -9750 CAD  @ 0 NOTHING

        """, closed_entries)

        # Check the index is correctly beginning after the list of summarizing entries.
        self.assertEqual(8, index)

        # Check that our original example list of entries does not balance.
        input_balance = interpolate.compute_entries_balance(self.entries)
        self.assertFalse(input_balance.is_empty())

        # Check that the truncated entries does not balance.
        balances = interpolate.compute_entries_balance(closed_entries[:index])
        self.assertFalse(balances.is_empty())

        # Check that the closed entries add up to precisely zero.
        balances = interpolate.compute_entries_balance(closed_entries)
        self.assertTrue(balances.is_empty())
Ejemplo n.º 2
0
    def test_compute_entries_balance_currencies(self, entries, _, __):
        """
        2014-01-01 open Assets:Bank:Checking
        2014-01-01 open Assets:Bank:Savings
        2014-01-01 open Assets:Investing
        2014-01-01 open Assets:Other

        2014-06-01 *
          Assets:Bank:Checking  111.23 USD
          Assets:Other

        2014-06-02 *
          Assets:Bank:Savings   222.74 USD
          Assets:Other

        2014-06-03 *
          Assets:Bank:Savings   17.23 CAD
          Assets:Other

        2014-06-04 *
          Assets:Investing      10000 EUR
          Assets:Other

        """
        computed_balance = interpolate.compute_entries_balance(entries)
        expected_balance = inventory.Inventory()
        self.assertEqual(expected_balance, computed_balance)
Ejemplo n.º 3
0
    def test_clear(self):
        date = datetime.date(2013, 1, 1)
        clear_entries, index = self.do_clear(self.entries, date,
                                             self.account_types,
                                             'Equity:Earnings:Current')

        self.assertEqualEntries(
            """

        2012-01-01 open Income:Salary
        2012-01-01 open Expenses:Taxes
        2012-01-01 open Assets:US:Checking
        2012-01-01 open Assets:CA:Checking

        2012-03-01 * "Some income and expense to be summarized"
          Income:Salary        10000 USD
          Expenses:Taxes        3600 USD
          Assets:US:Checking  -13600 USD

        2012-03-02 * "Some conversion to be summarized"
          Assets:US:Checking   -5000 USD @ 1.2 CAD
          Assets:CA:Checking    6000 CAD

        ;; 2012-06-01  BEGIN --------------------------------

        2012-08-01 * "Some income and expense to show"
          Income:Salary        11000 USD
          Expenses:Taxes        3200 USD
          Assets:US:Checking  -14200 USD

        2012-08-02 * "Some other conversion to be summarized"
          Assets:US:Checking   -3000 USD @ 1.25 CAD
          Assets:CA:Checking    3750 CAD

        ;; 2012-09-01  END   --------------------------------

        2012-11-01 * "Some income and expense to be truncated"
          Income:Salary        10000 USD
          Expenses:Taxes        3600 USD
          Assets:US:Checking  -13600 USD

        2012-12-31 T "Transfer balance for 'Expenses:Taxes' (Transfer balance)"
          Expenses:Taxes           -10400 USD
          Equity:Earnings:Current   10400 USD

        2012-12-31 T "Transfer balance for 'Income:Salary' (Transfer balance)"
          Income:Salary             -31000 USD
          Equity:Earnings:Current    31000 USD

        """, clear_entries)

        # Check the index is correctly beginning after the list of summarizing entries.
        self.assertEqual(9, index)

        # Check that the cleared entries do not necessarily up to precisely zero
        # without closing.
        balances = interpolate.compute_entries_balance(clear_entries)
        self.assertFalse(balances.is_empty())
Ejemplo n.º 4
0
    def test_conversions__not_needed(self):
        date = datetime.date(2012, 3, 2)
        conversion_entries = summarize.conversions(self.entries, self.ACCOUNT,
                                                   'NOTHING', date)
        self.assertEqualEntries(self.entries, conversion_entries)

        converted_balance = interpolate.compute_entries_balance(
            conversion_entries, date=date)
        self.assertTrue(converted_balance.cost().is_empty())
Ejemplo n.º 5
0
def conversions(entries, conversion_account, conversion_currency, date=None):
    """Insert a conversion entry at date 'date' at the given account.

    Args:
      entries: A list of entries.
      conversion_account: A string, the account to book against.
      conversion_currency: A string, the transfer currency to use for zero prices
        on the conversion entry.
      date: The date before which to insert the conversion entry. The new
        entry will be inserted as the last entry of the date just previous
        to this date.
    Returns:
      A modified list of entries.
    """
    # Compute the balance at the given date.
    conversion_balance = interpolate.compute_entries_balance(entries,
                                                             date=date)

    # Early exit if there is nothing to do.
    conversion_cost_balance = conversion_balance.reduce(convert.get_cost)
    if conversion_cost_balance.is_empty():
        return entries

    # Calculate the index and the date for the new entry. We want to store it as
    # the last transaction of the day before.
    if date is not None:
        index = bisect_key.bisect_left_with_key(entries,
                                                date,
                                                key=lambda entry: entry.date)
        last_date = date - datetime.timedelta(days=1)
    else:
        index = len(entries)
        last_date = entries[-1].date

    meta = data.new_metadata('<conversions>', -1)
    narration = 'Conversion for {}'.format(conversion_balance)
    conversion_entry = Transaction(meta, last_date, flags.FLAG_CONVERSIONS,
                                   None, narration, data.EMPTY_SET,
                                   data.EMPTY_SET, [])
    for position in conversion_cost_balance.get_positions():
        # Important note: Set the cost to zero here to maintain the balance
        # invariant. (This is the only single place we cheat on the balance rule
        # in the entire system and this is necessary; see documentation on
        # Conversions.)
        price = amount.Amount(ZERO, conversion_currency)
        neg_pos = -position
        conversion_entry.postings.append(
            data.Posting(conversion_account, neg_pos.units, neg_pos.cost,
                         price, None, None))

    # Make a copy of the list of entries and insert the new transaction into it.
    new_entries = list(entries)
    new_entries.insert(index, conversion_entry)

    return new_entries
Ejemplo n.º 6
0
    def test_conversions__no_date(self):
        conversion_entries = summarize.conversions(self.entries, self.ACCOUNT,
                                                   'NOTHING')
        self.assertIncludesEntries(self.entries, conversion_entries)
        self.assertIncludesEntries(
            """

        2012-05-01 C "Conversion for (-700.00 USD, 100.00 CAD, 60 NT {10 CAD})"
          Equity:Conversions   700.00 USD  @ 0 NOTHING
          Equity:Conversions  -700.00 CAD  @ 0 NOTHING

        """, conversion_entries)

        converted_balance = interpolate.compute_entries_balance(
            conversion_entries)
        self.assertTrue(converted_balance.cost().is_empty())
Ejemplo n.º 7
0
    def test_conversions__with_transactions_at_cost(self):
        date = datetime.date(2012, 3, 10)
        conversion_entries = summarize.conversions(self.entries, self.ACCOUNT,
                                                   'XFER', date)
        self.assertIncludesEntries(self.entries, conversion_entries)
        self.assertIncludesEntries(
            """

        2012-03-09 C "Conversion for (-800.00 USD, 200.00 CAD, 60 NT {10 CAD})"
          Equity:Conversions   800.00 USD  @ 0 XFER
          Equity:Conversions  -800.00 CAD  @ 0 XFER

        """, conversion_entries)

        converted_balance = interpolate.compute_entries_balance(
            conversion_entries, date=date)
        self.assertTrue(converted_balance.cost().is_empty())
Ejemplo n.º 8
0
    def test_conversions__needed_middle(self):
        date = datetime.date(2012, 3, 3)
        conversion_entries = summarize.conversions(self.entries, self.ACCOUNT,
                                                   'NOTHING', date)
        self.assertIncludesEntries(self.entries, conversion_entries)
        self.assertIncludesEntries(
            """

        2012-03-02 C "Conversion for (-800.00 USD, 800.00 CAD)"
          Equity:Conversions       800.00 USD @ 0 NOTHING
          Equity:Conversions      -800.00 CAD @ 0 NOTHING

        """, conversion_entries)

        converted_balance = interpolate.compute_entries_balance(
            conversion_entries, date=date)
        self.assertTrue(converted_balance.cost().is_empty())
Ejemplo n.º 9
0
    def test_compute_entries_balance_conversions(self, entries, _, __):
        """
        2014-01-01 open Assets:Investing
        2014-01-01 open Assets:Other

        2014-06-06 *
          Assets:Investing          1000 EUR @ 1.78 GBP
          Assets:Other

        2014-06-07 *
          Assets:Investing          1000 EUR @@ 1780 GBP
          Assets:Other
        """
        computed_balance = interpolate.compute_entries_balance(entries)
        expected_balance = inventory.Inventory()
        expected_balance.add_amount(A('2000.00 EUR'))
        expected_balance.add_amount(A('-3560.00 GBP'))
        self.assertEqual(expected_balance, computed_balance)
Ejemplo n.º 10
0
    def test_compute_entries_balance_at_cost(self, entries, _, __):
        """
        2014-01-01 open Assets:Investing
        2014-01-01 open Assets:Other

        2014-06-05 *
          Assets:Investing      30 HOOL {40 USD}
          Assets:Other

        2014-06-05 *
          Assets:Investing      -20 HOOL {40 USD}
          Assets:Other

        """
        computed_balance = interpolate.compute_entries_balance(entries)
        expected_balance = inventory.Inventory()
        expected_balance.add_amount(A('-400 USD'))
        expected_balance.add_amount(A('10 HOOL'), A('40 USD'))
        self.assertEqual(expected_balance, computed_balance)
Ejemplo n.º 11
0
    def test_open(self):
        date = datetime.date(2012, 6, 1)
        opened_entries, index = self.do_open(self.entries, date,
                                             self.account_types, 'NOTHING',
                                             'Equity:Earnings:Previous',
                                             'Equity:Opening-Balances',
                                             'Equity:Conversions:Previous')

        self.assertEqualEntries(
            """

        2012-01-01 open Income:Salary
        2012-01-01 open Expenses:Taxes
        2012-01-01 open Assets:US:Checking
        2012-01-01 open Assets:CA:Checking

        2012-05-31 S "Opening balance for 'Assets:CA:Checking' (Summarization)"
          Assets:CA:Checking             6,000 CAD
          Equity:Opening-Balances       -6,000 CAD

        2012-05-31 S "Opening balance for 'Assets:US:Checking' (Summarization)"
          Assets:US:Checking           -18,600 USD
          Equity:Opening-Balances       18,600 USD

        2012-05-31 S "Opening balance for 'Equity:Earnings:Previous' (Summarization)"
          Equity:Earnings:Previous      13,600 USD
          Equity:Opening-Balances      -13,600 USD

        2012-05-31 S "Opening balance for 'Equity:Conversions:Previous' (Summarization)"
          Equity:Conversions:Previous    5,000 USD
          Equity:Opening-Balances       -5,000 USD
          Equity:Conversions:Previous   -6,000 CAD
          Equity:Opening-Balances        6,000 CAD

        ;; 2012-06-01  BEGIN --------------------------------

        2012-08-01 * "Some income and expense to show"
          Income:Salary                 11,000 USD
          Expenses:Taxes                 3,200 USD
          Assets:US:Checking           -14,200 USD

        2012-08-02 * "Some other conversion to be summarized"
          Assets:US:Checking            -3,000 USD @ 1.25 CAD ;  -3,750 CAD
          Assets:CA:Checking             3,750 CAD            ;   3,750 CAD

        2012-11-01 * "Some income and expense to be truncated"
          Income:Salary                 10,000 USD
          Expenses:Taxes                 3,600 USD
          Assets:US:Checking           -13,600 USD

        """, opened_entries)

        # Check the index is correctly beginning after the list of summarizing entries.
        self.assertEqual(8, index)

        # Check that our original example list of entries does not balance.
        input_balance = interpolate.compute_entries_balance(self.entries)
        self.assertFalse(input_balance.is_empty())

        # Check that the summarized entries add up to precisely zero.
        summarized_entries = opened_entries[:index]
        balances = interpolate.compute_entries_balance(summarized_entries)
        self.assertTrue(balances.is_empty())

        # Check further conversions aren't accounted for (the close operation
        # takes care of this).
        opened_balance = interpolate.compute_entries_balance(opened_entries)
        self.assertFalse(opened_balance.is_empty())
Ejemplo n.º 12
0
    def test_clamp(self, entries, errors, options_map):
        """
        2012-01-01 open Income:Salary
        2012-01-01 open Expenses:Taxes
        2012-01-01 open Assets:US:Checking
        2012-01-01 open Assets:CA:Checking

        2012-03-01 * "Some income and expense to be summarized"
          Income:Salary        10000.00 USD
          Expenses:Taxes        3600.00 USD
          Assets:US:Checking  -13600.00 USD

        2012-03-02 * "Some conversion to be summarized"
          Assets:US:Checking   -5000.00 USD @ 1.2 CAD
          Assets:CA:Checking    6000.00 CAD

        ;; 2012-06-01  BEGIN --------------------------------

        2012-08-01 * "Some income and expense to show"
          Income:Salary        11000.00 USD
          Expenses:Taxes        3200.00 USD
          Assets:US:Checking  -14200.00 USD

        2012-08-02 * "Some other conversion to be summarized"
          Assets:US:Checking   -3000.00 USD @ 1.25 CAD
          Assets:CA:Checking    3750.00 CAD

        ;; 2012-09-01  END   --------------------------------

        2012-11-01 * "Some income and expense to be truncated"
          Income:Salary        10000.00 USD
          Expenses:Taxes        3600.00 USD
          Assets:US:Checking  -13600.00 USD

        """
        self.assertFalse(errors)

        begin_date = datetime.date(2012, 6, 1)
        end_date = datetime.date(2012, 9, 1)
        account_types = options.get_account_types(options_map)
        clamped_entries, index = summarize.clamp(entries, begin_date, end_date,
                                                 account_types, 'NOTHING',
                                                 'Equity:Earnings',
                                                 'Equity:Opening-Balances',
                                                 'Equity:Conversions')
        self.assertEqualEntries(
            """

        2012-01-01 open Income:Salary
        2012-01-01 open Expenses:Taxes
        2012-01-01 open Assets:US:Checking
        2012-01-01 open Assets:CA:Checking

        2012-05-31 S "Opening balance for 'Assets:CA:Checking' (Summarization)"
          Assets:CA:Checking              6000.00 CAD
          Equity:Opening-Balances         -6000.00 CAD

        2012-05-31 S "Opening balance for 'Assets:US:Checking' (Summarization)"
          Assets:US:Checking            -18600.00 USD
          Equity:Opening-Balances         18600.00 USD

        2012-05-31 S "Opening balance for 'Equity:Earnings' (Summarization)"
          Equity:Earnings                13600.00 USD
          Equity:Opening-Balances        -13600.00 USD

        ;; 2012-06-01  BEGIN --------------------------------

        2012-08-01 * "Some income and expense to show"
          Income:Salary                  11000.00 USD
          Expenses:Taxes                  3200.00 USD
          Assets:US:Checking            -14200.00 USD

        2012-08-02 * "Some other conversion to be summarized"
          Assets:US:Checking             -3000.00 USD  @ 1.25 CAD
          Assets:CA:Checking              3750.00 CAD

        ;; 2012-09-01  END   --------------------------------

        2012-08-31 C "Conversion for (-3000.00 USD, 3750.00 CAD)"
          Equity:Conversions              3000.00 USD  @ 0 NOTHING
          Equity:Conversions             -3750.00 CAD  @ 0 NOTHING

        """, clamped_entries)

        self.assertEqual(7, index)

        input_balance = interpolate.compute_entries_balance(entries)
        self.assertFalse(input_balance.is_empty())

        clamped_balance = interpolate.compute_entries_balance(clamped_entries)
        self.assertTrue(clamped_balance.is_empty())
Ejemplo n.º 13
0
 def inventory(self, account_name):
     return compute_entries_balance(self.entries, prefix=account_name)
Ejemplo n.º 14
0
 def inventory(self, account_name):
     return compute_entries_balance(self.entries, prefix=account_name)