Class: Activity
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Activity
- Includes:
- ActionView::Helpers::TextHelper, Models::Auditable, Models::Embeddable, PgSearch::Model
- Defined in:
- app/models/activity.rb
Overview
== Schema Information
Table name: activities
Database name: primary
id :integer not null, primary key
completion_datetime :datetime
description :string(255)
lock_target_datetime :boolean default(FALSE)
notes :text
original_target_datetime :datetime
resource_type :string(255)
start_datetime :datetime
target_datetime :datetime
uploads_count :integer default(0)
created_at :datetime
updated_at :datetime
activity_result_type_id :integer
activity_type_id :integer
assigned_resource_id :integer
call_record_id :integer
campaign_id :integer
closed_by_id :integer
communication_id :integer
creator_id :integer
customer_id :integer
opportunity_id :integer
original_assigned_resource_id :integer
parent_activity_id :integer
party_id :integer
resource_id :integer
updater_id :integer
visit_id :integer
Indexes
by_act_type_w (activity_type_id) WHERE (activity_result_type_id IS NULL)
by_type_and_assi_resrc_w (activity_type_id,assigned_resource_id) WHERE (activity_result_type_id IS NULL)
index_activities_on_activity_result_type_id (activity_result_type_id)
index_activities_on_activity_type_id (activity_type_id)
index_activities_on_assigned_resource_id (assigned_resource_id)
index_activities_on_call_record_id (call_record_id)
index_activities_on_campaign_id (campaign_id)
index_activities_on_closed_by_id (closed_by_id)
index_activities_on_communication_id (communication_id)
index_activities_on_creator_id (creator_id)
index_activities_on_customer_id (customer_id)
index_activities_on_opportunity_id (opportunity_id)
index_activities_on_party_id (party_id)
index_activities_on_resource_type_and_resource_id (resource_type,resource_id) WHERE ((resource_type IS NOT NULL) AND (resource_id IS NOT NULL))
index_activities_on_target_datetime (target_datetime) USING brin
index_activities_on_updater_id (updater_id)
index_activities_on_visit_id (visit_id)
index_activities_resource_id (resource_id)
Foreign Keys
activities_activity_result_type_id_fkey (activity_result_type_id => activity_result_types.id)
activities_activity_type_id_fkey (activity_type_id => activity_types.id)
activities_communication_id_fk (communication_id => communications.id) ON DELETE => nullify
activities_creator_id_fk (creator_id => parties.id) ON DELETE => nullify
activities_party_id_fk (party_id => parties.id) ON DELETE => cascade
activities_updater_id_fk (updater_id => parties.id) ON DELETE => nullify
fk_rails_... (call_record_id => call_records.id) ON DELETE => nullify
fk_rails_... (customer_id => parties.id)
fk_rails_... (opportunity_id => opportunities.id) ON DELETE => nullify ON UPDATE => cascade
fk_rails_... (visit_id => visits.id)
Defined Under Namespace
Classes: AssignmentNotificationHandler, AutoChainCloser, ChainRunner, ChainRunnerHandler, CompactNotes, EmailNotificationHandler, ExpiredActivityCloser, OpenActivitiesStamper, Prioritizer, ResourceList, SalesActivityHandler, SynchronousEffectsHandler, TypeRulesCreatedHandler, TypeRulesUpdatedHandler, VoicemailReadHandler
Constant Summary collapse
- NOTE_RESULT_ID =
Note result id.
2- NATURAL_ORDER =
Natural order.
'activities.activity_result_type_id IS NULL DESC, COALESCE(activities.completion_datetime,activities.target_datetime) DESC'- RESOURCE_TYPES =
Recognised resource types.
%w[Delivery Opportunity Order SupportCase Party SpiffEnrollment Receipt CreditMemo SupportCaseParticipant StatementOfAccount Rma Invoice RoomConfiguration ExportedCatalogItemPacket LocatorRecord CreditApplication CampaignDelivery PurchaseOrder Payment Quote SchedulerBooking].freeze
- FINAL_SERVICES =
Final services.
[ActivityTypeConstants::ONSITESERVICE, ActivityTypeConstants::SSI_INSTALL, ActivityTypeConstants::SGS_ONSITESUPPORT, ActivityTypeConstants::SGS_REMOTESUPPORT, ActivityTypeConstants::SSFIX_ONSITE_SERVICE].freeze
- INITIAL_SERVICES =
Initial services.
[ActivityTypeConstants::SERVICECONFIRM, ActivityTypeConstants::SSI_PREPLAN_MEET, ActivityTypeConstants::SGS_ONSITE_PREPLAN_MEET, ActivityTypeConstants::SGS_REMOTE_PREPLAN_MEET, ActivityTypeConstants::SSFIX_SERVICE_CONFIRM].freeze
- MIN_EMBEDDABLE_NOTES_LENGTH =
Minimum embeddable notes length.
50
Constants included from Models::Embeddable
Models::Embeddable::MAX_CONTENT_LENGTH
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
-
#assignment_resource_ids ⇒ Object
Returns the value of attribute assignment_resource_ids.
-
#chained_activity_result ⇒ Object
Returns the value of attribute chained_activity_result.
-
#fallback_employee_id ⇒ Object
Returns the value of attribute fallback_employee_id.
-
#halt_chain ⇒ Object
Returns the value of attribute halt_chain.
-
#linked_party_ids ⇒ Object
Returns the value of attribute linked_party_ids.
-
#mileage ⇒ Object
Returns the value of attribute mileage.
-
#new_target_date ⇒ Object
Returns the value of attribute new_target_date.
-
#new_target_time ⇒ Object
Returns the value of attribute new_target_time.
-
#service_date ⇒ Object
Returns the value of attribute service_date.
-
#service_duration ⇒ Object
Returns the value of attribute service_duration.
-
#service_time ⇒ Object
Returns the value of attribute service_time.
-
#skip_callbacks ⇒ Object
Returns the value of attribute skip_callbacks.
-
#skip_check_for_open_sales_activity ⇒ Object
Returns the value of attribute skip_check_for_open_sales_activity.
-
#skip_check_for_valid_party ⇒ Object
Returns the value of attribute skip_check_for_valid_party.
-
#support_case_closed_reason ⇒ Object
Returns the value of attribute support_case_closed_reason.
-
#support_case_event ⇒ Object
Returns the value of attribute support_case_event.
-
#travel_time ⇒ Object
Returns the value of attribute travel_time.
-
#updated_activities ⇒ Object
Returns the value of attribute updated_activities.
Belongs to collapse
- #activity_result_type ⇒ ActivityResultType
- #activity_type ⇒ ActivityType
- #assigned_resource ⇒ Employee
- #call_record ⇒ CallRecord
- #campaign ⇒ Campaign
- #closed_by ⇒ Party
- #communication ⇒ Communication
- #customer ⇒ Customer
- #opportunity ⇒ Opportunity
- #original_assigned_resource ⇒ Employee
- #parent_activity ⇒ Activity
- #party ⇒ Party
- #resource ⇒ Resource
- #resource_opportunity ⇒ Opportunity
- #resource_order ⇒ Order
- #resource_quote ⇒ Quote
- #resource_room_configuration ⇒ RoomConfiguration
- #resource_scheduler_booking ⇒ SchedulerBooking
-
#resource_support_case ⇒ SupportCase
Type-specific resource associations for eager loading (polymorphic can't be preloaded).
- #visit ⇒ Visit
Methods included from Models::Auditable
Has many collapse
- #child_activities ⇒ ActiveRecord::Relation<Activity>
-
#historical_open_activities ⇒ ActiveRecord::Relation<HistoricalOpenActivity>
Track each time the activity was left open at end of day.
- #mail_activities ⇒ ActiveRecord::Relation<MailActivity>
- #triggered_communications ⇒ ActiveRecord::Relation<Communication>
- #uploads ⇒ ActiveRecord::Relation<Upload>
Methods included from Models::Embeddable
Has and belongs to many collapse
Delegated Instance Attributes collapse
-
#cancelled? ⇒ Object
Alias for Activity_result_type#cancelled?.
-
#complete? ⇒ Object
Alias for Activity_result_type#complete?.
-
#is_email? ⇒ Object
Alias for Activity_type#is_email?.
-
#result_code ⇒ Object
(also: #activity_result_code)
Alias for Activity_result_type#result_code.
Class Method Summary collapse
- .all_activity_filters ⇒ Object
-
.completed ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are completed.
-
.completion_order ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are completion order.
-
.embeddable_content_types ⇒ Object
-- Embeddable interface ---------------------------------------------------.
-
.final_service_completed ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are final service completed.
-
.for_customer_and_contacts ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are for customer and contacts.
- .heatwave_assistant_id ⇒ Object
-
.high_priority ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are high priority.
-
.inbound_emails ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are inbound emails.
-
.initial_service_completed ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are initial service completed.
-
.iqoppfu ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are iqoppfu.
-
.leads ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are leads.
- .mcp_searchable? ⇒ Boolean
-
.meeting ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are meeting.
-
.natural_order ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are natural order.
- .non_cob_time(datetime) ⇒ Object
-
.non_notes ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are non notes.
-
.not_tagged_with ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are not tagged with.
-
.notes_only ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are notes only.
-
.open_activities ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are open activities.
-
.overdue_activities ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are overdue activities.
- .position_of_activity(activity_id, relation) ⇒ Object
-
.preloaded ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are preloaded.
-
.quofu ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are quofu.
- .ransackable_scopes(_auth_object = nil) ⇒ Object
-
.recency_order ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are recency order.
- .resource_types ⇒ Object
-
.sales_activities ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are sales activities.
-
.tagged_with ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are tagged with.
-
.training ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are training.
-
.visible_by_default ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are visible by default.
-
.with_activity_uploads_count ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are with activity uploads count.
-
.with_customer_as_c ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are with customer as c.
Instance Method Summary collapse
- #activity_type_for_select ⇒ Object
- #age_in_days ⇒ Object
- #auto_assign(allocate_on = nil, current_user = nil, options = {}) ⇒ Object
- #auto_assign_and_schedule(ideal_target_date = nil, options = {}) ⇒ Object
-
#auto_close_if_applicable(auto_save: true) ⇒ Object
Our activity chain might have special rules, such as an auto close result when the due date is reached, useful for triggering drip email chains.
-
#best_resource(current_user = nil, options = {}) ⇒ Object
current_user: a value to use as the currently logged in user.
- #best_resource_employee(current_user = nil, options = {}) ⇒ Object
- #campaign_options_for_select ⇒ Object
- #cancel(options = {}) ⇒ Object
- #closed? ⇒ Boolean
- #compact_notes ⇒ Object
- #complete(options = {}) ⇒ Object
- #contact_options_for_select ⇒ Object
- #content_for_embedding(_content_type = :primary) ⇒ Object
- #default_resource_for_select ⇒ Object
- #description ⇒ Object
- #display_date ⇒ Object
- #display_type ⇒ Object
- #effective_date ⇒ Object
- #effective_origin_date ⇒ Object
- #embedding_content_changed? ⇒ Boolean
- #has_time? ⇒ Boolean
- #is_note? ⇒ Boolean
- #is_onsite_service? ⇒ Boolean
- #is_service_confirm? ⇒ Boolean
- #is_service_confirm_completed? ⇒ Boolean
- #is_smartservice_related? ⇒ Boolean
- #lock ⇒ Object
- #new_note ⇒ Object
- #new_note=(n) ⇒ Object
- #open? ⇒ Boolean
- #overdue? ⇒ Boolean
- #party_name ⇒ Object
-
#preloaded ⇒ ActiveRecord::Relation
Eager-loads all associations required to render activity cards without N+1 queries.
- #primary_address_id ⇒ Object
-
#resource_combo=(val) ⇒ Object
Backwards-compat: cached browser forms may still submit the old "ClassName|id" format.
- #resource_gid ⇒ Object
- #resource_gid=(gid_string) ⇒ Object
- #result_options_for_select ⇒ Object
- #return_to ⇒ Object
- #sales_activity? ⇒ Boolean
- #sender_for_email_templates ⇒ Object
-
#sender_party ⇒ Object
For emails, who is the sender?.
- #set_assigned_rep ⇒ Object
- #set_campaign ⇒ Object
- #set_linked_parties ⇒ Object
- #target_date ⇒ Object
- #target_datetime_outside_business_hours? ⇒ Boolean
- #target_time ⇒ Object
- #to_s ⇒ Object (also: #name)
- #unlock ⇒ Object
Methods included from Models::Embeddable
#embeddable_locales, #embedding_content_hash, embedding_partition_class, #embedding_stale?, #embedding_type_name, #embedding_vector, #find_content_embedding, #find_similar, #generate_all_embeddings!, #generate_chunked_embeddings!, #generate_embedding!, #has_embedding?, #locale_for_embedding, #needs_chunking?, regenerate_all_embeddings, semantic_search
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#assignment_resource_ids ⇒ Object
Returns the value of attribute assignment_resource_ids.
269 270 271 |
# File 'app/models/activity.rb', line 269 def assignment_resource_ids @assignment_resource_ids end |
#chained_activity_result ⇒ Object
Returns the value of attribute chained_activity_result.
269 270 271 |
# File 'app/models/activity.rb', line 269 def chained_activity_result @chained_activity_result end |
#fallback_employee_id ⇒ Object
Returns the value of attribute fallback_employee_id.
269 270 271 |
# File 'app/models/activity.rb', line 269 def fallback_employee_id @fallback_employee_id end |
#halt_chain ⇒ Object
Returns the value of attribute halt_chain.
269 270 271 |
# File 'app/models/activity.rb', line 269 def halt_chain @halt_chain end |
#linked_party_ids ⇒ Object
Returns the value of attribute linked_party_ids.
269 270 271 |
# File 'app/models/activity.rb', line 269 def linked_party_ids @linked_party_ids end |
#mileage ⇒ Object
Returns the value of attribute mileage.
269 270 271 |
# File 'app/models/activity.rb', line 269 def mileage @mileage end |
#new_target_date ⇒ Object
Returns the value of attribute new_target_date.
269 270 271 |
# File 'app/models/activity.rb', line 269 def new_target_date @new_target_date end |
#new_target_time ⇒ Object
Returns the value of attribute new_target_time.
269 270 271 |
# File 'app/models/activity.rb', line 269 def new_target_time @new_target_time end |
#service_date ⇒ Object
Returns the value of attribute service_date.
269 270 271 |
# File 'app/models/activity.rb', line 269 def service_date @service_date end |
#service_duration ⇒ Object
Returns the value of attribute service_duration.
269 270 271 |
# File 'app/models/activity.rb', line 269 def service_duration @service_duration end |
#service_time ⇒ Object
Returns the value of attribute service_time.
269 270 271 |
# File 'app/models/activity.rb', line 269 def service_time @service_time end |
#skip_callbacks ⇒ Object
Returns the value of attribute skip_callbacks.
269 270 271 |
# File 'app/models/activity.rb', line 269 def skip_callbacks @skip_callbacks end |
#skip_check_for_open_sales_activity ⇒ Object
Returns the value of attribute skip_check_for_open_sales_activity.
269 270 271 |
# File 'app/models/activity.rb', line 269 def skip_check_for_open_sales_activity @skip_check_for_open_sales_activity end |
#skip_check_for_valid_party ⇒ Object
Returns the value of attribute skip_check_for_valid_party.
269 270 271 |
# File 'app/models/activity.rb', line 269 def skip_check_for_valid_party @skip_check_for_valid_party end |
#support_case_closed_reason ⇒ Object
Returns the value of attribute support_case_closed_reason.
269 270 271 |
# File 'app/models/activity.rb', line 269 def support_case_closed_reason @support_case_closed_reason end |
#support_case_event ⇒ Object
Returns the value of attribute support_case_event.
269 270 271 |
# File 'app/models/activity.rb', line 269 def support_case_event @support_case_event end |
#travel_time ⇒ Object
Returns the value of attribute travel_time.
269 270 271 |
# File 'app/models/activity.rb', line 269 def travel_time @travel_time end |
#updated_activities ⇒ Object
Returns the value of attribute updated_activities.
269 270 271 |
# File 'app/models/activity.rb', line 269 def updated_activities @updated_activities end |
Class Method Details
.all_activity_filters ⇒ Object
517 518 519 |
# File 'app/models/activity.rb', line 517 def self.all_activity_filters %w[Party Contact Opportunity] end |
.completed ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are completed. Active Record Scope
124 |
# File 'app/models/activity.rb', line 124 scope :completed, -> { joins(:activity_result_type).merge(ActivityResultType.completed) } |
.completion_order ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are completion order. Active Record Scope
129 |
# File 'app/models/activity.rb', line 129 scope :completion_order, -> { order('activities.completion_datetime desc') } |
.embeddable_content_types ⇒ Object
-- Embeddable interface ---------------------------------------------------
566 567 568 |
# File 'app/models/activity.rb', line 566 def self. [:primary] end |
.final_service_completed ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are final service completed. Active Record Scope
192 |
# File 'app/models/activity.rb', line 192 scope :final_service_completed, -> { where(activity_type_id: FINAL_SERVICES, activity_result_type_id: ActivityResultTypeConstants::CMP) } |
.for_customer_and_contacts ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are for customer and contacts. Active Record Scope
170 |
# File 'app/models/activity.rb', line 170 scope :for_customer_and_contacts, ->(customer) { where(party_id: customer.self_and_contacts_party_ids_arr) } |
.heatwave_assistant_id ⇒ Object
626 627 628 |
# File 'app/models/activity.rb', line 626 def self.heatwave_assistant_id Employee.joins(:contact_points).merge(ContactPoint.emails).where(ContactPoint[:detail].eq('hwav@warmlyyours.com')).pick(:id) end |
.high_priority ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are high priority. Active Record Scope
127 |
# File 'app/models/activity.rb', line 127 scope :high_priority, -> { joins(:activity_type).where(activity_types: { priority: 1 }) } |
.inbound_emails ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are inbound emails. Active Record Scope
190 |
# File 'app/models/activity.rb', line 190 scope :inbound_emails, -> { where(activity_type_id: ActivityTypeConstants::EMAILIN_TYPES) } |
.initial_service_completed ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are initial service completed. Active Record Scope
191 |
# File 'app/models/activity.rb', line 191 scope :initial_service_completed, -> { where(activity_type_id: INITIAL_SERVICES, activity_result_type_id: ActivityResultTypeConstants::CMP) } |
.iqoppfu ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are iqoppfu. Active Record Scope
122 |
# File 'app/models/activity.rb', line 122 scope :iqoppfu, -> { where(activity_type_id: ActivityTypeConstants::IQOPPFUS_IDS) } |
.leads ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are leads. Active Record Scope
123 |
# File 'app/models/activity.rb', line 123 scope :leads, -> { where(activity_type_id: ActivityTypeConstants::LEAD_FORM) } |
.mcp_searchable? ⇒ Boolean
570 571 572 |
# File 'app/models/activity.rb', line 570 def self.mcp_searchable? false end |
.meeting ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are meeting. Active Record Scope
137 |
# File 'app/models/activity.rb', line 137 scope :meeting, -> { joins(:activity_type).merge(ActivityType.meeting) } |
.natural_order ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are natural order. Active Record Scope
128 |
# File 'app/models/activity.rb', line 128 scope :natural_order, -> { order(Arel.sql(NATURAL_ORDER)) } |
.non_cob_time(datetime) ⇒ Object
602 603 604 605 606 607 608 609 |
# File 'app/models/activity.rb', line 602 def self.non_cob_time(datetime) return unless datetime closing_time = WorkingHours.advance_to_closing_time(datetime) return unless datetime != closing_time && (datetime.min != 0) datetime.strftime('%I:%M %p') end |
.non_notes ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are non notes. Active Record Scope
120 |
# File 'app/models/activity.rb', line 120 scope :non_notes, -> { where.not(activity_type_id: nil) } |
.not_tagged_with ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are not tagged with. Active Record Scope
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'app/models/activity.rb', line 172 scope :not_tagged_with, ->(*) { = [].flatten.filter_map(&:presence).uniq.map(&:downcase) return all if .empty? # Exclude activities whose activity_type has ANY of the specified tags # Activity types without the tags OR activities without an activity type are included tagged_activity_type_ids = ActivityType.joins(:tag_records) .where('LOWER(tags.name) IN (?)', ) .distinct .ids if tagged_activity_type_ids.any? where('activities.activity_type_id IS NULL OR activities.activity_type_id NOT IN (?)', tagged_activity_type_ids) else all end } |
.notes_only ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are notes only. Active Record Scope
119 |
# File 'app/models/activity.rb', line 119 scope :notes_only, -> { where(activity_type_id: nil) } |
.open_activities ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are open activities. Active Record Scope
125 |
# File 'app/models/activity.rb', line 125 scope :open_activities, -> { where(activity_result_type_id: nil).non_notes } |
.overdue_activities ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are overdue activities. Active Record Scope
126 |
# File 'app/models/activity.rb', line 126 scope :overdue_activities, -> { open_activities.where(Activity[:target_datetime].lteq(Time.current)) } |
.position_of_activity(activity_id, relation) ⇒ Object
309 310 311 |
# File 'app/models/activity.rb', line 309 def self.position_of_activity(activity_id, relation) relation.order(relation.values[:order] || :id).ids.index(activity_id).try(:+, 1) end |
.preloaded ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are preloaded. Active Record Scope
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'app/models/activity.rb', line 141 scope :preloaded, -> { includes( :party, :activity_result_type, :campaign, :call_record, :creator, :updater, :uploads, { activity_type: :tag_records }, { assigned_resource: :profile_image }, { closed_by: :profile_image }, { communication: :uploads }, # parent_activity (with its activity_type) is rendered in the metadata # footer of the selected activity's form (_activity_form.html.erb). { parent_activity: :activity_type }, # Polymorphic resource — Rails groups by resource_type and runs one # query per type. Covers SupportCase / Opportunity / Order / Quote / # RoomConfiguration / SchedulerBooking *and* Invoice / Delivery / Rma / # CreditApplication / PurchaseOrder / CreditMemo / LocatorRecord / # SpiffEnrollment which were previously N+1. :resource ) } |
.quofu ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are quofu. Active Record Scope
121 |
# File 'app/models/activity.rb', line 121 scope :quofu, -> { where(activity_type_id: ActivityTypeConstants::QUOFUS_IDS) } |
.ransackable_scopes(_auth_object = nil) ⇒ Object
301 302 303 |
# File 'app/models/activity.rb', line 301 def self.ransackable_scopes(_auth_object = nil) %i[tagged_with not_tagged_with] end |
.recency_order ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are recency order. Active Record Scope
134 135 |
# File 'app/models/activity.rb', line 134 scope :recency_order, -> { order(Arel.sql('COALESCE(activities.completion_datetime, activities.target_datetime) DESC NULLS LAST')) } |
.resource_types ⇒ Object
305 306 307 |
# File 'app/models/activity.rb', line 305 def self.resource_types RESOURCE_TYPES end |
.sales_activities ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are sales activities. Active Record Scope
138 |
# File 'app/models/activity.rb', line 138 scope :sales_activities, -> { joins(:activity_type).merge(ActivityType.sales_activities) } |
.tagged_with ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are tagged with. Active Record Scope
171 |
# File 'app/models/activity.rb', line 171 scope :tagged_with, ->(*) { joins(:activity_type).merge(ActivityType.tagged_with()) } |
.training ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are training. Active Record Scope
136 |
# File 'app/models/activity.rb', line 136 scope :training, -> { joins(:activity_type).merge(ActivityType.training) } |
.visible_by_default ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are visible by default. Active Record Scope
189 |
# File 'app/models/activity.rb', line 189 scope :visible_by_default, -> { not_tagged_with(['Drip']) } |
.with_activity_uploads_count ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are with activity uploads count. Active Record Scope
169 |
# File 'app/models/activity.rb', line 169 scope :with_activity_uploads_count, -> { select("activities.*, (select count(u.id) from uploads u where u.resource_type = 'Activity' and u.resource_id = activities.id) as uploads_count") } |
.with_customer_as_c ⇒ ActiveRecord::Relation<Activity>
A relation of Activities that are with customer as c. Active Record Scope
165 166 167 168 |
# File 'app/models/activity.rb', line 165 scope :with_customer_as_c, -> { joins('inner join parties p on p.id = activities.party_id') .joins("left join parties c on ((p.type = 'Contact' and p.customer_id = c.id) or (p.type = 'Customer' and p.id = c.id))") } |
Instance Method Details
#activity_result_type ⇒ ActivityResultType
92 |
# File 'app/models/activity.rb', line 92 belongs_to :activity_result_type, inverse_of: :activities, optional: true |
#activity_type ⇒ ActivityType
78 |
# File 'app/models/activity.rb', line 78 belongs_to :activity_type, inverse_of: :activities, optional: true |
#activity_type_for_select ⇒ Object
357 358 359 |
# File 'app/models/activity.rb', line 357 def activity_type_for_select ActivityType.(party:, include_activity_type_id: activity_type_id) end |
#age_in_days ⇒ Object
313 314 315 316 |
# File 'app/models/activity.rb', line 313 def age_in_days end_date = closed? ? completion_datetime.to_date : Date.current (end_date - effective_origin_date).to_i end |
#assigned_resource ⇒ Employee
82 |
# File 'app/models/activity.rb', line 82 belongs_to :assigned_resource, class_name: 'Employee', optional: true |
#auto_assign(allocate_on = nil, current_user = nil, options = {}) ⇒ Object
459 460 461 462 463 464 465 |
# File 'app/models/activity.rb', line 459 def auto_assign(allocate_on = nil, current_user = nil, = {}) self.target_datetime ||= created_at # Set a default if we don't have one for an odd reason self.original_target_datetime ||= target_datetime self.target_datetime = allocate_on if allocate_on && !lock_target_datetime # if allocate on is passed and our activity is not time locked we use it self.original_assigned_resource ||= assigned_resource self.assigned_resource = best_resource_employee(current_user, ) end |
#auto_assign_and_schedule(ideal_target_date = nil, options = {}) ⇒ Object
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
# File 'app/models/activity.rb', line 430 def auto_assign_and_schedule(ideal_target_date = nil, = {}) # What is the best target date to schedule this activity? logger = [:logger] || Rails.logger original_scheduled_date = ideal_target_date || target_datetime allocate_on = original_scheduled_date return false unless allocate_on begin logger.debug "Processing activity #{id} with a target date of #{allocate_on}." # Pass the date processed to the calling block so special pre-loading can occur in case of batch reassignments # This is necessary so that as we advance the days we scoop them in our deck yield(allocate_on) if allocate_on.present? && block_given? auto_assign(allocate_on, ) # Provides a resource for that day success = false # Sensible default if assigned_resource.present? # Was a resource available and assigned on that day? save # Then save the record success = true # And mark the operation as a success allocate_on = nil # To break the loop, set allocate_on to nil elsif allocate_on > (original_scheduled_date + 1.month) # Try for one month, if we can't succeed at this point break we'll end up in a never ending loop allocate_on = nil # Breaks the loop logger.error ' * Could not find a suitable resource for activity after 30 days' else # No assigned resource and not past the 1 month limit, so move up one day and try again allocate_on += 1.day end logger.debug " ** assigned resource is #{assigned_resource.try(:full_name)} allocate on is now #{allocate_on}" end while allocate_on success end |
#auto_close_if_applicable(auto_save: true) ⇒ Object
Our activity chain might have special rules, such as an auto close result when the due date is reached, useful for triggering
drip email chains
469 470 471 472 473 474 475 476 477 478 |
# File 'app/models/activity.rb', line 469 def auto_close_if_applicable(auto_save: true) return :not_applicable if is_note? || closed? return :not_applicable unless (art = activity_type.auto_close_result_chain) return :not_overdue unless overdue? && art.due_date? self.activity_result_type = art.activity_result_type save! if auto_save :overdue_auto_close end |
#best_resource(current_user = nil, options = {}) ⇒ Object
current_user: a value to use as the currently logged in user
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
# File 'app/models/activity.rb', line 481 def best_resource(current_user = nil, = {}) return nil if is_note? current_user = nil unless current_user.is_a?(Employee) # Sensible default when operating in batch mode. current_user ||= self.original_assigned_resource current_user ||= creator if creator.is_a?(Employee) current_user ||= updater if updater.is_a?(Employee) at = activity_type if resource.instance_of?(SupportCase) && customer.nil? resource.assigned_to_id || at.activity_type_assignment_queues.first.try(:fallback_employee_id) || current_user elsif customer at.determine_assigned_resource_id(customer, current_user.try(:id), self.target_datetime, resource, ) end end |
#best_resource_employee(current_user = nil, options = {}) ⇒ Object
497 498 499 500 501 502 |
# File 'app/models/activity.rb', line 497 def best_resource_employee(current_user = nil, = {}) rep_id = best_resource(current_user, ) return Employee.find(rep_id) if rep_id nil end |
#call_record ⇒ CallRecord
97 |
# File 'app/models/activity.rb', line 97 belongs_to :call_record, optional: true |
#campaign ⇒ Campaign
94 |
# File 'app/models/activity.rb', line 94 belongs_to :campaign, optional: true |
#campaign_options_for_select ⇒ Object
382 383 384 385 386 387 388 389 |
# File 'app/models/activity.rb', line 382 def = [] if (customer = party.try(:customer) || resource.try(:customer)) = Campaign.joins(subscriber_lists: :subscribers).where(subscribers: { customer_id: customer.id }).pluck(:name, :id) << [campaign.name, campaign.id] if campaign end .compact.uniq end |
#cancel(options = {}) ⇒ Object
554 555 556 557 |
# File 'app/models/activity.rb', line 554 def cancel( = {}) opts = { activity_result_type_id: ActivityResultTypeConstants::CANCEL, completion_datetime: Time.current }.merge() update(opts) end |
#cancelled? ⇒ Object
Alias for Activity_result_type#cancelled?
209 |
# File 'app/models/activity.rb', line 209 delegate :complete?, :cancelled?, :result_code, to: :activity_result_type, allow_nil: true |
#child_activities ⇒ ActiveRecord::Relation<Activity>
100 |
# File 'app/models/activity.rb', line 100 has_many :child_activities, class_name: 'Activity', inverse_of: :parent_activity |
#closed? ⇒ Boolean
422 423 424 |
# File 'app/models/activity.rb', line 422 def closed? activity_type_id.nil? || activity_result_type_id.present? end |
#closed_by ⇒ Party
77 |
# File 'app/models/activity.rb', line 77 belongs_to :closed_by, class_name: 'Party', optional: true |
#communication ⇒ Communication
93 |
# File 'app/models/activity.rb', line 93 belongs_to :communication, optional: true |
#compact_notes ⇒ Object
559 560 561 562 |
# File 'app/models/activity.rb', line 559 def compact_notes d = notes || description d.gsub(/\[.*\]/, '').strip end |
#complete(options = {}) ⇒ Object
549 550 551 552 |
# File 'app/models/activity.rb', line 549 def complete( = {}) opts = { activity_result_type_id: ActivityResultTypeConstants::CMP, completion_datetime: Time.current }.merge() update(opts) end |
#complete? ⇒ Object
Alias for Activity_result_type#complete?
209 |
# File 'app/models/activity.rb', line 209 delegate :complete?, :cancelled?, :result_code, to: :activity_result_type, allow_nil: true |
#contact_options_for_select ⇒ Object
369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'app/models/activity.rb', line 369 def # Memoize these values to ensure the guard check and the builder call use the same values. # This prevents edge cases where association state changes between the check and the call # (e.g., during failed updates where party_id is cleared but not saved). p = party r = resource return [] unless p || r skip_persons = activity_type&.party_must_be_company? skip_organizations = activity_type&.party_must_be_contact? ContactPoint::AddressBookBuilder.(resource: r, party: p, skip_persons:, skip_organizations:) end |
#content_for_embedding(_content_type = :primary) ⇒ Object
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
# File 'app/models/activity.rb', line 577 def (_content_type = :primary) return nil if notes.blank? || notes.length < MIN_EMBEDDABLE_NOTES_LENGTH parts = [] parts << "Activity: #{activity_type&.task_type || 'Note'}" parts << "Tags: #{activity_type..join(', ')}" if activity_type&.&.any? parts << "Status: #{result_code || 'Open'}" parts << "Priority: #{activity_type.priority}" if activity_type&.priority.present? parts << "Party: #{party&.full_name}" if party parts << "Customer: #{customer&.full_name}" if customer && customer != party parts << "Assigned to: #{assigned_resource&.full_name}" if assigned_resource parts << "Date: #{effective_date.strftime('%B %d, %Y')}" if effective_date parts << "Due: #{target_datetime.strftime('%B %d, %Y')}" if target_datetime && open? parts << "Overdue" if overdue? parts << "Completed: #{completion_datetime.strftime('%B %d, %Y')}" if completion_datetime parts << "Resource: #{resource_type} ##{resource_id}" if resource_type.present? parts << "Campaign: #{campaign&.name}" if campaign parts << compact_notes parts.compact.join("\n\n") end |
#customer ⇒ Customer
80 |
# File 'app/models/activity.rb', line 80 belongs_to :customer, optional: true, inverse_of: :related_activities |
#default_resource_for_select ⇒ Object
658 659 660 661 662 663 |
# File 'app/models/activity.rb', line 658 def default_resource_for_select return [] unless resource formatter = Activity::ResourceList.build_formatter(resource) [[formatter.display, formatter.identifier]] end |
#description ⇒ Object
665 666 667 |
# File 'app/models/activity.rb', line 665 def description notes.try(:first, 500) || activity_type.try(:description) end |
#display_date ⇒ Object
521 522 523 |
# File 'app/models/activity.rb', line 521 def display_date effective_date.to_s(has_time? ? :crm_default : :crm_date_only) end |
#display_type ⇒ Object
426 427 428 |
# File 'app/models/activity.rb', line 426 def display_type activity_type&.task_type || 'Note' end |
#effective_date ⇒ Object
529 530 531 |
# File 'app/models/activity.rb', line 529 def effective_date completion_datetime || self.target_datetime || created_at end |
#effective_origin_date ⇒ Object
334 335 336 |
# File 'app/models/activity.rb', line 334 def effective_origin_date (original_target_datetime || target_datetime || created_at).to_date end |
#embedding_content_changed? ⇒ Boolean
598 599 600 |
# File 'app/models/activity.rb', line 598 def saved_change_to_notes? end |
#has_time? ⇒ Boolean
525 526 527 |
# File 'app/models/activity.rb', line 525 def has_time? effective_date != effective_date.beginning_of_day end |
#historical_open_activities ⇒ ActiveRecord::Relation<HistoricalOpenActivity>
Track each time the activity was left open at end of day
103 |
# File 'app/models/activity.rb', line 103 has_many :historical_open_activities |
#is_email? ⇒ Object
Alias for Activity_type#is_email?
208 |
# File 'app/models/activity.rb', line 208 delegate :is_email?, to: :activity_type, allow_nil: true |
#is_note? ⇒ Boolean
533 534 535 |
# File 'app/models/activity.rb', line 533 def is_note? activity_type_id.nil? end |
#is_onsite_service? ⇒ Boolean
541 542 543 |
# File 'app/models/activity.rb', line 541 def is_onsite_service? [ActivityTypeConstants::ONSITESERVICE, ActivityTypeConstants::SSI_INSTALL, ActivityTypeConstants::SSFIX_ONSITE_SERVICE, ActivityTypeConstants::SGS_ONSITESUPPORT].include?(activity_type_id) end |
#is_service_confirm? ⇒ Boolean
537 538 539 |
# File 'app/models/activity.rb', line 537 def is_service_confirm? [ActivityTypeConstants::SERVICECONFIRM, ActivityTypeConstants::SSI_PREPLAN_MEET, ActivityTypeConstants::SSFIX_SERVICE_CONFIRM].include?(activity_type_id) end |
#is_service_confirm_completed? ⇒ Boolean
767 768 769 770 771 772 773 |
# File 'app/models/activity.rb', line 767 def is_service_confirm_completed? true if activity_type_id.in?([ActivityTypeConstants::SERVICECONFIRM, ActivityTypeConstants::SSI_PREPLAN_MEET, ActivityTypeConstants::SGS_ONSITE_PREPLAN_MEET, ActivityTypeConstants::SGS_REMOTE_PREPLAN_MEET, ActivityTypeConstants::SSFIX_SERVICE_CONFIRM]) && (activity_result_type_id == ActivityResultTypeConstants::CMP) end |
#is_smartservice_related? ⇒ Boolean
754 755 756 757 758 759 760 761 762 763 764 765 |
# File 'app/models/activity.rb', line 754 def activity_type_id.in?([ActivityTypeConstants::SERVICECONFIRM, ActivityTypeConstants::ONSITESERVICE, ActivityTypeConstants::SSI_PREPLAN_MEET, ActivityTypeConstants::SSI_INSTALL, ActivityTypeConstants::SGS_ONSITE_PREPLAN_MEET, ActivityTypeConstants::SGS_REMOTE_PREPLAN_MEET, ActivityTypeConstants::SGS_ONSITESUPPORT, ActivityTypeConstants::SGS_REMOTESUPPORT, ActivityTypeConstants::SSFIX_ONSITE_SERVICE, ActivityTypeConstants::SSFIX_SERVICE_CONFIRM]) end |
#lock ⇒ Object
318 319 320 321 322 |
# File 'app/models/activity.rb', line 318 def lock self.skip_callbacks = true self.lock_target_datetime = true save end |
#mail_activities ⇒ ActiveRecord::Relation<MailActivity>
102 |
# File 'app/models/activity.rb', line 102 has_many :mail_activities |
#new_note ⇒ Object
412 413 414 |
# File 'app/models/activity.rb', line 412 def new_note '' end |
#new_note=(n) ⇒ Object
402 403 404 405 406 407 408 409 410 |
# File 'app/models/activity.rb', line 402 def new_note=(n) return if n.blank? date_stamp = [] date_stamp << Time.current.to_fs(:crm_default) date_stamp << CurrentScope.user&.show_name_4 if CurrentScope.user.respond_to?(:show_name_4) self.notes = "[#{date_stamp.compact.join(' ')}]\n#{n}\n#{notes}" self.description = n&.first(80) end |
#open? ⇒ Boolean
545 546 547 |
# File 'app/models/activity.rb', line 545 def open? activity_result_type.nil? end |
#opportunity ⇒ Opportunity
95 |
# File 'app/models/activity.rb', line 95 belongs_to :opportunity, inverse_of: :linked_activities, optional: true |
#original_assigned_resource ⇒ Employee
83 |
# File 'app/models/activity.rb', line 83 belongs_to :original_assigned_resource, class_name: 'Employee', optional: true |
#overdue? ⇒ Boolean
391 392 393 394 395 396 |
# File 'app/models/activity.rb', line 391 def overdue? return false if closed? return false if target_datetime.blank? (target_datetime < Time.current) end |
#parent_activity ⇒ Activity
81 |
# File 'app/models/activity.rb', line 81 belongs_to :parent_activity, class_name: 'Activity', inverse_of: :child_activities, optional: true |
#parties ⇒ ActiveRecord::Relation<Party>
105 |
# File 'app/models/activity.rb', line 105 has_and_belongs_to_many :parties |
#party_name ⇒ Object
418 419 420 |
# File 'app/models/activity.rb', line 418 def party_name party&.full_name end |
#preloaded ⇒ ActiveRecord::Relation
Eager-loads all associations required to render activity cards without N+1 queries.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'app/models/activity.rb', line 141 scope :preloaded, -> { includes( :party, :activity_result_type, :campaign, :call_record, :creator, :updater, :uploads, { activity_type: :tag_records }, { assigned_resource: :profile_image }, { closed_by: :profile_image }, { communication: :uploads }, # parent_activity (with its activity_type) is rendered in the metadata # footer of the selected activity's form (_activity_form.html.erb). { parent_activity: :activity_type }, # Polymorphic resource — Rails groups by resource_type and runs one # query per type. Covers SupportCase / Opportunity / Order / Quote / # RoomConfiguration / SchedulerBooking *and* Invoice / Delivery / Rma / # CreditApplication / PurchaseOrder / CreditMemo / LocatorRecord / # SpiffEnrollment which were previously N+1. :resource ) } |
#primary_address_id ⇒ Object
513 514 515 |
# File 'app/models/activity.rb', line 513 def primary_address_id customer.try(:mailing_address_id) || customer.try(:shipping_address_id) || customer.try(:billing_address_id) end |
#resource ⇒ Resource
84 |
# File 'app/models/activity.rb', line 84 belongs_to :resource, polymorphic: true, optional: true |
#resource_combo=(val) ⇒ Object
Backwards-compat: cached browser forms may still submit the old
"ClassName|id" format. Silently convert to GlobalID so
Activity.new(params[:activity]) doesn't blow up.
649 650 651 652 653 654 655 656 |
# File 'app/models/activity.rb', line 649 def resource_combo=(val) if val.present? class_name, rid = val.split("|", 2) self.resource_gid = URI::GID.build(app: GlobalID.app, model_name: class_name, model_id: rid.to_s).to_s else self.resource_gid = nil end end |
#resource_gid ⇒ Object
630 631 632 633 634 |
# File 'app/models/activity.rb', line 630 def resource_gid return unless resource_type.present? && resource_id.present? URI::GID.build(app: GlobalID.app, model_name: resource_type, model_id: resource_id.to_s).to_s end |
#resource_gid=(gid_string) ⇒ Object
636 637 638 639 640 641 642 643 644 |
# File 'app/models/activity.rb', line 636 def resource_gid=(gid_string) if gid_string.present? && (gid = GlobalID.parse(gid_string)) self.resource_type = gid.model_name self.resource_id = gid.model_id else self.resource_type = nil self.resource_id = nil end end |
#resource_opportunity ⇒ Opportunity
87 |
# File 'app/models/activity.rb', line 87 belongs_to :resource_opportunity, class_name: 'Opportunity', foreign_key: :resource_id, optional: true |
#resource_order ⇒ Order
88 |
# File 'app/models/activity.rb', line 88 belongs_to :resource_order, class_name: 'Order', foreign_key: :resource_id, optional: true |
#resource_quote ⇒ Quote
89 |
# File 'app/models/activity.rb', line 89 belongs_to :resource_quote, class_name: 'Quote', foreign_key: :resource_id, optional: true |
#resource_room_configuration ⇒ RoomConfiguration
90 |
# File 'app/models/activity.rb', line 90 belongs_to :resource_room_configuration, class_name: 'RoomConfiguration', foreign_key: :resource_id, optional: true |
#resource_scheduler_booking ⇒ SchedulerBooking
91 |
# File 'app/models/activity.rb', line 91 belongs_to :resource_scheduler_booking, class_name: 'SchedulerBooking', foreign_key: :resource_id, optional: true |
#resource_support_case ⇒ SupportCase
Type-specific resource associations for eager loading (polymorphic can't be preloaded)
86 |
# File 'app/models/activity.rb', line 86 belongs_to :resource_support_case, class_name: 'SupportCase', foreign_key: :resource_id, optional: true |
#result_code ⇒ Object Also known as: activity_result_code
Alias for Activity_result_type#result_code
209 |
# File 'app/models/activity.rb', line 209 delegate :complete?, :cancelled?, :result_code, to: :activity_result_type, allow_nil: true |
#result_options_for_select ⇒ Object
351 352 353 354 355 |
# File 'app/models/activity.rb', line 351 def return unless activity_type activity_type. end |
#return_to ⇒ Object
365 366 367 |
# File 'app/models/activity.rb', line 365 def return_to resource || party end |
#sales_activity? ⇒ Boolean
330 331 332 |
# File 'app/models/activity.rb', line 330 def sales_activity? activity_type.try(:sales_activity) end |
#sender_for_email_templates ⇒ Object
398 399 400 |
# File 'app/models/activity.rb', line 398 def sender_for_email_templates assigned_resource || updater || creator end |
#sender_party ⇒ Object
For emails, who is the sender?
612 613 614 615 616 617 618 619 620 621 622 623 624 |
# File 'app/models/activity.rb', line 612 def sender_party primary_rep = party&.customer&.primary_sales_rep sp = primary_rep if activity_type.sales_rep_as_sender sp ||= activity_type.sender_party sp ||= assigned_resource unless assigned_resource_id == self.class.heatwave_assistant_id sp ||= primary_rep = party.try(:primary_sales_rep) sp ||= creator if creator.is_a?(Employee) sp = nil if sp&.id == self.class.heatwave_assistant_id # just in case we never never allow the bot sp ||= Employee.find(105) # 'Julia Billen' raise StandardError, "Unable to determine sender_party for activity id #{id}" unless sp sp end |
#set_assigned_rep ⇒ Object
731 732 733 734 735 736 |
# File 'app/models/activity.rb', line 731 def set_assigned_rep return true if closed? self.assigned_resource ||= best_resource_employee self.original_assigned_resource ||= self.assigned_resource end |
#set_campaign ⇒ Object
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 |
# File 'app/models/activity.rb', line 738 def set_campaign use_campaign = campaign || activity_type&.campaign return unless use_campaign # customer can be determined? return unless (cust = customer) # add customer to campaign res = use_campaign.add_customer cust return unless res.subscribed? # assign this activity to that campaign self.campaign = use_campaign end |
#set_linked_parties ⇒ Object
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
# File 'app/models/activity.rb', line 669 def set_linked_parties pids = [party_id] # Initially we will use the linked party if linked_party_ids.present? # Array of additional party linked to us if linked_party_ids.is_a?(Array) pids += linked_party_ids elsif linked_party_ids.is_a?(String) pids += linked_party_ids.split(',') end end pids += resource.link_party_ids if resource.respond_to?(:link_party_ids) # Pull those from our resources pids = pids.compact.uniq.map(&:to_i) # Load up customer of contacts (compact to remove nil customer_ids) pids += Contact.where(id: pids).pluck(Arel.sql('distinct customer_id')).compact pids.uniq! # Drop party IDs that no longer exist (e.g. customer merge destroyed the party while a # resource still reports the old id via #link_party_ids — AppSignal #3373 / FK on activities_parties). valid_pids = Party.where(id: pids).ids if valid_pids.size < pids.size logger.warn( "Activity#set_linked_parties skipping missing party_ids=#{(pids - valid_pids).join(', ')} " \ "activity_id=#{persisted? ? id : 'new'}" ) end pids = valid_pids return if pids.blank? # For new records, use standard assignment - no race condition possible yet unless persisted? logger.info "Activity (new) linked party ids will become #{pids.join(', ')}" self.party_ids = pids return end # For existing records, only add party_ids that don't already exist to avoid # race conditions when multiple workers process the same record concurrently existing_pids = party_ids.to_a new_pids = pids - existing_pids return if new_pids.empty? logger.info "Activity #{id} linked party ids adding #{new_pids.join(', ')} (existing: #{existing_pids.join(', ')})" # Use upsert to avoid RecordNotUnique errors from concurrent workers # trying to add the same party-activity associations new_pids.each do |pid| self.class.lease_connection.execute( self.class.sanitize_sql_array([ 'INSERT INTO activities_parties (activity_id, party_id) VALUES (?, ?) ON CONFLICT (party_id, activity_id) DO NOTHING', id, pid ]) ) end # Reload the association to reflect the new state parties.reset rescue ActiveRecord::RecordNotUnique # Race condition - another process already created this record # This is expected when multiple workers process the same invoicing concurrently logger.info "Activity #{id} set_linked_parties encountered RecordNotUnique - records already exist" parties.reset end |
#target_date ⇒ Object
338 339 340 |
# File 'app/models/activity.rb', line 338 def target_date target_datetime.nil? ? nil : target_datetime.to_datetime.to_date.to_fs(:crm_default) end |
#target_datetime_outside_business_hours? ⇒ Boolean
775 776 777 778 779 780 781 |
# File 'app/models/activity.rb', line 775 def target_datetime_outside_business_hours? # The lack of a target datetime will imply we are outside business hours return true unless target_datetime # Because the closing time is exclusive, we need to subtract 1 second to do this check !(target_datetime - 1.second).in_working_hours? end |
#target_time ⇒ Object
342 343 344 345 346 347 348 349 |
# File 'app/models/activity.rb', line 342 def target_time return unless target_datetime # The following code causes time zone jumps based on the user # rounded = Time.at((target_datetime.to_time.to_i / 900.0).round * 900) # rounded_dt = target_datetime.is_a?(DateTime) ? rounded.to_datetime : rounded target_datetime.strftime('%I:%M %P') end |
#to_s ⇒ Object Also known as: name
504 505 506 507 508 509 510 |
# File 'app/models/activity.rb', line 504 def to_s [ target_datetime.try(:to_s).try(:crm_date_only), assigned_resource.try(:name), activity_type.try(:task_type) ].compact.join(' ') end |
#triggered_communications ⇒ ActiveRecord::Relation<Communication>
101 |
# File 'app/models/activity.rb', line 101 has_many :triggered_communications, class_name: 'Communication' |
#unlock ⇒ Object
324 325 326 327 328 |
# File 'app/models/activity.rb', line 324 def unlock self.skip_callbacks = true self.lock_target_datetime = false save end |
#uploads ⇒ ActiveRecord::Relation<Upload>
99 |
# File 'app/models/activity.rb', line 99 has_many :uploads, as: :resource, dependent: :destroy |