Module: Models::CustomerContacts

Extended by:
ActiveSupport::Concern
Includes:
Memery
Included in:
Customer
Defined in:
app/concerns/models/customer_contacts.rb

Overview

Aggregate emails, communications, contactable override, contact management.

See Also:

Instance Method Summary collapse

Instance Method Details

#account_teamArray<Employee>

The customer's account team: local, primary, and secondary reps, deduplicated.

Returns:



212
213
214
215
216
# File 'app/concerns/models/customer_contacts.rb', line 212

def 
  team = []
  team << local_sales_rep << primary_sales_rep << secondary_sales_rep
  team.compact.uniq
end

#all_addressesActiveRecord::Relation<Address> Also known as: all_billing_addresses

Addresses belonging to this customer and its parent.

Returns:

  • (ActiveRecord::Relation<Address>)


182
183
184
# File 'app/concerns/models/customer_contacts.rb', line 182

def all_addresses
  Address.where(party_id: [id, parent_id].compact)
end

#all_addresses_including_contactsActiveRecord::Relation<Address>

Addresses belonging to this customer and all of its contacts.

Returns:

  • (ActiveRecord::Relation<Address>)


175
176
177
# File 'app/concerns/models/customer_contacts.rb', line 175

def all_addresses_including_contacts
  Address.where(party_id: [id, *contact_ids].flatten.compact).order(:id)
end

#all_contact_pointsActiveRecord::Relation<ContactPoint>

All contact points belonging to this customer and its active contacts.

Returns:



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

def all_contact_points
  ContactPoint.joins(:party).merge(contacts_and_self)
end

#all_emailsArray<String>

Unique email addresses across this customer and its active contacts.

Returns:

  • (Array<String>)


27
28
29
# File 'app/concerns/models/customer_contacts.rb', line 27

def all_emails
  ContactPoint.emails.where(party_id: all_my_active_party_ids).pluck(:detail).uniq
end

#all_my_active_party_idsArray<Integer>

This customer's party id plus active contact ids, deduplicated. Memoized.

Returns:

  • (Array<Integer>)


88
89
90
# File 'app/concerns/models/customer_contacts.rb', line 88

def all_my_active_party_ids
  ([id] + contacts.active.order(:full_name).ids).compact.uniq
end

#all_my_party_idsArray<Integer>

This customer's party id plus all contact ids, deduplicated.

Returns:

  • (Array<Integer>)


81
82
83
# File 'app/concerns/models/customer_contacts.rb', line 81

def all_my_party_ids
  ([id] + contacts.ids).compact.uniq
end

#all_notification_channelsArray<NotificationChannel>

Notification channels configured for this customer.

Returns:



234
235
236
# File 'app/concerns/models/customer_contacts.rb', line 234

def all_notification_channels
  NotificationChannel.for_customer(self)
end

#all_phone_numbersArray<String>

Unique dialable phone numbers across this customer and its active contacts.

Returns:

  • (Array<String>)


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

def all_phone_numbers
  ContactPoint.dialable.where(party_id: all_my_active_party_ids).pluck(:detail).uniq
end

Billing, shipping, mailing, and other addresses, deduplicated.

Returns:



191
192
193
# File 'app/concerns/models/customer_contacts.rb', line 191

def all_related_addresses
  ([billing_address, shipping_address, mailing_address] + addresses.to_a).flatten.compact.uniq
end

All communications related to this customer and its contacts.

Returns:



13
14
15
# File 'app/concerns/models/customer_contacts.rb', line 13

def all_related_communications
  Query::CustomerRelatedCommunications.call(self)
end

#contact_select_options(active_only: false) ⇒ Array<Array(String, Integer)>

Options for a contact select element, ordered with active contacts first.

:reek:BooleanParameter :reek:ControlParameter

Parameters:

  • active_only (Boolean) (defaults to: false)

    exclude inactive contacts

Returns:

  • (Array<Array(String, Integer)>)

    [full name, contact id] pairs



43
44
45
46
47
# File 'app/concerns/models/customer_contacts.rb', line 43

def contact_select_options(active_only: false)
  contacts_to_use = contacts.order(:inactive)
  contacts_to_use = contacts_to_use.active if active_only
  contacts_to_use.pluck(:full_name, :id)
end

#contactable?Boolean

Whether this customer or any of its active contacts has at least one contact point.

Returns:

  • (Boolean)


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

def contactable?
  contact_points.exists? ||
    ContactPoint.where(party_id: contacts.active.select(:id)).exists?
end

#contacts_and_selfActiveRecord::Relation<Party>

This customer and its active contacts as Party records.

Returns:

  • (ActiveRecord::Relation<Party>)


66
67
68
# File 'app/concerns/models/customer_contacts.rb', line 66

def contacts_and_self
  Party.where(id: all_my_active_party_ids)
end

#contacts_and_self_callable_contact_pointsActiveRecord::Relation<ContactPoint>

Voice-callable contact points for this customer and its active contacts.

Returns:



103
104
105
# File 'app/concerns/models/customer_contacts.rb', line 103

def contacts_and_self_callable_contact_points
  all_contact_points.voice_callable
