From 586552013ef5556816abf141744c1de49146309f Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Fri, 15 Mar 2024 10:55:40 +0530 Subject: [PATCH] feat: Update the `contact_type` when creating or updating the contact (#9107) * feat: Update location and country code when the contact create/update * feat: Update the location and country_code when creating or updating the contact. * chore: improve comments * feat: Update the contact_type when the contact created/updated * chore: add more specs * chore: code cleanups * chore: code cleanups * Update contact_spec.rb * Update inbox.rb * Update sync_attributes_spec.rb * chore: build fixes * chore: check visitor type before update * chore: review fixes --- app/models/contact.rb | 9 ++-- app/services/contacts/sync_attributes.rb | 37 +++++++++++++++ spec/models/contact_spec.rb | 19 ++++++++ .../services/contacts/sync_attributes_spec.rb | 46 +++++++++++++++++++ 4 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 app/services/contacts/sync_attributes.rb create mode 100644 spec/services/contacts/sync_attributes_spec.rb diff --git a/app/models/contact.rb b/app/models/contact.rb index 1f3d2fb90..a60e9f4d2 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -61,7 +61,7 @@ class Contact < ApplicationRecord after_create_commit :dispatch_create_event, :ip_lookup after_update_commit :dispatch_update_event after_destroy_commit :dispatch_destroy_event - before_save :update_contact_location_and_country_code + before_save :sync_contact_attributes enum contact_type: { visitor: 0, lead: 1, customer: 2 } @@ -207,11 +207,8 @@ class Contact < ApplicationRecord self.custom_attributes = {} if custom_attributes.blank? end - def update_contact_location_and_country_code - # TODO: Ensure that location and country_code are updated from additional_attributes. - # We will remove this once all contacts are updated and both the location and country_code fields are standardized throughout the app. - self.location = additional_attributes['city'] - self.country_code = additional_attributes['country'] + def sync_contact_attributes + ::Contacts::SyncAttributes.new(self).perform end def dispatch_create_event diff --git a/app/services/contacts/sync_attributes.rb b/app/services/contacts/sync_attributes.rb new file mode 100644 index 000000000..bc10def66 --- /dev/null +++ b/app/services/contacts/sync_attributes.rb @@ -0,0 +1,37 @@ +class Contacts::SyncAttributes + attr_reader :contact + + def initialize(contact) + @contact = contact + end + + def perform + update_contact_location_and_country_code + set_contact_type + end + + private + + def update_contact_location_and_country_code + # Ensure that location and country_code are updated from additional_attributes. + # TODO: Remove this once all contacts are updated and both the location and country_code fields are standardized throughout the app. + @contact.location = @contact.additional_attributes['city'] + @contact.country_code = @contact.additional_attributes['country'] + end + + def set_contact_type + # If the contact is already a lead or customer then do not change the contact type + return unless @contact.contact_type == 'visitor' + # If the contact has an email or phone number or social details( facebook_user_id, instagram_user_id, etc) then it is a lead + # If contact is from external channel like facebook, instagram, whatsapp, etc then it is a lead + return unless @contact.email.present? || @contact.phone_number.present? || social_details_present? + + @contact.contact_type = 'lead' + end + + def social_details_present? + @contact.additional_attributes.keys.any? do |key| + key.start_with?('social_') && @contact.additional_attributes[key].present? + end + end +end diff --git a/spec/models/contact_spec.rb b/spec/models/contact_spec.rb index ff186466a..2ca65fa4e 100644 --- a/spec/models/contact_spec.rb +++ b/spec/models/contact_spec.rb @@ -22,11 +22,13 @@ RSpec.describe Contact do it 'sets email to lowercase' do contact = create(:contact, email: 'Test@test.com') expect(contact.email).to eq('test@test.com') + expect(contact.contact_type).to eq('lead') end it 'sets email to nil when empty string' do contact = create(:contact, email: '') expect(contact.email).to be_nil + expect(contact.contact_type).to eq('visitor') end it 'sets custom_attributes to {} when nil' do @@ -83,4 +85,21 @@ RSpec.describe Contact do expect(contact.country_code).to eq 'US' end end + + context 'when a contact is created' do + it 'has contact type "visitor" by default' do + contact = create(:contact) + expect(contact.contact_type).to eq 'visitor' + end + + it 'has contact type "lead" when email is present' do + contact = create(:contact, email: 'test@test.com') + expect(contact.contact_type).to eq 'lead' + end + + it 'has contact type "lead" when contacted through a social channel' do + contact = create(:contact, additional_attributes: { social_facebook_user_id: '123' }) + expect(contact.contact_type).to eq 'lead' + end + end end diff --git a/spec/services/contacts/sync_attributes_spec.rb b/spec/services/contacts/sync_attributes_spec.rb new file mode 100644 index 000000000..447bcd740 --- /dev/null +++ b/spec/services/contacts/sync_attributes_spec.rb @@ -0,0 +1,46 @@ +# spec/services/contacts/sync_attributes_spec.rb + +require 'rails_helper' + +RSpec.describe Contacts::SyncAttributes do + describe '#perform' do + let(:contact) { create(:contact, additional_attributes: { 'city' => 'New York', 'country' => 'US' }) } + + context 'when contact has neither email/phone number nor social details' do + it 'does not change contact type' do + described_class.new(contact).perform + expect(contact.reload.contact_type).to eq('visitor') + end + end + + context 'when contact has email or phone number' do + it 'sets contact type to lead' do + contact.email = 'test@test.com' + contact.save + described_class.new(contact).perform + + expect(contact.reload.contact_type).to eq('lead') + end + end + + context 'when contact has social details' do + it 'sets contact type to lead' do + contact.additional_attributes['social_facebook_user_id'] = '123456789' + contact.save + described_class.new(contact).perform + + expect(contact.reload.contact_type).to eq('lead') + end + end + + context 'when location and country code are updated from additional attributes' do + it 'updates location and country code' do + described_class.new(contact).perform + + # Expect location and country code to be updated + expect(contact.reload.location).to eq('New York') + expect(contact.reload.country_code).to eq('US') + end + end + end +end