Class: Customer::NewCustomer

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::API, ActiveModel::Attributes, ActiveModel::Validations, ActiveModel::Validations::Callbacks, Heatwave::AttributeNormalizing, StripAttributes
Defined in:
app/services/customer/new_customer.rb

Overview

Service object: new customer.

Constant Summary collapse

REP_ASSIGN_METHODS =

Rep assign methods.

{ aa: 'Auto Assign', sa: 'Self Assign', ma: 'Manually Assign', dna: 'Do Not Assign' }.with_indifferent_access

Instance Attribute Summary collapse

Delegated Instance Attributes collapse

Instance Method Summary collapse

Methods included from Heatwave::AttributeNormalizing

normalize

Instance Attribute Details

#cellObject (readonly)



70
# File 'app/services/customer/new_customer.rb', line 70

validates :phone, :phone2, :cell, :fax, phone_format: true

#emailObject (readonly)

We always validate these fields no matter what step we're in

Validations:

  • Email_format


69
# File 'app/services/customer/new_customer.rb', line 69

validates :email, :email2, email_format: true

#email2Object (readonly)

We always validate these fields no matter what step we're in

Validations:

  • Email_format


69
# File 'app/services/customer/new_customer.rb', line 69

validates :email, :email2, email_format: true

#faxObject (readonly)



70
# File 'app/services/customer/new_customer.rb', line 70

validates :phone, :phone2, :cell, :fax, phone_format: true

#phoneObject (readonly)



70
# File 'app/services/customer/new_customer.rb', line 70

validates :phone, :phone2, :cell, :fax, phone_format: true

#phone2Object (readonly)



70
# File 'app/services/customer/new_customer.rb', line 70

validates :phone, :phone2, :cell, :fax, phone_format: true

#websiteObject (readonly)



71
# File 'app/services/customer/new_customer.rb', line 71

validates :website, url: { allow_nil: true, allow_blank: true }

Instance Method Details

#address_complete?Boolean

Bare mininum information we need for a valid address

Returns:

  • (Boolean)


327
328
329
# File 'app/services/customer/new_customer.rb', line 327

def address_complete?
  %i[street1 city postal_code country_iso].all? { |f| send(f).presence }
end

#allow_disablement_of_address_validation?Boolean

Accessor method to determine if we can allow disabling the address validation

Returns:

  • (Boolean)


380
381
382
# File 'app/services/customer/new_customer.rb', line 380

def allow_disablement_of_address_validation?
  @address_carrier_error
end

#assignment_step?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'app/services/customer/new_customer.rb', line 105

def assignment_step?
  step == :assignment
end

#build_address(address) ⇒ Object

Copy over address attributes



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'app/services/customer/new_customer.rb', line 295

def build_address(address)
  address.street1 = street1
  address.street2 = street2
  address.city = city
  address.state_code = state_code
  address.zip = postal_code
  address.country_iso3 = Country.find_by(iso: country_iso).iso3
  address.is_residential = residential_address.nil? ? false : residential_address
  address.lat = lat
  address.lng = lng
  address.has_loading_dock = has_loading_dock
  address.is_construction_site = is_construction_site
  address.requires_inside_delivery = requires_inside_delivery
  address.requires_liftgate = requires_liftgate
  address.limited_access = limited_access
  address.requires_appointment = requires_appointment
  address.disable_address_correction = disable_address_correction.nil? ? false : disable_address_correction
  address
end

#build_and_save_customer(check_for_spam: false) ⇒ Object

Builds, qualify, create lead and save customer



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'app/services/customer/new_customer.rb', line 336

def build_and_save_customer(check_for_spam: false)
  customer = build_customer
  if check_for_spam && is_spam?
    customer.errors.add(:base, 'Spam customer detected')
  else
    customer.state = 'lead_qualify'
    customer.state_event = :complete_qualification unless start_in_lead_qualify?

    if customer.save
      # Update the return path
      self.return_path = return_path && customer.id && return_path.gsub('new_party_id', customer.id.to_s)
      NewLead::LeadActivityAssigner.new.process(customer, notes: notes) # unless customer.primary_sales_rep_id.nil?
      # record email preferences
      set_email_preferences
      # Broadcast product interest if any
      customer.broadcast_product_interest_changed(product_line_ids_added: customer.product_line_ids)
      # Broadcast buying groups if any
      customer.broadcast_buying_group_changed(buying_group_id_added: customer.buying_group_id)
      # Queue profile image lookup (logo from Clearbit)
      PartyProfileImageWorker.perform_async(customer.id)
    end
  end
  customer
end

#build_contact_points(party) ⇒ Object

Build the contact points into the party



316
317
318
319
320
321
322
323
324
# File 'app/services/customer/new_customer.rb', line 316

