1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-02 12:05:19 +02:00

Add Live Data to Account Page (#464)

* Add trends, time series, seed data

* Remove test data

* Replace old view values with helpers

* Fix tooltip bugs in D3 chart

* Fix tests

* Fix smoke test

* Add CRUD actions for valuations

* Scaffold out inline editing with Turbo
This commit is contained in:
Zach Gollwitzer 2024-02-20 09:07:55 -05:00 committed by GitHub
parent 298b50a909
commit b5b2d335fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 512 additions and 167 deletions

View file

@ -1,6 +1,7 @@
class Account < ApplicationRecord
belongs_to :family
has_many :account_balances
has_many :balances, class_name: "AccountBalance"
has_many :valuations
delegated_type :accountable, types: Accountable::TYPES, dependent: :destroy
@ -8,6 +9,15 @@ class Account < ApplicationRecord
before_create :check_currency
# Show all valuations in history table (no date range filtering)
def valuations_with_trend
series_for(valuations, :value)
end
def balances_with_trend(date_range = default_date_range)
series_for(balances, :balance, date_range)
end
def check_currency
if self.original_currency == self.family.currency
self.converted_balance = self.original_balance
@ -17,4 +27,36 @@ class Account < ApplicationRecord
self.converted_currency = self.family.currency
end
end
private
def default_date_range
{ start: 30.days.ago.to_date, end: Date.today }
end
# TODO: probably a better abstraction for this in the future
def series_for(collection, value_attr, date_range = {})
collection = filtered_by_date_for(collection, date_range)
overall_trend = Trend.new(collection.last&.send(value_attr), collection.first&.send(value_attr))
collection_with_trends = [ nil, *collection ].each_cons(2).map do |previous, current|
{
current: current,
previous: previous,
date: current.date,
currency: current.currency,
value: current.send(value_attr),
trend: Trend.new(current.send(value_attr), previous&.send(value_attr))
}
end
{ date_range: date_range, trend: overall_trend, series: collection_with_trends }
end
def filtered_by_date_for(association, date_range)
scope = association
scope = scope.where("date >= ?", date_range[:start]) if date_range[:start]
scope = scope.where("date <= ?", date_range[:end]) if date_range[:end]
scope.order(:date).to_a
end
end

3
app/models/adjustment.rb Normal file
View file

@ -0,0 +1,3 @@
# Used for manual account value adjustments (e.g. to correct for a missing transaction)
class Adjustment < Valuation
end

3
app/models/appraisal.rb Normal file
View file

@ -0,0 +1,3 @@
# Used to update the value of an account based on a manual or external appraisal (i.e. Zillow)
class Appraisal < Valuation
end

26
app/models/trend.rb Normal file
View file

@ -0,0 +1,26 @@
class Trend
attr_reader :current, :previous
def initialize(current, previous)
@current = current
@previous = previous
end
def direction
return "flat" unless @previous
return "up" if @current > @previous
return "down" if @current < @previous
"flat"
end
def amount
return 0 if @previous.nil?
@current - @previous
end
def percent
return 0 if @previous.nil?
return Float::INFINITY if @previous == 0
((@current - @previous).abs / @previous.to_f * 100).round(1)
end
end

5
app/models/valuation.rb Normal file
View file

@ -0,0 +1,5 @@
# STI model to represent a point-in-time "valuation" of an account's value
# Types include: Appraisal, Adjustment
class Valuation < ApplicationRecord
belongs_to :account
end