Class: Query::CustomerFinder

Inherits:
Object
  • Object
show all
Defined in:
app/services/query/customer_finder.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(search_params = {}) ⇒ CustomerFinder

Returns a new instance of CustomerFinder.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'app/services/query/customer_finder.rb', line 5

def initialize(search_params = {})
  @search_params = search_params
  #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.map{|a| (a.lat.present? and a.lng.present?) ? [a.lat,a.lng] : nil }.compact.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_scopeObject (readonly)

Returns the value of attribute customer_scope.



3
4
5
# File 'app/services/query/customer_finder.rb', line 3

def customer_scope
  @customer_scope
end

#search_paramsObject (readonly)

Returns the value of attribute search_params.



3
4
5
# File 'app/services/query/customer_finder.rb', line 3

def search_params
  @search_params
end

Instance Method Details

#cellObject



38
39
40
# File 'app/services/query/customer_finder.rb', line 38

def cell
  @search_params[:cell].presence
end

#company_nameObject



46
47
48
# File 'app/services/query/customer_finder.rb', line 46

def company_name
  @search_params[:company_name].presence
end

#coordinateObject



71
72
73
# File 'app/services/query/customer_finder.rb', line 71

def coordinate
  ( lat.nil? or lng.nil? ) ? nil : [lat,lng]
end

#coordinatesObject



66
67
68
69
# File 'app/services/query/customer_finder.rb', line 66

def coordinates
  res = @search_params[:coordinates] || [coordinate]
  res.uniq.compact.select{|coord| coord.length == 2}
end

#emailObject



22
23
24
# File 'app/services/query/customer_finder.rb', line 22

def email
  @search_params[:email].presence
end

#email2Object



26
27
28
# File 'app/services/query/customer_finder.rb', line 26

def email2
  @search_params[:email2].presence
end

#exclude_customer_idsObject



75
76
77
# File 'app/services/query/customer_finder.rb', line 75

def exclude_customer_ids
  [ @search_params[:exclude_customer_ids] ].flatten.compact.uniq
end

#faxObject



42
43
44
# File 'app/services/query/customer_finder.rb', line 42

def fax
  @search_params[:fax].presence
end

#find_contact_pointsObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'app/services/query/customer_finder.rb', line 96

def find_contact_points
  phones = [phone, phone2, cell].flatten.map(&:presence).uniq.compact
  phones = phones.map{|p| PhoneNumber.parse_and_format(p) }.compact
  details = phones + [email, email2].flatten.map(&:presence).uniq.compact
  return ContactPoint.none unless details.present?
  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_duplicatesObject



87
88
89
90
91
92
93
94
# File 'app/services/query/customer_finder.rb', line 87

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 )
  if exclude_customer_ids.present?
    customers = customers.where.not(id: exclude_customer_ids)
  end
  customers
end

#find_matching_customer_namesObject



117
118
119
120
121
122
123
124
125
126
127
# File 'app/services/query/customer_finder.rb', line 117

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{|x| segment = x.squish.downcase; ['inc','inc','llc','ltd'].include?(segment) || segment.length <= 2 }&.join(' ')
    cids = []
    cids += customer_scope.where(Customer[:full_name].matches("%#{search_name}%")).limit(5).pluck(:id)
    cids += customer_scope.lookup(search_name).limit(6).pluck(:id)
    # cids += customer_scope.where("full_name ILIKE ?", "%#{search_name}%").limit(2).pluck(:id)
    cids
  end.flatten.uniq
end

#find_matching_person_namesObject



129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'app/services/query/customer_finder.rb', line 129

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
    if 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)
    else
      nil
    end
  end.flatten.uniq
end

#find_party_nearbyObject



144
145
146
147
148
# File 'app/services/query/customer_finder.rb', line 144

def find_party_nearby
  coordinates.map do |coord|
    Address.geocoded.where.not(party_id: nil).near(coord,0.1).map(&:party_id)
  end
end

#latObject



79
80
81
# File 'app/services/query/customer_finder.rb', line 79

def lat
  @search_params[:lat].presence ? @search_params[:lat].to_f : nil
end

#lngObject



83
84
85
# File 'app/services/query/customer_finder.rb', line 83

def lng
  @search_params[:lng].presence ? @search_params[:lng].to_f : nil
end

#person_first_nameObject



54
55
56
# File 'app/services/query/customer_finder.rb', line 54

def person_first_name
  split_person_name.first
end

#person_last_nameObject



58
59
60
# File 'app/services/query/customer_finder.rb', line 58

def person_last_name
  split_person_name.last
end

#person_nameObject



50
51
52
# File 'app/services/query/customer_finder.rb', line 50

def person_name
  @search_params[:person_name].presence
end

#phoneObject



30
31
32
# File 'app/services/query/customer_finder.rb', line 30

def phone
  @search_params[:phone].presence
end

#phone2Object



34
35
36
# File 'app/services/query/customer_finder.rb', line 34

def phone2
  @search_params[:phone2].presence
end

#split_person_nameObject



62
63
64
# File 'app/services/query/customer_finder.rb', line 62

def split_person_name
  @split_person_name ||= PersonNameParser.new(person_name)
end