mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 05:09:38 +02:00
* Remove balance mode, sketch out refactor * Activity view checkpoint * Entry partials, checkpoint * Finish txn partial * Give entries context when editing for different turbo responses * Calculate change of balance for each entry * Account tabs consolidation * Translations, linting, brakeman updates * Account actions concern * Finalize forms, get account system tests passing * Get tests passing * Lint, rubocop, schema updates * Improve routing and stream responses * Fix broken routes * Add import option for adding accounts * Fix system test * Fix test specificity * Fix sparklines * Improve account redirects
131 lines
2.7 KiB
Ruby
131 lines
2.7 KiB
Ruby
class TimeSeries::Trend
|
|
include ActiveModel::Validations
|
|
|
|
attr_reader :current, :previous, :favorable_direction
|
|
|
|
validate :values_must_be_of_same_type, :values_must_be_of_known_type
|
|
|
|
def initialize(current:, previous:, series: nil, favorable_direction: nil)
|
|
@current = current
|
|
@previous = previous
|
|
@series = series
|
|
@favorable_direction = get_favorable_direction(favorable_direction)
|
|
|
|
validate!
|
|
end
|
|
|
|
def direction
|
|
if previous.nil? || current == previous
|
|
"flat"
|
|
elsif current && current > previous
|
|
"up"
|
|
else
|
|
"down"
|
|
end.inquiry
|
|
end
|
|
|
|
def color
|
|
case direction
|
|
when "up"
|
|
favorable_direction.down? ? red_hex : green_hex
|
|
when "down"
|
|
favorable_direction.down? ? green_hex : red_hex
|
|
else
|
|
gray_hex
|
|
end
|
|
end
|
|
|
|
def icon
|
|
if direction.flat?
|
|
"minus"
|
|
elsif direction.up?
|
|
"arrow-up"
|
|
else
|
|
"arrow-down"
|
|
end
|
|
end
|
|
|
|
def value
|
|
if previous.nil?
|
|
current.is_a?(Money) ? Money.new(0, current.currency) : 0
|
|
else
|
|
current - previous
|
|
end
|
|
end
|
|
|
|
def percent
|
|
if previous.nil? || (previous.zero? && current.zero?)
|
|
0.0
|
|
elsif previous.zero?
|
|
Float::INFINITY
|
|
else
|
|
change = (current_amount - previous_amount)
|
|
base = previous_amount.to_f
|
|
|
|
(change / base * 100).round(1).to_f
|
|
end
|
|
end
|
|
|
|
def as_json
|
|
{
|
|
favorable_direction: favorable_direction,
|
|
direction: direction,
|
|
value: value,
|
|
percent: percent
|
|
}.as_json
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :series
|
|
|
|
def red_hex
|
|
"#F13636" # red-500
|
|
end
|
|
|
|
def green_hex
|
|
"#10A861" # green-600
|
|
end
|
|
|
|
def gray_hex
|
|
"#737373" # gray-500
|
|
end
|
|
|
|
def values_must_be_of_same_type
|
|
unless current.class == previous.class || [ previous, current ].any?(&:nil?)
|
|
errors.add :current, :must_be_of_the_same_type_as_previous
|
|
errors.add :previous, :must_be_of_the_same_type_as_current
|
|
end
|
|
end
|
|
|
|
def values_must_be_of_known_type
|
|
unless current.is_a?(Money) || current.is_a?(Numeric) || current.nil?
|
|
errors.add :current, :must_be_of_type_money_numeric_or_nil
|
|
end
|
|
|
|
unless previous.is_a?(Money) || previous.is_a?(Numeric) || previous.nil?
|
|
errors.add :previous, :must_be_of_type_money_numeric_or_nil
|
|
end
|
|
end
|
|
|
|
def current_amount
|
|
extract_numeric current
|
|
end
|
|
|
|
def previous_amount
|
|
extract_numeric previous
|
|
end
|
|
|
|
def extract_numeric(obj)
|
|
if obj.is_a? Money
|
|
obj.amount
|
|
else
|
|
obj
|
|
end
|
|
end
|
|
|
|
def get_favorable_direction(favorable_direction)
|
|
direction = favorable_direction.presence || series&.favorable_direction
|
|
(direction.presence_in(TimeSeries::DIRECTIONS) || "up").inquiry
|
|
end
|
|
end
|