feat: exporting contacts takes the filters into account (#9347)

- This PR allows contacts to be exported using the current filter in CRM view

Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
Shivam Mishra
2024-05-08 08:48:36 +05:30
committed by GitHub
parent de044e29f0
commit 2ef767d60f
12 changed files with 213 additions and 65 deletions

View File

@@ -46,7 +46,8 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def export def export
column_names = params['column_names'] column_names = params['column_names']
Account::ContactsExportJob.perform_later(Current.account.id, column_names, Current.user.email) filter_params = { :payload => params.permit!['payload'], :label => params.permit!['label'] }
Account::ContactsExportJob.perform_later(Current.account.id, Current.user.id, column_names, filter_params)
head :ok, message: I18n.t('errors.contacts.export.success') head :ok, message: I18n.t('errors.contacts.export.success')
end end
@@ -61,7 +62,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def show; end def show; end
def filter def filter
result = ::Contacts::FilterService.new(params.permit!, current_user).perform result = ::Contacts::FilterService.new(Current.account, Current.user, params.permit!).perform
contacts = result[:contacts] contacts = result[:contacts]
@contacts_count = result[:count] @contacts_count = result[:count]
@contacts = fetch_contacts(contacts) @contacts = fetch_contacts(contacts)

View File

@@ -77,8 +77,8 @@ class ContactAPI extends ApiClient {
return axios.delete(`${this.url}/${contactId}/avatar`); return axios.delete(`${this.url}/${contactId}/avatar`);
} }
exportContacts() { exportContacts(queryPayload) {
return axios.get(`${this.url}/export`); return axios.post(`${this.url}/export`, queryPayload);
} }
} }

View File

