Class: LocatorRecord

Inherits:
ApplicationRecord show all
Extended by:
FriendlyId
Includes:
Models::Auditable, Models::LiquidMethods, Models::Taggable
Defined in:
app/models/locator_record.rb

Overview

== Schema Information

Table name: locator_records
Database name: primary

id :integer not null, primary key
confirmed_at :datetime
date_of_wy_visit :datetime
date_wyu_last_passed :datetime
has_countertop_display :boolean
has_had_wy_visit :boolean
has_in_floor_display :boolean
has_in_house_service_team :boolean
has_marketing_materials :boolean
has_passed_wyu :boolean
is_electrician :boolean
is_inactive :boolean default(FALSE), not null
is_installer :boolean
is_remodel_contractor :boolean
is_retailer :boolean
is_wy_certified :boolean
jobs_a_year :string
last_confirmed_at :datetime
maintains_wy_stock :boolean
preferred_dealer :boolean
profile_ids :text
slug :string
star_status_level :integer
state :string(255)
supports_comfort_products :boolean
supports_flooring :boolean
supports_roof_deicing :boolean
supports_snowmelting :boolean
created_at :datetime
updated_at :datetime
address_id :integer
customer_id :integer

Indexes

idx_state (state)
index_locator_records_confirmed_at (confirmed_at)
index_locator_records_customer_id (customer_id)
index_locator_records_on_address_id (address_id)
index_locator_records_on_slug (slug)
index_locator_records_on_supports_roof_deicing (supports_roof_deicing)

Constant Summary collapse

STAR_STATUS_LEVELS =
%w[0 1 2 3 4 5].freeze
JOBS_A_YEAR =
%w[1-5 5-10 10-50 50+].freeze

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has many collapse

Methods included from Models::Taggable

#tag_records, #taggings

Delegated Instance Attributes collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Taggable

#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

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, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Class Method Details

.activeActiveRecord::Relation<LocatorRecord>

A relation of LocatorRecords that are active. Active Record Scope

Returns:

See Also:



73
# File 'app/models/locator_record.rb', line 73

scope :active, -> { where(is_inactive: false) }

.are_confirmedActiveRecord::Relation<LocatorRecord>

A relation of LocatorRecords that are are confirmed. Active Record Scope

Returns:

See Also:



74
# File 'app/models/locator_record.rb', line 74

scope :are_confirmed, -> { where(state: 'confirmed') }

.filter_optionsObject



118
119
120
121
122
123
124
125
126
127
128
129
# File 'app/models/locator_record.rb', line 118

def self.filter_options
  { 'Supports Comfort Products' => 'supports_comfort_products' }
  # { "Retailer" => "is_retailer",
  #   "Installer" => "is_installer",
  #   "Electrician" => "is_electrician",
  #   "Remodeling Contractor" => "is_remodel_contractor",
  #   "Supports Floor Heating" => "supports_flooring",
  #   "Supports Snow Melting" => "supports_snowmelting",
  #   "Supports Roof & Gutter Deicing" => "supports_roof_deicing",
  #   "Supports Comfort Products" => "supports_comfort_products",
  #   "Preferred Stocking Kit Dealer" => "preferred_dealer" }
end

.near_coordinatesActiveRecord::Relation<LocatorRecord>

A relation of LocatorRecords that are near coordinates. Active Record Scope

Returns:

See Also:



75
76
77
78
79
80
81
# File 'app/models/locator_record.rb', line 75

scope :near_coordinates, lambda { |coordinates, distance|
  are_confirmed
    .active
    .joins(:address, :customer)
    .merge(Address.near(coordinates, distance))
    .select('locator_records.*')
}

.notify_non_qualifying_dealersObject



383
384
385
386
387
388
389
390
391
392
393
# File 'app/models/locator_record.rb', line 383

def self.notify_non_qualifying_dealers
  customers_to_delete = Customer.locator_expired.joins(locator_record: :contact_points)
                                .where(LocatorRecord[:state].eq('confirmed'))
                                .where(ContactPoint[:category].eq('email'))
  customers_to_delete.find_each(batch_size: 100) do |c|
    processed = c.locator_record.send_dealer_deletion_notice
  end
  return if customers_to_delete.empty?

  InternalMailer.dealer_locator_communication_report(customers_to_delete.map(&:locator_record), 'Dealers Set to Delete - First notice').deliver
