Class: SalesRepQueueEntry
Overview
== Schema Information
Table name: sales_rep_queue_entries
Database name: primary
id :integer not null, primary key
apply_paired_sales_rep :boolean
local_sales_rep_ids :integer default([]), is an Array
local_sales_rep_stack :integer default([]), is an Array
local_sales_rep_weights :integer default([]), is an Array
name :string(255)
position :integer
primary_sales_rep_ids :integer default([]), is an Array
primary_sales_rep_stack :integer default([]), is an Array
primary_sales_rep_weights :integer default([]), is an Array
secondary_sales_rep_ids :integer default([]), is an Array
secondary_sales_rep_stack :integer default([]), is an Array
secondary_sales_rep_weights :integer default([]), is an Array
created_at :datetime
updated_at :datetime
creator_id :integer
customer_filter_id :integer
sales_rep_queue_id :integer
updater_id :integer
Indexes
idx_sales_rep_queue_id (sales_rep_queue_id)
sales_rep_queue_entries_customer_filter_id_idx (customer_filter_id)
Foreign Keys
sales_rep_queue_entries_customer_filter_id_fk (customer_filter_id => customer_filters.id)
Constant Summary
Models::Auditable::ALWAYS_IGNORED
Constants included
from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
#creator, #updater
Class Method Summary
collapse
Instance Method Summary
collapse
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
config
#after_commit
#publish_event
Instance Attribute Details
#customer_filter_id ⇒ Object
56
|
# File 'app/models/sales_rep_queue_entry.rb', line 56
validates :customer_filter_id, uniqueness: { scope: :sales_rep_queue_id }
|
#name ⇒ Object
54
|
# File 'app/models/sales_rep_queue_entry.rb', line 54
validates :name, :sales_rep_queue, presence: true
|
Class Method Details
.name_map(rel, role_prefix, include_token = true) ⇒ Object
89
90
91
92
93
94
95
|
# File 'app/models/sales_rep_queue_entry.rb', line 89
def self.name_map(rel, role_prefix, include_token = true)
rel.map do |srw|
res = srw.employee.full_name.to_s
res += " [#{role_prefix}:#{srw.weight}:#{srw.effective_remaining}(#{srw.remaining})]" if include_token
res
end
end
|
A relation of SalesRepQueueEntries that are sorted. Active Record Scope
61
|
# File 'app/models/sales_rep_queue_entry.rb', line 61
scope :sorted, -> { order("sales_rep_queue_entries.position") }
|
Instance Method Details
#all_rep_names(include_token = true) ⇒ Object
109
110
111
112
113
|
# File 'app/models/sales_rep_queue_entry.rb', line 109
def all_rep_names(include_token = true)
(primary_sales_reps_names(include_token) +
secondary_sales_reps_names(include_token) +
local_sales_reps_names(include_token)).uniq
end
|
#applies_to_customer?(customer) ⇒ Boolean
77
78
79
|
# File 'app/models/sales_rep_queue_entry.rb', line 77
def applies_to_customer?(customer)
sales_rep_weights.present? and (customer_filter ? customer_filter.applies_to_customer?(customer) : true)
end
|
#assign_combined_values(rep_type, val) ⇒ Object
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
# File 'app/models/sales_rep_queue_entry.rb', line 127
def assign_combined_values(rep_type, val)
rep_type = rep_type.to_s
return if val.blank?
valids = []
val.each do |rep_id, weight|
rep_id = rep_id.to_i
weight = weight.to_i
next unless weight > 0
obj = sales_rep_weights.find { |srw| srw.employee_id == rep_id && srw.role == rep_type }
if obj.nil?
obj = sales_rep_weights.build(employee_id: rep_id, role: rep_type, weight: weight)
else
obj.weight = weight
end
raise "Sales rep weight for #{obj.role} id #{rep_id} with value #{weight} is invalid, #{obj.errors_to_s}" unless obj.valid?
valids << obj
end
sales_rep_weights.select { |srw| srw.role == rep_type }.reject { |srw| valids.map(&:id).include?(srw.id) }.each(&:destroy)
end
|
#available_customer_filters ⇒ Object
63
64
65
66
67
68
69
70
71
|
# File 'app/models/sales_rep_queue_entry.rb', line 63
def available_customer_filters
CustomerFilter.options_for_select do |rel|
filter_in_use_ids = SalesRepQueueEntry.where(sales_rep_queue_id: sales_rep_queue_id).pluck(:customer_filter_id) - [customer_filter_id]
filter_in_use_ids = filter_in_use_ids.compact.uniq
newrel = rel.where(store_id: sales_rep_queue.store_id)
newrel = newrel.where.not(customer_filters: { id: filter_in_use_ids }) if filter_in_use_ids.present?
newrel
end
end
|
#check_sales_rep_queue_rules ⇒ Object
151
152
153
154
155
156
157
158
159
160
161
162
163
|
# File 'app/models/sales_rep_queue_entry.rb', line 151
def check_sales_rep_queue_rules
return if primary_sales_rep_in_queue?
if secondary_sales_rep_in_queue? || local_sales_rep_in_queue?
errors.add(:base, " must have at least one non-zero entry (or Local Sales Rep Weights can have one non-zero entry if 'Apply Paired Sales Rep' is checked)")
elsif secondary_sales_rep_in_queue?
errors.add(:base, " must have at least one non-zero entry if Secondary Sales Rep Weights has one non-zero entry")
end
return unless local_sales_rep_in_queue? && !apply_paired_sales_rep?
errors.add(:base, " must have at least one non-zero entry if Local Sales Rep Weights has one non-zero entry and 'Apply Paired Sales Rep' is not checked")
end
|
50
|
# File 'app/models/sales_rep_queue_entry.rb', line 50
belongs_to :customer_filter, inverse_of: :sales_rep_queue_entries, optional: true
|
#default? ⇒ Boolean
73
74
75
|
# File 'app/models/sales_rep_queue_entry.rb', line 73
def default?
customer_filter.nil?
end
|
#description ⇒ Object
85
86
87
|
# File 'app/models/sales_rep_queue_entry.rb', line 85
def description
"#{sales_rep_queue} - #{name} : #{all_rep_names(true).join(', ')}"
end
|
#find_sales_rep_weight_for(role, sales_rep_id) ⇒ Object
206
207
208
|
# File 'app/models/sales_rep_queue_entry.rb', line 206
def find_sales_rep_weight_for(role, sales_rep_id)
sales_rep_weights.where(role: role, employee_id: sales_rep_id).pick(:weight) || 0
end
|
#get_assignable_weights(sales_rep_type) ⇒ Object
185
186
187
188
189
190
191
192
|
# File 'app/models/sales_rep_queue_entry.rb', line 185
def get_assignable_weights(sales_rep_type)
weights = sales_rep_weights.reload.assignable.where(role: sales_rep_type).select { |w| w.effective_remaining.positive? }
if weights.blank?
reset_weights(sales_rep_type)
weights = sales_rep_weights.reload.assignable.where(role: sales_rep_type).select { |w| w.effective_remaining.positive? }
end
weights.to_a
end
|
#get_sales_rep(sales_rep_type = :primary_sales_rep) ⇒ Object
194
195
196
197
198
199
200
201
202
203
204
|
# File 'app/models/sales_rep_queue_entry.rb', line 194
def get_sales_rep(sales_rep_type = :primary_sales_rep)
weights = get_assignable_weights(sales_rep_type)
if weights.present?
weights.shuffle!
weight = weights.shift
weight.remaining = [weight.remaining - 1, 0].max
weight.save
rep = weight.employee
end
rep
end
|
#local_sales_rep_in_queue? ⇒ Boolean
173
174
175
|
# File 'app/models/sales_rep_queue_entry.rb', line 173
def local_sales_rep_in_queue?
sales_rep_weights.where(role: :local_sales_rep).exists?
end
|
#local_sales_rep_weights_combined=(val) ⇒ Object
123
124
125
|
# File 'app/models/sales_rep_queue_entry.rb', line 123
def local_sales_rep_weights_combined=(val)
assign_combined_values :local_sales_rep, val
end
|
#local_sales_reps_names(include_token = true) ⇒ Object
105
106
107
|
# File 'app/models/sales_rep_queue_entry.rb', line 105
def local_sales_reps_names(include_token = true)
self.class.name_map sales_rep_weights.local_sales_reps.with_employee_sorted, "L", include_token
end
|
#prevent_paired_rep_duplicates ⇒ Object
To prevent duplicate assignment of a rep in multiple role we must validate each rep and potential backup rep in each role
If any are possibly listed twice then we error out
212
213
214
215
216
217
218
|
# File 'app/models/sales_rep_queue_entry.rb', line 212
def prevent_paired_rep_duplicates
rep_ids = sales_rep_weights.map &:employee_id
rep_ids += sales_rep_weights.filter_map { |srw| srw.employee.try(:employee_record).try(:backup_rep_id) } if apply_paired_sales_rep
duplicate_employee_ids = rep_ids.group_by { |e| e }.select { |_k, v| v.size > 1 }.map(&:first)
duplicate_employee_names = Employee.where(id: duplicate_employee_ids).pluck(:full_name)
errors.add(:base, "#{duplicate_employee_names.to_sentence} can potentially be duplicated causing an assignment error, make sure reps only appear in one role.") if duplicate_employee_names.present?
end
|
#primary_sales_rep_in_queue? ⇒ Boolean
165
166
167
|
# File 'app/models/sales_rep_queue_entry.rb', line 165
def primary_sales_rep_in_queue?
sales_rep_weights.where(role: :primary_sales_rep).exists?
end
|
#primary_sales_rep_weights_combined=(val) ⇒ Object
115
116
117
|
# File 'app/models/sales_rep_queue_entry.rb', line 115
def primary_sales_rep_weights_combined=(val)
assign_combined_values :primary_sales_rep, val
end
|
#primary_sales_reps_names(include_token = true) ⇒ Object
97
98
99
|
# File 'app/models/sales_rep_queue_entry.rb', line 97
def primary_sales_reps_names(include_token = true)
self.class.name_map sales_rep_weights.primary_sales_reps.with_employee_sorted, "P", include_token
end
|
#reset_weights(roles = nil) ⇒ Object
177
178
179
180
181
182
183
|
# File 'app/models/sales_rep_queue_entry.rb', line 177
def reset_weights(roles = nil)
roles = [roles].flatten.compact
roles = SalesRepQueue::SALES_REP_TYPES if roles.blank?
logger.debug "Retrieving a fresh stack of rep for #{roles.join} on sales queue #{id}"
sales_rep_weights.where(role: roles).update_all("remaining = weight")
sales_rep_weights.reload end
|
Validations:
49
|
# File 'app/models/sales_rep_queue_entry.rb', line 49
belongs_to :sales_rep_queue, inverse_of: :sales_rep_queue_entries, optional: true
|
#sales_rep_weights ⇒ ActiveRecord::Relation<SalesRepWeight>
52
|
# File 'app/models/sales_rep_queue_entry.rb', line 52
has_many :sales_rep_weights, inverse_of: :sales_rep_queue_entry, autosave: true
|
#secondary_sales_rep_in_queue? ⇒ Boolean
169
170
171
|
# File 'app/models/sales_rep_queue_entry.rb', line 169
def secondary_sales_rep_in_queue?
sales_rep_weights.where(role: :secondary_sales_rep).exists?
end
|
#secondary_sales_rep_weights_combined=(val) ⇒ Object
119
120
121
|
# File 'app/models/sales_rep_queue_entry.rb', line 119
def secondary_sales_rep_weights_combined=(val)
assign_combined_values :secondary_sales_rep, val
end
|
#secondary_sales_reps_names(include_token = true) ⇒ Object
101
102
103
|
# File 'app/models/sales_rep_queue_entry.rb', line 101
def secondary_sales_reps_names(include_token = true)
self.class.name_map sales_rep_weights.secondary_sales_reps.with_employee_sorted, "S", include_token
end
|
#to_partial_path ⇒ Object
Partial lives under app/views/sales_rep_queues/, not the
conventional app/views/sales_rep_queue_entries/. Override so
render sales_rep_queue_entry / render @sales_rep_queue_entries
resolves from any controller.
43
44
45
|
# File 'app/models/sales_rep_queue_entry.rb', line 43
def to_partial_path
'sales_rep_queues/sales_rep_queue_entry'
end
|
#to_s ⇒ Object
81
82
83
|
# File 'app/models/sales_rep_queue_entry.rb', line 81
def to_s
name
end
|