chore: Automation bug fix (#4442)
This commit is contained in:
parent
b6ad468eb4
commit
923b4637db
12 changed files with 47 additions and 164 deletions
|
@ -194,7 +194,7 @@ export default {
|
||||||
required: requiredIf(prop => {
|
required: requiredIf(prop => {
|
||||||
return !(
|
return !(
|
||||||
prop.action_name === 'mute_conversation' ||
|
prop.action_name === 'mute_conversation' ||
|
||||||
prop.action_name === 'snooze_convresation' ||
|
prop.action_name === 'snooze_conversation' ||
|
||||||
prop.action_name === 'resolve_convresation'
|
prop.action_name === 'resolve_convresation'
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -198,7 +198,7 @@ export default {
|
||||||
required: requiredIf(prop => {
|
required: requiredIf(prop => {
|
||||||
return !(
|
return !(
|
||||||
prop.action_name === 'mute_conversation' ||
|
prop.action_name === 'mute_conversation' ||
|
||||||
prop.action_name === 'snooze_convresation' ||
|
prop.action_name === 'snooze_conversation' ||
|
||||||
prop.action_name === 'resolve_convresation'
|
prop.action_name === 'resolve_convresation'
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -92,7 +92,7 @@ export const AUTOMATIONS = {
|
||||||
attributeI18nKey: 'MUTE_CONVERSATION',
|
attributeI18nKey: 'MUTE_CONVERSATION',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'snooze_convresation',
|
key: 'snooze_conversation',
|
||||||
name: 'Snooze conversation',
|
name: 'Snooze conversation',
|
||||||
attributeI18nKey: 'MUTE_CONVERSATION',
|
attributeI18nKey: 'MUTE_CONVERSATION',
|
||||||
},
|
},
|
||||||
|
@ -166,7 +166,7 @@ export const AUTOMATIONS = {
|
||||||
attributeI18nKey: 'MUTE_CONVERSATION',
|
attributeI18nKey: 'MUTE_CONVERSATION',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'snooze_convresation',
|
key: 'snooze_conversation',
|
||||||
name: 'Snooze conversation',
|
name: 'Snooze conversation',
|
||||||
attributeI18nKey: 'MUTE_CONVERSATION',
|
attributeI18nKey: 'MUTE_CONVERSATION',
|
||||||
},
|
},
|
||||||
|
@ -254,7 +254,7 @@ export const AUTOMATIONS = {
|
||||||
attributeI18nKey: 'MUTE_CONVERSATION',
|
attributeI18nKey: 'MUTE_CONVERSATION',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'snooze_convresation',
|
key: 'snooze_conversation',
|
||||||
name: 'Snooze conversation',
|
name: 'Snooze conversation',
|
||||||
attributeI18nKey: 'MUTE_CONVERSATION',
|
attributeI18nKey: 'MUTE_CONVERSATION',
|
||||||
},
|
},
|
||||||
|
@ -314,7 +314,7 @@ export const AUTOMATION_ACTION_TYPES = [
|
||||||
inputType: null,
|
inputType: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'snooze_convresation',
|
key: 'snooze_conversation',
|
||||||
label: 'Snooze conversation',
|
label: 'Snooze conversation',
|
||||||
inputType: null,
|
inputType: null,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
class AutomationRuleListener < BaseListener
|
class AutomationRuleListener < BaseListener
|
||||||
def conversation_updated(event_obj)
|
def conversation_updated(event_obj)
|
||||||
|
return if performed_by_automation?(event_obj)
|
||||||
|
|
||||||
conversation = event_obj.data[:conversation]
|
conversation = event_obj.data[:conversation]
|
||||||
account = conversation.account
|
account = conversation.account
|
||||||
|
|
||||||
|
@ -11,19 +13,9 @@ class AutomationRuleListener < BaseListener
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def conversation_status_changed(event_obj)
|
|
||||||
conversation = event_obj.data[:conversation]
|
|
||||||
account = conversation.account
|
|
||||||
|
|
||||||
return unless rule_present?('conversation_status_changed', account)
|
|
||||||
|
|
||||||
@rules.each do |rule|
|
|
||||||
conditions_match = ::AutomationRules::ConditionsFilterService.new(rule, conversation).perform
|
|
||||||
AutomationRules::ActionService.new(rule, account, conversation).perform if conditions_match.present?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def conversation_created(event_obj)
|
def conversation_created(event_obj)
|
||||||
|
return if performed_by_automation?(event_obj)
|
||||||
|
|
||||||
conversation = event_obj.data[:conversation]
|
conversation = event_obj.data[:conversation]
|
||||||
account = conversation.account
|
account = conversation.account
|
||||||
|
|
||||||
|
@ -36,6 +28,8 @@ class AutomationRuleListener < BaseListener
|
||||||
end
|
end
|
||||||
|
|
||||||
def message_created(event_obj)
|
def message_created(event_obj)
|
||||||
|
return if performed_by_automation?(event_obj)
|
||||||
|
|
||||||
message = event_obj.data[:message]
|
message = event_obj.data[:message]
|
||||||
account = message.try(:account)
|
account = message.try(:account)
|
||||||
|
|
||||||
|
@ -57,4 +51,8 @@ class AutomationRuleListener < BaseListener
|
||||||
)
|
)
|
||||||
@rules.any?
|
@rules.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def performed_by_automation?(event_obj)
|
||||||
|
event_obj.data[:performed_by].present? && event_obj.data[:performed_by].instance_of?(AutomationRule)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,18 +35,14 @@ class TeamNotifications::AutomationNotificationMailer < ApplicationMailer
|
||||||
private
|
private
|
||||||
|
|
||||||
def send_an_email_to_team
|
def send_an_email_to_team
|
||||||
@agents.each do |agent|
|
subject = 'This email has been sent via automation rule actions.'
|
||||||
subject = "#{agent.user.available_name}, This email has been sent via automation rule actions."
|
@action_url = app_account_conversation_url(account_id: @conversation.account_id, id: @conversation.display_id)
|
||||||
@action_url = app_account_conversation_url(account_id: @conversation.account_id, id: @conversation.display_id)
|
@agent_emails = @agents.collect(&:user).pluck(:email)
|
||||||
@agent = agent
|
send_mail_with_liquid(to: @agent_emails, subject: subject) and return
|
||||||
|
|
||||||
send_mail_with_liquid(to: @agent.user.email, subject: subject)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def liquid_droppables
|
def liquid_droppables
|
||||||
super.merge!({
|
super.merge!({
|
||||||
user: @agent.user,
|
|
||||||
conversation: @conversation,
|
conversation: @conversation,
|
||||||
inbox: @conversation.inbox
|
inbox: @conversation.inbox
|
||||||
})
|
})
|
||||||
|
|
|
@ -214,10 +214,9 @@ class Conversation < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatcher_dispatch(event_name, changed_attributes = nil)
|
def dispatcher_dispatch(event_name, changed_attributes = nil)
|
||||||
return if Current.executed_by.present? && Current.executed_by.instance_of?(AutomationRule)
|
|
||||||
|
|
||||||
Rails.configuration.dispatcher.dispatch(event_name, Time.zone.now, conversation: self, notifiable_assignee_change: notifiable_assignee_change?,
|
Rails.configuration.dispatcher.dispatch(event_name, Time.zone.now, conversation: self, notifiable_assignee_change: notifiable_assignee_change?,
|
||||||
changed_attributes: changed_attributes)
|
changed_attributes: changed_attributes,
|
||||||
|
performed_by: Current.executed_by)
|
||||||
end
|
end
|
||||||
|
|
||||||
def conversation_status_changed_to_open?
|
def conversation_status_changed_to_open?
|
||||||
|
|
|
@ -166,19 +166,15 @@ class Message < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatch_create_events
|
def dispatch_create_events
|
||||||
return if Current.executed_by.present? && Current.executed_by.instance_of?(AutomationRule)
|
Rails.configuration.dispatcher.dispatch(MESSAGE_CREATED, Time.zone.now, message: self, performed_by: Current.executed_by)
|
||||||
|
|
||||||
Rails.configuration.dispatcher.dispatch(MESSAGE_CREATED, Time.zone.now, message: self)
|
|
||||||
|
|
||||||
if outgoing? && conversation.messages.outgoing.count == 1
|
if outgoing? && conversation.messages.outgoing.count == 1
|
||||||
Rails.configuration.dispatcher.dispatch(FIRST_REPLY_CREATED, Time.zone.now, message: self)
|
Rails.configuration.dispatcher.dispatch(FIRST_REPLY_CREATED, Time.zone.now, message: self, performed_by: Current.executed_by)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatch_update_event
|
def dispatch_update_event
|
||||||
return if Current.executed_by.present? && Current.executed_by.instance_of?(AutomationRule)
|
Rails.configuration.dispatcher.dispatch(MESSAGE_UPDATED, Time.zone.now, message: self, performed_by: Current.executed_by)
|
||||||
|
|
||||||
Rails.configuration.dispatcher.dispatch(MESSAGE_UPDATED, Time.zone.now, message: self)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_reply
|
def send_reply
|
||||||
|
|
|
@ -41,7 +41,7 @@ class AutomationRules::ActionService
|
||||||
end
|
end
|
||||||
|
|
||||||
def snooze_conversation(_params)
|
def snooze_conversation(_params)
|
||||||
@conversation.ensure_snooze_until_reset
|
@conversation.snoozed!
|
||||||
end
|
end
|
||||||
|
|
||||||
def change_status(status)
|
def change_status(status)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<p>Hi {{user.available_name}}</p>
|
<p>This is the mail from Automation System</p>
|
||||||
|
|
||||||
|
|
||||||
<p>{{ custom_message }}</p>
|
<p>{{ custom_message }}</p>
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when it is an authenticated user' do
|
context 'when it is an authenticated user' do
|
||||||
it 'returns for cloned automation_rule for account' do
|
it 'returns for updated automation_rule for account' do
|
||||||
params = { name: 'Update name' }
|
params = { name: 'Update name' }
|
||||||
expect(account.automation_rules.count).to eq(1)
|
expect(account.automation_rules.count).to eq(1)
|
||||||
|
|
||||||
|
@ -271,6 +271,20 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do
|
||||||
body = JSON.parse(response.body, symbolize_names: true)
|
body = JSON.parse(response.body, symbolize_names: true)
|
||||||
expect(body[:payload][:name]).to eq('Update name')
|
expect(body[:payload][:name]).to eq('Update name')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns for updated active flag for automation_rule' do
|
||||||
|
expect(automation_rule.active).to eq(true)
|
||||||
|
params = { active: false }
|
||||||
|
|
||||||
|
patch "/api/v1/accounts/#{account.id}/automation_rules/#{automation_rule.id}",
|
||||||
|
headers: administrator.create_new_auth_token,
|
||||||
|
params: params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
body = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
expect(body[:payload][:active]).to eq(false)
|
||||||
|
expect(automation_rule.reload.active).to eq(false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -50,125 +50,6 @@ describe AutomationRuleListener do
|
||||||
automation_rule.save
|
automation_rule.save
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#conversation_status_changed' do
|
|
||||||
context 'when rule matches' do
|
|
||||||
it 'triggers automation rule send webhook events' do
|
|
||||||
payload = conversation.webhook_data.merge(event: "automation_event: #{automation_rule.event_name}")
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
expect(WebhookJob).to receive(:perform_later).with('https://www.example.com', payload).once
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule to assign team' do
|
|
||||||
expect(conversation.team_id).not_to eq(team.id)
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
expect(conversation.team_id).to eq(team.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule to add label' do
|
|
||||||
expect(conversation.labels).to eq([])
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
|
|
||||||
expect(conversation.labels.pluck(:name)).to contain_exactly('support', 'priority_customer')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule to assign best agents' do
|
|
||||||
expect(conversation.assignee).to be_nil
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
|
|
||||||
expect(conversation.assignee).to eq(user_1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule send message to the contacts' do
|
|
||||||
expect(conversation.messages).to be_empty
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
|
|
||||||
expect(conversation.messages.first.content).to eq('Send this message.')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule changes status to snoozed' do
|
|
||||||
expect(conversation.status).to eq('resolved')
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
|
|
||||||
expect(conversation.status).to eq('snoozed')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule send email transcript to the mentioned email' do
|
|
||||||
mailer = double
|
|
||||||
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
|
|
||||||
allow(mailer).to receive(:conversation_transcript)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule send email to the team' do
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'triggers automation rule send attachments in messages' do
|
|
||||||
automation_rule
|
|
||||||
|
|
||||||
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
|
||||||
|
|
||||||
listener.conversation_status_changed(event)
|
|
||||||
|
|
||||||
conversation.reload
|
|
||||||
|
|
||||||
expect(conversation.messages.last.attachments.count).to eq(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#conversation_updated with contacts attributes' do
|
describe '#conversation_updated with contacts attributes' do
|
||||||
before do
|
before do
|
||||||
conversation.contact.update!(custom_attributes: { customer_type: 'platinum', signed_in_at: '2022-01-19' },
|
conversation.contact.update!(custom_attributes: { customer_type: 'platinum', signed_in_at: '2022-01-19' },
|
||||||
|
|
|
@ -55,7 +55,7 @@ RSpec.describe Conversation, type: :model do
|
||||||
# send_events
|
# send_events
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation, notifiable_assignee_change: false,
|
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation, notifiable_assignee_change: false,
|
||||||
changed_attributes: nil)
|
changed_attributes: nil, performed_by: nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,16 +121,16 @@ RSpec.describe Conversation, type: :model do
|
||||||
|
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
.with(described_class::CONVERSATION_RESOLVED, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
.with(described_class::CONVERSATION_RESOLVED, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
||||||
changed_attributes: status_change)
|
changed_attributes: status_change, performed_by: nil)
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
.with(described_class::CONVERSATION_READ, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
.with(described_class::CONVERSATION_READ, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
||||||
changed_attributes: nil)
|
changed_attributes: nil, performed_by: nil)
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
.with(described_class::ASSIGNEE_CHANGED, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
.with(described_class::ASSIGNEE_CHANGED, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
||||||
changed_attributes: nil)
|
changed_attributes: nil, performed_by: nil)
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
.with(described_class::CONVERSATION_UPDATED, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
.with(described_class::CONVERSATION_UPDATED, kind_of(Time), conversation: conversation, notifiable_assignee_change: true,
|
||||||
changed_attributes: changed_attributes)
|
changed_attributes: changed_attributes, performed_by: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'will not run conversation_updated event for empty updates' do
|
it 'will not run conversation_updated event for empty updates' do
|
||||||
|
|
Loading…
Reference in a new issue