end

.process_task(task_name, task_condition, task_include_associations, task_method, trial_run = false, logger = nil, _stop_hours = 3, batch = 100) ⇒ Object



560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'app/models/locator_record.rb', line 560

def self.process_task(task_name, task_condition, task_include_associations, task_method, trial_run = false, logger = nil, _stop_hours = 3, batch = 100)
  # Process a task on all locator records that meet the conditions, work for stop_hours, it will resume the next time the task is run
  logger ||= Rails.logger
  logger.info "* #{task_name} started #{Time.current}"
  logger.info '* TRIAL RUN MODE ' if trial_run
  logger.info "** Dealer Locator Records, finding all locator_records that meet criteria: #{task_condition}"
  locator_record_counter = 0
  locator_record_processed_counter = 0
  start_datetime = Time.current
  locator_record_ids_with_errors = []
  locator_records = LocatorRecord.where(task_condition).includes(task_include_associations).references(task_include_associations)
  locator_records.find_each(batch_size: batch) do |l|
    locator_record_counter += 1
    processed = l.send(task_method, trial_run)
    if processed[:status_code] == :ok
      locator_record_processed_counter += 1
      logger.info  "*** Locator record #{l.customer.name} #{l.id} completed, status message #{processed[:status_message]}"
    else
      logger.error "!!! Locator record #{l.customer.name} #{l.id} failed to process  with #{task_method}, status message was #{processed[:status_message]}"
      locator_record_ids_with_errors << [l.id, l.customer.try(:name), processed[:status_code], processed[:status_message]]
    end
  end
  # Send email to Elodie
  InternalMailer.dealer_locator_communication_report(locator_records, task_name).deliver_later unless locator_records.empty?
  unless @locator_record_ids_with_errors.nil? || @locator_record_ids_with_errors.empty?
    ErrorReporting.error("*** #{task_name} Processed #{locator_record_processed_counter} and failed to process #{locator_record_ids_with_errors.size} records,  #{Time.current}. These are the locator record ids: #{locator_record_ids_with_errors}")
  end
  logger.info "*** #{task_name} Processed #{locator_record_processed_counter} and failed to process #{locator_record_ids_with_errors.size} records,  #{Time.current}"
  locator_record_ids_with_errors.each do |e|
    logger.error "**** Locator record error #{e.join(' ')}"
  end
end

.purge_invalid_locator_recordsObject



376
377
378
379
380
381
# File 'app/models/locator_record.rb', line 376

def self.purge_invalid_locator_records
  # LocatorRecord.joins(:customer => :profile).where(Profile[:locator_eligible].eq(false)).find_each do |lr|
  LocatorRecord.joins(:customer).where(Customer[:profile_id].eq(ProfileConstants::HOMEOWNER)).find_each do |lr|
    lr.remove_dealer_from_locator(false)
  end
end

.star_level_options_for_select(nil_option = true) ⇒ Object



146
147
148
149
150
# File 'app/models/locator_record.rb', line 146

def self.star_level_options_for_select(nil_option = true)
  base_options = []
  base_options = [[' ', nil]] if nil_option
  base_options.concat(STAR_STATUS_LEVELS.map { |rl| [rl.to_s, rl.to_i] })
end

.states_for_selectObject



142
143
144
# File 'app/models/locator_record.rb', line 142

def self.states_for_select
  state_machines[:state].states.map { |s| [s.human_name, s.value] }
end

Instance Method Details

#addressAddress

Returns:

See Also:

Validations:



58
# File 'app/models/locator_record.rb', line 58

belongs_to :address, inverse_of: :locator_record, optional: true

#blacklistObject



257
258
259
# File 'app/models/locator_record.rb', line 257

def blacklist
  update(is_inactive: true)
end

#capabilitiesObject



133
134
135
136
137
138
139
140
# File 'app/models/locator_record.rb', line 133

def capabilities
  res = []
  res << 'Supports Floor Heating' if supports_flooring?
  res << 'Supports Snow Melting' if supports_snowmelting?
  res << 'Supports Roof & Gutter Deicing' if supports_roof_deicing?
  res << 'Supports Comfort Products' if supports_comfort_products?
  res
end

