fdd9f2847b
We've long supported skipping documentation checks by flagging the transaction. We haven't done the same for enumerated metadata because we need it less often, and bad values tend to do more damage to reports. However, occasionally when something very off-process happens, we do need it as a matter of expediency. So support it. In order to skip validation of these fields, the plugin requires that the value start with the string "FIXME". This helps ensure that reports have a consistent way to detect and warn about unfilled values in flagged transactions.
154 lines
4.9 KiB
Python
154 lines
4.9 KiB
Python
"""Test handling of tax-implication metadata"""
|
|
# Copyright © 2020 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_implication
|
|
|
|
VALID_VALUES = {
|
|
'1099': '1099-NEC',
|
|
'1099-NEC': '1099-NEC',
|
|
'1099nec': '1099-NEC',
|
|
'1099-MISC-Other': '1099-MISC-Other',
|
|
'1099misc-other': '1099-MISC-Other',
|
|
'Bank-Transfer': 'Bank-Transfer',
|
|
'Chargeback': 'Chargeback',
|
|
'Foreign-Corporation': 'Foreign-Corporation',
|
|
'foreign-corp': 'Foreign-Corporation',
|
|
'Foreign-Grantee': 'Foreign-Grantee',
|
|
'Foreign-Individual-Contractor': 'Foreign-Individual-Contractor',
|
|
'Loan': 'Loan',
|
|
'Refund': 'Refund',
|
|
'Reimbursement': 'Reimbursement',
|
|
'Retirement-Pretax': 'Retirement-Pretax',
|
|
'Tax-Payment': 'Tax-Payment',
|
|
'USA-501c3': 'USA-501c3',
|
|
'USA-Corporation': 'USA-Corporation',
|
|
'us-corp': 'USA-Corporation',
|
|
'USA-Grantee': 'USA-Grantee',
|
|
'US-Grantee': 'USA-Grantee',
|
|
'W2': 'W2',
|
|
}
|
|
|
|
INVALID_VALUES = {
|
|
'199',
|
|
'W3',
|
|
'Payrol',
|
|
'',
|
|
}
|
|
|
|
TEST_KEY = 'tax-implication'
|
|
|
|
@pytest.fixture(scope='module')
|
|
def hook():
|
|
config = testutil.TestConfig()
|
|
return meta_tax_implication.MetaTaxImplication(config)
|
|
|
|
@pytest.mark.parametrize('src_value,set_value', VALID_VALUES.items())
|
|
def test_valid_values_on_postings(hook, src_value, set_value):
|
|
txn = testutil.Transaction(postings=[
|
|
('Liabilities:Payable:Accounts', 25),
|
|
('Assets:Cash', -25, {TEST_KEY: src_value}),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert not errors
|
|
testutil.check_post_meta(txn, None, {TEST_KEY: set_value})
|
|
|
|
@pytest.mark.parametrize('src_value', INVALID_VALUES)
|
|
def test_invalid_values_on_postings(hook, src_value):
|
|
txn = testutil.Transaction(postings=[
|
|
('Liabilities:Payable:Accounts', 25),
|
|
('Assets:Cash', -25, {TEST_KEY: src_value}),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert errors
|
|
testutil.check_post_meta(txn, None, {TEST_KEY: src_value})
|
|
|
|
@pytest.mark.parametrize('src_value,set_value', VALID_VALUES.items())
|
|
def test_valid_values_on_transactions(hook, src_value, set_value):
|
|
txn = testutil.Transaction(**{TEST_KEY: src_value}, postings=[
|
|
('Liabilities:Payable:Accounts', 25),
|
|
('Assets:Cash', -25),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert not errors
|
|
testutil.check_post_meta(txn, None, {TEST_KEY: set_value})
|
|
|
|
@pytest.mark.parametrize('src_value', INVALID_VALUES)
|
|
def test_invalid_values_on_transactions(hook, src_value):
|
|
txn = testutil.Transaction(**{TEST_KEY: src_value}, postings=[
|
|
('Liabilities:Payable:Accounts', 25),
|
|
('Assets:Cash', -25),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert errors
|
|
testutil.check_post_meta(txn, None, None)
|
|
|
|
@pytest.mark.parametrize('count,account', enumerate([
|
|
'Assets:Payable:Accounts',
|
|
'Assets:Prepaid:Expenses',
|
|
'Equity:OpeningBalance',
|
|
'Expenses:Other',
|
|
'Income:Other',
|
|
'Liabilities:CreditCard',
|
|
'Liabilities:Payable:Accounts',
|
|
'Liabilities:UnearnedIncome:Donations',
|
|
], 1))
|
|
def test_non_payment_accounts_skipped(hook, account, count):
|
|
amount = count * 100
|
|
meta = {TEST_KEY: 'USA-Corporation'}
|
|
txn = testutil.Transaction(postings=[
|
|
(account, amount),
|
|
('Assets:Checking', -amount, meta.copy()),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert not errors
|
|
testutil.check_post_meta(txn, None, meta)
|
|
|
|
def test_asset_credits_skipped(hook):
|
|
txn = testutil.Transaction(postings=[
|
|
('Income:Donations', -25),
|
|
('Assets:Cash', 25),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert not errors
|
|
testutil.check_post_meta(txn, None, None)
|
|
|
|
@pytest.mark.parametrize('date,need_value', [
|
|
(testutil.EXTREME_FUTURE_DATE, False),
|
|
(testutil.FUTURE_DATE, True),
|
|
(testutil.FY_START_DATE, True),
|
|
(testutil.FY_MID_DATE, True),
|
|
(testutil.PAST_DATE, False),
|
|
])
|
|
def test_validation_only_in_date_range(hook, date, need_value):
|
|
txn = testutil.Transaction(date=date, postings=[
|
|
('Liabilites:CreditCard', 25),
|
|
('Assets:Cash', -25),
|
|
])
|
|
errors = list(hook.run(txn))
|
|
assert bool(errors) == bool(need_value)
|
|
testutil.check_post_meta(txn, None, None)
|
|
|
|
@pytest.mark.parametrize('src_value', INVALID_VALUES)
|
|
def test_flagged_txn_checked(hook, src_value):
|
|
txn = testutil.Transaction(flag='!', **{TEST_KEY: src_value}, postings=[
|
|
('Liabilities:Payable:Accounts', 25),
|
|
('Assets:Cash', -25),
|
|
])
|
|
assert list(hook.run(txn))
|
|
|
|
@pytest.mark.parametrize('src_value', testutil.FIXME_VALUES)
|
|
def test_flagged_fixme_ok(hook, src_value):
|
|
txn = testutil.Transaction(flag='!', postings=[
|
|
('Liabilities:Payable:Accounts', 25),
|
|
('Assets:Cash', -25, {TEST_KEY: src_value}),
|
|
])
|
|
assert not list(hook.run(txn))
|
|
testutil.check_post_meta(txn, None, {TEST_KEY: src_value})
|