Module: CustomerSalesMarketing

Extended by:
ActiveSupport::Concern
Included in:
Customer
Defined in:
app/models/concerns/customer_sales_marketing.rb

Overview

Campaigns, sources, visit attribution, Reviews.io, watch flags, sales reps, activities.

See Also:

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.rating_options_for_selectObject



164
165
166
167
168
169
170
171
# File 'app/models/concerns/customer_sales_marketing.rb', line 164

def rating_options_for_select
  [['Retained high potential account (1 call / 30 day)', 'A'],
   ['Retained (1 call / 45 day)', 'B'],
   ['Retained Transactional (1 call / 60 day)', 'C'],
   %w[Challenging D],
   %w[Uncommunicative E],
   ['No Potential', 'F']]
end

.rating_options_for_select_with_rankObject



173
174
175
# File 'app/models/concerns/customer_sales_marketing.rb', line 173

def rating_options_for_select_with_rank
  rating_options_for_select.map { |e| ["[#{e[1]}] #{e[0]}", e[1]] }
end

.watch_states_for_selectObject

:reek:UtilityFunction



177
178
179
# File 'app/models/concerns/customer_sales_marketing.rb', line 177

def watch_states_for_select # :reek:UtilityFunction
  Customer.watches.map { |key, _val| [Customer::WATCH_STATES[key], key] }
end

Instance Method Details

#active_sales_subscriptionsObject



20
21
22
23
24
25
# File 'app/models/concerns/customer_sales_marketing.rb', line 20

def active_sales_subscriptions
  emails = all_emails
  sql_cond = +'subscribers.customer_id = :customer_id'
  sql_cond << ' OR subscribers.email_address IN (:emails)' if emails.present?
  Subscriber.active.where(sql_cond, customer_id: id, emails:).joins(subscriber_list: :campaigns).merge(Campaign.active.outside_sales).order('subscribers.created_at DESC'.sql_safe)
end

#active_subscriptionsObject



27
28
29
30
31
32
# File 'app/models/concerns/customer_sales_marketing.rb', line 27

def active_subscriptions
  emails = all_emails
  sql_cond = +'subscribers.customer_id = :customer_id'
  sql_cond << ' OR subscribers.email_address IN (:emails)' if emails.present?
  Subscriber.active.where(sql_cond, customer_id: id, emails:).joins(subscriber_list: :campaigns).merge(Campaign.active)
end


50
51
52
# File 'app/models/concerns/customer_sales_marketing.rb', line 50

def all_related_visits
  Visit.where(user_id: all_my_party_ids)
end

#broadcast_customer_source_changedObject

Published after_commit when source change passes the guard.
CustomerSourceChangedHandler subscribes.



67
68
69
70
71
72
# File 'app/models/concerns/customer_sales_marketing.rb', line 67

def broadcast_customer_source_changed
  Rails.configuration.event_store.publish(
    Events::CustomerSourceChanged.new(data: { customer_id: id, source_id: source_id }),
    stream_name: "Customer-#{id}"
  )
end

#campaignsObject



13
14
15
16
17
18
# File 'app/models/concerns/customer_sales_marketing.rb', line 13

def campaigns
  emails = all_emails
  sql_cond = +'subscribers.customer_id = :customer_id'
  sql_cond << ' OR subscribers.email_address IN (:emails)' if emails.present?
  Campaign.joins(subscriber_lists: :subscribers).merge(Subscriber.active).where(sql_cond, customer_id: id, emails:).order('subscribers.created_at DESC'.sql_safe)
end

#can_spiff?Boolean

Returns:

  • (Boolean)


34
35
36
# File 'app/models/concerns/customer_sales_marketing.rb', line 34

def can_spiff?
  Spiff.valid_for_customer(self).present?
end

#check_for_open_sales_activityObject



96
97
98
# File 'app/models/concerns/customer_sales_marketing.rb', line 96

def check_for_open_sales_activity
  CustomerSalesActivityFlagSync.call(self)
end

#company_review_urlObject



74
75
76
# File 'app/models/concerns/customer_sales_marketing.rb', line 74

def company_review_url
  Api::ReviewsIo::DynamicLinkBuilder.for_customer(self)
end

#create_intro_activity(description = nil) ⇒ Object



46
47
48
# File 'app/models/concerns/customer_sales_marketing.rb', line 46

def create_intro_activity(description = nil)
  create_activity('NEWAM', description:)
end

#human_watch_nameObject



82
83
84
# File 'app/models/concerns/customer_sales_marketing.rb', line 82

def human_watch_name
  Customer::WATCH_STATES[watch] || 'Unknown'
end

#last_completed_sales_activity_dateObject



86
87
88
89
90
# File 'app/models/concerns/customer_sales_marketing.rb', line 86

def last_completed_sales_activity_date
  related_activities.completed.sales_activities
                    .where.not(completion_datetime: nil)
                    .order(Activity[:completion_datetime].desc).pick(:completion_datetime)&.to_date