#communicationsActiveRecord::Relation<Communication>

Returns:

See Also:



60
# File 'app/models/locator_record.rb', line 60

has_many :communications, -> { order(:id).reverse_order }, as: :resource, dependent: :nullify

#contact_pointsActiveRecord::Relation<ContactPoint>

Returns:

See Also:



59
# File 'app/models/locator_record.rb', line 59

has_many :contact_points, inverse_of: :locator_record


251
252
253
# File 'app/models/locator_record.rb', line 251

def crm_link
  UrlHelper.instance.customer_path(customer)
end

#customerCustomer

Returns:

See Also:



57
# File 'app/models/locator_record.rb', line 57

belongs_to :customer, inverse_of: :locator_record, optional: true

#dealer_confirmObject



269
270
271
272
273
274
275
276
277
278
279
280
# File 'app/models/locator_record.rb', line 269

def dealer_confirm
  self.last_confirmed_at = Time.current
  if confirmed_at
    save
    dealer_confirmed! unless state == 'confirmed'
  else
    # ensure that the confirmation date and state change to confirmed is set only once on the *initial* confirmation
    self.confirmed_at = Time.current
    save
    dealer_confirmed!
  end
end

#emailObject



183
184
185
186
187
# File 'app/models/locator_record.rb', line 183

def email
  contact_points.detect { |cp| cp.category == 'email' }.detail
rescue StandardError
  nil
end

#email_idObject



177
178
179
180
181
# File 'app/models/locator_record.rb', line 177

def email_id
  contact_points.detect { |cp| cp.category == 'email' }.id
rescue StandardError
  nil
end

#email_id=(cp_id) ⇒ Object



166
167
168
169
170
171
172
173
174
175
# File 'app/models/locator_record.rb', line 166

def email_id=(cp_id)
  current_cp = contact_points.detect { |cp| cp.category == 'email' }
  contact_points.delete(current_cp) if current_cp
  return if cp_id.blank?

  cp = ContactPoint.find(cp_id)
  contact_points << cp
  # don't want duplicates say validation issue to block save
  # cp.save(:validate => false)
end

#faxObject



207
208
209
210
211
# File 'app/models/locator_record.rb', line 207

def fax
  contact_points.detect { |cp| cp.category == 'fax' }.detail
rescue StandardError
  nil
end

#fax_idObject



201
202
203
204
205
# File 'app/models/locator_record.rb', line 201

def fax_id
  contact_points.detect { |cp| cp.category == 'fax' }.id
rescue StandardError
  nil
end

#fax_id=(cp_id) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
# File 'app/models/locator_record.rb', line 189

def fax_id=(cp_id)
  current_cp = contact_points.detect { |cp| cp.category == 'fax' }
  contact_points.delete(current_cp) if current_cp
  contact_points << ContactPoint.find(cp_id) if cp_id.present?
  return if cp_id.blank?

  cp = ContactPoint.find(cp_id)
  contact_points << cp
  # don't want duplicates (say) validation issue to block save
  # cp.save(:validate => false)
end

#first_nameObject

Alias for Customer#first_name

Returns:

  • (Object)

    Customer#first_name

See Also:



131
# File 'app/models/locator_record.rb', line 131

delegate :first_name, to: :customer

#generate_confirmation_form_urlObject

On Aprl 25th 2022 we decided to stop sending email notifications for dealers
def self.send_ongoing_dealer_locator_communications(trial_run = false, logger = nil, stop_hours = 3, batch = 100)

First purge invalids

purge_invalid_locator_records

Potential dealers that do qualify, inviting them to update/confirm their information so that they can be part of the new dealer database.

process_task('New Dealer Locator Invitations', "locator_records.state = 'not_invited' and locator_records.is_inactive IS NOT TRUE and contact_points.category = 'email'", [:contact_points], 'send_dealer_invite', trial_run, logger, stop_hours, batch)

Contact potential dealers who have been invited but have not confirmed after 30 days.

process_task('Invited Dealers 30 Day Reminder', "locator_records.state = 'invited' and locator_records.created_at < '#30.days.ago.to_fs(:db)' and locator_records.is_inactive IS NOT TRUE and contact_points.category = 'email'", [:contact_points], 'send_invited_dealers_30_day_reminder', trial_run, logger, stop_hours, batch)

