Class: Query::CustomerFinder
- Inherits:
-
Object
- Object
- Query::CustomerFinder
- Defined in:
- app/services/query/customer_finder.rb
Overview
Service object: customer finder.
Instance Attribute Summary collapse
-
#customer_scope ⇒ Object
readonly
Returns the value of attribute customer_scope.
-
#search_params ⇒ Object
readonly
Returns the value of attribute search_params.
Instance Method Summary collapse
- #cell ⇒ Object
- #company_name ⇒ Object
- #coordinate ⇒ Object
- #coordinates ⇒ Object
- #email ⇒ Object
- #email2 ⇒ Object
- #exclude_customer_ids ⇒ Object
- #fax ⇒ Object
- #find_contact_points ⇒ Object
- #find_duplicates ⇒ Object
- #find_matching_customer_names ⇒ Object
- #find_matching_person_names ⇒ Object
- #find_party_nearby ⇒ Object
-
#initialize(search_params = {}) ⇒ CustomerFinder
constructor
A new instance of CustomerFinder.
- #lat ⇒ Object
- #lng ⇒ Object
- #person_first_name ⇒ Object
- #person_last_name ⇒ Object
- #person_name ⇒ Object
- #phone ⇒ Object
- #phone2 ⇒ Object
- #split_person_name ⇒ Object
Constructor Details
#initialize(search_params = {}) ⇒ CustomerFinder
Returns a new instance of CustomerFinder.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'app/services/query/customer_finder.rb', line 6 def initialize(search_params = {}) # Callers key this hash differently: the customers controller passes # symbol keys ({ customer: … }), while Customer::NewCustomer passes its # ActiveModel attributes hash, which has STRING keys. Every accessor below # reads @search_params[:symbol], so normalize to indifferent access — a # Virtus→ActiveModel::Attributes migration flipped NewCustomer#attributes # to string keys and silently broke the new-customer duplicate check. @search_params = (search_params || {}).to_h.with_indifferent_access # Extract components if (customer = @search_params[:customer]) @search_params[:email] = customer.all_emails @search_params[:phone] = customer.all_phone_numbers @search_params[:company_name] = customer.full_name @search_params[:person_names] = customer.contacts.active.pluck(:full_name) @search_params[:person_names] << customer.full_name if customer.is_homeowner? @search_params[:coordinates] = customer.addresses.filter_map { |a| a.lat.present? && a.lng.present? ? [a.lat, a.lng] : nil }.uniq @search_params[:exclude_customer_ids] = [customer.id] end @customer_scope = search_params[:customer_scope] || Customer.all @customer_scope = @customer_scope.where.not(id: exclude_customer_ids) if exclude_customer_ids.present? end |
Instance Attribute Details
#customer_scope ⇒ Object (readonly)
Returns the value of attribute customer_scope.
4 5 6 |
# File 'app/services/query/customer_finder.rb', line 4 def customer_scope @customer_scope end |
#search_params ⇒ Object (readonly)
Returns the value of attribute search_params.
4 5 6 |
# File 'app/services/query/customer_finder.rb', line 4 def search_params @search_params end |
Instance Method Details
#cell ⇒ Object
45 46 47 |
# File 'app/services/query/customer_finder.rb', line 45 def cell @search_params[:cell].presence end |
#company_name ⇒ Object
53 54 55 |
# File 'app/services/query/customer_finder.rb', line 53 def company_name @search_params[:company_name].presence end |
#coordinate ⇒ Object
78 79 80 |
# File 'app/services/query/customer_finder.rb', line 78 def coordinate lat.nil? || lng.nil? ? nil : [lat, lng] end |
#coordinates ⇒ Object
73 74 75 76 |
# File 'app/services/query/customer_finder.rb', line 73 def coordinates res = @search_params[:coordinates] || [coordinate] res.uniq.compact.select { |coord| coord.length == 2 } end |
#email ⇒ Object
29 30 31 |
# File 'app/services/query/customer_finder.rb', line 29 def email @search_params[:email].presence end |
#email2 ⇒ Object
33 34 35 |
# File 'app/services/query/customer_finder.rb', line 33 def email2 @search_params[:email2].presence end |
#exclude_customer_ids ⇒ Object
82 83 84 |
# File 'app/services/query/customer_finder.rb', line 82 def exclude_customer_ids [@search_params[:exclude_customer_ids]].flatten.compact.uniq end |
#fax ⇒ Object
49 50 51 |
# File 'app/services/query/customer_finder.rb', line 49 def fax @search_params[:fax].presence end |
#find_contact_points ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'app/services/query/customer_finder.rb', line 101 def find_contact_points phones = [phone, phone2, cell].flatten.map(&:presence).uniq.compact phones = phones.filter_map { |p| PhoneNumber.parse_and_format(p) } details = phones + [email, email2].flatten.map(&:presence).uniq.compact return ContactPoint.none if details.blank? contact_points = ContactPoint.belonging_to_party.where(detail: details) party_ids = [] if contact_points.present? party_ids = contact_points.pluck(:party_id) else # Try email match on domain [email, email2].compact.each do |e| domain = QuickSearch::ContactPointEmailQuickSearch.domain_scan(e) if domain domain_contact_points = ContactPoint.emails.joins(:party).where.not(Party[:inactive].eq(true)).contains("@#{domain}") party_ids += domain_contact_points.pluck(:party_id) end end end party_ids.compact.uniq end |
#find_duplicates ⇒ Object
94 95 96 97 98 99 |
# File 'app/services/query/customer_finder.rb', line 94 def find_duplicates party_ids = [find_matching_customer_names, find_matching_person_names, find_contact_points, find_party_nearby].flatten.compact.uniq customers = customer_scope.where("parties.id IN (:party_id) or exists(select 1 from parties cnt where cnt.id IN (:party_id) and cnt.customer_id = parties.id)", party_id: party_ids) customers = customers.where.not(id: exclude_customer_ids) if exclude_customer_ids.present? customers end |
#find_matching_customer_names ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'app/services/query/customer_finder.rb', line 123 def find_matching_customer_names [company_name, person_name].flatten.map(&:presence).uniq.compact.map do |customer_name| # filter out noise words search_name = customer_name.split(/[ ,.\-&]/).delete_if do |x| segment = x.squish.downcase %w[inc inc llc ltd].include?(segment) || segment.length <= 2 end&.join(' ') cids = [] cids += customer_scope.where(Customer[:full_name].matches("%#{search_name}%")).limit(5).ids cids += customer_scope.lookup(search_name).limit(6).ids # cids += customer_scope.where("full_name ILIKE ?", "%#{search_name}%").limit(2).pluck(:id) cids end.flatten.uniq end |
#find_matching_person_names ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'app/services/query/customer_finder.rb', line 138 def find_matching_person_names [person_name].flatten.map(&:presence).uniq.compact.map do |full_name| # For the purpose of finding contact matches, we will only use firstname, lastname but we will still try an exact match pnp = PersonNameParser.new(full_name) # Only attempt match if we have first and last name or we'll have a lot of junk next unless pnp.first && pnp.last Contact.where(Contact[:full_name].matches("%#{pnp.simple_name}%")).where.not(customer_id: nil).limit(5).pluck(:customer_id) + Contact.lookup(pnp.full_name).limit(6).pluck(:customer_id) # Contact.where( "full_name ILIKE ?", "%#{pnp.simple_name}%").limit(2).pluck(:customer_id) end.flatten.uniq end |
#find_party_nearby ⇒ Object
151 152 153 154 155 |
# File 'app/services/query/customer_finder.rb', line 151 def find_party_nearby coordinates.map do |coord| Address.geocoded.where.not(party_id: nil).near(coord, 0.1).map(&:party_id) end end |
#lat ⇒ Object
86 87 88 |
# File 'app/services/query/customer_finder.rb', line 86 def lat @search_params[:lat].presence ? @search_params[:lat].to_f : nil end |
#lng ⇒ Object
90 91 92 |
# File 'app/services/query/customer_finder.rb', line 90 def lng @search_params[:lng].presence ? @search_params[:lng].to_f : nil end |
#person_first_name ⇒ Object
61 62 63 |
# File 'app/services/query/customer_finder.rb', line 61 def person_first_name split_person_name.first end |
#person_last_name ⇒ Object
65 66 67 |
# File 'app/services/query/customer_finder.rb', line 65 def person_last_name split_person_name.last end |
#person_name ⇒ Object
57 58 59 |
# File 'app/services/query/customer_finder.rb', line 57 def person_name @search_params[:person_name].presence end |
#phone ⇒ Object
37 38 39 |
# File 'app/services/query/customer_finder.rb', line 37 def phone @search_params[:phone].presence end |
#phone2 ⇒ Object
41 42 43 |
# File 'app/services/query/customer_finder.rb', line 41 def phone2 @search_params[:phone2].presence end |
#split_person_name ⇒ Object
69 70 71 |
# File 'app/services/query/customer_finder.rb', line 69 def split_person_name @split_person_name ||= PersonNameParser.new(person_name) end |