Class: AssignmentQueue

Inherits:
ApplicationRecord show all
Extended by:
Memery
Includes:
Memery, Models::Auditable
Defined in:
app/models/assignment_queue.rb

Overview

== Schema Information

Table name: assignment_queues
Database name: primary

id :integer not null, primary key
queue :string(255) default([]), not null, is an Array
created_at :datetime not null
updated_at :datetime
creator_id :integer
updater_id :integer

Indexes

idx_assignment_queues_queue (queue) UNIQUE

Defined Under Namespace

Classes: UnassignableActivity

Constant Summary collapse

VARIABLE_OPTIONS =

Available variable options.

[['Logged-in User', 'current_user'],
['Primary Sales Rep', 'primary_sales_rep'],
['Primary Sales Rep Backup', 'primary_sales_rep_backup'],
['Secondary Sales Rep', 'secondary_sales_rep'],
['Local Sales Rep', 'local_sales_rep'],
['Service Rep', 'service_rep']].freeze
TICKET_VARIABLE_OPTIONS =

Available ticket variable options.

[['Assigned Rep', 'ticket_assigned_rep']].freeze

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Constants included from Schedulable

Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #creator, #should_not_save_version, #stamp_record, #updater

Methods inherited from ApplicationRecord

ransackable_associations, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#lbr_methodObject

Returns the value of attribute lbr_method.



49
50
51
# File 'app/models/assignment_queue.rb', line 49

def lbr_method
  @lbr_method
end

Class Method Details

.containing_entry_namedActiveRecord::Relation<AssignmentQueue>

A relation of AssignmentQueues that are containing entry named. Active Record Scope

Returns:

See Also:



32
33
34
35
36
37
38
39
# File 'app/models/assignment_queue.rb', line 32

scope :containing_entry_named, ->(val) {
  return all if val.blank?

  matching = queue_select_options
             .select { |label, _| label.downcase.include?(val.to_s.downcase) }
             .map(&:last)
  matching.any? ? where("queue && ARRAY[?]::varchar[]", matching) : none
}

.employee_select_optionsObject

Builds a list of possible employees to use in activity assignment queues



91
92
93
# File 'app/models/assignment_queue.rb', line 91

def employee_select_options
  Employee.select_options.map { |o| [o[0], "Employee|#{o[1]}"] }
end

.grouped_queue_select_optionsObject

Returns a grouped list of queue options suitable for an options for select grouped



71
72
73
74
75
76
77
78
# File 'app/models/assignment_queue.rb', line 71

def grouped_queue_select_options
  {
    'Customer Roles' => VARIABLE_OPTIONS,
    'Support Case Roles' => TICKET_VARIABLE_OPTIONS,
    'Least Busy by Role' => role_select_options,
    'Employees' => employee_select_options
  }
end

.interpolate_with_customer(q, c, current_user_id = nil, target_date = nil, excluded_rep_ids = [], assignment_matrix = nil, resource = nil) ⇒ Integer?

Note:

When c (the customer) is nil — e.g. an Activity is created
against a Contact whose customer association is unset — the cache
key is built without dereferencing c and customer-dependent entries
return nil (semantics: "this entry can't yield a rep") instead of
raising. Customer-independent entries continue to resolve normally.
This mirrors the existing nil-guard on the resource arg.

Resolves a queue entry to a rep id, using the customer/context as input.

Result is memoized per CurrentScope (request- or job-scoped) keyed on
all arguments, so a given queue traversal computes each entry once.

Logic Details

Queue entries fall into two contracts:

  • Customer-dependent: primary_sales_rep, primary_sales_rep_backup,
    secondary_sales_rep, local_sales_rep, service_rep. These read the
    rep id off the customer record.
  • Customer-independent: current_user, Employee|<id>, LBR|<role>,
    ticket_assigned_rep. These resolve from current_user_id, the entry
    itself, an assignment_matrix lookup, or resource.

