Class: ActivityType
Overview
== Schema Information
Table name: activity_types
Database name: primary
id :integer not null, primary key
allow_time_lock :boolean default(FALSE), not null
autopin :boolean default(TRUE), not null
closing_instructions :text
description :string(255)
email_defer_days :integer
email_defer_tod :time
grouping :string(255)
inactive :boolean default(FALSE), not null
instructions :text
max_age_in_days :integer
next_instructions :text
notify_assigned_resource :boolean default(FALSE), not null
party_requirement :enum default("party_unrestricted"), not null
priority :integer default(2)
resource_requirement :enum default("resource_optional")
resource_restriction :string default([]), is an Array
sales_rep_as_sender :boolean default(FALSE), not null
skip_email_template_with_result :boolean default(FALSE), not null
task_type :string(255)
uniqueness :enum default("unrestricted")
created_at :datetime
updated_at :datetime
campaign_id :integer
customer_filter_id :integer
default_assignee_id :integer
email_template_id :integer
sender_party_id :integer
Indexes
activity_types_customer_filter_id_idx (customer_filter_id)
activity_types_email_template_id_idx (email_template_id)
by_id_w (id) WHERE (priority IS NOT NULL)
by_idn_w (id) WHERE (priority IS NULL)
index_activity_types_on_campaign_id (campaign_id)
index_activity_types_on_inactive_and_task_type (inactive,task_type)
index_activity_types_on_priority (priority)
index_activity_types_on_sender_party_id (sender_party_id)
index_activity_types_on_task_type (task_type)
Foreign Keys
activity_types_customer_filter_id_fk (customer_filter_id => customer_filters.id)
activity_types_email_template_id_fk (email_template_id => email_templates.id) ON DELETE => nullify
fk_rails_... (campaign_id => campaigns.id)
fk_rails_... (sender_party_id => parties.id)
Constant Summary
collapse
- PRIORITY_MAX =
Priority Activities always get assigned to someone
2
- TOTAL_TIERS =
5
- TAGS_FOR_REPORTS =
[['CLOSE_THE_DEAL', 0], ['LEAD_THE_WAY', 1], ['NURTURE_ME', 2], ['MISC', 3], ['CALLBLOCK', 4], ['OTHERS', 5]].freeze
Models::Auditable::ALWAYS_IGNORED
Constants included
from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
#creator, #updater
#tag_records, #taggings
Has and belongs to many
collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#activity_chain_types_for_select ⇒ Object
-
#auto_close_result_chain ⇒ Object
-
#cancel_invalid_activities(options = {}) ⇒ Object
Over time activity type rules can change.
-
#deep_dup ⇒ Object
-
#determine_assigned_resource(party, cur_user_id = nil, target_date = nil, resource = nil, options = {}) ⇒ Object
-
#determine_assigned_resource_id(party, cur_user_id = nil, target_date = nil, resource = nil, options = {}) ⇒ Object
For a given customer (which is handled by a specific wy company) this method will determine the resource to assign to the activity party : the customer object, contact, or supplier cur_user_id : the current user target_date : the intended target date for the activity, this is used to determine the individual resource when a group type assignment is desired and we need to determine the least busy agent.
-
#email_template_description ⇒ Object
-
#email_transmit_at_time ⇒ Object
Calculates the date/time when the creation email for this activity should be transmitted.
-
#invalid_activities(options = {}) ⇒ Object
-
#invalidate_activity(a, _options = {}) ⇒ Object
-
#is_a_quote_follow_up? ⇒ Boolean
-
#is_email? ⇒ Boolean
-
#name ⇒ Object
-
#priority_friendly_name ⇒ Object
-
#priority_tier? ⇒ Boolean
-
#result_options_for_select ⇒ Object
-
#sales_activity ⇒ Object
-
#to_s ⇒ Object
-
#valid_for_party?(party) ⇒ Boolean
#add_tag, all_tags, #has_tag?, normalize_tag_names, not_tagged_with, #remove_tag, #tag_list, #tag_list=, #taggable_type_for_tagging, tagged_with, #tags, #tags=, tags_cloud, tags_exclude, tags_include, with_all_tags, with_any_tags, without_all_tags, without_any_tags
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation
config
#after_commit
#publish_event
Instance Attribute Details
#description ⇒ Object
97
|
# File 'app/models/activity_type.rb', line 97
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
#party_requirement ⇒ Object
97
|
# File 'app/models/activity_type.rb', line 97
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
#priority ⇒ Object
97
|
# File 'app/models/activity_type.rb', line 97
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
#task_type ⇒ Object
95
|
# File 'app/models/activity_type.rb', line 95
validates :task_type, uniqueness: true
|
#uniqueness ⇒ Object
97
|
# File 'app/models/activity_type.rb', line 97
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
Class Method Details
.active ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are active. Active Record Scope
102
|
# File 'app/models/activity_type.rb', line 102
scope :active, -> { where(inactive: false) }
|
.condensed_options_for_select ⇒ Object
161
162
163
|
# File 'app/models/activity_type.rb', line 161
def self.condensed_options_for_select
active.sorted.map { |at| [at.task_type, at.id] }
end
|
.email_activities ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are email activities. Active Record Scope
110
|
# File 'app/models/activity_type.rb', line 110
scope :email_activities, -> { where(ActivityType[:task_type].matches('EMAIL%')) }
|
.meeting ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are meeting. Active Record Scope
107
|
# File 'app/models/activity_type.rb', line 107
scope :meeting, -> { where(task_type: ActivityTypeConstants::MEETING_TYPES) }
|
.options_for_select(options = {}) ⇒ Object
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# File 'app/models/activity_type.rb', line 125
def self.options_for_select(options = {})
cache_key = [:activity_options_for_select]
cache_key << (options[:party] ? options[:party].cache_key : :all_parties)
cache_key << (options[:include_activity_type_id] || :default)
cache_key << (options[:exclude_activity_type_id] || :default)
cache_key << ActivityType.maximum(:updated_at).to_i
Rails.cache.fetch(cache_key, expires_in: 15.minutes) do
activities = ActivityType.where(ActivityType[:inactive].eq(false))
activities = activities.where.not(id: options[:exclude_activity_type_id]) if options[:exclude_activity_type_id]
activities = activities.or(ActivityType.where(id: options[:include_activity_type_id])) if options[:include_activity_type_id].present?
if options[:party].present?
activities = activities.includes(customer_filter: %i[parties catalogs profiles buying_groups sources tier2_program_pricings])
activities = activities.select { |at| at.id == options[:include_activity_type_id] || at.valid_for_party?(options[:party]) }
end
activities = activities.sort_by(&:task_type)
activities.map { |at| [at.name, at.id] }
end
end
|
.options_for_select_by_user(user, extra_at_id = nil) ⇒ Object
242
243
244
245
246
247
248
249
|
# File 'app/models/activity_type.rb', line 242
def self.options_for_select_by_user(user, = nil)
rids = user.account.inherited_role_ids
ActivityType.where(
'NOT EXISTS(select 1 from activity_types_roles atr WHERE atr.activity_type_id = activity_types.id) OR EXISTS(select 1 from activity_types_roles atr WHERE atr.activity_type_id = activity_types.id AND atr.role_id IN (?)) OR activity_types.id = ?', rids,
).order('activity_types.task_type').map do |at|
[at.name, at.id]
end
end
|
.options_for_select_short ⇒ Object
145
146
147
|
# File 'app/models/activity_type.rb', line 145
def self.options_for_select_short
ActivityType.where.not(inactive: true).order(:task_type).pluck(:task_type, :id)
end
|
.party_requirement_options_for_select ⇒ Object
157
158
159
|
# File 'app/models/activity_type.rb', line 157
def self.party_requirement_options_for_select
party_requirements.map { |k, _v| [k.humanize, k] }
end
|
.priority_friendly_name(i) ⇒ Object
169
170
171
172
173
|
# File 'app/models/activity_type.rb', line 169
def self.priority_friendly_name(i)
return 'Unprioritized' unless i
"Tier #{i} #{'(High Priority)' if i <= PRIORITY_MAX}"
end
|
.priority_select_options ⇒ Object
165
166
167
|
# File 'app/models/activity_type.rb', line 165
def self.priority_select_options
(1...6).to_a.map { |i| [priority_friendly_name(i), i] }
end
|
.ransackable_scopes(_auth_object = nil) ⇒ Object
121
122
123
|
# File 'app/models/activity_type.rb', line 121
def self.ransackable_scopes(_auth_object = nil)
%i[tagged_with not_tagged_with tags_include]
end
|
.resource_requirement_options_for_select ⇒ Object
153
154
155
|
# File 'app/models/activity_type.rb', line 153
def self.resource_requirement_options_for_select
resource_requirements.map { |k, _v| [k.humanize, k] }
end
|
.resource_type_for_select ⇒ Object
175
176
177
|
# File 'app/models/activity_type.rb', line 175
def self.resource_type_for_select
%w[ServiceJob CreditApplication Invoice SpiffEnrollment Party PurchaseOrder Delivery Opportunity SupportCaseParticipant Order CreditMemo Quote RoomConfiguration SupportCase LocatorRecord Rma].map { |v| [v.titleize.humanize, v] }
end
|
.sales_activities ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are sales activities. Active Record Scope
109
|
# File 'app/models/activity_type.rb', line 109
scope :sales_activities, -> { tagged_with('sale', 'sales_call') }
|
.sorted ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are sorted. Active Record Scope
103
|
# File 'app/models/activity_type.rb', line 103
scope :sorted, -> { order(:priority, :task_type) }
|
.training ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are training. Active Record Scope
106
|
# File 'app/models/activity_type.rb', line 106
scope :training, -> { where(task_type: ActivityTypeConstants::TRAINING_TYPES) }
|
.uniqueness_options_for_select ⇒ Object
149
150
151
|
# File 'app/models/activity_type.rb', line 149
def self.uniqueness_options_for_select
uniquenesses.map { |k, _v| [k.humanize, k] }
end
|
.with_customer_filter ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are with customer filter. Active Record Scope
105
|
# File 'app/models/activity_type.rb', line 105
scope :with_customer_filter, -> { where.not(activity_types: { customer_filter_id: nil }) }
|
.with_open_counter ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are with open counter. Active Record Scope
104
|
# File 'app/models/activity_type.rb', line 104
scope :with_open_counter, -> { select('activity_types.*, (select count(a.id) from activities a where a.activity_type_id = activity_types.id and a.activity_result_type_id IS NULL) as open_counter') }
|
Instance Method Details
#activities ⇒ ActiveRecord::Relation<Activity>
86
|
# File 'app/models/activity_type.rb', line 86
has_many :activities, dependent: :nullify, inverse_of: :activity_type
|
#activity_chain_types ⇒ ActiveRecord::Relation<ActivityChainType>
87
|
# File 'app/models/activity_type.rb', line 87
has_many :activity_chain_types, dependent: :destroy
|
#activity_chain_types_for_select ⇒ Object
187
188
189
|
# File 'app/models/activity_type.rb', line 187
def activity_chain_types_for_select
activity_chain_types.map { |act| [act.activity_result_type.result_code, act.id] }
end
|
#activity_result_types ⇒ ActiveRecord::Relation<ActivityResultType>
88
|
# File 'app/models/activity_type.rb', line 88
has_many :activity_result_types, through: :activity_chain_types
|
#activity_type_assignment_queues ⇒ ActiveRecord::Relation<ActivityTypeAssignmentQueue>
89
|
# File 'app/models/activity_type.rb', line 89
has_many :activity_type_assignment_queues, dependent: :destroy
|
#activity_type_rules ⇒ ActiveRecord::Relation<ActivityTypeRule>
91
|
# File 'app/models/activity_type.rb', line 91
has_many :activity_type_rules, dependent: :destroy
|
#assignment_queues ⇒ ActiveRecord::Relation<AssignmentQueue>
90
|
# File 'app/models/activity_type.rb', line 90
has_many :assignment_queues, through: :activity_type_assignment_queues
|
#auto_close_result_chain ⇒ Object
324
325
326
|
# File 'app/models/activity_type.rb', line 324
def auto_close_result_chain
activity_chain_types.find { |act| !act.not_set? }
end
|
85
|
# File 'app/models/activity_type.rb', line 85
belongs_to :campaign, optional: true
|
#cancel_invalid_activities(options = {}) ⇒ Object
Over time activity type rules can change.
in particular the customer state restriction
Whenever this is called all activities open with a customer state restriction
now met will be cancelled
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
|
# File 'app/models/activity_type.rb', line 263
def cancel_invalid_activities(options = {})
return unless customer_filter
logr = options[:logger] || logger
logr.info "ActivityType#cancel_invalid_activities for Activity Type id (#{id}/#{task_type}), looking for activities scheduled on customer not matching filter #{customer_filter}"
counter = 0
error_msg = []
invalid_activities(options).find_each do |activity|
logr.info "Invalidating activity id #{activity.id}"
if invalidate_activity(activity, options)
counter += 1
else
err_msg = "Activity id #{activity.id} #{activity.errors_to_s}"
logr.error err_msg
error_msg << err_msg
end
end
msg = "Cancelled invalid activities completed, cancelled: #{counter} activities"
logr.info msg
msg += ", errors: \n#{error_msg.join(",\n")}" if error_msg.present?
msg
end
|
84
|
# File 'app/models/activity_type.rb', line 84
belongs_to :customer_filter, optional: true
|
#deep_dup ⇒ Object
67
68
69
70
71
|
# File 'app/models/activity_type.rb', line 67
def deep_dup
deep_clone(include: %i[activity_chain_types activity_type_assignment_queues]) do |original, copy|
copy.task_type = "#{original.task_type}_COPY" if copy.is_a?(ActivityType)
end
end
|
#default_assignee ⇒ Employee
81
|
# File 'app/models/activity_type.rb', line 81
belongs_to :default_assignee, class_name: 'Employee', optional: true
|
#determine_assigned_resource(party, cur_user_id = nil, target_date = nil, resource = nil, options = {}) ⇒ Object
203
204
205
206
207
208
|
# File 'app/models/activity_type.rb', line 203
def determine_assigned_resource(party, cur_user_id = nil, target_date = nil, resource = nil, options = {})
rep = nil
rep_id = determine_assigned_resource_id(party, cur_user_id, target_date, resource, options)
rep = Employee.find(rep_id) if rep_id
rep
end
|
#determine_assigned_resource_id(party, cur_user_id = nil, target_date = nil, resource = nil, options = {}) ⇒ Object
For a given customer (which is handled by a specific wy company) this method will determine
the resource to assign to the activity
party : the customer object, contact, or supplier
cur_user_id : the current user
target_date : the intended target date for the activity, this is used to determine the individual resource when a
group type assignment is desired and we need to determine the least busy agent.
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
# File 'app/models/activity_type.rb', line 226
def determine_assigned_resource_id(party, cur_user_id = nil, target_date = nil, resource = nil, options = {})
assigned_resource_id = nil
company_id = party&.determine_company_id || Company::USA
customer = party&.customer
begin
if (ataq = activity_type_assignment_queues.find { |ataq| ataq.company_id == company_id })
assigned_resource_id = ataq.get_first_resource(customer, cur_user_id, target_date, priority, nil, resource, options)
end
rescue AssignmentQueue::UnassignableActivity
logger.error "Could not determine an assignable rep for activity type #{id} on party_id #{party.id}"
end
assigned_resource_id ||= cur_user_id
assigned_resource_id
end
|
83
|
# File 'app/models/activity_type.rb', line 83
belongs_to :email_template, optional: true
|
#email_template_description ⇒ Object
328
329
330
331
332
333
334
335
|
# File 'app/models/activity_type.rb', line 328
def email_template_description
s = []
s << email_template.description
s << "[#{email_template.category}]" if email_template.category.present?
s << "+#{email_defer_days}d" if email_defer_days.present?
s << "@#{email_defer_tod.strftime('%I:%M %p')}" if email_defer_tod.present?
s.join(' ')
end
|
#email_transmit_at_time ⇒ Object
Calculates the date/time when the creation email for this activity
should be transmitted. It will transmit immediately by default. If the
activity type has configured email deferral rules, it will apply those
by adding a number of days or setting the time of day to transmit.
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
|
# File 'app/models/activity_type.rb', line 341
def email_transmit_at_time
return unless email_defer_days&.positive? || email_defer_tod.present?
transmit_at = Time.current
if email_defer_days&.positive?
transmit_at += email_defer_days.days
end
if email_defer_tod
transmit_at = email_defer_tod.on(transmit_at)
transmit_at += 1.day if transmit_at < Time.current
end
transmit_at
end
|
#invalid_activities(options = {}) ⇒ Object
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
# File 'app/models/activity_type.rb', line 299
def invalid_activities(options = {})
res = Activity.none
return res unless customer_filter
logger.info "ActivityType#cancel_invalid_activities : Hunting for customers with a filter that does not match #{customer_filter}"
invalid_customer_ids = []
customers = Customer.joins(:linked_activities).merge(activities.open_activities)
customers = customers.limit(options[:batch_size]) if options[:batch_size].present?
customers.find_each do |customer|
invalid_customer_ids << customer.id unless valid_for_party?(customer)
end
invalid_customer_ids = invalid_customer_ids.compact.uniq
res = activities.open_activities.where(customer_id: invalid_customer_ids).select('activities.*') if invalid_customer_ids.present?
res
end
|
#invalidate_activity(a, _options = {}) ⇒ Object
286
287
288
289
290
291
292
293
294
295
296
297
|
# File 'app/models/activity_type.rb', line 286
def invalidate_activity(a, _options = {})
a.new_note = 'Cancelled after customer state change no longer meets criteria established for this activity type.'
a.activity_result_type_id = ActivityResultTypeConstants::CANCEL
a.completion_datetime = Time.current
res = a.save
if res
logger.info(" * cancelled activity id #{a.id}")
else
logger.error(" * could not cancel activity id #{a.id}")
end
res
end
|
#is_a_quote_follow_up? ⇒ Boolean
195
196
197
|
# File 'app/models/activity_type.rb', line 195
def is_a_quote_follow_up?
ActivityTypeConstants::QUOFUS_IDS.include?(id)
end
|
#is_email? ⇒ Boolean
199
200
201
|
# File 'app/models/activity_type.rb', line 199
def is_email?
task_type.match?(/^EMAIL/)
end
|
#name ⇒ Object
251
252
253
|
# File 'app/models/activity_type.rb', line 251
def name
"#{task_type} - #{description}"
end
|
#priority_friendly_name ⇒ Object
255
256
257
|
# File 'app/models/activity_type.rb', line 255
def priority_friendly_name
self.class.priority_friendly_name(priority)
end
|
#priority_tier? ⇒ Boolean
191
192
193
|
# File 'app/models/activity_type.rb', line 191
def priority_tier?
priority && priority <= PRIORITY_MAX
end
|
#result_options_for_select ⇒ Object
210
211
212
213
214
215
216
217
218
|
# File 'app/models/activity_type.rb', line 210
def result_options_for_select
chains = activity_chain_types.includes(:activity_result_type, :email_template)
chains.map do |c|
display = c.activity_result_type.result_code.to_s
display += " [Email: #{c.email_template.description}]" if c.email_template
[display, c.activity_result_type_id]
end.uniq
end
|
#roles ⇒ ActiveRecord::Relation<Role>
93
|
# File 'app/models/activity_type.rb', line 93
has_and_belongs_to_many :roles
|
#sales_activity ⇒ Object
183
184
185
|
# File 'app/models/activity_type.rb', line 183
def sales_activity
has_tag?('sale')
end
|
82
|
# File 'app/models/activity_type.rb', line 82
belongs_to :sender_party, class_name: 'Employee', optional: true
|
#to_s ⇒ Object
179
180
181
|
# File 'app/models/activity_type.rb', line 179
def to_s
"#{task_type} [#{id}]"
end
|
#valid_for_party?(party) ⇒ Boolean
315
316
317
318
319
320
321
322
|
# File 'app/models/activity_type.rb', line 315
def valid_for_party?(party)
return true unless party
return true unless customer_filter
return true unless (customer = party.try(:customer))
return true unless customer.is_a?(Customer)
customer_filter.applies_to_customer?(customer)
end
|