module Ecom module Core class CrewTime < ApplicationRecord # Time Ranges MORNING = 'Morning'.freeze AFTERNOON = 'Afternoon'.freeze BOTH = 'Both'.freeze TIME_RANGE = { MORNING => { start: Time.zone.parse('5:00 AM'), end: Time.zone.parse('9:00 AM') }, AFTERNOON => { start: Time.zone.parse('10:00 AM'), end: Time.zone.parse('2:00 PM') }, BOTH => { start: Time.zone.parse('5:00 AM'), end: Time.zone.parse('2:00 PM') } }.freeze belongs_to :attendance_sheet_entry belongs_to :revision_to, class_name: 'Ecom::Core::CrewTime', optional: true belongs_to :created_by, class_name: 'Ecom::Core::User' has_one :revision, class_name: 'Ecom::Core::CrewTime', foreign_key: :revision_to_id validates :checkin_time, presence: true, if: :checkout_time scope :by_attendance, lambda { |id| joins(:attendance_sheet_entry).where(ecom_core_attendance_sheet_entries: { attendance_sheet_id: id }) } scope :revised, ->(revised) { where(revised: revised) } before_save :calculate_hours after_save :calculate_total def calculate_hours self.hours = if checkout_time.nil? || checkin_time.nil? 0 else compute_hours end end def calculate_total compute_total_for_entry if saved_change_to_hours? end def compute_total_for_entry attendance_sheet_entry.total_hours = Ecom::Core::CrewTime.where( attendance_sheet_entry: attendance_sheet_entry, revised: false ).sum(:hours) attendance_sheet_entry.save end # A method to check if checkin and checkout range falls in the morning, # afternoon, or both. def find_range(start, finish) if start.before?(TIME_RANGE[MORNING][:end]) && finish.before?(TIME_RANGE[AFTERNOON][:start]) MORNING elsif start.after?(TIME_RANGE[MORNING][:end]) && finish.after?(TIME_RANGE[AFTERNOON][:start]) AFTERNOON else BOTH end end # A method to adjust time ranges by trimming any time value outside # of the defined morning and afternoon ranges def compute_hours # Reparse time to avoid errors caused by date differences start = Time.zone.parse(checkin_time.strftime('%I:%M%p')) finish = Time.zone.parse(checkout_time.strftime('%I:%M%p')) range = find_range(start, finish) left = start.before?(TIME_RANGE[range][:start]) ? TIME_RANGE[range][:start] : start right = finish.after?(TIME_RANGE[range][:end]) ? TIME_RANGE[range][:end] : finish time = (right - left) / 1.hour time -= 1 if range == BOTH time end end end end