Add income and spending insight cards to dashboard #668
Reference in New Issue
Block a user
Delete Branch "feature/transaction-insight-cards"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This PR implements the income and spending insight cards for the dashboard.
Requirements
Family, scoped toPeriod.last_30_days/claim #645
Resolves #645
/claim #645
The structure of this looks good to me, just added some notes regarding tests / exchange rate conversions for handling multi-currency.
@@ -28,6 +28,49 @@ class Family < ApplicationRecord}Small nitpick—this may be something to handle in
Period, but I'm thinkingdays_rollingshould always be a function of the period. If we changedperiodto bePeriod.last_365_days, I'd probably expect the calculation to switch to a "trailing 12 month" (365 day) period.Would you agree with that? Might be worth expressing that here.
@@ -31,0 +69,4 @@income_series: TimeSeries.new(income, favorable_direction: "up"),spending_series: TimeSeries.new(spending, favorable_direction: "down")}endI like the overall direction of this query. Definitely a complex one (that will likely need to be modified as we start adding various transaction types), so I'm thinking we may need a few test cases for documentation purposes. As a quick summary of this comment:
Familyhaswithmethod that may make this a little easier to scan top-to-bottom?Looking at the output for the demo account (
rake demo_data:reset):In the screenshot above, I would expect these insights to always show in the
Family.currency(the demo account isUSD, but one of the top moving accounts isEUR). Also, it appears that both currency series from the query are being included, causing the count to be62rather than the intended31.To handle multiple currencies, I'm thinking we'll need an additional step that will normalize everything into the
Family.currencyprior to summing it all upexchange_ratestable somewhere within this query and do the filtering there (rather than trying to callexchange_toon each money instance after-the-fact). In this strategy, we'd basically be saying, "we'll try to convert, but if the app doesn't already have the needed exchange rates cached to the DB, we can't calculate this and will omit it"I've been using this spreadsheet to visualize the expected results and conversions a little bit better. Just throwing it out there in case it helps with this one.
As this is a tricky one, I'm open to ideas! All the comments above are just my best guess at how we could approach it.
Here's a sketch of what I was thinking for the exchange rates (haven't tested thoroughly, using some hardcoded placeholders):
IMO, these CTEs read a little easier but I know it completely deviates from ActiveRecord convention. Not sure what the best approach is?
@@ -28,6 +28,49 @@ class Family < ApplicationRecord}Yep makes sense to me, we can just count the days in period we're using and then use that to build the query. I'll get that updated.
@@ -31,0 +69,4 @@income_series: TimeSeries.new(income, favorable_direction: "up"),spending_series: TimeSeries.new(spending, favorable_direction: "down")}endThanks! Yeah it's been a tricky one, that makes sense regarding the currencies I was mirroring what was going on with the net worth chart but this makes more sense.
I'll take a look at working the currency conversion into things, and while I do that I'll see if I can do anything to improve the readability.
@@ -31,0 +69,4 @@income_series: TimeSeries.new(income, favorable_direction: "up"),spending_series: TimeSeries.new(spending, favorable_direction: "down")}endSounds good. Yeah, the NW chart benefits from having the
account_balancestable to read from which is "normalized" (which includes currency conversion) during the account sync process, which makes it easier to just filter by the family's currency (and assume any account balances that aren't in this subset couldn't be converted).This one is definitely tricky since we have to normalize and convert on-the-fly
@@ -31,0 +69,4 @@income_series: TimeSeries.new(income, favorable_direction: "up"),spending_series: TimeSeries.new(spending, favorable_direction: "down")}end@JoshAntBrown I had previously experimented around with a DB table called
family_snapshotsthat would essentially act as a daily "cache" table for these sorts of calculations (similar toaccount_balances):We'd essentially be doing the same calculations here but rather than on-the-fly we'd have a daily cron running to calculate them and then here we'd just read the values.
Not sure if that would really make any of this easier but thought I'd float the idea in case it helped with this one at all.
I've had a bit of a refactor and added a test in a similar fashion to the other account snapshot.
Hopefully this is a bit more manageable now without straying too far from Active Record conventions.
Here's my copy of the test cases, updated to include spending and income on a rolling basis:
https://docs.google.com/spreadsheets/d/112tRiy0l8WWngEGMdEX2JprYJmYWUW--B2UDUiW9nOE/edit
Here's how it looks with the demo data:

Looks great, thanks for adding those test cases! I have copy/pasted the expected results into that main spreadsheet for now and we'll eventually get all those into an easier format to collaborate on.
Ah, that's an interesting solution. I was starting to get a hang of the models, the associations between them, and the TimeSeries, but even if I got a few more days, I doubt I would've completed the feature.
I guess I'll hang around in this repo and slowly learn how the whole thing is put together.
You all are doing amazing work.
Thanks for the opportunity to contribute. ✨