Files @ 89bbf8434732
Branch filter:

Location: NPO-Accounting/conservancy_beancount/tests/test_reports_balance_sheet.py - annotation

Brett Smith
reports: Balance tolerance can be an int.
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
a87d4bfc6c0c
"""test_reports_balance_sheet.py - Unit tests for balance sheet report"""
# Copyright © 2020  Brett Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

import datetime
import io
import itertools

from decimal import Decimal

import pytest

from . import testutil

import odf.opendocument

from beancount.core.data import Open

from conservancy_beancount import data
from conservancy_beancount.reports import balance_sheet

Fund = balance_sheet.Fund
Period = balance_sheet.Period

clean_account_meta = pytest.fixture(scope='module')(testutil.clean_account_meta)

@pytest.fixture(scope='module')
def income_expense_balances():
    txns = []
    prior_date = datetime.date(2019, 2, 2)
    period_date = datetime.date(2019, 4, 4)
    for (acct, post_type), fund in itertools.product([
            ('Income:Donations', 'Donations'),
            ('Income:Sales', 'RBI'),
            ('Expenses:Postage', 'fundraising'),
            ('Expenses:Postage', 'management'),
            ('Expenses:Postage', 'program'),
            ('Expenses:Services', 'fundraising'),
            ('Expenses:Services', 'program'),
    ], ['Conservancy', 'Alpha']):
        root_acct, _, classification = acct.partition(':')
        try:
            data.Account(acct).meta
        except KeyError:
            data.Account.load_opening(Open(
                {'classification': classification},
                datetime.date(2000, 1, 1),
                acct, None, None,
            ))
        meta = {
            'project': fund,
            f'{root_acct.lower().rstrip("s")}-type': post_type,
        }
        sign = '' if root_acct == 'Expenses' else '-'
        txns.append(testutil.Transaction(date=prior_date, postings=[
            (acct, f'{sign}2.40', meta),
        ]))
        txns.append(testutil.Transaction(date=period_date, postings=[
            (acct, f'{sign}2.60', meta),
        ]))
    return balance_sheet.Balances(
        data.Posting.from_entries(txns),
        datetime.date(2019, 3, 1),
        datetime.date(2020, 3, 1),
    )

@pytest.mark.parametrize('kwargs,expected', [
    ({'account': 'Income:Donations'}, -10),
    ({'account': 'Income'}, -20),
    ({'account': 'Income:Nonexistent'}, None),
    ({'classification': 'Postage'}, 30),
    ({'classification': 'Services'}, 20),
    ({'classification': 'Nonexistent'}, None),
    ({'period': Period.OPENING, 'account': 'Income'}, '-9.60'),
    ({'period': Period.PERIOD, 'account': 'Expenses'}, 26),
    ({'fund': Fund.RESTRICTED, 'account': 'Income'}, -10),
    ({'fund': Fund.UNRESTRICTED, 'account': 'Expenses'}, 25),
    ({'post_type': 'Donations'}, -10),
    ({'post_type': 'fundraising'}, 20),
    ({'post_type': 'management'}, 10),
    ({'post_type': 'Nonexistent'}, None),
    ({'period': Period.OPENING, 'post_type': 'RBI'}, '-4.80'),
    ({'fund': Fund.RESTRICTED, 'post_type': 'program'}, 10),
    ({'period': Period.PERIOD, 'fund': Fund.UNRESTRICTED, 'post_type': 'RBI'}, '-2.60'),
    ({'period': Period.OPENING, 'fund': Fund.RESTRICTED, 'post_type': 'program'}, '4.80'),
    ({'period': Period.PERIOD, 'fund': Fund.RESTRICTED, 'post_type': 'ø'}, None),
])
def test_balance_total(income_expense_balances, kwargs, expected):
    actual = income_expense_balances.total(**kwargs)
    if expected is None:
        assert not actual
    else:
        assert actual == {'USD': testutil.Amount(expected)}

def run_main(arglist=[], config=None):
    if config is None:
        config = testutil.TestConfig(books_path=testutil.test_path('books/fund.beancount'))
    stdout = io.BytesIO()
    stderr = io.StringIO()
    retcode = balance_sheet.main(['-O', '-'] + arglist, stdout, stderr, config)
    stdout.seek(0)
    stderr.seek(0)
    return retcode, stdout, stderr

def test_main():
    retcode, stdout, stderr = run_main()
    assert retcode == 0
    assert not stderr.getvalue()
    report = odf.opendocument.load(stdout)
    assert report.spreadsheet.childNodes