Simplefin liabilities recording fix (#410)

* Add tests and logic for Simplefin account balance normalization

- Introduced `SimplefinAccountProcessorTest` to verify balance normalization logic.
- Updated `SimplefinAccount::Processor` to invert negative balances for liability accounts (credit cards and loans) while keeping asset balances unchanged.
- Added comments to clarify balance conventions and sign normalization rules.

* Refactor balances-only sync logic and improve tests for edge cases

- Updated `SimplefinItem::Importer` and `SimplefinItem::Syncer` to ensure `last_synced_at` remains nil during balances-only runs, preserving chunked-history behavior for full syncs.
- Introduced additional comments to clarify balances-only implications and syncing logic.
- Added test case in `SimplefinAccountProcessorTest` to verify correct handling of overpayment for credit card liabilities.
- Refined balance normalization in `SimplefinAccount::Processor` to always invert liability balances for consistency.

---------

Co-authored-by: Josh Waldrep <joshua.waldrep5+github@gmail.com>
This commit is contained in:
LPW
2025-12-03 12:40:37 -05:00
committed by GitHub
parent 1727b772ed
commit a91a4397e9
5 changed files with 140 additions and 19 deletions

View File

@@ -41,10 +41,14 @@ class SimplefinAccount::Processor
account = simplefin_account.current_account
balance = simplefin_account.current_balance || simplefin_account.available_balance || 0
# SimpleFIN balance convention matches our app convention:
# - Positive balance = debt (you owe money)
# - Negative balance = credit balance (bank owes you, e.g., overpayment)
# No sign conversion needed - pass through as-is (same as Plaid)
# Normalize balances for liabilities (SimpleFIN typically uses opposite sign)
# App convention:
# - Liabilities: positive => you owe; negative => provider owes you (overpayment/credit)
# Since providers often send the opposite sign, ALWAYS invert for liabilities so
# that both debt and overpayment cases are represented correctly.
if [ "CreditCard", "Loan" ].include?(account.accountable_type)
balance = -balance
end
# Calculate cash balance correctly for investment accounts
cash_balance = if account.accountable_type == "Investment"