Parameters:

  • q (String)

    queue entry type (one of the values listed above, or
    the pipe-delimited Employee|<id> / LBR|<role_id> form)

  • c (#primary_sales_rep_id, #backup_rep_id, #secondary_sales_rep_id, #local_sales_rep_id, #service_rep_id, #id, nil)

    the customer (or
    contact/supplier with a customer-shaped interface). nil is allowed.

  • current_user_id (Integer, nil) (defaults to: nil)

    id of the logged-in user creating
    the activity, used by the current_user queue entry

  • target_date (Date, nil) (defaults to: nil)

    target date for the activity; required
    for LBR|... (least-busy-rep) entries. Defaults to Date.current.

  • excluded_rep_ids (Array<Integer>) (defaults to: [])

    rep ids to skip (already tried
    and bounced); the result is forced to nil if it lands in this list

  • assignment_matrix (Hash, nil) (defaults to: nil)

    optional precomputed
    { employee_id => workload } map; when present, LBR|<role> picks
    from this hash instead of issuing a DB query

  • resource (#id, nil) (defaults to: nil)

    resource the activity is attached to, used
    by ticket_assigned_rep to read assigned_to_id

Returns:

  • (Integer, nil)

    rep id when an entry resolves; nil when the
    entry cannot yield a rep (excluded, zero, customer missing for a
    customer-dependent entry, etc.)



160
161
162
163
164
165
166
167
168
# File 'app/models/assignment_queue.rb', line 160

def interpolate_with_customer(q, c, current_user_id = nil, target_date = nil, excluded_rep_ids = [], assignment_matrix = nil, resource = nil)
  target_date ||= Date.current

  cache_key = [:interpolate_with_customer, q, c && [c.class.name, c.id], current_user_id, target_date,
               excluded_rep_ids, assignment_matrix, resource && [resource.class.name, resource.id]]
  fetch_cached(*cache_key) do
    compute_interpolate_with_customer(q, c, current_user_id, target_date, excluded_rep_ids, assignment_matrix, resource)
  end
end

.least_busy_rep_by_role(target_date, role_id, excluded_rep_ids, assignment_matrix = nil) ⇒ Object

Queries database to find out the least busy rep



171
172
173
174
175
# File 'app/models/assignment_queue.rb', line 171

def least_busy_rep_by_role(target_date, role_id, excluded_rep_ids, assignment_matrix = nil)
  fetch_cached(:least_busy_rep_by_role, target_date, role_id, excluded_rep_ids, assignment_matrix) do
    compute_least_busy_rep_by_role(target_date, role_id, excluded_rep_ids, assignment_matrix)
  end
end

.queue_select_optionsObject

Builds a list of possible queue values, variable role based values and individuals



86
87
88
# File 'app/models/assignment_queue.rb', line 86

def queue_select_options
  [] + VARIABLE_OPTIONS + TICKET_VARIABLE_OPTIONS + role_select_options + employee_select_options
end

.queue_value_expanded(q) ⇒ Object

Translates a queue value to a friendly name



100
101
102
103
104
105
106
107
108
# File 'app/models/assignment_queue.rb', line 100

def queue_value_expanded(q)
  match = queue_select_options.find { |e| e[1] == q }
  if match
    match[0]
  else
    logger.error " !!! queue_value_expanded: Could not determine the value of q -> #{q}"
    raise "Value of q missing in table #{q}"
  end
end

.ransackable_attributes(_auth_object = nil) ⇒ Object



45
46
47
# File 'app/models/assignment_queue.rb', line 45

def self.ransackable_attributes(_auth_object = nil)
  %w[id queue created_at updated_at]
end

.ransackable_scopes(_auth_object = nil) ⇒ Object



41
42
43
# File 'app/models/assignment_queue.rb', line 41

def self.ransackable_scopes(_auth_object = nil)
  %i[containing_entry_named]
end

.rep_id_for_backup(rep_id) ⇒ Object



110
111
112
113
114
115
116
# File 'app/models/assignment_queue.rb', line 110

def rep_id_for_backup(rep_id)
  return nil unless rep_id

  fetch_cached(:rep_id_for_backup, rep_id) do
    EmployeeRecord.where(party_id: rep_id).pick(:backup_rep_id)
  end
end

.role_select_optionsObject



95
96
97
# File 'app/models/assignment_queue.rb', line 95

def role_select_options
  Role.select_options.map { |r| [r[0], "LBR|#{r[1]}"] }
end

.select_optionsObject

Provides a list of assignment queues to select from



66
67
68
# File 'app/models/assignment_queue.rb', line 66

def select_options
  all.to_a.reject { |aq| aq.name.nil? }.sort_by(&:name).map { |aq| ["#{aq.name} [#{aq.id}]", aq.id] }
end

.valid_valuesObject

Returns a list of valid values for the queue type selection



81
82
83
# File 'app/models/assignment_queue.rb', line 81

def valid_values
  queue_select_options.pluck(1)
end

Instance Method Details

#activity_type_assignment_queuesActiveRecord::Relation<ActivityTypeAssignmentQueue>

Returns:

See Also:



23
# File 'app/models/assignment_queue.rb', line 23

has_many :activity_type_assignment_queues, inverse_of: :assignment_queue

#activity_typesActiveRecord::Relation<ActivityType>

Returns:

See Also:



24
# File 'app/models/assignment_queue.rb', line 24

has_many :activity_types, through: :activity_type_assignment_queues

#nameObject



253
254
255
256
257
# File 'app/models/assignment_queue.rb', line 253

def name
  queue.map { |e| self.class.queue_value_expanded(e) }.join(' -> ')
rescue StandardError
  nil
end