Module: Models::EmployeeWorkStatus
- Extended by:
- ActiveSupport::Concern
- Includes:
- Memery, EmployeeActivityCapacity
- Included in:
- Employee
- Defined in:
- app/concerns/models/employee_work_status.rb
Overview
Day status, schedule preloading, and next-working-day logic for employees.
This concern is mixed into the Employee model and depends on
EmployeeActivityCapacity for capacity-related behaviour.
Instance Method Summary collapse
-
#active_work_schedule(date) ⇒ ActiveRecord::Relation<WorkSchedule>
Effective work schedule for the employee on the given date.
-
#capacity_ratio(date) ⇒ Float
Ratio of capacity available on the given date, from 0.0 to 1.0.
-
#current_company_holidays_array ⇒ Array<Date>
Company holidays on or after today for the employee's company.
-
#day_employee_events(date) ⇒ Array<TimeOffRequestDate>?
Approved time-off events for the employee on the given date.
-
#day_status_employee_event(date) ⇒ Symbol?
Determines the work status for the employee on a date based on approved time-off events.
-
#day_status_holiday_check(date) ⇒ Symbol?
Checks whether the given date is a company holiday or weekend.
-
#day_status_work_schedule(date) ⇒ Symbol?
Checks whether the employee has no effective working schedule for the given date.
-
#employee_events_loaded(start_date = nil) ⇒ ActiveRecord::Relation<TimeOffRequestDate>
Approved time-off request dates for this employee, optionally scoped to a single date.
-
#next_business_day(start_date = nil, offset = 1) ⇒ Date?
Next date that is not a closed/non-working day for the employee.
-
#next_business_day_closing_time(start_date = nil, offset = 1) ⇒ DateTime?
Closing time on the employee's next business day.
-
#next_working_day(start_date = nil, offset = 1) ⇒ Date
Next date on which the employee is working.
-
#preload_time_off_events(start_date, end_date) ⇒ Hash{Date => Array<TimeOffRequestDate>}
Preloads approved time-off events into an in-memory cache for a date range.
-
#preload_working_hours(start_date, end_date) ⇒ Hash{Date => Numeric}
Preloads scheduled working hours into an in-memory cache for a date range.
-
#work_status_on_day(date) ⇒ Symbol
Overall work status for the employee on the given date.
-
#working_hours_on_date(date) ⇒ Numeric
Total scheduled working hours for the employee on the given date.
-
#working_on_day?(date) ⇒ Boolean
Whether the employee is working at all on the given date.
Methods included from EmployeeActivityCapacity
#activity_load_on_day, #can_take_activities_on_day?, #maximum_activities_per_day, #maximum_priority_tier_activities_per_day, #maximum_standard_tier_activities_per_day, #priority_tier_activities_ratio
Instance Method Details
#active_work_schedule(date) ⇒ ActiveRecord::Relation<WorkSchedule>
Effective work schedule for the employee on the given date.
138 139 140 |
# File 'app/concerns/models/employee_work_status.rb', line 138 def active_work_schedule(date) work_schedules.effective_on(date) end |
#capacity_ratio(date) ⇒ Float
Ratio of capacity available on the given date, from 0.0 to 1.0.
123 124 125 126 127 128 129 130 131 |
# File 'app/concerns/models/employee_work_status.rb', line 123 def capacity_ratio(date) date = date.to_date unless date.is_a?(Date) day_status = day_status_employee_event(date) return 1.0 if day_status.nil? || day_status == :working return compute_partial_capacity(date) if day_status == :partial_timeoff 0.0 end |
#current_company_holidays_array ⇒ Array<Date>
Company holidays on or after today for the employee's company.
21 22 23 |
# File 'app/concerns/models/employee_work_status.rb', line 21 def current_company_holidays_array @current_company_holidays_array ||= company.company_holidays.where(CompanyHoliday[:holiday_date].gteq(Date.current)).pluck(:holiday_date) end |
#day_employee_events(date) ⇒ Array<TimeOffRequestDate>?
Approved time-off events for the employee on the given date.
41 42 43 44 45 46 |
# File 'app/concerns/models/employee_work_status.rb', line 41 def day_employee_events(date) date = date.to_date unless date.is_a?(Date) return @preloaded_time_off_events[date] if @preloaded_time_off_events&.key?(date) employee_events_loaded(date) end |
#day_status_employee_event(date) ⇒ Symbol?
Determines the work status for the employee on a date based on approved time-off events.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'app/concerns/models/employee_work_status.rb', line 53 def day_status_employee_event(date) evts = day_employee_events(date) return if evts.blank? wh = working_hours_on_date(date) if evts.any? { |ev| ev.time_off_request.time_off_type_id == TimeOffType::BANKED_TIME_ID } :working elsif partial_day_pto_present?(evts, wh) :partial_timeoff else evts.first.time_off_request.time_off_type.name.to_sym end end |
#day_status_holiday_check(date) ⇒ Symbol?
Checks whether the given date is a company holiday or weekend.
29 30 31 32 33 34 |
# File 'app/concerns/models/employee_work_status.rb', line 29 def day_status_holiday_check(date) date = date.to_date unless date.is_a?(Date) return :not_working_closed unless date.on_weekday? :not_working_closed if current_company_holidays_array.include?(date) end |
#day_status_work_schedule(date) ⇒ Symbol?
Checks whether the employee has no effective working schedule for the given date.
88 89 90 91 92 93 |
# File 'app/concerns/models/employee_work_status.rb', line 88 def day_status_work_schedule(date) has_effective = work_schedules.loaded? ? effective_schedule_in_memory?(date) : work_schedules.effective_on(date).exists? return unless has_effective && working_hours_on_date(date).zero? :not_working_closed end |
#employee_events_loaded(start_date = nil) ⇒ ActiveRecord::Relation<TimeOffRequestDate>
Approved time-off request dates for this employee, optionally scoped to a single date.
100 101 102 103 104 |
# File 'app/concerns/models/employee_work_status.rb', line 100 def employee_events_loaded(start_date = nil) evts = TimeOffRequestDate.joins(:time_off_request).where(time_off_requests: { state: 'approved', employee_id: id }) evts = evts.where(date: start_date) if start_date evts.distinct end |
#next_business_day(start_date = nil, offset = 1) ⇒ Date?
Next date that is not a closed/non-working day for the employee.
178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'app/concerns/models/employee_work_status.rb', line 178 def next_business_day(start_date = nil, offset = 1) start_date ||= Date.current search_date = start_date.dup.to_date + offset.days counter = 1 while work_status_on_day(search_date) == :not_working_closed search_date += 1.day if (counter += 1) > 30 search_date = nil break end end search_date end |
#next_business_day_closing_time(start_date = nil, offset = 1) ⇒ DateTime?
Closing time on the employee's next business day.
197 198 199 200 |
# File 'app/concerns/models/employee_work_status.rb', line 197 def next_business_day_closing_time(start_date = nil, offset = 1) dt = next_business_day(start_date, offset) WorkingHours.advance_to_closing_time(dt) end |
#next_working_day(start_date = nil, offset = 1) ⇒ Date
Next date on which the employee is working.
159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'app/concerns/models/employee_work_status.rb', line 159 def next_working_day(start_date = nil, offset = 1) start_date ||= Date.current search_date = start_date.dup.to_date + offset.days preload_time_off_events(search_date, search_date + 30.days) attempts = 0 until working_on_day?(search_date) search_date += 1.day attempts += 1 raise no_working_day_within_search_limit_error if attempts > 730 end search_date end |
#preload_time_off_events(start_date, end_date) ⇒ Hash{Date => Array<TimeOffRequestDate>}
Preloads approved time-off events into an in-memory cache for a date range.
207 208 209 210 211 212 213 214 215 216 217 |
# File 'app/concerns/models/employee_work_status.rb', line 207 def preload_time_off_events(start_date, end_date) @preloaded_time_off_events ||= {} events = TimeOffRequestDate.joins(:time_off_request) .includes(time_off_request: :time_off_type) .where(time_off_requests: { state: 'approved', employee_id: id }) .where(date: start_date..end_date) .distinct events.group_by(&:date).each { |date, evts| @preloaded_time_off_events[date] = evts } (start_date..end_date).each { |date| @preloaded_time_off_events[date] ||= [] } end |
#preload_working_hours(start_date, end_date) ⇒ Hash{Date => Numeric}
Preloads scheduled working hours into an in-memory cache for a date range.
224 225 226 227 228 229 230 231 232 |
# File 'app/concerns/models/employee_work_status.rb', line 224 def preload_working_hours(start_date, end_date) @preloaded_working_hours ||= {} schedules = schedules_for_preload(start_date, end_date) hours_lookup = hours_by_schedule_and_wday(schedules) (start_date..end_date).each do |date| @preloaded_working_hours[date] = sum_working_hours_for_date(schedules, hours_lookup, date) end end |
#work_status_on_day(date) ⇒ Symbol
Overall work status for the employee on the given date.
Priority order is: holiday, employee event, work schedule, then :working.
113 114 115 116 |
# File 'app/concerns/models/employee_work_status.rb', line 113 def work_status_on_day(date) date = date.to_date unless date.is_a?(Date) day_status_holiday_check(date) || day_status_employee_event(date) || day_status_work_schedule(date) || :working end |
#working_hours_on_date(date) ⇒ Numeric
Total scheduled working hours for the employee on the given date.
73 74 75 76 77 78 79 80 81 |
# File 'app/concerns/models/employee_work_status.rb', line 73 def working_hours_on_date(date) date = date.to_date unless date.is_a?(Date) return @preloaded_working_hours[date] if @preloaded_working_hours&.key?(date) work_schedules.effective_on(date) .joins(:work_schedule_days) .where(work_schedule_days: { day_of_week: date.wday }) .sum('work_schedule_days.hours') end |
#working_on_day?(date) ⇒ Boolean
Whether the employee is working at all on the given date.
147 148 149 150 151 |
# File 'app/concerns/models/employee_work_status.rb', line 147 def working_on_day?(date) date = date.to_date unless date.is_a?(Date) ws = work_status_on_day(date) ws == :working || (ws == :partial_timeoff && capacity_ratio(date).positive?) end |