Dealers that don't qualify anymore, sending them a notice so they can manually decide to remain in the delaer list

notify_non_qualifying_dealers

Dealers that were noticed for deletion and didn't confirm their stay, sending them a final notice so they can manually decide to remain in the delaer list

process_task('Deletion in 7 day Reminder', "locator_records.state = 'set_to_delete' and locator_records.updated_at < '#7.days.ago.to_fs(:db)' and contact_points.category = 'email'", [:contact_points], 'send_dealer_deletion_notice_7_day_reminder', trial_run, logger, stop_hours, batch)

Dealers that were noticed for deletion and didn't confirm their stay, deleting

process_task('Dealers Deleted', "locator_records.state = 'set_to_delete_remainded' and locator_records.updated_at < '#7.days.ago.to_fs(:db)' and contact_points.category = 'email'", [:contact_points], 'remove_dealer', trial_run, logger, stop_hours, batch)
end



411
412
413
# File 'app/models/locator_record.rb', line 411

def generate_confirmation_form_url
  url = LOCATOR_RECORD_FORM_BASE_URL + "?locator_record_id=#{CGI.escape(Encryption.encrypt_string(id.to_s))}"
end

#get_callable_cpObject



154
155
156
157
158
# File 'app/models/locator_record.rb', line 154

def get_callable_cp
  contact_points.voice_callable.first
rescue StandardError
  nil
end

#get_cp_by_category(cat) ⇒ Object



160
161
162
163
164
# File 'app/models/locator_record.rb', line 160

def get_cp_by_category(cat)
  contact_points.detect { |cp| cp.category == cat }.detail
rescue StandardError
  nil
end


536
537
538
# File 'app/models/locator_record.rb', line 536

def map_link(label)
  "<a target = '_new' href='http://maps.google.com/maps?f=q&amp;source=embed&amp;hl=en&amp;geocode=&amp;q=#{address.street1}+#{address.street2}+#{address.street3}+#{address.city}+#{address.state_code}+#{address.zip}+#{address.country_iso3}&amp;sll=#{address.lat},#{address.lng}&amp;sspn=0.008969,0.021522&amp;ie=UTF8&amp;hq=&amp;hnear=#{address.street1}+#{address.street2}+#{address.street3}+#{address.city}+#{address.state_code}+#{address.zip}+#{address.country_iso3}&amp;z=16&amp;ll=#{address.lat},#{address.lng}'>#{label || 'View On Map'}</a>"
end

#must_be_an_organizationObject (protected)



548
549
550
551
552
# File 'app/models/locator_record.rb', line 548

def must_be_an_organization
  return unless customer&.is_homeowner?

  errors.add :base, "Homeowner can't be in dealer locator dealer must be an organization"
end

#nameObject

Alias for Customer#name

Returns:

  • (Object)

    Customer#name

See Also:



152
# File 'app/models/locator_record.rb', line 152

delegate :name, to: :customer

#not_blacklistedObject (protected)



542
543
544
545
546
# File 'app/models/locator_record.rb', line 542

def not_blacklisted
  return unless customer&.locator_black_listing && new_record?

  errors.add :base, "Dealer can't be in locator dealer is blacklisted"
end

#phoneObject



230
231
232
# File 'app/models/locator_record.rb', line 230

def phone
  contact_points.detect { |cp| ContactPoint::CAN_VOICE.include? cp.category }&.detail
end

#phone_idObject



224
225
226
227
228
# File 'app/models/locator_record.rb', line 224

def phone_id
  contact_points.voice_callable.first.id
rescue StandardError
  nil
end

#phone_id=(cp_id) ⇒ Object



213
214
215
216
217
218
219
220
221
222
# File 'app/models/locator_record.rb', line 213

def phone_id=(cp_id)
  current_cp = contact_points.detect { |cp| %w[phone cell].include?(cp.category) }
  contact_points.delete(current_cp) if current_cp
  return if cp_id.blank?

  cp = ContactPoint.find(cp_id)
  contact_points << cp
  # don't want duplicates (say) validation issue to block save
  # cp.save(:validate => false)
end

#profilesObject



265
266
267
# File 'app/models/locator_record.rb', line 265

def profiles
  Profile.where(id: profile_ids)
end

#remove_dealer(trial_run = false) ⇒ Object



