Transfer and Payment auto-matching, model and UI improvements #1585
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR is an overhaul of
Transfer
model and the UI flows for identifying, marking, and viewing transfers.Changes
Association updates
Previously,
Account::Transfer
had ahas_many :entries
relationship. This posed a few problems when trying to easily validate both sides of the transfer. It was cumbersome to identify the "inflow" transaction and the "outflow" transaction. Furthermore, this was set at theAccount::Entry
level, while transfers are not possible for other entry types likeAccount::Valuation
andAccount::Trade
.The new
Transfer
model is more reflective of reality, which enables easier access patterns such asentry.account_transaction.transfer?
to determine if the transaction is one side of a transfer.Validation and data integrity updates
Previously, the system had a
marked_as_transfer
boolean field onAccount::Entry
, which was in place to identify "1-sided transfers" (i.e. transfers where one of the accounts was not in the app). This created confusing logic where we needed to update/query 2 separate places (transfer_id
andmarked_as_transfer
) to identify a one-way or two-way transfer.In the new system all transfers are 2-way, which reflects the domain a lot more closely. In future PRs, I'll be adding additional ways to exclude transactions from budgeting calculations while keeping this "transfer" concept intact.
Auto matching
I have also removed the "matching" UI, disabled selections of transfer transactions, and created a much more seamless "auto-matching" background process that will intelligently match transfers for the user and ask them to confirm the match. Our app can identify 90% of transfers by looking at the amount, account, and date. Two transactions with opposite amounts, within a few days of each other from different accounts give high confidence that we're dealing with a transfer.
Transfers and Payments overview
One of the major goals of this app is to treat "transfers" and "payments" as first-class citizens rather than a categorical afterthought. Most personal finance apps leave it to the user to identify transfers and payments, which generally ends in the user asking, "How do I incorporate transfers in my budget and goals?". This leads to inaccurate calculations of spending, income, and overall budgets because the app does not give the user a clear way to separate these concepts from expenses and income (the primary purpose of budgeting). Our goal is to give transfers/payments a clear "home" in the app and assist the user in identifying them. Below are some technical definitions of each:
Transfer/Payment treatment
Transfers and payments are incorporated into a user's budget based on the classification of account in which they correspond to.
Basic transfer matching and one-time expense demo
CleanShot.2025-01-03.at.19.13.29.mp4