refactor: route assignment handoff through service
This commit is contained in:
@@ -34,8 +34,11 @@ class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Account
|
||||
end
|
||||
|
||||
def set_team
|
||||
@team = Current.account.teams.find_by(id: params[:team_id])
|
||||
@conversation.update!(team: @team)
|
||||
@team = Conversations::AssignmentService.new(
|
||||
conversation: @conversation,
|
||||
team_id: params[:team_id]
|
||||
).perform
|
||||
|
||||
render json: @team
|
||||
end
|
||||
|
||||
|
||||
+12
-17
@@ -66,6 +66,7 @@ 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
|
||||
@@ -116,7 +117,6 @@ 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
|
||||
@@ -166,9 +166,18 @@ class Conversation < ApplicationRecord
|
||||
def bot_handoff!
|
||||
mark_bot_handoff
|
||||
save!
|
||||
dispatch_bot_handoff
|
||||
end
|
||||
|
||||
def dispatch_bot_handoff
|
||||
dispatcher_dispatch(CONVERSATION_BOT_HANDOFF)
|
||||
end
|
||||
|
||||
def mark_bot_handoff
|
||||
self.waiting_since ||= Time.current
|
||||
self.status = :open
|
||||
end
|
||||
|
||||
def unread_messages
|
||||
agent_last_seen_at.present? ? messages.created_since(agent_last_seen_at) : messages
|
||||
end
|
||||
@@ -271,18 +280,12 @@ class Conversation < ApplicationRecord
|
||||
self.additional_attributes = {} unless additional_attributes.is_a?(Hash)
|
||||
end
|
||||
|
||||
def handle_agent_bot_takeover_by_assignee
|
||||
return if assignee_id.blank? || assignee_agent_bot_id.blank?
|
||||
def reset_agent_bot_when_assignee_present
|
||||
return if assignee_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?
|
||||
|
||||
@@ -339,7 +342,6 @@ 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|
|
||||
@@ -347,13 +349,6 @@ 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,
|
||||
|
||||
@@ -41,7 +41,7 @@ class ActionService
|
||||
end
|
||||
|
||||
def assign_agent(agent_ids = [])
|
||||
return @conversation.update!(assignee_id: nil) if agent_ids[0] == 'nil'
|
||||
return assign_conversation_agent(nil) if agent_ids[0] == 'nil'
|
||||
|
||||
agent_ids = [last_responding_agent_id] if agent_ids[0] == 'last_responding_agent'
|
||||
return unless agent_belongs_to_inbox?(agent_ids)
|
||||
@@ -49,7 +49,7 @@ class ActionService
|
||||
@agent = @account.users.find_by(id: agent_ids)
|
||||
return unless @agent.present? && @agent.confirmed?
|
||||
|
||||
@conversation.update!(assignee_id: @agent.id)
|
||||
assign_conversation_agent(@agent.id)
|
||||
end
|
||||
|
||||
def remove_label(labels)
|
||||
@@ -62,21 +62,21 @@ class ActionService
|
||||
def assign_team(team_ids = [])
|
||||
# Keep nil/0 handling for existing automation and macro payloads.
|
||||
should_unassign = team_ids.blank? || %w[nil 0].include?(team_ids[0].to_s)
|
||||
return @conversation.update!(team_id: nil) if should_unassign
|
||||
return assign_conversation_team(nil) if should_unassign
|
||||
|
||||
# check if team belongs to account only if team_id is present
|
||||
# if team_id is nil, then it means that the team is being unassigned
|
||||
return unless !team_ids[0].nil? && team_belongs_to_account?(team_ids)
|
||||
|
||||
@conversation.update!(team_id: team_ids[0])
|
||||
assign_conversation_team(team_ids[0])
|
||||
end
|
||||
|
||||
def remove_assigned_agent(_params)
|
||||
@conversation.update!(assignee_id: nil)
|
||||
assign_conversation_agent(nil)
|
||||
end
|
||||
|
||||
def remove_assigned_team(_params)
|
||||
@conversation.update!(team_id: nil)
|
||||
assign_conversation_team(nil)
|
||||
end
|
||||
|
||||
def send_email_transcript(emails)
|
||||
@@ -99,6 +99,14 @@ class ActionService
|
||||
@conversation.messages.outgoing.where(sender_type: 'User', private: false).last&.sender_id
|
||||
end
|
||||
|
||||
def assign_conversation_agent(assignee_id)
|
||||
Conversations::AssignmentService.new(conversation: @conversation, assignee_id: assignee_id).perform
|
||||
end
|
||||
|
||||
def assign_conversation_team(team_id)
|
||||
Conversations::AssignmentService.new(conversation: @conversation, team_id: team_id).perform
|
||||
end
|
||||
|
||||
def agent_belongs_to_inbox?(agent_ids)
|
||||
member_ids = @conversation.inbox.members.pluck(:user_id)
|
||||
assignable_agent_ids = member_ids + @account.administrators.ids
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
class Conversations::AssignmentService
|
||||
def initialize(conversation:, assignee_id:, assignee_type: nil)
|
||||
TEAM_ID_UNSET = Object.new.freeze
|
||||
private_constant :TEAM_ID_UNSET
|
||||
|
||||
def initialize(conversation:, assignee_id: nil, assignee_type: nil, team_id: TEAM_ID_UNSET)
|
||||
@conversation = conversation
|
||||
@assignee_id = assignee_id
|
||||
@assignee_type = assignee_type
|
||||
@team_id = team_id
|
||||
end
|
||||
|
||||
def perform
|
||||
return assign_team if team_assignment?
|
||||
|
||||
agent_bot_assignment? ? assign_agent_bot : assign_agent
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :conversation, :assignee_id, :assignee_type
|
||||
attr_reader :conversation, :assignee_id, :assignee_type, :team_id
|
||||
|
||||
def assign_agent
|
||||
bot_handoff = bot_handoff_to_human?(assignee)
|
||||
|
||||
conversation.assignee = assignee
|
||||
conversation.assignee_agent_bot = nil if assignee.blank?
|
||||
conversation.assignee_agent_bot = nil
|
||||
conversation.mark_bot_handoff if bot_handoff
|
||||
conversation.save!
|
||||
conversation.dispatch_bot_handoff if bot_handoff
|
||||
|
||||
assignee
|
||||
end
|
||||
|
||||
@@ -30,6 +41,20 @@ class Conversations::AssignmentService
|
||||
agent_bot
|
||||
end
|
||||
|
||||
def assign_team
|
||||
conversation.team = team
|
||||
validate_current_assignee_team
|
||||
conversation.assignee ||= find_assignee_from_team
|
||||
|
||||
bot_handoff = bot_handoff_to_human?(conversation.assignee)
|
||||
conversation.assignee_agent_bot = nil if conversation.assignee.present?
|
||||
conversation.mark_bot_handoff if bot_handoff
|
||||
conversation.save!
|
||||
conversation.dispatch_bot_handoff if bot_handoff
|
||||
|
||||
team
|
||||
end
|
||||
|
||||
def assignee
|
||||
@assignee ||= conversation.account.users.find_by(id: assignee_id)
|
||||
end
|
||||
@@ -41,4 +66,27 @@ class Conversations::AssignmentService
|
||||
def agent_bot_assignment?
|
||||
assignee_type.to_s == 'AgentBot'
|
||||
end
|
||||
|
||||
def team_assignment?
|
||||
team_id != TEAM_ID_UNSET
|
||||
end
|
||||
|
||||
def team
|
||||
@team ||= conversation.account.teams.find_by(id: team_id)
|
||||
end
|
||||
|
||||
def validate_current_assignee_team
|
||||
conversation.assignee = nil if team&.members&.exclude?(conversation.assignee)
|
||||
end
|
||||
|
||||
def find_assignee_from_team
|
||||
return if team&.allow_auto_assign.blank?
|
||||
|
||||
team_members_with_capacity = conversation.inbox.member_ids_with_assignment_capacity & team.members.ids
|
||||
::AutoAssignment::AgentAssignmentService.new(conversation: conversation, allowed_agent_ids: team_members_with_capacity).find_assignee
|
||||
end
|
||||
|
||||
def bot_handoff_to_human?(assignee)
|
||||
assignee.present? && conversation.assignee_agent_bot.present? && conversation.pending?
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user