Class: QueueCoverage::Rep

Inherits:
Data
  • Object
show all
Defined in:
app/services/queue_coverage.rb

Overview

One rep's day.

+scheduled+ is the shift before meetings come out; +intervals+ is what is
left after. Keeping both is what lets the grid say why a rep is off queue
at 12:00 — lunch reads differently from a meeting, and both read differently
from "their shift has not started". +meetings+ and +other_queues+ drive the
cell state and the dedicated/shared split; +calendar_unreadable+ marks a rep
whose grant we could not read, so "no meetings" is never read as "no data".

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#calendar_unreadableObject (readonly)

Returns the value of attribute calendar_unreadable

Returns:

  • (Object)

    the current value of calendar_unreadable



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def calendar_unreadable
  @calendar_unreadable
end

#codeObject (readonly)

Returns the value of attribute code

Returns:

  • (Object)

    the current value of code



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def code
  @code
end

#employeeObject (readonly)

Returns the value of attribute employee

Returns:

  • (Object)

    the current value of employee



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def employee
  @employee
end

#intervalsObject (readonly)

Returns the value of attribute intervals

Returns:

  • (Object)

    the current value of intervals



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def intervals
  @intervals
end

#meetingsObject (readonly)

Returns the value of attribute meetings

Returns:

  • (Object)

    the current value of meetings



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def meetings
  @meetings
end

#other_queuesObject (readonly)

Returns the value of attribute other_queues

Returns:

  • (Object)

    the current value of other_queues



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def other_queues
  @other_queues
end

#scheduledObject (readonly)

Returns the value of attribute scheduled

Returns:

  • (Object)

    the current value of scheduled



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def scheduled
  @scheduled
end

#time_offObject (readonly)

Returns the value of attribute time_off

Returns:

  • (Object)

    the current value of time_off



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def time_off
  @time_off
end

#work_statusObject (readonly)

Returns the value of attribute work_status

Returns:

  • (Object)

    the current value of work_status



46
47
48
# File 'app/services/queue_coverage.rb', line 46

def work_status
  @work_status
end

Instance Method Details

#dedicated?Boolean

Returns true when this queue is the rep's only live queue.

Returns:

  • (Boolean)

    true when this queue is the rep's only live queue



49
50
# File 'app/services/queue_coverage.rb', line 49

def dedicated? = other_queues.zero?
# @return [Boolean] true when the rep has no queue time at all today

#off?Boolean

Returns true when the rep has no queue time at all today.

Returns:

  • (Boolean)

    true when the rep has no queue time at all today



51
52
# File 'app/services/queue_coverage.rb', line 51

def off? = intervals.empty?
# @return [Boolean] true when the rep is working at all today

#on_queue_at?(minute) ⇒ Boolean

Parameters:

  • minute (Integer)

    minutes from midnight

Returns:

  • (Boolean)


56
# File 'app/services/queue_coverage.rb', line 56

def on_queue_at?(minute) = covers?(intervals, minute)

#reason_at(minute) {|a| ... } ⇒ String?

Why this rep is not on queue at +minute+, for the cell popover. The grid
shows plain coloured squares, so this is where "and why?" lives.

Parameters:

  • minute (Integer)

    minutes from midnight

Yield Parameters:

  • a (Integer)

    minute to format as HH:MM

Returns:

  • (String, nil)

    nil when they are on queue and nothing needs explaining



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'app/services/queue_coverage.rb', line 82

def reason_at(minute)
  case state_at(minute)
  when :on then nil
  when :meeting
    window = meetings.find { |(from, to)| from <= minute && to > minute }
    # Calendar titles are deliberately never read.
    "In a meeting #{yield(window.first)}-#{yield(window.last)}"
  when :break
    shift = scheduled.map { |(from, to)| "#{yield(from)}-#{yield(to)}" }.join(', ')
    # "Lunch", not "break": EmployeeWorkSchedule#hours stores the gap under
    # a +lunch+ key, and that is the word the team uses for it.
    "Scheduled lunch between shifts (#{shift})"
  when :not_working
    [work_status.to_s.humanize, time_off].compact_blank.join(' - ').presence
  else
    "Outside their shift (#{yield(scheduled.first.first)}-#{yield(scheduled.last.last)})"
  end
end

#state_at(minute) ⇒ Symbol

Why this rep is (or is not) on queue at +minute+ — one cell of the grid.

Order matters, and :meeting is gated on the shift: calendar windows are
clipped to the day, not to this rep's hours, so a 7am dentist appointment
or a lunchtime call would otherwise read MTG on a grid another rep widened
— implying queue time was lost when the rep was never due on queue.

Parameters:

  • minute (Integer)

    minutes from midnight

Returns:

  • (Symbol)

    :on, :meeting, :break, :off_shift or :not_working



67
68
69
70
71
72
73
74
# File 'app/services/queue_coverage.rb', line 67

def state_at(minute)
  return :not_working unless working?
  return :on if covers?(intervals, minute)
  return :meeting if covers?(meetings, minute) && covers?(scheduled, minute)
  return :break if minute >= scheduled.first.first && minute < scheduled.last.last

  :off_shift
end

#working?Boolean

Returns true when the rep is working at all today.

Returns:

  • (Boolean)

    true when the rep is working at all today



53
54
55
# File 'app/services/queue_coverage.rb', line 53

def working? = scheduled.any?
# @param minute [Integer] minutes from midnight
# @return [Boolean]