Payment Invoice Reconciliation (Review Session)
Date: 2026-03-25 Category: Parsing / Financial Logic Parts Completed: 3/3 (review) Language: Python
Problem Summary
Match payments to invoices using three-tier matching: exact ID match from memo → amount match → fuzzy match with forgiveness threshold. Sorted by earliest date.
Key Bugs Found on Review
1. self.invoices referenced before assignment
# Bug: self.invoices doesn't exist yet
self.invoices = [inv.lower() for inv in self.invoices]
# Fix: use the parameter
self.invoices = [inv.lower() for inv in invoices]2. Variable shadowing — amount reused
payment_id, amount, memo = ... # payment amount
curr_id, date, amount = ... # overwrites with invoice amount!
# Fix: use distinct names (payment_amount, inv_amount)3. id vs inv_id — using Python built-in
f"... for invoice {id} ..." # Python's built-in id() function!
# Fix: use curr_id or inv_id4. Missing .strip() on extracted invoice ID
inv_id = memo[pos + len("paying for:"):].strip() # .strip() was missing5. Duplicate amountMatch call instead of fuzzyMatch
# Bug: called amountMatch twice
res = self.amountMatch(payment_id, amount)
res = self.amountMatch(payment_id, amount) # should be fuzzyMatch6. Fuzzy runs even when amount matches — needs elif
# Bug: separate if statements, both can fire
# Fix: elif so fuzzy only runs when amount match fails
res = self.amountMatch(payment_id, amount)
if res:
result.append(res)
elif self.forgiveness is not None:
res = self.fuzzyMatch(payment_id, amount)7. fuzzyMatch crashes when forgiveness is None
- Guard with
elif self.forgiveness is not Nonebefore calling fuzzyMatch
8. Inconsistent split across methods
- fuzzyMatch used
split(", ")while others usedsplit(",")with strip - Fix: use consistent
split(",")+ strip everywhere
Key Learnings
self.xvs parameterxin__init__is a common Python gotcha- Variable shadowing across scopes is easy to miss — use distinct names
- Fallback tiers must use elif, not separate if statements
- Always guard against None before comparison operators