323
324
325
326
327
328
329
330
331
332
333
# File 'app/models/locator_record.rb', line 323

def remove_dealer(trial_run = false)
  stat = { status_code: :ok, status_message: "Dealer deleted, locator record id #{id}" }
  co = CommunicationBuilder.new(resource: self, template_system_code: 'DEALER_DELETED').create
  if co.errors.any?
    stat[:status_code] = :error
    stat[:status_message] = "There were problem deleting a dealer to locator record #{id} : #{co.errors.full_messages}"
  else
    destroy unless trial_run
  end
  stat
end

#remove_dealer_from_locator(trial_run = false) ⇒ Object



368
369
370
371
372
373
374
# File 'app/models/locator_record.rb', line 368

def remove_dealer_from_locator(trial_run = false)
  stat = { status_code: :ok, status_message: 'Dealer is white listed, removal ignored' }
  unless customer.locator_white_listing
    destroy unless trial_run
  end
  stat
end

#schedule_dealer_locator_activity(task_type) ⇒ Object



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'app/models/locator_record.rb', line 282

def schedule_dealer_locator_activity(task_type)
  activity_type_id = begin
    ActivityType.find_by(task_type: task_type).id
  rescue StandardError
    8
  end # worst case we at least have an OUTFLW
  activity = Activity.new
  activity.activity_type_id = activity_type_id
  activity.description = activity.activity_type.description + ", DL invite sent ~ #{created_at.to_fs(:crm_date_only)}"
  activity.new_note = "This #{task_type} activity was auto-generated by the customer confirming their dealer/installer record on #{Time.current.to_fs(:crm_date_only)}, and requesting marketing materials or displays."
  activity.party = customer
  activity.target_datetime = 1.day.from_now
  activity.assigned_resource = customer.primary_sales_rep
  activity.save(validate: false)
end

#send_confirmation_emailObject



359
360
361
362
363
364
365
366
# File 'app/models/locator_record.rb', line 359

def send_confirmation_email
  co = CommunicationBuilder.new(resource: self, template_system_code: 'DEALER_CONFIRMED').create
  return unless co.errors.any?

  stat[:status_code] = :error
  stat[:status_message] = "There were problem sending confirmation email to locator record #{id} : #{co.errors.full_messages}"
  ErrorReporting.error("There were problem sending confirmation email to locator record #{id} : #{co.errors.full_messages}")
end

#send_dealer_deletion_notice(trial_run = false) ⇒ Object



298
299
300
301
302
303
304
305
306
307
308
309
# File 'app/models/locator_record.rb', line 298

def send_dealer_deletion_notice(trial_run = false)
  stat = { status_code: :ok, status_message: "Sent notice to dealer for deletion, locator record id #{id}" }
  co = CommunicationBuilder.new(resource: self, template_system_code: 'DEALER_SET_TO_DELETE').create
  if co.errors.any?
    stat[:status_code] = :error
    stat[:status_message] = "There were problem sending notice to dealer for deletion to locator record #{id} : #{co.errors.full_messages}"
    ErrorReporting.error("There were problem sending notice to dealer for deletion to locator record #{id} : #{co.errors.full_messages}")
  elsif !trial_run && state == 'confirmed'
    dealer_deletion_noticed!
  end
  stat
end

#send_dealer_deletion_notice_7_day_reminder(trial_run = false) ⇒ Object



311
312
313
314
315
316
317
318
319
320
321
# File 'app/models/locator_record.rb', line 311

def send_dealer_deletion_notice_7_day_reminder(trial_run = false)
  stat = { status_code: :ok, status_message: "Sent remainder to dealer for deletion, locator record id #{id}" }
  co = CommunicationBuilder.new(resource: self, template_system_code: 'DEALER_DELETE_IN7DAY').create
  if co.errors.any?
    stat[:status_code] = :error
    stat[:status_message] = "There were problem reminding a dealer locator record #{id} : #{co.errors.full_messages}"
  else
    dealer_deletion_remainded! unless trial_run
  end
  stat
end

#send_dealer_invite(trial_run = false) ⇒ Object



335
336
337
338
339
340
341
342
343
344
345
# File 'app/models/locator_record.rb', line 335