def build_contact_points(party)
  party.contact_points.build(detail: phone, category: ContactPoint::PHONE) if phone.present?
  party.contact_points.build(detail: phone2, category: ContactPoint::PHONE) if phone2.present?
  party.contact_points.build(detail: cell, category: ContactPoint::CELL) if cell.present?
  party.contact_points.build(detail: fax, category: ContactPoint::FAX) if fax.present?
  party.contact_points.build(detail: email, category: ContactPoint::EMAIL) if email.present?
  party.contact_points.build(detail: email2, category: ContactPoint::EMAIL) if email2.present?
  party.contact_points.build(detail: website, category: ContactPoint::WEBSITE) if website.present?
end

#build_customerObject

Instantiate a new customer translating all attributes from newcustomer



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'app/services/customer/new_customer.rb', line 254

def build_customer
  cu = Customer.new
  cu.profile_id = profile_id
  cu.buying_group_id = buying_group_id
  cu.source_id = source_id
  cu.source_info = source_info.presence
  cu.preferred_language = preferred_language
  cu.catalog_id = catalog_id
  cu.tier2_program_pricing_id = tier2_program_pricing_id
  cu.gclid = gclid.presence
  # Split the person name, we'll reuse that later
  pnp = split_person_name
  if company_name.blank?
    pnp.to_party(cu)
  else # If not company, build a person
    cu.full_name = company_name
    if pnp.valid? # A contact is present
      cnt = cu.contacts.build
      pnp.to_party(cnt)
      cnt.job_title = job_title
    end
  end
  # Build the contact points into the contact if present otherwise customer
  build_contact_points(cnt || cu)
  cu.primary_sales_rep_id = primary_sales_rep_id
  cu.secondary_sales_rep_id = secondary_sales_rep_id
  cu.local_sales_rep_id = local_sales_rep_id
  cu.service_rep_id = service_rep_id
  cu.do_not_auto_assign = (rep_assignment_method.to_s.to_sym == :dna)
  cu.creation_method = creation_method

  # Build the address if we have all the elements
  if address_complete?
    a = build_address(cu.addresses.new)
    cu.shipping_address = cu.billing_address = cu.mailing_address = a
  end
  cu.product_line_ids = (product_line_ids || []).compact.uniq
  cu
end

#buying_groupObject

Accessor method to retrieve buying group



218
219
220
# File 'app/services/customer/new_customer.rb', line 218

def buying_group
  BuyingGroup.find(buying_group_id.presence) if buying_group_id.presence
end

#buying_group_options_for_selectObject

Retrieves a list of buying available for the customer company



223
224
225
# File 'app/services/customer/new_customer.rb', line 223

def buying_group_options_for_select
  BuyingGroup.options_for_select(company_id: company_id)
end

#catalogObject

Catalog is based on country in this model



228
229
230
231
# File 'app/services/customer/new_customer.rb', line 228

def catalog
  # Always return a catalog; default to US when country is not provided
  Catalog.default_for_country(country_iso)
end

#catalog_idObject



233
234
235
# File 'app/services/customer/new_customer.rb', line 233

def catalog_id
  catalog.try(:id)
end

#catalog_nameObject



237
238
239
# File 'app/services/customer/new_customer.rb', line 237

def catalog_name
  catalog.try(:name)
end

#company_idObject

Alias for Catalog#company_id

Returns:

  • (Object)

    Catalog#company_id

See Also:



241
# File 'app/services/customer/new_customer.rb', line 241

delegate :company_id, to: :catalog

#company_name_partsObject

Split company name in parts for highlighting on screen



168
169
170
# File 'app/services/customer/new_customer.rb', line 168

def company_name_parts
  company_name.to_s.split(/[ ,.]/).filter_map(&:presence)
end

#contact_point_detailsObject



158
159
160
# File 'app/services/customer/new_customer.rb', line 158

def contact_point_details
  [email, phone, fax].compact.uniq
end

#default_pricing_programObject



180
181
182
183
184
185
186
# File 'app/services/customer/new_customer.rb', line 180

def default_pricing_program
  if is_individual?
    Coupon::Tier2ProgramPricing.msrp_tier2_pricing_coupon
  else
    Coupon::Tier2ProgramPricing.customer_default_trade
  end
end

#default_profileObject



188
189
190
191
192
193
194
# File 'app/services/customer/new_customer.rb', line 188

def default_profile
  if is_individual?
    Profile.homeowner_profile
  else
    Profile.unknown_trade
  end
end

#find_duplicatesObject



145
146
147
148
# File 'app/services/customer/new_customer.rb', line 145

def find_duplicates
  cf = Query::CustomerFinder.new(attributes)
  cf.find_duplicates
end

#full_addressObject



331
332
333
# File 'app/services/customer/new_customer.rb', line 331

def full_address
  %i[street1 city postal_code country_iso].map { |f| send(f).presence }.join(' ')
end

#has_address?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'app/services/customer/new_customer.rb', line 115

def has_address?
  street1.present?
end

#identify_step?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'app/services/customer/new_customer.rb', line 97

def identify_step?
  step == :identify
end

#is_individual?Boolean

Returns:

  • (Boolean)


172
173
174
# File 'app/services/customer/new_customer.rb', line 172

