Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95aab43e3b | ||
|
|
5f397db19b | ||
|
|
ce178cd3fe | ||
|
|
1f35360ecb | ||
|
|
4a0933aaf6 | ||
|
|
f5ba24a9c5 | ||
|
|
4c25024f74 | ||
|
|
98592b6e62 | ||
|
|
0848c40c0f | ||
|
|
7ec4468af2 | ||
|
|
14d7df5e50 | ||
|
|
26691aa9ed | ||
|
|
210ab45c8e | ||
|
|
f208af126d | ||
|
|
1c5ebcea0c | ||
|
|
50b373c151 | ||
|
|
ffa9e45d70 | ||
|
|
81b4d7abfc |
@@ -74,7 +74,6 @@ class Conversation < ApplicationRecord
|
||||
validates :inbox_id, presence: true
|
||||
validates :contact_id, presence: true
|
||||
before_validation :validate_additional_attributes
|
||||
before_validation :reset_agent_bot_when_assignee_present
|
||||
validates :additional_attributes, jsonb_attributes_length: true
|
||||
validates :custom_attributes, jsonb_attributes_length: true
|
||||
validates :uuid, uniqueness: true
|
||||
@@ -125,6 +124,7 @@ class Conversation < ApplicationRecord
|
||||
has_many :attachments, through: :messages
|
||||
has_many :reporting_events, dependent: :destroy_async
|
||||
|
||||
before_save :handle_agent_bot_takeover_by_assignee
|
||||
before_save :ensure_snooze_until_reset
|
||||
before_create :determine_conversation_status
|
||||
before_create :ensure_waiting_since
|
||||
@@ -172,8 +172,8 @@ class Conversation < ApplicationRecord
|
||||
end
|
||||
|
||||
def bot_handoff!
|
||||
update(waiting_since: Time.current) if waiting_since.blank?
|
||||
open!
|
||||
mark_bot_handoff
|
||||
save!
|
||||
dispatcher_dispatch(CONVERSATION_BOT_HANDOFF)
|
||||
end
|
||||
|
||||
@@ -280,12 +280,18 @@ class Conversation < ApplicationRecord
|
||||
self.additional_attributes = {} unless additional_attributes.is_a?(Hash)
|
||||
end
|
||||
|
||||
def reset_agent_bot_when_assignee_present
|
||||
return if assignee_id.blank?
|
||||
def handle_agent_bot_takeover_by_assignee
|
||||
return if assignee_id.blank? || assignee_agent_bot_id.blank?
|
||||
|
||||
mark_bot_handoff if pending?
|
||||
self.assignee_agent_bot_id = nil
|
||||
end
|
||||
|
||||
def mark_bot_handoff
|
||||
self.waiting_since ||= Time.current
|
||||
self.status = :open
|
||||
end
|
||||
|
||||
def determine_conversation_status
|
||||
self.status = :resolved and return if contact.blocked?
|
||||
|
||||
@@ -355,6 +361,7 @@ class Conversation < ApplicationRecord
|
||||
CONVERSATION_OPENED => -> { saved_change_to_status? && open? },
|
||||
CONVERSATION_RESOLVED => -> { saved_change_to_status? && resolved? },
|
||||
CONVERSATION_STATUS_CHANGED => -> { saved_change_to_status? },
|
||||
CONVERSATION_BOT_HANDOFF => -> { agent_bot_takeover_by_assignee? },
|
||||
CONVERSATION_READ => -> { saved_change_to_contact_last_seen_at? },
|
||||
CONVERSATION_CONTACT_CHANGED => -> { saved_change_to_contact_id? }
|
||||
}.each do |event, condition|
|
||||
@@ -362,6 +369,13 @@ class Conversation < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def agent_bot_takeover_by_assignee?
|
||||
assignee_id.present? &&
|
||||
saved_change_to_status?(from: 'pending', to: 'open') &&
|
||||
saved_change_to_assignee_agent_bot_id? &&
|
||||
assignee_agent_bot_id.blank?
|
||||
end
|
||||
|
||||
def dispatcher_dispatch(event_name, changed_attributes = nil)
|
||||
Rails.configuration.dispatcher.dispatch(event_name, Time.zone.now, conversation: self, notifiable_assignee_change: notifiable_assignee_change?,
|
||||
changed_attributes: changed_attributes,
|
||||
|
||||
@@ -15,7 +15,7 @@ class Conversations::AssignmentService
|
||||
|
||||
def assign_agent
|
||||
conversation.assignee = assignee
|
||||
conversation.assignee_agent_bot = nil
|
||||
conversation.assignee_agent_bot = nil if assignee.blank?
|
||||
conversation.save!
|
||||
assignee
|
||||
end
|
||||
@@ -25,6 +25,7 @@ class Conversations::AssignmentService
|
||||
|
||||
conversation.assignee = nil
|
||||
conversation.assignee_agent_bot = agent_bot
|
||||
conversation.status = :pending
|
||||
conversation.save!
|
||||
agent_bot
|
||||
end
|
||||
|
||||
@@ -44,6 +44,7 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
||||
end
|
||||
|
||||
it 'assigns a user to the conversation' do
|
||||
conversation.update!(assignee_agent_bot: agent_bot, status: :pending)
|
||||
params = { assignee_id: agent.id }
|
||||
|
||||
post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
|
||||
@@ -52,10 +53,13 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.assignee).to eq(agent)
|
||||
conversation.reload
|
||||
expect(conversation.assignee).to eq(agent)
|
||||
expect(conversation.status).to eq('open')
|
||||
end
|
||||
|
||||
it 'assigns an agent bot to the conversation' do
|
||||
conversation.update!(status: :open)
|
||||
params = { assignee_id: agent_bot.id, assignee_type: 'AgentBot' }
|
||||
|
||||
expect(Conversations::AssignmentService).to receive(:new)
|
||||
@@ -72,12 +76,14 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
||||
conversation.reload
|
||||
expect(conversation.assignee_agent_bot).to eq(agent_bot)
|
||||
expect(conversation.assignee).to be_nil
|
||||
expect(conversation.status).to eq('pending')
|
||||
end
|
||||
|
||||
it 'assigns a team to the conversation' do
|
||||
team_member = create(:user, account: account, role: :agent, auto_offline: false)
|
||||
create(:inbox_member, inbox: conversation.inbox, user: team_member)
|
||||
create(:team_member, team: team, user: team_member)
|
||||
conversation.update!(assignee_agent_bot: agent_bot, status: :pending)
|
||||
params = { team_id: team.id }
|
||||
|
||||
post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
|
||||
@@ -88,7 +94,10 @@ RSpec.describe 'Conversation Assignment API', type: :request do
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(conversation.reload.team).to eq(team)
|
||||
# assignee will be from team
|
||||
expect(conversation.reload.assignee).to eq(team_member)
|
||||
conversation.reload
|
||||
expect(conversation.assignee).to eq(team_member)
|
||||
expect(conversation.assignee_agent_bot).to be_nil
|
||||
expect(conversation.status).to eq('open')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -57,6 +57,33 @@ describe ActionService do
|
||||
action_service.assign_agent([agent.id])
|
||||
expect(conversation.reload.assignee).to eq(agent)
|
||||
end
|
||||
|
||||
it 'opens bot-owned pending conversations when assigning the agent' do
|
||||
inbox_member
|
||||
conversation.update!(assignee: nil, assignee_agent_bot: create(:agent_bot, account: account), status: :pending)
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
|
||||
action_service.assign_agent([agent.id])
|
||||
|
||||
conversation.reload
|
||||
expect(conversation.assignee).to eq(agent)
|
||||
expect(conversation.assignee_agent_bot).to be_nil
|
||||
expect(conversation.status).to eq('open')
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||
.with(Events::Types::CONVERSATION_BOT_HANDOFF, kind_of(Time), hash_including(conversation: conversation))
|
||||
end
|
||||
|
||||
it 'dispatches bot handoff once when the same conversation is saved again' do
|
||||
inbox_member
|
||||
conversation.update!(assignee: nil, assignee_agent_bot: create(:agent_bot, account: account), status: :pending)
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
|
||||
action_service.assign_agent([agent.id])
|
||||
conversation.update!(priority: :urgent)
|
||||
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||
.with(Events::Types::CONVERSATION_BOT_HANDOFF, kind_of(Time), hash_including(conversation: conversation)).once
|
||||
end
|
||||
end
|
||||
|
||||
context 'when agent is unconfirmed' do
|
||||
|
||||
@@ -19,20 +19,45 @@ describe Conversations::AssignmentService do
|
||||
expect(conversation.assignee_id).to be_nil
|
||||
expect(conversation.assignee_agent_bot_id).to be_nil
|
||||
end
|
||||
|
||||
it 'preserves conversation status' do
|
||||
conversation.update!(status: :snoozed, snoozed_until: 1.day.from_now)
|
||||
|
||||
described_class.new(conversation: conversation, assignee_id: nil).perform
|
||||
|
||||
expect(conversation.reload.status).to eq('snoozed')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when assigning a user' do
|
||||
before do
|
||||
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil)
|
||||
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil, status: :pending)
|
||||
end
|
||||
|
||||
it 'sets the agent and clears agent bot' do
|
||||
it 'sets the agent, clears agent bot and opens the conversation' do
|
||||
result = described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
||||
|
||||
conversation.reload
|
||||
expect(result).to eq(agent)
|
||||
expect(conversation.assignee_id).to eq(agent.id)
|
||||
expect(conversation.assignee_agent_bot_id).to be_nil
|
||||
expect(conversation.status).to eq('open')
|
||||
end
|
||||
|
||||
it 'preserves status for ordinary human assignment changes' do
|
||||
conversation.update!(assignee_agent_bot: nil, status: :resolved)
|
||||
|
||||
described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
||||
|
||||
expect(conversation.reload.status).to eq('resolved')
|
||||
end
|
||||
|
||||
it 'preserves status when taking over a bot-owned non-pending conversation' do
|
||||
conversation.update!(assignee_agent_bot: agent_bot, status: :resolved)
|
||||
|
||||
described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
||||
|
||||
expect(conversation.reload.status).to eq('resolved')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,8 +70,8 @@ describe Conversations::AssignmentService do
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the agent bot and clears human assignee' do
|
||||
conversation.update!(assignee: agent, assignee_agent_bot: nil)
|
||||
it 'sets the agent bot, clears human assignee and marks the conversation pending' do
|
||||
conversation.update!(assignee: agent, assignee_agent_bot: nil, status: :open)
|
||||
|
||||
result = service.perform
|
||||
|
||||
@@ -54,6 +79,7 @@ describe Conversations::AssignmentService do
|
||||
expect(result).to eq(agent_bot)
|
||||
expect(conversation.assignee_agent_bot_id).to eq(agent_bot.id)
|
||||
expect(conversation.assignee_id).to be_nil
|
||||
expect(conversation.status).to eq('pending')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user