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 :integer default("party_unrestricted"), not null
priority :integer default(2)
resource_requirement :integer 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 :integer 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
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
#publish_event
Instance Attribute Details
#description ⇒ Object
92
|
# File 'app/models/activity_type.rb', line 92
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
#party_requirement ⇒ Object
92
|
# File 'app/models/activity_type.rb', line 92
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
#priority ⇒ Object
92
|
# File 'app/models/activity_type.rb', line 92
validates :task_type, :priority, :description, :party_requirement, :uniqueness, presence: true
|
#task_type ⇒ Object
90
|
# File 'app/models/activity_type.rb', line 90
validates :task_type, uniqueness: true
|
#uniqueness ⇒ Object
92
|
# File 'app/models/activity_type.rb', line 92
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
97
|
# File 'app/models/activity_type.rb', line 97
scope :active, -> { where(inactive: false) }
|
.condensed_options_for_select ⇒ Object
157
158
159
|
# File 'app/models/activity_type.rb', line 157
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
105
|
# File 'app/models/activity_type.rb', line 105
scope :email_activities, -> { where(ActivityType[:task_type].matches('EMAIL%')) }
|
.meeting ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are meeting. Active Record Scope
102
|
# File 'app/models/activity_type.rb', line 102
scope :meeting, -> { where(task_type: ActivityTypeConstants::MEETING_TYPES) }
|
.options_for_select(options = {}) ⇒ Object
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
# File 'app/models/activity_type.rb', line 121
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: [: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
238
239
240
241
242
243
244
245
|
# File 'app/models/activity_type.rb', line 238
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
141
142
143
|
# File 'app/models/activity_type.rb', line 141
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
153
154
155
|
# File 'app/models/activity_type.rb', line 153
def self.party_requirement_options_for_select
party_requirements.map { |k, _v| [k.humanize, k] }
end
|
.priority_friendly_name(i) ⇒ Object
165
166
167
168
169
|
# File 'app/models/activity_type.rb', line 165
def self.priority_friendly_name(i)
return 'Unprioritized' unless i
"Tier #{i} #{'(High Priority)' if i <= PRIORITY_MAX}"
end
|
.priority_select_options ⇒ Object
161
162
163
|
# File 'app/models/activity_type.rb', line 161
def self.priority_select_options
(1...6).to_a.map { |i| [priority_friendly_name(i), i] }
end
|
.ransackable_scopes(_auth_object = nil) ⇒ Object
117
118
119
|
# File 'app/models/activity_type.rb', line 117
def self.ransackable_scopes(_auth_object = nil)
%i[tagged_with not_tagged_with tags_include]
end
|
.resource_requirement_options_for_select ⇒ Object
149
150
151
|
# File 'app/models/activity_type.rb', line 149
def self.resource_requirement_options_for_select
resource_requirements.map { |k, _v| [k.humanize, k] }
end
|
.resource_type_for_select ⇒ Object
171
172
173
|
# File 'app/models/activity_type.rb', line 171
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
104
|
# File 'app/models/activity_type.rb', line 104
scope :sales_activities, -> { tagged_with('sale', 'sales_call') }
|
.sorted ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are sorted. Active Record Scope
98
|
# File 'app/models/activity_type.rb', line 98
scope :sorted, -> { order(:priority, :task_type) }
|
.training ⇒ ActiveRecord::Relation<ActivityType>
A relation of ActivityTypes that are training. Active Record Scope
101
|
# File 'app/models/activity_type.rb', line 101
scope :training, -> { where(task_type: ActivityTypeConstants::TRAINING_TYPES) }
|
.uniqueness_options_for_select ⇒ Object
145
146
147
|
# File 'app/models/activity_type.rb', line 145
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
100
|
# File 'app/models/activity_type.rb', line 100
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
99
|
# File 'app/models/activity_type.rb', line 99
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>
81
|
# File 'app/models/activity_type.rb', line 81
has_many :activities, dependent: :nullify, inverse_of: :activity_type
|
#activity_chain_types ⇒ ActiveRecord::Relation<ActivityChainType>
82
|
# File 'app/models/activity_type.rb', line 82
has_many :activity_chain_types, dependent: :destroy
|
#activity_chain_types_for_select ⇒ Object
183
184
185
|
# File 'app/models/activity_type.rb', line 183
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>
83
|
# File 'app/models/activity_type.rb', line 83
has_many :activity_result_types, through: :activity_chain_types
|
#activity_type_assignment_queues ⇒ ActiveRecord::Relation<ActivityTypeAssignmentQueue>
84
|
# File 'app/models/activity_type.rb', line 84
has_many :activity_type_assignment_queues, dependent: :destroy
|
#activity_type_rules ⇒ ActiveRecord::Relation<ActivityTypeRule>
86
|
# File 'app/models/activity_type.rb', line 86
has_many :activity_type_rules, dependent: :destroy
|
#assignment_queues ⇒ ActiveRecord::Relation<AssignmentQueue>
85
|
# File 'app/models/activity_type.rb', line 85
has_many :assignment_queues, through: :activity_type_assignment_queues
|
#auto_close_result_chain ⇒ Object
320
321
322
|
# File 'app/models/activity_type.rb', line 320
def auto_close_result_chain
activity_chain_types.detect { |act| !act.not_set? }
end
|
80
|
# File 'app/models/activity_type.rb', line 80
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
# File 'app/models/activity_type.rb', line 259
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
|
79
|
# File 'app/models/activity_type.rb', line 79
belongs_to :customer_filter, optional: true
|
#deep_dup ⇒ Object
64
65
66
67
68
|
# File 'app/models/activity_type.rb', line 64
def deep_dup
deep_clone(include: [: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
76
|
# File 'app/models/activity_type.rb', line 76
belongs_to :default_assignee, class_name: 'Employee', optional: true
|
#determine_assigned_resource(party, cur_user_id = nil, target_date = nil, resource = nil, options = {}) ⇒ Object
199
200
201
202
203
204
|
# File 'app/models/activity_type.rb', line 199
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.
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
# File 'app/models/activity_type.rb', line 222
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.detect { |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
|
78
|
# File 'app/models/activity_type.rb', line 78
belongs_to :email_template, optional: true
|
#email_template_description ⇒ Object
324
325
326
327
328
329
330
331
|
# File 'app/models/activity_type.rb', line 324
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.
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
# File 'app/models/activity_type.rb', line 337
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
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
# File 'app/models/activity_type.rb', line 295
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
282
283
284
285
286
287
288
289
290
291
292
293
|
# File 'app/models/activity_type.rb', line 282
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
191
192
193
|
# File 'app/models/activity_type.rb', line 191
def is_a_quote_follow_up?
ActivityTypeConstants::QUOFUS_IDS.include?(id)
end
|
#is_email? ⇒ Boolean
195
196
197
|
# File 'app/models/activity_type.rb', line 195
def is_email?
task_type.match?(/^EMAIL/)
end
|
#name ⇒ Object
247
248
249
|
# File 'app/models/activity_type.rb', line 247
def name
"#{task_type} - #{description}"
end
|
#priority_friendly_name ⇒ Object
251
252
253
|
# File 'app/models/activity_type.rb', line 251
def priority_friendly_name
self.class.priority_friendly_name(priority)
end
|
#priority_tier? ⇒ Boolean
187
188
189
|
# File 'app/models/activity_type.rb', line 187
def priority_tier?
priority && priority <= PRIORITY_MAX
end
|
#result_options_for_select ⇒ Object
206
207
208
209
210
211
212
213
214
|
# File 'app/models/activity_type.rb', line 206
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>
88
|
# File 'app/models/activity_type.rb', line 88
has_and_belongs_to_many :roles
|
#sales_activity ⇒ Object
179
180
181
|
# File 'app/models/activity_type.rb', line 179
def sales_activity
has_tag?('sale')
end
|
77
|
# File 'app/models/activity_type.rb', line 77
belongs_to :sender_party, class_name: 'Employee', optional: true
|
#to_s ⇒ Object
175
176
177
|
# File 'app/models/activity_type.rb', line 175
def to_s
"#{task_type} [#{id}]"
end
|
#valid_for_party?(party) ⇒ Boolean
311
312
313
314
315
316
317
318
|
# File 'app/models/activity_type.rb', line 311
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
|