end

#last_meeting_activities(num = 3) ⇒ Object



42
43
44
# File 'app/models/concerns/customer_sales_marketing.rb', line 42

def last_meeting_activities(num = 3)
  related_activities.meeting.completed.completion_order.limit(num)
end

#last_training_activities(num = 3) ⇒ Object



38
39
40
# File 'app/models/concerns/customer_sales_marketing.rb', line 38

def last_training_activities(num = 3)
  related_activities.training.completed.completion_order.limit(num)
end

#local_sales_rep_nameObject



140
141
142
# File 'app/models/concerns/customer_sales_marketing.rb', line 140

def local_sales_rep_name
  local_sales_rep&.full_name
end

#most_recent_attributable_visit_source(window: 90.days) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'app/models/concerns/customer_sales_marketing.rb', line 113

def most_recent_attributable_visit_source(window: 90.days)
  visits
    .where(started_at: window.ago..)
    .where("gclid IS NOT NULL AND gclid != '' OR gbraid IS NOT NULL AND gbraid != '' OR wbraid IS NOT NULL AND wbraid != ''")
    .where.not(source_id: nil)
    .order(started_at: :desc)
    .limit(1)
    .pick(:source_id)
    &.then { |sid| Source.find_by(id: sid) }
end

#open_activities_counterObject



104
105
106
# File 'app/models/concerns/customer_sales_marketing.rb', line 104

def open_activities_counter
  related_activities.open_activities.visible_by_default.size
end

#open_sales_activity?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'app/models/concerns/customer_sales_marketing.rb', line 92

def open_sales_activity?
  related_activities.open_activities.sales_activities.present?
end

#primary_sales_rep_nameObject



132
133
134
# File 'app/models/concerns/customer_sales_marketing.rb', line 132

def primary_sales_rep_name
  primary_sales_rep&.full_name
end

#profile_nameObject



144
145
146
# File 'app/models/concerns/customer_sales_marketing.rb', line 144

def profile_name
  profile&.name
end

#protected_leadsObject



100
101
102
# File 'app/models/concerns/customer_sales_marketing.rb', line 100

def protected_leads
  Customer.protected_by(id)
end

#recalculate_profiling_information(_logger = Rails.logger) ⇒ Object

rubocop:disable Naming/PredicateMethod -- imperative side effect: enqueues worker



157
158
159
160
# File 'app/models/concerns/customer_sales_marketing.rb', line 157

def recalculate_profiling_information(_logger = Rails.logger)
  CustomerProfilingWorker.perform_async(id)
  true
end

#resources_for_select(options = {}) ⇒ Object



152
153
154
# File 'app/models/concerns/customer_sales_marketing.rb', line 152

def resources_for_select(options = {})
  Activity::ResourceList.new.process(self, options)
end

#sales_managerObject



148
149
150
# File 'app/models/concerns/customer_sales_marketing.rb', line 148

def sales_manager
  catalog.sales_manager&.party
end

#sales_repsObject



124
125
126
# File 'app/models/concerns/customer_sales_marketing.rb', line 124

def sales_reps
  [primary_sales_rep, secondary_sales_rep, local_sales_rep].compact.uniq
end

#sales_reps_idsObject



128
129
130
# File 'app/models/concerns/customer_sales_marketing.rb', line 128

def sales_reps_ids
  [primary_sales_rep_id, secondary_sales_rep_id, local_sales_rep_id].compact.uniq
end

#secondary_sales_rep_nameObject



136
137
138
# File 'app/models/concerns/customer_sales_marketing.rb', line 136

def secondary_sales_rep_name
  secondary_sales_rep&.full_name
end

#should_broadcast_source_change?Boolean

Predicate used by Customer's after_commit guard. Captures the historical
condition: source_id just changed AND the new source is linked to a campaign.
saved_change_to_*? is available in after_commit (unlike *_changed?).

Returns:

  • (Boolean)


61
62
63
# File 'app/models/concerns/customer_sales_marketing.rb', line 61

def should_broadcast_source_change?
  saved_change_to_source_id? && source&.linked_to_campaign?
end

#signup_visitObject



9
10
11
# File 'app/models/concerns/customer_sales_marketing.rb', line 9

def 
  visit || visits.first
end

#source_for_opps_and_orders(effective_date = Date.current) ⇒ Object



108
109
110
111
# File 'app/models/concerns/customer_sales_marketing.rb', line 108

def source_for_opps_and_orders(effective_date = Date.current)
  auto_assign_campaign = resolve_auto_assign_campaign(effective_date)
  auto_assign_campaign&.source || source
end

#source_unknown?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'app/models/concerns/customer_sales_marketing.rb', line 54

def source_unknown?
  source.nil? || (source && (source.name == 'Unknown'))
end

#watched?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'app/models/concerns/customer_sales_marketing.rb', line 78

def watched?
  watch_auto? || watch_forced?
end