2024-03-19 09:10:40 -04:00
|
|
|
class TimeSeries::Trend
|
2024-04-22 06:30:42 -06:00
|
|
|
include ActiveModel::Validations
|
2024-03-19 09:10:40 -04:00
|
|
|
|
2024-06-21 16:23:28 -04:00
|
|
|
attr_reader :current, :previous, :favorable_direction
|
2024-04-22 06:30:42 -06:00
|
|
|
|
|
|
|
validate :values_must_be_of_same_type, :values_must_be_of_known_type
|
|
|
|
|
2024-06-21 16:23:28 -04:00
|
|
|
def initialize(current:, previous:, series: nil, favorable_direction: nil)
|
2024-03-19 09:10:40 -04:00
|
|
|
@current = current
|
|
|
|
@previous = previous
|
2024-04-22 06:30:42 -06:00
|
|
|
@series = series
|
2024-06-21 16:23:28 -04:00
|
|
|
@favorable_direction = get_favorable_direction(favorable_direction)
|
2024-04-22 06:30:42 -06:00
|
|
|
|
|
|
|
validate!
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def direction
|
2024-04-22 06:30:42 -06:00
|
|
|
if previous.nil? || current == previous
|
|
|
|
"flat"
|
|
|
|
elsif current && current > previous
|
|
|
|
"up"
|
|
|
|
else
|
|
|
|
"down"
|
|
|
|
end.inquiry
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
|
|
|
|
2024-06-21 16:23:28 -04:00
|
|
|
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
|
|
|
|
|
2024-11-04 20:27:31 -05:00
|
|
|
def icon
|
|
|
|
if direction.flat?
|
|
|
|
"minus"
|
|
|
|
elsif direction.up?
|
|
|
|
"arrow-up"
|
|
|
|
else
|
|
|
|
"arrow-down"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-19 09:10:40 -04:00
|
|
|
def value
|
2024-04-22 06:30:42 -06:00
|
|
|
if previous.nil?
|
2024-11-04 20:27:31 -05:00
|
|
|
current.is_a?(Money) ? Money.new(0, current.currency) : 0
|
2024-04-22 06:30:42 -06:00
|
|
|
else
|
|
|
|
current - previous
|
|
|
|
end
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def percent
|
2024-07-25 16:46:04 -04:00
|
|
|
if previous.nil? || (previous.zero? && current.zero?)
|
2024-04-22 06:30:42 -06:00
|
|
|
0.0
|
|
|
|
elsif previous.zero?
|
|
|
|
Float::INFINITY
|
|
|
|
else
|
2024-04-29 14:56:38 +01:00
|
|
|
change = (current_amount - previous_amount)
|
|
|
|
base = previous_amount.to_f
|
2024-04-22 06:30:42 -06:00
|
|
|
|
|
|
|
(change / base * 100).round(1).to_f
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def as_json
|
|
|
|
{
|
|
|
|
favorable_direction: favorable_direction,
|
|
|
|
direction: direction,
|
|
|
|
value: value,
|
|
|
|
percent: percent
|
|
|
|
}.as_json
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2024-06-21 16:23:28 -04:00
|
|
|
|
2024-04-22 06:30:42 -06:00
|
|
|
attr_reader :series
|
|
|
|
|
2024-06-21 16:23:28 -04:00
|
|
|
def red_hex
|
|
|
|
"#F13636" # red-500
|
|
|
|
end
|
|
|
|
|
|
|
|
def green_hex
|
|
|
|
"#10A861" # green-600
|
|
|
|
end
|
|
|
|
|
|
|
|
def gray_hex
|
|
|
|
"#737373" # gray-500
|
|
|
|
end
|
|
|
|
|
2024-04-22 06:30:42 -06:00
|
|
|
def values_must_be_of_same_type
|
|
|
|
unless current.class == previous.class || [ previous, current ].any?(&:nil?)
|
2024-08-13 01:38:58 +01:00
|
|
|
errors.add :current, :must_be_of_the_same_type_as_previous
|
|
|
|
errors.add :previous, :must_be_of_the_same_type_as_current
|
2024-04-22 06:30:42 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def values_must_be_of_known_type
|
|
|
|
unless current.is_a?(Money) || current.is_a?(Numeric) || current.nil?
|
2024-08-13 01:38:58 +01:00
|
|
|
errors.add :current, :must_be_of_type_money_numeric_or_nil
|
2024-04-22 06:30:42 -06:00
|
|
|
end
|
|
|
|
|
|
|
|
unless previous.is_a?(Money) || previous.is_a?(Numeric) || previous.nil?
|
2024-08-13 01:38:58 +01:00
|
|
|
errors.add :previous, :must_be_of_type_money_numeric_or_nil
|
2024-04-22 06:30:42 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def current_amount
|
|
|
|
extract_numeric current
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
|
|
|
|
2024-04-22 06:30:42 -06:00
|
|
|
def previous_amount
|
|
|
|
extract_numeric previous
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def extract_numeric(obj)
|
2024-04-22 06:30:42 -06:00
|
|
|
if obj.is_a? Money
|
|
|
|
obj.amount
|
|
|
|
else
|
|
|
|
obj
|
|
|
|
end
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|
2024-06-21 16:23:28 -04:00
|
|
|
|
|
|
|
def get_favorable_direction(favorable_direction)
|
|
|
|
direction = favorable_direction.presence || series&.favorable_direction
|
|
|
|
(direction.presence_in(TimeSeries::DIRECTIONS) || "up").inquiry
|
|
|
|
end
|
2024-03-19 09:10:40 -04:00
|
|
|
end
|