111 lines
2.4 KiB
Ruby
111 lines
2.4 KiB
Ruby
class MaintenanceScheduleStatus
|
|
UPCOMING_PERCENT = 0.05
|
|
|
|
attr_reader :schedule, :latest_entry, :status, :due_odometer, :due_date
|
|
|
|
def initialize(schedule, latest_entry, current_odometer:)
|
|
@schedule = schedule
|
|
@latest_entry = latest_entry
|
|
@current_odometer = current_odometer
|
|
@due_odometer = baseline_odometer + schedule.mileage_interval
|
|
@due_date = baseline_date + schedule.time_interval.days
|
|
@status = calculate_status
|
|
end
|
|
|
|
def overdue?
|
|
status == "overdue"
|
|
end
|
|
|
|
def upcoming?
|
|
status == "upcoming"
|
|
end
|
|
|
|
def no_history?
|
|
status == "no_history"
|
|
end
|
|
|
|
def current?
|
|
status == "current"
|
|
end
|
|
|
|
def status_label
|
|
case status
|
|
when "overdue" then "Overdue"
|
|
when "upcoming" then "Upcoming"
|
|
when "no_history" then "No history"
|
|
else "Current"
|
|
end
|
|
end
|
|
|
|
def reason
|
|
case status
|
|
when "overdue"
|
|
overdue_reasons.join(" and ")
|
|
when "upcoming"
|
|
upcoming_reasons.join(" and ")
|
|
when "no_history"
|
|
"No matching maintenance entry has been recorded."
|
|
else
|
|
"Maintenance is current."
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :current_odometer
|
|
|
|
def calculate_status
|
|
return "overdue" if mileage_overdue? || time_overdue?
|
|
return "upcoming" if mileage_upcoming? || time_upcoming?
|
|
return "no_history" if latest_entry.blank?
|
|
|
|
"current"
|
|
end
|
|
|
|
def baseline_odometer
|
|
latest_entry&.odometer || schedule.baseline_odometer
|
|
end
|
|
|
|
def baseline_date
|
|
latest_entry&.date || schedule.baseline_date
|
|
end
|
|
|
|
def mileage_overdue?
|
|
current_odometer >= due_odometer
|
|
end
|
|
|
|
def time_overdue?
|
|
Date.current >= due_date
|
|
end
|
|
|
|
def mileage_upcoming?
|
|
current_odometer >= due_odometer - mileage_upcoming_window
|
|
end
|
|
|
|
def time_upcoming?
|
|
Date.current >= due_date - time_upcoming_window.days
|
|
end
|
|
|
|
def mileage_upcoming_window
|
|
(schedule.mileage_interval * UPCOMING_PERCENT).ceil
|
|
end
|
|
|
|
def time_upcoming_window
|
|
(schedule.time_interval * UPCOMING_PERCENT).ceil
|
|
end
|
|
|
|
def overdue_reasons
|
|
reasons = []
|
|
reasons << "mileage interval reached" if mileage_overdue?
|
|
reasons << "time interval reached" if time_overdue?
|
|
reasons
|
|
end
|
|
|
|
def upcoming_reasons
|
|
reasons = []
|
|
reasons << "within #{mileage_upcoming_window} miles of due odometer" if mileage_upcoming?
|
|
reasons << "within #{time_upcoming_window} days of due date" if time_upcoming?
|
|
reasons
|
|
end
|
|
end
|