end

#contacts_and_self_callable_options_for_selectArray<Array(String, Integer)>

Options for a select element of voice-callable contact points.

Returns:

  • (Array<Array(String, Integer)>)

    [label, contact point id] pairs



118
119
120
121
122
123
# File 'app/concerns/models/customer_contacts.rb', line 118

def contacts_and_self_callable_options_for_select
  contacts_and_self_callable_contact_points.includes(:party).map do |contact_point|
    party_label = party_label_for_contact_point(contact_point)
    ["#{contact_point} (#{party_label})", contact_point.id]
  end
end

#contacts_and_self_contact_points_by_category(category) ⇒ ActiveRecord::Relation<ContactPoint>

Contact points of a given category for this customer and its active contacts.

Parameters:

  • category (String)

    contact point category

Returns:



111
112
113
# File 'app/concerns/models/customer_contacts.rb', line 111

def contacts_and_self_contact_points_by_category(category)
  ContactPoint.where(category: category).where(party_id: all_my_active_party_ids)
end

#contacts_and_self_contact_points_by_category_options_for_select(category) ⇒ Array<Array(String, Integer)>

Options for a select element of contact points of a given category.

Parameters:

  • category (String)

    contact point category

Returns:

  • (Array<Array(String, Integer)>)

    [label, contact point id] pairs



129
130
131
132
133
134
# File 'app/concerns/models/customer_contacts.rb', line 129

def contacts_and_self_contact_points_by_category_options_for_select(category)
  contacts_and_self_contact_points_by_category(category).includes(:party).map do |contact_point|
    party_label = party_label_for_contact_point(contact_point, capitalize: true)
    ["#{contact_point} (#{party_label})", contact_point.id]
  end
end

#emailString?

Customer's email, falling back to the first or last active contact's email.

Returns:

  • (String, nil)


161
162
163
# File 'app/concerns/models/customer_contacts.rb', line 161

def email
  super || contacts.active.first&.email || contacts.active.last&.email
end

#generate_guest_accountHash

Build a passwordless guest account for this customer, keyed off their email.

Returns:

  • (Hash)

    { success: true, account: Account } on success,
    { success: false, errors: Array<String> } on validation failure,
    or { success: false } when an account exists or no email is available



243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'app/concerns/models/customer_contacts.rb', line 243

def 
  return { success: false } if .present? || email.nil?

  acct = 
  acct. = Account.(email)
  acct.email = email
  acct.require_password = false
  if acct.save
    { success: true, account: acct }
  else
    { success: false, errors: acct.errors.full_messages }
  end
end

#guess_best_callable_contact_pointContactPoint?

Best guess at which voice-callable contact point to use.

Returns:



139
140
141
# File 'app/concerns/models/customer_contacts.rb', line 139

def guess_best_callable_contact_point
  contacts_and_self_callable_contact_points.first
end

#guess_best_contact_point_by_category(category) ⇒ ContactPoint?

Best guess at which contact point of a given category to use.

Parameters:

  • category (String)

    contact point category

Returns:



147
148
149
# File 'app/concerns/models/customer_contacts.rb', line 147

def guess_best_contact_point_by_category(category)
  contacts_and_self_contact_points_by_category(category).first
end

#lead_score_pass?Boolean

Whether the lead verification score passes the threshold (above 50).

Returns:

  • (Boolean)


59
60
61
# File 'app/concerns/models/customer_contacts.rb', line 59

def lead_score_pass?
  lead_verification_score.to_i > 50
end

#obfuscated_emailString?

The customer's email with the middle of both parts masked.

Returns:

  • (String, nil)


168
169
170
# File 'app/concerns/models/customer_contacts.rb', line 168

def obfuscated_email
  email&.gsub(/(?<=.{2}).*@.*(?=\S{2})/, '****@****')
end

#primary_contactParty?

The primary contact: self when a person, otherwise the first contact.

Returns:



154
155
156
# File 'app/concerns/models/customer_contacts.rb', line 154

def primary_contact
  person? ? self : contacts.first
end

#primary_repEmployee?

The primary sales representative.

Returns:



198
199
200
# File 'app/concerns/models/customer_contacts.rb', line 198

def primary_rep
  primary_sales_rep
end

#secondary_repEmployee?

The secondary sales representative.

Returns:



205
206
207
# File 'app/concerns/models/customer_contacts.rb', line 205

def secondary_rep
  secondary_sales_rep
end

#self_and_contacts_party_ids_arrArray<Integer>

This customer's party id plus all contact party ids.

Returns:

  • (Array<Integer>)


52
53
54
# File 'app/concerns/models/customer_contacts.rb', line 52

def self_and_contacts_party_ids_arr
  [id] + contact_ids
end

#sms_enabled_numbersArray<String>

SMS-capable phone numbers for this customer and its contacts, formatted for SMS.

Returns:

  • (Array<String>)


20
21
22
# File 'app/concerns/models/customer_contacts.rb', line 20

def sms_enabled_numbers
  ContactPoint.where(party_id: [id] + contact_ids).sms_numbers.order(:detail).map(&:formatted_for_sms)
end