def send_dealer_invite(trial_run = false)
  stat = { status_code: :ok, status_message: "Dealer invited, locator record id #{id}" }
  co = CommunicationBuilder.new(resource: self, template_system_code: 'DEALER_INVITE').create
  if co.errors.any?
    stat[:status_code] = :error
    stat[:status_message] = "There were problem sending dealer invite to locator record #{id} : #{co.errors.full_messages}"
  elsif not_invited? && !trial_run
    dealer_invited!
  end
  stat
end

#send_invited_dealers_30_day_reminder(trial_run = false) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
# File 'app/models/locator_record.rb', line 347

def send_invited_dealers_30_day_reminder(trial_run = false)
  stat = { status_code: :ok, status_message: "Dealer 30 day invitation reminder sent, locator record id #{id}" }
  co = CommunicationBuilder.new(resource: self, template_system_code: 'DEALER_REMINDER').create
  if co.errors.any?
    stat[:status_code] = :error
    stat[:status_message] = "There were problem sending dealer invite 30 days reminders to locator record #{id} : #{co.errors.full_messages}"
  else
    invite_reminded! unless trial_run
  end
  stat
end

#slug_candidatesObject (protected)



554
555
556
# File 'app/models/locator_record.rb', line 554

def slug_candidates
  customer.name
end

#unblacklistObject



261
262
263
# File 'app/models/locator_record.rb', line 261

def unblacklist
  update(is_inactive: false)
end

#update_from_user_params(params) ⇒ Object



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
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
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
# File 'app/models/locator_record.rb', line 415