@@ -84,6 +84,7 @@
"CONFIRM": { "CONFIRM": {
"TITLE": "Export Contacts", "TITLE": "Export Contacts",
"MESSAGE": "Are you sure you want to export all contacts?", "MESSAGE": "Are you sure you want to export all contacts?",
"FILTERED_MESSAGE": "Are you sure you want to export all the filtered contacts?",
"YES": "Yes, Export", "YES": "Yes, Export",
"NO": "No, Cancel" "NO": "No, Cancel"
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="w-full flex flex-row"> <div class="flex flex-row w-full">
<div class="flex flex-col h-full" :class="wrapClass"> <div class="flex flex-col h-full" :class="wrapClass">
<contacts-header <contacts-header
:search-query="searchQuery" :search-query="searchQuery"
@@ -391,8 +391,19 @@ export default {
this.fetchContacts(this.pageParameter); this.fetchContacts(this.pageParameter);
}, },
onExportSubmit() { onExportSubmit() {
let query = { payload: [] };
if (this.hasActiveSegments) {
query = this.activeSegment.query;
} else if (this.hasAppliedFilters) {
query = filterQueryGenerator(this.getAppliedContactFilters);
}
try { try {
this.$store.dispatch('contacts/export'); this.$store.dispatch('contacts/export', {
...query,
label: this.label,
});
this.showAlert(this.$t('EXPORT_CONTACTS.SUCCESS_MESSAGE')); this.showAlert(this.$t('EXPORT_CONTACTS.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert( this.showAlert(

View File

@@ -1,12 +1,12 @@
<template> <template>
<header <header
class="bg-white dark:bg-slate-900 border-b border-slate-50 dark:border-slate-800" class="bg-white border-b dark:bg-slate-900 border-slate-50 dark:border-slate-800"
> >
<div class="flex justify-between w-full py-2 px-4"> <div class="flex justify-between w-full px-4 py-2">
<div class="flex items-center justify-center max-w-full min-w-[6.25rem]"> <div class="flex items-center justify-center max-w-full min-w-[6.25rem]">
<woot-sidemenu-icon /> <woot-sidemenu-icon />
<h1 <h1
class="m-0 text-xl text-slate-900 dark:text-slate-100 overflow-hidden whitespace-nowrap text-ellipsis my-0 mx-2" class="m-0 mx-2 my-0 overflow-hidden text-xl text-slate-900 dark:text-slate-100 whitespace-nowrap text-ellipsis"
> >
{{ headerTitle }} {{ headerTitle }}
</h1> </h1>
@@ -18,7 +18,7 @@
<div class="flex items-center absolute h-full left-2.5"> <div class="flex items-center absolute h-full left-2.5">
<fluent-icon <fluent-icon
icon="search" icon="search"
class="h-5 leading-9 text-sm text-slate-700 dark:text-slate-200" class="h-5 text-sm leading-9 text-slate-700 dark:text-slate-200"
/> />
</div> </div>
<input <input
@@ -59,7 +59,7 @@
<div v-if="!hasActiveSegments" class="relative"> <div v-if="!hasActiveSegments" class="relative">
<div <div
v-if="hasAppliedFilters" v-if="hasAppliedFilters"
class="absolute h-2 w-2 top-1 right-3 bg-slate-500 dark:bg-slate-500 rounded-full" class="absolute w-2 h-2 rounded-full top-1 right-3 bg-slate-500 dark:bg-slate-500"
/> />
<woot-button <woot-button
class="clear" class="clear"
@@ -116,7 +116,7 @@
<woot-confirm-modal <woot-confirm-modal
ref="confirmExportContactsDialog" ref="confirmExportContactsDialog"
:title="$t('EXPORT_CONTACTS.CONFIRM.TITLE')" :title="$t('EXPORT_CONTACTS.CONFIRM.TITLE')"
:description="$t('EXPORT_CONTACTS.CONFIRM.MESSAGE')" :description="exportDescription"
:confirm-label="$t('EXPORT_CONTACTS.CONFIRM.YES')" :confirm-label="$t('EXPORT_CONTACTS.CONFIRM.YES')"
:cancel-label="$t('EXPORT_CONTACTS.CONFIRM.NO')" :cancel-label="$t('EXPORT_CONTACTS.CONFIRM.NO')"
/> />
@@ -162,6 +162,11 @@ export default {
hasActiveSegments() { hasActiveSegments() {
return this.segmentsId !== 0; return this.segmentsId !== 0;
}, },
exportDescription() {
return this.hasAppliedFilters
? this.$t('EXPORT_CONTACTS.CONFIRM.FILTERED_MESSAGE')
: this.$t('EXPORT_CONTACTS.CONFIRM.MESSAGE');
},
}, },
methods: { methods: {
onToggleSegmentsModal() { onToggleSegmentsModal() {

View File

@@ -138,9 +138,10 @@ export const actions = {
} }
}, },
export: async ({ commit }) => { export: async ({ commit }, { payload, label }) => {
try { try {
await ContactAPI.exportContacts(); await ContactAPI.exportContacts({ payload, label });
commit(types.SET_CONTACT_UI_FLAG, { isCreating: false }); commit(types.SET_CONTACT_UI_FLAG, { isCreating: false });
} catch (error) { } catch (error) {
commit(types.SET_CONTACT_UI_FLAG, { isCreating: false }); commit(types.SET_CONTACT_UI_FLAG, { isCreating: false });

View File

@@ -1,44 +1,62 @@
class Account::ContactsExportJob < ApplicationJob class Account::ContactsExportJob < ApplicationJob
queue_as :low queue_as :low
def perform(account_id, column_names, email_to) def perform(account_id, user_id, column_names, params)
account = Account.find(account_id) @account = Account.find(account_id)
headers = valid_headers(column_names) @params = params
generate_csv(account, headers) @account_user = @account.users.find(user_id)
file_url = account_contact_export_url(account)
AdministratorNotifications::ChannelNotificationsMailer.with(account: account).contact_export_complete(file_url, email_to)&.deliver_later headers = valid_headers(column_names)
generate_csv(headers)
send_mail
end end
def generate_csv(account, headers) private
def generate_csv(headers)
csv_data = CSV.generate do |csv| csv_data = CSV.generate do |csv|
csv << headers csv << headers
account.contacts.each do |contact| contacts.each do |contact|
csv << headers.map { |header| contact.send(header) } csv << headers.map { |header| contact.send(header) }
end end
end end
attach_export_file(account, csv_data) attach_export_file(csv_data)
end
def contacts
if @params.present? && @params[:payload].present? && @params[:payload].any?
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)
else
@account.contacts.resolved_contacts
end
end end
def valid_headers(column_names) def valid_headers(column_names)
columns = (column_names.presence || default_columns) (column_names.presence || default_columns) & Contact.column_names
headers = columns.map { |column| column if Contact.column_names.include?(column) }
headers.compact
end end
def attach_export_file(account, csv_data) def attach_export_file(csv_data)
return if csv_data.blank? return if csv_data.blank?
account.contacts_export.attach( @account.contacts_export.attach(
io: StringIO.new(csv_data), io: StringIO.new(csv_data),
filename: "#{account.name}_#{account.id}_contacts.csv", filename: "#{@account.name}_#{@account.id}_contacts.csv",
content_type: 'text/csv' content_type: 'text/csv'
) )
end end
def account_contact_export_url(account) def send_mail
Rails.application.routes.url_helpers.rails_blob_url(account.contacts_export) file_url = account_contact_export_url
mailer = AdministratorNotifications::ChannelNotificationsMailer.with(account: @account)
mailer.contact_export_complete(file_url, @account_user.email)&.deliver_later
end
def account_contact_export_url
Rails.application.routes.url_helpers.rails_blob_url(@account.contacts_export)
end end
def default_columns def default_columns

View File

@@ -1,6 +1,13 @@
class Contacts::FilterService < FilterService class Contacts::FilterService < FilterService
ATTRIBUTE_MODEL = 'contact_attribute'.freeze ATTRIBUTE_MODEL = 'contact_attribute'.freeze
def initialize(account, user, params)
@account = account
# TODO: Change the order of arguments in FilterService maybe?
# account, user, params makes more sense
super(params, user)
end
def perform def perform
@contacts = query_builder(@filters['contacts']) @contacts = query_builder(@filters['contacts'])
@@ -21,8 +28,9 @@ class Contacts::FilterService < FilterService
end end
end end
# TODO: @account.contacts.resolved_contacts ? to stay consistant with the behavior in ui
def base_relation def base_relation
Current.account.contacts @account.contacts
end end
def filter_config def filter_config

View File

@@ -125,7 +125,7 @@ Rails.application.routes.draw do
get :search get :search
post :filter post :filter
post :import post :import
get :export post :export
end end
member do member do
get :contactable_inboxes get :contactable_inboxes

View File

@@ -2,6 +2,16 @@ require 'rails_helper'
RSpec.describe 'Contacts API', type: :request do RSpec.describe 'Contacts API', type: :request do
let(:account) { create(:account) } let(:account) { create(:account) }
let(:email_filter) do
{
attribute_key: 'email',
filter_operator: 'contains',
values: 'looped',
query_operator: 'and',
attribute_model: 'standard',
custom_attribute_type: ''
}
end
describe 'GET /api/v1/accounts/{account.id}/contacts' do describe 'GET /api/v1/accounts/{account.id}/contacts' do
context 'when it is an unauthenticated user' do context 'when it is an unauthenticated user' do
@@ -175,7 +185,7 @@ RSpec.describe 'Contacts API', type: :request do
describe 'POST /api/v1/accounts/{account.id}/contacts/export' do describe 'POST /api/v1/accounts/{account.id}/contacts/export' do
context 'when it is an unauthenticated user' do context 'when it is an unauthenticated user' do
it 'returns unauthorized' do it 'returns unauthorized' do
get "/api/v1/accounts/#{account.id}/contacts/export" post "/api/v1/accounts/#{account.id}/contacts/export"
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
@@ -185,9 +195,9 @@ RSpec.describe 'Contacts API', type: :request do
let(:agent) { create(:user, account: account, role: :agent) } let(:agent) { create(:user, account: account, role: :agent) }
it 'returns unauthorized' do it 'returns unauthorized' do
get "/api/v1/accounts/#{account.id}/contacts/export", post "/api/v1/accounts/#{account.id}/contacts/export",
headers: agent.create_new_auth_token, headers: agent.create_new_auth_token,
as: :json as: :json
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
@@ -197,21 +207,35 @@ RSpec.describe 'Contacts API', type: :request do
let(:admin) { create(:user, account: account, role: :administrator) } let(:admin) { create(:user, account: account, role: :administrator) }
it 'enqueues a contact export job' do it 'enqueues a contact export job' do
expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, nil, admin.email).once expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, admin.id, nil, { :payload => nil, :label => nil }).once
get "/api/v1/accounts/#{account.id}/contacts/export", post "/api/v1/accounts/#{account.id}/contacts/export",
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token
params: { column_names: nil }
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
it 'enqueues a contact export job with sent_columns' do it 'enqueues a contact export job with sent_columns' do
expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, %w[phone_number email], admin.email).once expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, admin.id, %w[phone_number email],
{ :payload => nil, :label => nil }).once
get "/api/v1/accounts/#{account.id}/contacts/export", post "/api/v1/accounts/#{account.id}/contacts/export",
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,
params: { column_names: %w[phone_number email] } params: { column_names: %w[phone_number email] }
expect(response).to have_http_status(:success)
end
it 'enqueues a contact export job with payload' do
expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, admin.id, nil,
{
:payload => [ActionController::Parameters.new(email_filter).permit!],
:label => nil
}).once
post "/api/v1/accounts/#{account.id}/contacts/export",
headers: admin.create_new_auth_token,
params: { payload: [email_filter] }
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end

View File

@@ -3,7 +3,43 @@ require 'rails_helper'
RSpec.describe Account::ContactsExportJob do RSpec.describe Account::ContactsExportJob do
subject(:job) { described_class.perform_later } subject(:job) { described_class.perform_later }
let!(:account) { create(:account) } let(:account) { create(:account) }
let(:user) { create(:user, account: account, email: 'account-user-test@test.com') }
let(:label) { create(:label, title: 'spec-billing', maccount: account) }
let(:email_filter) do
{
:attribute_key => 'email',
:filter_operator => 'contains',
:values => 'looped',
:query_operator => 'and',
:attribute_model => 'standard',
:custom_attribute_type => ''
}
end
let(:city_filter) do
{
:attribute_key => 'country_code',
:filter_operator => 'equal_to',
:values => ['India'],
:query_operator => 'and',
:attribute_model => 'standard',
:custom_attribute_type => ''
}
end
let(:single_filter) do
{
:payload => [email_filter.merge(:query_operator => nil)]
}
end
let(:multiple_filters) do
{
:payload => [city_filter, email_filter.merge(:query_operator => nil)]
}
end
it 'enqueues the job' do it 'enqueues the job' do
expect { job }.to have_enqueued_job(described_class) expect { job }.to have_enqueued_job(described_class)
@@ -13,8 +49,11 @@ RSpec.describe Account::ContactsExportJob do
context 'when export_contacts' do context 'when export_contacts' do
before do before do
create(:contact, account: account, phone_number: '+910808080818', email: 'test1@text.example') create(:contact, account: account, phone_number: '+910808080818', email: 'test1@text.example')
8.times do 4.times do |i|
create(:contact, account: account) create(:contact, account: account, email: "looped-#{i + 3}@text.example.com")
end
4.times do |i|
create(:contact, account: account, additional_attributes: { :country_code => 'India' }, email: "looped-#{i + 10}@text.example.com")
end end
create(:contact, account: account, phone_number: '+910808080808', email: 'test2@text.example') create(:contact, account: account, phone_number: '+910808080808', email: 'test2@text.example')
end end
@@ -24,17 +63,17 @@ RSpec.describe Account::ContactsExportJob do
allow(AdministratorNotifications::ChannelNotificationsMailer).to receive(:with).with(account: account).and_return(mailer) allow(AdministratorNotifications::ChannelNotificationsMailer).to receive(:with).with(account: account).and_return(mailer)
allow(mailer).to receive(:contact_export_complete) allow(mailer).to receive(:contact_export_complete)
described_class.perform_now(account.id, [], 'test@test.com') described_class.perform_now(account.id, user.id, [], {})
file_url = Rails.application.routes.url_helpers.rails_blob_url(account.contacts_export) file_url = Rails.application.routes.url_helpers.rails_blob_url(account.contacts_export)
expect(account.contacts_export).to be_present expect(account.contacts_export).to be_present
expect(file_url).to be_present expect(file_url).to be_present
expect(mailer).to have_received(:contact_export_complete).with(file_url, 'test@test.com') expect(mailer).to have_received(:contact_export_complete).with(file_url, user.email)
end end
it 'generates valid data export file' do it 'generates valid data export file' do
described_class.perform_now(account.id, [], 'test@test.com') described_class.perform_now(account.id, user.id, %w[id name email phone_number column_not_present], {})
csv_data = CSV.parse(account.contacts_export.download, headers: true) csv_data = CSV.parse(account.contacts_export.download, headers: true)
emails = csv_data.pluck('email') emails = csv_data.pluck('email')
@@ -45,5 +84,46 @@ RSpec.describe Account::ContactsExportJob do
expect(emails).to include('test1@text.example', 'test2@text.example') expect(emails).to include('test1@text.example', 'test2@text.example')
expect(phone_numbers).to include('+910808080818', '+910808080808') expect(phone_numbers).to include('+910808080818', '+910808080808')
end end
it 'returns all resolved contacts as results when filter is not prvoided' do
create(:contact, account: account, email: nil, phone_number: nil)
described_class.perform_now(account.id, user.id, %w[id name email column_not_present], {})
csv_data = CSV.parse(account.contacts_export.download, headers: true)
expect(csv_data.length).to eq(account.contacts.resolved_contacts.count)
end
it 'returns resolved contacts filtered if labels are provided' do
# Adding label to a resolved contact
Contact.last.add_labels(['spec-billing'])
contact = create(:contact, account: account, email: nil, phone_number: nil)
contact.add_labels(['spec-billing'])
described_class.perform_now(account.id, user.id, [], { :payload => nil, :label => 'spec-billing' })
csv_data = CSV.parse(account.contacts_export.download, headers: true)
# since there is only 1 resolved contact with 'spec-billing' label
expect(csv_data.length).to eq(1)
end
# TODO: This returns unresolved contacts as well since filter service returns the same
# Change this when we make changes to filter service and ensure only resolved contacts are returned
it 'returns filtered data which inclues unresolved contacts when filter is provided' do
create(:contact, account: account, email: nil, phone_number: nil, additional_attributes: { :country_code => 'India' })
described_class.perform_now(account.id, user.id, [], { :payload => [city_filter.merge(:query_operator => nil)] }.with_indifferent_access)
csv_data = CSV.parse(account.contacts_export.download, headers: true)
expect(csv_data.length).to eq(5)
end
it 'returns filtered data when multiple filters are provided' do
described_class.perform_now(account.id, user.id, [], multiple_filters.with_indifferent_access)
csv_data = CSV.parse(account.contacts_export.download, headers: true)
# since there are only 4 contacts with 'looped' in email and 'India' as country_code
expect(csv_data.length).to eq(4)
end
it 'returns filtered data when a single filter is provided' do
described_class.perform_now(account.id, user.id, [], single_filter.with_indifferent_access)
csv_data = CSV.parse(account.contacts_export.download, headers: true)
# since there are only 8 contacts with 'looped' in email
expect(csv_data.length).to eq(8)
end
end end
end end

View File

@@ -16,7 +16,6 @@ describe Contacts::FilterService do
create(:inbox_member, user: second_user, inbox: inbox) create(:inbox_member, user: second_user, inbox: inbox)
create(:conversation, account: account, inbox: inbox, assignee: first_user, contact: en_contact) create(:conversation, account: account, inbox: inbox, assignee: first_user, contact: en_contact)
create(:conversation, account: account, inbox: inbox, contact: el_contact) create(:conversation, account: account, inbox: inbox, contact: el_contact)
Current.account = account
create(:custom_attribute_definition, create(:custom_attribute_definition,
attribute_key: 'contact_additional_information', attribute_key: 'contact_additional_information',
@@ -59,7 +58,7 @@ describe Contacts::FilterService do
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:count]).to be 1 expect(result[:count]).to be 1
expect(result[:contacts].length).to be 1 expect(result[:contacts].length).to be 1
expect(result[:contacts].first.name).to eq(en_contact.name) expect(result[:contacts].first.name).to eq(en_contact.name)
@@ -71,7 +70,7 @@ describe Contacts::FilterService do
blocked_contact = create(:contact, account: account, blocked: true) blocked_contact = create(:contact, account: account, blocked: true)
params = { payload: [{ attribute_key: 'blocked', filter_operator: 'equal_to', values: ['true'], params = { payload: [{ attribute_key: 'blocked', filter_operator: 'equal_to', values: ['true'],
query_operator: nil }.with_indifferent_access] } query_operator: nil }.with_indifferent_access] }
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:count]).to be 1 expect(result[:count]).to be 1
expect(result[:contacts].first.id).to eq(blocked_contact.id) expect(result[:contacts].first.id).to eq(blocked_contact.id)
end end
@@ -79,7 +78,7 @@ describe Contacts::FilterService do
it 'filter contacts by not_blocked' do it 'filter contacts by not_blocked' do
params = { payload: [{ attribute_key: 'blocked', filter_operator: 'equal_to', values: [false], params = { payload: [{ attribute_key: 'blocked', filter_operator: 'equal_to', values: [false],
query_operator: nil }.with_indifferent_access] } query_operator: nil }.with_indifferent_access] }
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
# existing contacts are not blocked # existing contacts are not blocked
expect(result[:count]).to be 3 expect(result[:count]).to be 3
end end
@@ -96,7 +95,7 @@ describe Contacts::FilterService do
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be 2 expect(result[:contacts].length).to be 2
expect(result[:contacts].first.label_list).to include('support') expect(result[:contacts].first.label_list).to include('support')
expect(result[:contacts].last.label_list).to include('support') expect(result[:contacts].last.label_list).to include('support')
@@ -112,7 +111,7 @@ describe Contacts::FilterService do
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be 1 expect(result[:contacts].length).to be 1
expect(result[:contacts].first.id).to eq el_contact.id expect(result[:contacts].first.id).to eq el_contact.id
end end
@@ -127,7 +126,7 @@ describe Contacts::FilterService do
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be 2 expect(result[:contacts].length).to be 2
expect(result[:contacts].first.label_list).to include('support') expect(result[:contacts].first.label_list).to include('support')
expect(result[:contacts].last.label_list).to include('support') expect(result[:contacts].last.label_list).to include('support')
@@ -143,7 +142,7 @@ describe Contacts::FilterService do
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be 1 expect(result[:contacts].length).to be 1
expect(result[:contacts].first.id).to eq el_contact.id expect(result[:contacts].first.id).to eq el_contact.id
end end
@@ -180,7 +179,7 @@ describe Contacts::FilterService do
'test custom data' 'test custom data'
).count ).count
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be expected_count expect(result[:contacts].length).to be expected_count
expect(result[:contacts].first.id).to eq(el_contact.id) expect(result[:contacts].first.id).to eq(el_contact.id)
end end
@@ -197,7 +196,7 @@ describe Contacts::FilterService do
expected_count = Contact.where('last_activity_at < ?', (Time.zone.today - 2.days)).count expected_count = Contact.where('last_activity_at < ?', (Time.zone.today - 2.days)).count
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be expected_count expect(result[:contacts].length).to be expected_count
expect(result[:contacts].pluck(:id)).to include(el_contact.id) expect(result[:contacts].pluck(:id)).to include(el_contact.id)
expect(result[:contacts].pluck(:id)).to include(cs_contact.id) expect(result[:contacts].pluck(:id)).to include(cs_contact.id)
@@ -219,7 +218,7 @@ describe Contacts::FilterService do
it 'filter contacts by additional_attributes' do it 'filter contacts by additional_attributes' do
params[:payload] = payload params[:payload] = payload
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:count]).to be 1 expect(result[:count]).to be 1
expect(result[:contacts].first.id).to eq(en_contact.id) expect(result[:contacts].first.id).to eq(en_contact.id)
end end
@@ -247,7 +246,7 @@ describe Contacts::FilterService do
query_operator: nil query_operator: nil
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be 1 expect(result[:contacts].length).to be 1
expect(result[:contacts].first.id).to eq(cs_contact.id) expect(result[:contacts].first.id).to eq(cs_contact.id)
end end
@@ -273,7 +272,7 @@ describe Contacts::FilterService do
query_operator: nil query_operator: nil
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expect(result[:contacts].length).to be 1 expect(result[:contacts].length).to be 1
expect(result[:contacts].first.id).to eq(el_contact.id) expect(result[:contacts].first.id).to eq(el_contact.id)
end end
@@ -294,7 +293,7 @@ describe Contacts::FilterService do
query_operator: nil query_operator: nil
}.with_indifferent_access }.with_indifferent_access
] ]
result = filter_service.new(params, first_user).perform result = filter_service.new(account, first_user, params).perform
expected_count = Contact.where("created_at < ? AND custom_attributes->>'customer_type' = ?", Date.tomorrow, 'platinum').count expected_count = Contact.where("created_at < ? AND custom_attributes->>'customer_type' = ?", Date.tomorrow, 'platinum').count
expect(result[:contacts].length).to be expected_count expect(result[:contacts].length).to be expected_count