Files @ e00ec95d93bd
Branch filter:

Location: NPO-Accounting/conservancy_beancount/tests/test_data_posting.py

Brett Smith
Account: Add is_opening_balance method.
"""Test Posting class"""
# 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 pytest

from . import testutil

from decimal import Decimal

import beancount.core.amount as bc_amount

from conservancy_beancount import data

PAYMENT_ACCOUNTS = {
    'Assets:Cash',
    'Assets:Bank:Checking',
}

NON_PAYMENT_ACCOUNTS = {
    'Assets:Prepaid:Expenses',
    'Assets:Prepaid:Vacation',
    'Assets:Receivable:Accounts',
    'Equity:OpeningBalance',
    'Expenses:Other',
    'Income:Other',
    'Liabilities:CreditCard',
}

AMOUNTS = [
    None,
    '-25.50',
    0,
    '25.75',
]

def Posting(account, number,
            currency='USD', cost=None, price=None, flag=None,
            **meta):
    if not meta:
        meta = None
    if number is not None:
        number = Decimal(number)
    return data.Posting(
        data.Account(account),
        bc_amount.Amount(number, currency),
        cost,
        price,
        flag,
        meta,
    )

def check_all_thresholds(expected, method, threshold, *args):
    assert method(threshold, *args) is expected
    assert method(Decimal(threshold), *args) is expected

@pytest.mark.parametrize('amount', AMOUNTS)
def test_is_credit(amount):
    expected = None if amount is None else float(amount) > 0
    assert Posting('Assets:Cash', amount).is_credit() is expected

def test_is_credit_threshold():
    post = Posting('Assets:Cash', 25)
    check_all_thresholds(True, post.is_credit, 0)
    check_all_thresholds(True, post.is_credit, 20)
    check_all_thresholds(False, post.is_credit, 40)

def test_is_credit_default():
    post = Posting('Assets:Cash', None)
    assert post.is_credit(default=True) is True
    assert post.is_credit(default=False) is False

@pytest.mark.parametrize('amount', AMOUNTS)
def test_is_debit(amount):
    expected = None if amount is None else float(amount) < 0
    assert Posting('Assets:Cash', amount).is_debit() is expected

def test_is_debit_threshold():
    post = Posting('Assets:Cash', -25)
    check_all_thresholds(True, post.is_debit, 0)
    check_all_thresholds(True, post.is_debit, 20)
    check_all_thresholds(False, post.is_debit, 40)

def test_is_debit_default():
    post = Posting('Assets:Cash', None)
    assert post.is_debit(default=True) is True
    assert post.is_debit(default=False) is False

@pytest.mark.parametrize('acct', PAYMENT_ACCOUNTS)
def test_is_payment(acct):
    assert Posting(acct, -500).is_payment()

@pytest.mark.parametrize('acct,amount,threshold', testutil.combine_values(
    NON_PAYMENT_ACCOUNTS,
    range(5, 20, 5),
    range(0, 30, 10),
))
def test_is_not_payment_account(acct, amount, threshold):
    post = Posting(acct, -amount)
    assert not post.is_payment()
    check_all_thresholds(False, post.is_payment, threshold)

@pytest.mark.parametrize('acct', PAYMENT_ACCOUNTS)
def test_is_payment_with_threshold(acct):
    threshold = len(acct) * 10
    post = Posting(acct, -500)
    check_all_thresholds(True, post.is_payment, threshold)

@pytest.mark.parametrize('acct', PAYMENT_ACCOUNTS)
def test_is_not_payment_by_threshold(acct):
    threshold = len(acct) * 10
    post = Posting(acct, -9)
    check_all_thresholds(False, post.is_payment, threshold)

@pytest.mark.parametrize('acct', PAYMENT_ACCOUNTS)
def test_is_not_payment_but_credit(acct):
    post = Posting(acct, 9)
    assert not post.is_payment()
    check_all_thresholds(False, post.is_payment, 0)
    check_all_thresholds(False, post.is_payment, 5)
    check_all_thresholds(False, post.is_payment, 10)