def update_from_user_params(params)
  customer = self.customer
  # do tasks like
  # - create DISPINF, DISPHCTD, DISPTW or BINDER
  # - update customer name if valid, and sane
  # - create new contact points in customer and link to locator record if necessary based on comparison to existing cp details, scanning all other customer and contacts contact points for detail and type matching
  # - create new address in customer and link to locator record if necessary based on comparison to existing addresses
  update(params[:locator_record]) if params[:locator_record]
  ###################################################################################
  # check to see if the dealer name should be updated
  new_dealer_name = params[:dealer_name].to_s.strip
  # only do if it's not blank and the customer name doesn't already contain it (strip both first)
  unless new_dealer_name.blank? || customer.name.strip.index(new_dealer_name)
    # ok, now see if it's at least 3 characters long and contains some alphabetical character
    if new_dealer_name.length >= 3 && new_dealer_name =~ /([A-Z]|[a-z])/
      customer.name = new_dealer_name
      customer.save
    end
  end
  ###################################################################################
  # check to see if the dealer contact points should be updated
  cp_types = %w[email phone fax website]
  new_dealer_cps = []
  cp_types.each do |cp_type|
    # get contact point detail from params (remove any 'http://' in the detail)
    new_dealer_cp_detail = params["dealer_#{cp_type}"].to_s.strip.gsub('http://', '').downcase
    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: Checking!!! #{cp_type}: #{new_dealer_cp_detail}"
    new_dealer_cp = ContactPoint.new(detail: new_dealer_cp_detail, category: cp_type)
    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: new_dealer_cp: #{new_dealer_cp.inspect}"
    # only add to the new contact point validation list if it's not blank
    new_dealer_cps << new_dealer_cp if new_dealer_cp_detail.present?
    # test if new cp is valid, allow blank since that will force blank out that contact point
    next unless new_dealer_cp.errors.empty? || new_dealer_cp_detail.blank?

    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: TRUE: new_dealer_cp.errors.empty? || new_dealer_cp_detail.blank?"
    # handle callable vs the other types
    lr_cp = if cp_type == 'phone'
              get_callable_cp
            else
              get_cp_by_category(cp_type)
            end
    # test if it has the same detail
    next if (begin
      lr_cp.detail
    rescue StandardError
      nil
    end).to_s.strip.downcase == new_dealer_cp_detail

    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: FALSE: ((lr_cp.detail rescue nil).to_s.strip.downcase == new_dealer_cp_detail)"
    # not the same, remove this one, if it's blank we assume it is a delete request
    contact_points.delete(lr_cp) if lr_cp.present?
    next if new_dealer_cp_detail.blank?

    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: FALSE: new_dealer_cp_detail.blank?"
    # if it's not blank and different, scan each of the customer/contacts' contact points of type cp_type to see if it's one of those
    # handle callable vs the other types
    new_cp = if cp_type == 'phone'
               customer.contacts_and_self_callable_contact_points.detect { |cp| cp.detail.to_s.strip.downcase == new_dealer_cp_detail }
             else
               customer.contacts_and_self_contact_points_by_category(cp_type).detect { |cp| cp.detail.to_s.strip.downcase == new_dealer_cp_detail }
             end
    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: new_cp: type: #{new_cp.category rescue nil}, detail: #{new_cp.detail rescue nil}"
    new_cp ||= customer.contact_points.create(detail: new_dealer_cp_detail, category: cp_type)
    # add the contact point to the locator record
    contact_points << new_cp
  end
  ###################################################################################
  # check that address needs to be updated
  # check that address is valid
  new_dealer_address = Address.new(params[:dealer_address])
  # puts "params[:dealer_address]: #{params[:dealer_address]}"
  new_dealer_address.party_id = customer.id
  valid_address = new_dealer_address.geocode_me
  if valid_address && new_dealer_address.valid?
    # puts "valid_address: #{valid_address}"
    #  and isn't the same as the existing
    unless address.same_as(new_dealer_address)
      # puts "not the same as the existing address"
      # see if it's in the customer already
      dealer_address = customer.all_related_addresses.detect { |a| a.same_as(new_dealer_address) }
      unless dealer_address
        # puts "not the same as any existing address in customer"
        # nope so see if it's really close geocode wise to one of the existing, use 1000 ft since there's a big variation in these geocodings
        dealer_address = customer.all_related_addresses.detect { |a| new_dealer_address.distance_to(a) < 0.189 }
        unless dealer_address
          # puts "not real close to any existing address in customer"
          # nope so create it in the customer
          new_dealer_address.save
          # puts "new_dealer_address.errors: #{new_dealer_address.errors_to_s}"
          # puts "saving new: new_dealer_address.id: #{new_dealer_address.id rescue 'nil'}"
          dealer_address = new_dealer_address
          customer.addresses << dealer_address
        end
      end
      # puts "new_dealer_address.id: #{new_dealer_address.id rescue 'nil'}"
      self.address = dealer_address
      save
    end
  end
  if errors.empty? && new_dealer_address.errors.empty? && new_dealer_cps.all? { |cp| cp.errors.empty? }
    dealer_confirm
    res = 'ok'
    ###################################################################################
    # check to see if the dealer ordered display materials
    schedule_dealer_locator_activity(task_type = 'DISPINF') if params[:order_infloor_display] == '1'
    schedule_dealer_locator_activity(task_type = 'DISPHCTD') if params[:order_countertop_display] == '1'
    schedule_dealer_locator_activity(task_type = 'BINDER') if params[:order_marketing_materials] == '1'
  else
    all_error_messages = []
    all_error_messages.concat(new_dealer_address.errors.full_messages.dup)
    new_dealer_cps.each do |cp|
      # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: cp errors: #{cp.errors.full_messages.dup}, detail: #{cp.category rescue 'nil'}, detail: #{cp.detail rescue 'nil'}" unless cp.errors.full_messages.empty?
      all_error_messages.concat(cp.errors.full_messages.dup)
    end
    all_error_messages.concat(errors.full_messages.dup)
    # logger.warn "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!confirm_by_email_link: lr errors: #{self.errors.full_messages.dup}" unless self.errors.full_messages.empty?
    res = all_error_messages.join(' and ').to_s
  end
  res
end

#websiteObject



247
248
249
# File 'app/models/locator_record.rb', line 247

def website
  contact_points.by_category('website').first&.detail
end

#website_idObject



243
244
245
# File 'app/models/locator_record.rb', line 243

def website_id
  contact_points.by_category('website').first&.id
end

#website_id=(cp_id) ⇒ Object



234
235
236
237
238
239
240
241
# File 'app/models/locator_record.rb', line 234

def website_id=(cp_id)
  current_cp = contact_points.detect { |cp| cp.category == 'website' }
  contact_points.delete(current_cp) if current_cp
  return if cp_id.blank?

  cp = ContactPoint.find(cp_id)
  contact_points << cp
end

#whitelistObject



255
# File 'app/models/locator_record.rb', line 255

def whitelist; end