feat: Introduce the crm_v2 feature flag for CRM changes (#12014)
Introduce crm_v2 feature flag for our upcoming optimisations for CRM --------- Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
committed by
GitHub
parent
e5ee6027b4
commit
286e3a449d
@@ -122,7 +122,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||
def resolved_contacts
|
||||
return @resolved_contacts if @resolved_contacts
|
||||
|
||||
@resolved_contacts = Current.account.contacts.resolved_contacts
|
||||
@resolved_contacts = Current.account.contacts.resolved_contacts(use_crm_v2: Current.account.feature_enabled?('crm_v2'))
|
||||
|
||||
@resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present?
|
||||
@resolved_contacts
|
||||
|
||||
@@ -29,9 +29,9 @@ class Account::ContactsExportJob < ApplicationJob
|
||||
result = ::Contacts::FilterService.new(@account, @account_user, @params).perform
|
||||
result[:contacts]
|
||||
elsif @params[:label].present?
|
||||
@account.contacts.resolved_contacts.tagged_with(@params[:label], any: true)
|
||||
@account.contacts.resolved_contacts(use_crm_v2: @account.feature_enabled?('crm_v2')).tagged_with(@params[:label], any: true)
|
||||
else
|
||||
@account.contacts.resolved_contacts
|
||||
@account.contacts.resolved_contacts(use_crm_v2: @account.feature_enabled?('crm_v2'))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
# Indexes
|
||||
#
|
||||
# index_contacts_on_account_id (account_id)
|
||||
# index_contacts_on_account_id_and_contact_type (account_id,contact_type)
|
||||
# index_contacts_on_account_id_and_last_activity_at (account_id,last_activity_at DESC NULLS LAST)
|
||||
# index_contacts_on_blocked (blocked)
|
||||
# index_contacts_on_lower_email_account_id (lower((email)::text), account_id)
|
||||
@@ -175,8 +176,12 @@ class Contact < ApplicationRecord
|
||||
}
|
||||
end
|
||||
|
||||
def self.resolved_contacts
|
||||
where("contacts.email <> '' OR contacts.phone_number <> '' OR contacts.identifier <> ''")
|
||||
def self.resolved_contacts(use_crm_v2: false)
|
||||
if use_crm_v2
|
||||
where(contact_type: 'lead')
|
||||
else
|
||||
where("contacts.email <> '' OR contacts.phone_number <> '' OR contacts.identifier <> ''")
|
||||
end
|
||||
end
|
||||
|
||||
def discard_invalid_attrs
|
||||
|
||||
@@ -95,7 +95,9 @@ class SearchService
|
||||
@contacts = current_account.contacts.where(
|
||||
"name ILIKE :search OR email ILIKE :search OR phone_number
|
||||
ILIKE :search OR identifier ILIKE :search", search: "%#{search_query}%"
|
||||
).resolved_contacts.order_on_last_activity_at('desc').page(params[:page]).per(15)
|
||||
).resolved_contacts(
|
||||
use_crm_v2: current_account.feature_enabled?('crm_v2')
|
||||
).order_on_last_activity_at('desc').page(params[:page]).per(15)
|
||||
end
|
||||
|
||||
def filter_articles
|
||||
|
||||
@@ -187,3 +187,7 @@
|
||||
- name: whatsapp_campaign
|
||||
display_name: WhatsApp Campaign
|
||||
enabled: false
|
||||
- name: crm_v2
|
||||
display_name: CRM V2
|
||||
enabled: false
|
||||
chatwoot_internal: true
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class AddIndexOnContactTypeAndAccountIdToContacts < ActiveRecord::Migration[7.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :contacts, [:account_id, :contact_type], name: 'index_contacts_on_account_id_and_contact_type', algorithm: :concurrently
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_07_14_104358) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_07_22_152516) do
|
||||
# These extensions should be enabled to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "pg_trgm"
|
||||
@@ -539,6 +539,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_07_14_104358) do
|
||||
t.string "country_code", default: ""
|
||||
t.boolean "blocked", default: false, null: false
|
||||
t.index "lower((email)::text), account_id", name: "index_contacts_on_lower_email_account_id"
|
||||
t.index ["account_id", "contact_type"], name: "index_contacts_on_account_id_and_contact_type"
|
||||
t.index ["account_id", "email", "phone_number", "identifier"], name: "index_contacts_on_nonempty_fields", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))"
|
||||
t.index ["account_id", "last_activity_at"], name: "index_contacts_on_account_id_and_last_activity_at", order: { last_activity_at: "DESC NULLS LAST" }
|
||||
t.index ["account_id"], name: "index_contacts_on_account_id"
|
||||
|
||||
@@ -102,4 +102,98 @@ RSpec.describe Contact do
|
||||
expect(contact.contact_type).to eq 'lead'
|
||||
end
|
||||
end
|
||||
|
||||
describe '.resolved_contacts' do
|
||||
let(:account) { create(:account) }
|
||||
|
||||
context 'when crm_v2 feature flag is disabled' do
|
||||
it 'returns contacts with email, phone_number, or identifier using feature flag value' do
|
||||
# Create contacts with different attributes
|
||||
contact_with_email = create(:contact, account: account, email: 'test@example.com', name: 'John Doe')
|
||||
contact_with_phone = create(:contact, account: account, phone_number: '+1234567890', name: 'Jane Smith')
|
||||
contact_with_identifier = create(:contact, account: account, identifier: 'user123', name: 'Bob Wilson')
|
||||
contact_without_details = create(:contact, account: account, name: 'Alice Johnson', email: nil, phone_number: nil, identifier: nil)
|
||||
|
||||
resolved = account.contacts.resolved_contacts(use_crm_v2: false)
|
||||
|
||||
expect(resolved).to include(contact_with_email, contact_with_phone, contact_with_identifier)
|
||||
expect(resolved).not_to include(contact_without_details)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when crm_v2 feature flag is enabled' do
|
||||
it 'returns only contacts with contact_type lead' do
|
||||
# Contact with email and phone - should be marked as lead
|
||||
contact_with_details = create(:contact, account: account, email: 'customer@example.com', phone_number: '+1234567890', name: 'Customer One')
|
||||
expect(contact_with_details.contact_type).to eq('lead')
|
||||
|
||||
# Contact without email/phone - should be marked as visitor
|
||||
contact_without_details = create(:contact, account: account, name: 'Lead', email: nil, phone_number: nil)
|
||||
expect(contact_without_details.contact_type).to eq('visitor')
|
||||
|
||||
# Force set contact_type to lead for testing
|
||||
contact_without_details.update!(contact_type: 'lead')
|
||||
|
||||
resolved = account.contacts.resolved_contacts(use_crm_v2: true)
|
||||
|
||||
expect(resolved).to include(contact_with_details)
|
||||
expect(resolved).to include(contact_without_details)
|
||||
end
|
||||
|
||||
it 'includes all lead contacts regardless of email/phone presence' do
|
||||
# Create a lead contact with only name
|
||||
lead_contact = create(:contact, account: account, name: 'Test Lead')
|
||||
lead_contact.update!(contact_type: 'lead')
|
||||
|
||||
# Create a customer contact
|
||||
customer_contact = create(:contact, account: account, email: 'customer@test.com')
|
||||
customer_contact.update!(contact_type: 'customer')
|
||||
|
||||
# Create a visitor contact
|
||||
visitor_contact = create(:contact, account: account, name: 'Visitor')
|
||||
expect(visitor_contact.contact_type).to eq('visitor')
|
||||
|
||||
resolved = account.contacts.resolved_contacts(use_crm_v2: true)
|
||||
|
||||
expect(resolved).to include(lead_contact)
|
||||
expect(resolved).not_to include(customer_contact)
|
||||
expect(resolved).not_to include(visitor_contact)
|
||||
end
|
||||
|
||||
it 'returns contacts with email, phone_number, or identifier when explicitly passing use_crm_v2: false' do
|
||||
# Even though feature flag is enabled, we're explicitly passing false
|
||||
contact_with_email = create(:contact, account: account, email: 'test@example.com', name: 'John Doe')
|
||||
contact_with_phone = create(:contact, account: account, phone_number: '+1234567890', name: 'Jane Smith')
|
||||
contact_without_details = create(:contact, account: account, name: 'Alice Johnson', email: nil, phone_number: nil, identifier: nil)
|
||||
|
||||
resolved = account.contacts.resolved_contacts(use_crm_v2: false)
|
||||
|
||||
# Should use the old logic despite feature flag being enabled
|
||||
expect(resolved).to include(contact_with_email, contact_with_phone)
|
||||
expect(resolved).not_to include(contact_without_details)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with mixed contact types' do
|
||||
it 'correctly filters based on use_crm_v2 parameter regardless of feature flag' do
|
||||
# Create different types of contacts
|
||||
visitor_contact = create(:contact, account: account, name: 'Visitor')
|
||||
lead_with_email = create(:contact, account: account, email: 'lead@example.com', name: 'Lead')
|
||||
lead_without_email = create(:contact, account: account, name: 'Lead Only')
|
||||
lead_without_email.update!(contact_type: 'lead')
|
||||
customer_contact = create(:contact, account: account, email: 'customer@example.com', name: 'Customer')
|
||||
customer_contact.update!(contact_type: 'customer')
|
||||
|
||||
# Test with use_crm_v2: false
|
||||
resolved_old = account.contacts.resolved_contacts(use_crm_v2: false)
|
||||
expect(resolved_old).to include(lead_with_email, customer_contact)
|
||||
expect(resolved_old).not_to include(visitor_contact, lead_without_email)
|
||||
|
||||
# Test with use_crm_v2: true
|
||||
resolved_new = account.contacts.resolved_contacts(use_crm_v2: true)
|
||||
expect(resolved_new).to include(lead_with_email, lead_without_email)
|
||||
expect(resolved_new).not_to include(visitor_contact, customer_contact)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user