Files @ 5784068904e8
Branch filter:

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

bkuhn
payroll-type — US:403b:Employee:Roth — needed separate since taxable

Since Roth contributions are taxable, there are some reports that
need to include these amounts in total salary (i.e., when running a
report that seeks to show total taxable income for an employee). As
such, we need a `payroll-type` specifically for Roth 403(b)
contributions.
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
fe3560b748fa
"""test_meta_tax_reporting.py - Unit tests for tax-reporting metadata validation"""
# Copyright © 2021  Brett Smith
# License: AGPLv3-or-later WITH Beancount-Plugin-Additional-Permission-1.0
#
# Full copyright and licensing details can be found at toplevel file
# LICENSE.txt in the repository.

import pytest

from . import testutil

from conservancy_beancount.plugin import meta_tax_reporting

TEST_KEY = 'tax-reporting'
IMPLICATION_KEY = 'tax-implication'

REQUIRED_ACCOUNTS = {
    'Assets:Checking',
    'Assets:Bank:Savings',
}

NON_REQUIRED_ACCOUNTS = {
    'Assets:Prepaid:Expenses',
    'Assets:Receivable:Accounts',
    'Liabilities:CreditCard',
}

REQUIRED_AMOUNTS = {-50, -500}
NON_REQUIRED_AMOUNTS = {-5, 500}

REQUIRED_IMPLICATIONS = {
    '1099',
    '1099-Misc-Other',
    'foreign-grantee',
    'Foreign-Individual-Contractor',
    'USA-501c3',
    'US-Grantee',
}

NON_REQUIRED_IMPLICATIONS = {
    'Bank-Transfer',
    'chargeback',
    'Foreign-Corp',
    'Loan',
    'refund',
    'Reimbursement',
    'retirement-pretax',
    'Tax-Payment',
    'us-corp',
    'w2',
}

@pytest.fixture(scope='module')
def hook():
    config = testutil.TestConfig(payment_threshold=10)
    return meta_tax_reporting.MetaTaxReporting(config)

@pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
    testutil.LINK_METADATA_STRINGS,
))
def test_pass_on_txn(hook, account, amount, implication, value):
    txn_meta = {
        IMPLICATION_KEY: implication,
        TEST_KEY: value,
    }
    txn = testutil.Transaction(**txn_meta, postings=[
        (account, amount),
        ('Expenses:Other', -amount),
    ])
    assert not list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
    testutil.LINK_METADATA_STRINGS,
))
def test_pass_on_post(hook, account, amount, implication, value):
    post_meta = {
        IMPLICATION_KEY: implication,
        TEST_KEY: value,
    }
    txn = testutil.Transaction(postings=[
        (account, amount, post_meta),
        ('Expenses:Other', -amount),
    ])
    assert not list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
))
def test_error_when_missing(hook, account, amount, implication):
    txn = testutil.Transaction(postings=[
        (account, amount, {IMPLICATION_KEY: implication}),
        ('Expenses:Other', -amount),
    ])
    assert list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
    testutil.NON_LINK_METADATA_STRINGS,
))
def test_error_when_empty(hook, account, amount, implication, value):
    txn_meta = {
        IMPLICATION_KEY: implication,
        TEST_KEY: value,
    }
    txn = testutil.Transaction(**txn_meta, postings=[
        (account, amount),
        ('Expenses:Other', -amount),
    ])
    assert list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
    testutil.NON_STRING_METADATA_VALUES,
))
def test_error_when_wrong_type(hook, account, amount, implication, value):
    txn_meta = {
        IMPLICATION_KEY: implication,
        TEST_KEY: value,
    }
    txn = testutil.Transaction(**txn_meta, postings=[
        (account, amount),
        ('Expenses:Other', -amount),
    ])
    assert list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication', testutil.combine_values(
    NON_REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
))
def test_skip_by_account(hook, account, amount, implication):
    txn = testutil.Transaction(postings=[
        (account, amount, {IMPLICATION_KEY: implication}),
        ('Expenses:Other', -amount),
    ])
    assert not list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    NON_REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
))
def test_skip_by_amount(hook, account, amount, implication):
    txn = testutil.Transaction(postings=[
        (account, amount, {IMPLICATION_KEY: implication}),
        ('Expenses:Other', -amount),
    ])
    assert not list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    NON_REQUIRED_IMPLICATIONS,
))
def test_skip_by_implication(hook, account, amount, implication):
    txn = testutil.Transaction(postings=[
        (account, amount, {IMPLICATION_KEY: implication}),
        ('Expenses:Other', -amount),
    ])
    assert not list(hook.run(txn))

@pytest.mark.parametrize('account,amount,implication', testutil.combine_values(
    REQUIRED_ACCOUNTS,
    REQUIRED_AMOUNTS,
    REQUIRED_IMPLICATIONS,
))
def test_skip_by_flag(hook, account, amount, implication):
    txn = testutil.Transaction(flag='!', postings=[
        (account, amount, {IMPLICATION_KEY: implication}),
        ('Expenses:Other', -amount),
    ])
    assert not list(hook.run(txn))