@@ -13,6 +13,7 @@ from conservancy_beancount.reconcile.statement_reconciler import (
metadata_for_match,
write_metadata_to_books,
totals,
subset_match,
)
# These data structures represent individual transactions as taken from the
@@ -40,6 +41,13 @@ S3 = {
'check_id': '',
'line': 444,
}
S4 = {
'date': datetime.date(2022, 8, 11),
'amount': decimal.Decimal('-2260.00'),
'payee': 'Trust 0000000362 210',
'line': 555,
# Books transaction examples.
B1 = {
@@ -114,81 +122,116 @@ B3_unmatched_check_id = {
'line': 999,
'bank_statement': "Financial/Bank-Statements/AMEX/2022-01-12_AMEX_statement.pdf"
B4A = {
'amount': decimal.Decimal('-250.00'),
'payee': 'TRUST 0000000362 ACH Retirement Plan',
'line': 1000,
B4B = {
B4C = {
'amount': decimal.Decimal('-1760.00'),
def test_one_exact_match():
statement = [S1]
books = [B1]
assert match_statement_and_books(statement, books) == [
assert match_statement_and_books(statement, books) == (
# Match, match, notes.
#
# The matches are a list so we can implement subset-sum matching where
# multiple books transactions may match to a single statement
# transaction.
([S1], [B1], []),
]
[([S1], [B1], [])],
[],
def test_multiple_exact_matches():
statement = [S1, S2]
books = [B1, B2]
([S2], [B2], []),
[([S1], [B1], []), ([S2], [B2], [])],
def test_one_mismatch():
books = []
([S1], [], ['no match']),
[S1],
def test_multiple_mismatches():
books = [B2]
([], [B2], ['no match']),
[B2],
def test_next_day_matches():
statement = [S3]
books = [B3_next_day]
([S3], [B3_next_day], ['+/- 1 days']),
[([S3], [B3_next_day], ['+/- 1 days'])],
def test_next_week_matches():
books = [B3_next_week]
([S3], [B3_next_week], ['+/- 7 days']),
[([S3], [B3_next_week], ['+/- 7 days'])],
def test_incorrect_amount_does_not_match():
books = [B3_mismatch_amount]
([S3], [], ['no match']),
([], [B3_mismatch_amount], ['no match']),
[S3],
[B3_mismatch_amount],
def test_payee_mismatch_ok_when_only_one_that_amount_and_date():
books = [B3_payee_mismatch_1]
([S3], [B3_payee_mismatch_1], ['payee mismatch', 'only one decent match']),
[([S3], [B3_payee_mismatch_1], ['payee mismatch', 'only one decent match'])],
def test_payee_mismatch_not_ok_when_multiple_that_amount_and_date():
books = [B3_payee_mismatch_1, B3_payee_mismatch_2]
match = match_statement_and_books(statement, books)
assert match == [
([], [B3_payee_mismatch_1], ['no match']),
([], [B3_payee_mismatch_2], ['no match']),
assert match == (
[B3_payee_mismatch_1, B3_payee_mismatch_2],
def test_remove_payee_junk():
assert remove_payee_junk('WIDGETSRUS INC PAYMENT 1') == 'WIDGETSRUS'
@@ -251,7 +294,17 @@ def test_payee_not_considered_if_check_id_present():
# These records match aside from check-id.
books = [B3_unmatched_check_id]
([], [B3_unmatched_check_id], ['no match']),
[B3_unmatched_check_id],
def test_subset_sum_match():
statement = [S4]
books = [B4A, B4B, B4C]
assert subset_match(statement, books) == (
[([S4], [B4A, B4B, B4C], [])],
[], # No remaining statement trans.
[], # No remaining books trans.