def is_individual?
  company_name.blank?
end

#is_organization?Boolean

Returns:

  • (Boolean)


176
177
178
# File 'app/services/customer/new_customer.rb', line 176

def is_organization?
  company_name.present?
end

#is_spam?Boolean

Returns:

  • (Boolean)


384
385
386
387
388
389
# File 'app/services/customer/new_customer.rb', line 384

def is_spam?
  SpamCheck.new.process(
     author_email: email.presence,
     phone_number: phone.presence || phone2.presence || cell.presence || fax.presence
   )
end

#name_presenceObject

Check for name presence and normalize the person name using our name parser
e.g Smith, John III will be John Smith III



121
122
123
124
125
126
127
128
129
130
# File 'app/services/customer/new_customer.rb', line 121

def name_presence
  if person_name.present?
    pnp = split_person_name
    self.person_name = pnp.full_name
  end
  return if company_name.present? || person_name.present?

  errors.add :company_name, 'must be specified if no person name present'
  errors.add :person_name, 'must be specified if no company name present'
end

#person_first_nameObject



150
151
152
# File 'app/services/customer/new_customer.rb', line 150

def person_first_name
  pnp.first
end

#person_last_nameObject



154
155
156
# File 'app/services/customer/new_customer.rb', line 154

def person_last_name
  pnp.last
end

#person_name_partsObject

Split person name in parts for highlighting on screen



163
164
165
# File 'app/services/customer/new_customer.rb', line 163

def person_name_parts
  person_name.to_s.scan(/(\w+)/).flatten
end

#pricing_program_options_for_selectObject

Used in the final step to determine the pricing offered



197
198
199
# File 'app/services/customer/new_customer.rb', line 197

def pricing_program_options_for_select
  Coupon::Tier2ProgramPricing.select_options_for_customer(build_customer)
end

#profileObject

Accessor method to retrieve profile



202
203
204
# File 'app/services/customer/new_customer.rb', line 202

def profile
  Profile.find(profile_id) if profile_id.present?
end

#profile_collection_for_selectObject

List of profiles for selection, we assume an individual is always a homeowner
only, otherwise we pull up every trade



208
209
210
211
212
213
214
215
# File 'app/services/customer/new_customer.rb', line 208

def profile_collection_for_select
  profiles = if is_individual?
               Profile.homeowner
             else
               Profile.trades
             end
  profiles.order(:name).pluck(:name, :id)
end

#rep_assignment_method_nameObject



93
94
95
# File 'app/services/customer/new_customer.rb', line 93

def rep_assignment_method_name
  REP_ASSIGN_METHODS[rep_assignment_method]
end

#set_default_email_preferencesObject



243
244
245
246
247
248
249
250
251
# File 'app/services/customer/new_customer.rb', line 243

def set_default_email_preferences
  # If it's for US, subscribe to everything by default
  # Canada will therefore be unsubscribed by default
  default_value = company_id == 1
  %i[subscribe_to_announcements subscribe_to_events subscribe_to_newsletters
     subscribe_to_product_review_requests subscribe_to_promotions subscribe_to_webinars].each do |field|
    public_send(:"#{field}=", default_value) if public_send(field).nil?
  end
end

#set_email_preferencesObject

Creates or updates email preferences if an email address was provided



362
363
364
365
366
367
368
369
370
371
372
# File 'app/services/customer/new_customer.rb', line 362

def set_email_preferences
  return true if email.blank?

  ep = EmailPreference.find_or_initialize_by(email: email&.downcase)
  ep.disable_announcements = subscribe_to_announcements != true
  ep.disable_events = subscribe_to_events != true
  ep.disable_newsletters = subscribe_to_newsletters != true
  ep.disable_promotions = subscribe_to_promotions != true
  ep.disable_webinars = subscribe_to_webinars != true
  ep.save
end

#setup_or_assignment_step?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'app/services/customer/new_customer.rb', line 109

def setup_or_assignment_step?
  (setup_step? or assignment_step?)
end

#setup_step?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'app/services/customer/new_customer.rb', line 101

def setup_step?
  step == :setup
end

#split_person_nameObject

Calls the person name parser to split a name, returns a hash with :first_name, :last_name, :middle_name, :suffix, :prefix



375
376
377
# File 'app/services/customer/new_customer.rb', line 375

def split_person_name
  PersonNameParser.new(person_name)
end

#start_in_lead_qualify?Boolean

Returns:

  • (Boolean)


113
# File 'app/services/customer/new_customer.rb', line 113

def start_in_lead_qualify? = start_in_lead_qualify

#website_url_to_base_urlObject



132
133
134
135
136
137
138
139
140
141
142
143
# File 'app/services/customer/new_customer.rb', line 132

def website_url_to_base_url
  return if website.blank?

  pv = begin
    Addressable::URI.parse(website)
  rescue StandardError
    nil
  end
  return unless pv

  self.website = "#{pv.scheme || 'https'}://#{pv.host}"
end