diff --git a/app/javascript/dashboard/i18n/locale/en/advancedFilters.json b/app/javascript/dashboard/i18n/locale/en/advancedFilters.json index 46a573c42..a32c1bd9d 100644 --- a/app/javascript/dashboard/i18n/locale/en/advancedFilters.json +++ b/app/javascript/dashboard/i18n/locale/en/advancedFilters.json @@ -22,7 +22,8 @@ "is_not_present": "Is not present", "is_greater_than": "Is greater than", "is_less_than": "Is lesser than", - "days_before": "Is x days before" + "days_before": "Is x days before", + "starts_with": "Starts with" }, "ATTRIBUTE_LABELS": { "TRUE": "True", diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js index c3a0ffede..ea5d7238b 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js +++ b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js @@ -2,6 +2,7 @@ import { OPERATOR_TYPES_1, OPERATOR_TYPES_2, OPERATOR_TYPES_3, + OPERATOR_TYPES_6, } from './operators'; export const AUTOMATIONS = { @@ -35,6 +36,13 @@ export const AUTOMATIONS = { inputType: 'multi_select', filterOperators: OPERATOR_TYPES_1, }, + { + key: 'phone_number', + name: 'Phone Number', + attributeI18nKey: 'PHONE_NUMBER', + inputType: 'plain_text', + filterOperators: OPERATOR_TYPES_6, + }, ], actions: [ { @@ -125,6 +133,13 @@ export const AUTOMATIONS = { inputType: 'search_select', filterOperators: OPERATOR_TYPES_1, }, + { + key: 'phone_number', + name: 'Phone Number', + attributeI18nKey: 'PHONE_NUMBER', + inputType: 'plain_text', + filterOperators: OPERATOR_TYPES_6, + }, { key: 'referer', name: 'Referrer Link', @@ -242,6 +257,13 @@ export const AUTOMATIONS = { inputType: 'plain_text', filterOperators: OPERATOR_TYPES_2, }, + { + key: 'phone_number', + name: 'Phone Number', + attributeI18nKey: 'PHONE_NUMBER', + inputType: 'plain_text', + filterOperators: OPERATOR_TYPES_6, + }, { key: 'assignee_id', name: 'Assignee', @@ -373,6 +395,13 @@ export const AUTOMATIONS = { inputType: 'search_select', filterOperators: OPERATOR_TYPES_3, }, + { + key: 'phone_number', + name: 'Phone Number', + attributeI18nKey: 'PHONE_NUMBER', + inputType: 'plain_text', + filterOperators: OPERATOR_TYPES_6, + }, { key: 'team_id', name: 'Team', diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/operators.js b/app/javascript/dashboard/routes/dashboard/settings/automation/operators.js index c6691ac95..6fc22b707 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/automation/operators.js +++ b/app/javascript/dashboard/routes/dashboard/settings/automation/operators.js @@ -88,3 +88,26 @@ export const OPERATOR_TYPES_5 = [ label: 'Is x days before', }, ]; + +export const OPERATOR_TYPES_6 = [ + { + value: 'equal_to', + label: 'Equal to', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + }, + { + value: 'contains', + label: 'Contains', + }, + { + value: 'does_not_contain', + label: 'Does not contain', + }, + { + value: 'starts_with', + label: 'Starts With', + }, +]; diff --git a/app/models/automation_rule.rb b/app/models/automation_rule.rb index 36f2b833a..d46aaa583 100644 --- a/app/models/automation_rule.rb +++ b/app/models/automation_rule.rb @@ -31,7 +31,7 @@ class AutomationRule < ApplicationRecord scope :active, -> { where(active: true) } CONDITIONS_ATTRS = %w[content email country_code status message_type browser_language assignee_id team_id referer city company inbox_id - mail_subject].freeze + mail_subject phone_number].freeze ACTIONS_ATTRS = %w[send_message add_label send_email_to_team assign_team assign_agent send_webhook_event mute_conversation send_attachment change_status resolve_conversation snooze_conversation send_email_transcript].freeze diff --git a/app/services/automation_rules/conditions_filter_service.rb b/app/services/automation_rules/conditions_filter_service.rb index a1ef68bf9..432e9cfc3 100644 --- a/app/services/automation_rules/conditions_filter_service.rb +++ b/app/services/automation_rules/conditions_filter_service.rb @@ -32,6 +32,15 @@ class AutomationRules::ConditionsFilterService < FilterService records.any? end + def filter_operation(query_hash, current_index) + if query_hash[:filter_operator] == 'starts_with' + @filter_values["value_#{current_index}"] = "#{string_filter_values(query_hash)}%" + like_filter_string(query_hash[:filter_operator], current_index) + else + super + end + end + def apply_filter(query_hash, current_index) conversation_filter = @conversation_filters[query_hash['attribute_key']] contact_filter = @contact_filters[query_hash['attribute_key']] diff --git a/app/services/filter_service.rb b/app/services/filter_service.rb index bbc949efa..0254db1a7 100644 --- a/app/services/filter_service.rb +++ b/app/services/filter_service.rb @@ -150,7 +150,7 @@ class FilterService end def like_filter_string(filter_operator, current_index) - return "LIKE :value_#{current_index}" if filter_operator == 'contains' + return "LIKE :value_#{current_index}" if %w[contains starts_with].include?(filter_operator) "NOT LIKE :value_#{current_index}" end diff --git a/lib/automation_rules/conditions.json b/lib/automation_rules/conditions.json index 954d57470..c07b78448 100644 --- a/lib/automation_rules/conditions.json +++ b/lib/automation_rules/conditions.json @@ -100,6 +100,13 @@ "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "is_present", "is_not_present" ], "attribute_type": "standard" }, + "phone_number": { + "attribute_name": "Phone Number", + "input_type": "textbox", + "data_type": "text", + "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain", "starts_with" ], + "attribute_type": "standard" + }, "contact_id": { "attribute_name": "Contact Name", "input_type": "plain_text", diff --git a/lib/filters/filter_keys.json b/lib/filters/filter_keys.json index 939520ec8..43d961c50 100644 --- a/lib/filters/filter_keys.json +++ b/lib/filters/filter_keys.json @@ -109,7 +109,7 @@ }, "phone_number": { "attribute_name": "Phone Number", - "input_type": "search_box with name tags/plain text", + "input_type": "text", "data_type": "text", "filter_operators": [ "equal_to", "not_equal_to", "contains", "does_not_contain" ], "attribute_type": "standard" diff --git a/spec/services/automation_rules/conditions_filter_service_spec.rb b/spec/services/automation_rules/conditions_filter_service_spec.rb index 3e6ff2076..163430462 100644 --- a/spec/services/automation_rules/conditions_filter_service_spec.rb +++ b/spec/services/automation_rules/conditions_filter_service_spec.rb @@ -5,25 +5,57 @@ RSpec.describe AutomationRules::ConditionsFilterService do let(:conversation) { create(:conversation, account: account) } let(:rule) { create(:automation_rule, account: account) } - describe '#perform' do - before do - rule.conditions = [{ 'values': ['open'], 'attribute_key': 'status', 'query_operator': nil, 'filter_operator': 'equal_to' }] - rule.save - end + before do + conversation = create(:conversation, account: account) + conversation.contact.update(phone_number: '+918484828282', email: 'test@test.com') + create(:conversation, account: account) + create(:conversation, account: account) + end - context 'when conditions in rule matches with object' do - it 'will return true' do - expect(described_class.new(rule, conversation, { changed_attributes: { status: [nil, 'open'] } }).perform).to be(true) + describe '#perform' do + context 'when conditions based on filter_operator equal_to' do + before do + rule.conditions = [{ 'values': ['open'], 'attribute_key': 'status', 'query_operator': nil, 'filter_operator': 'equal_to' }] + rule.save + end + + context 'when conditions in rule matches with object' do + it 'will return true' do + expect(described_class.new(rule, conversation, { changed_attributes: { status: [nil, 'open'] } }).perform).to be(true) + end + end + + context 'when conditions in rule does not match with object' do + it 'will return false' do + conversation.update(status: 'resolved') + expect(described_class.new(rule, conversation, { changed_attributes: { status: %w[open resolved] } }).perform).to be(false) + end end end - context 'when conditions in rule does not match with object' do - it 'will return false' do - conversation.update(status: 'resolved') - expect(described_class.new(rule, conversation, { changed_attributes: { status: %w[open resolved] } }).perform).to be(false) + context 'when conditions based on filter_operator start_with' do + before do + contact = conversation.contact + contact.update(phone_number: '+918484848484') + rule.conditions = [ + { 'values': ['+918484'], 'attribute_key': 'phone_number', 'query_operator': 'OR', 'filter_operator': 'starts_with' }, + { 'values': ['test'], 'attribute_key': 'email', 'query_operator': nil, 'filter_operator': 'contains' } + ] + rule.save + end + + context 'when conditions in rule matches with object' do + it 'will return true' do + expect(described_class.new(rule, conversation, { changed_attributes: {} }).perform).to be(true) + end + end + + context 'when conditions in rule does not match with object' do + it 'will return false' do + conversation.contact.update(phone_number: '+918585858585') + expect(described_class.new(rule, conversation, { changed_attributes: {} }).perform).to be(false) + end end end end - - ## TODO: add tests for the other conditions end