diff --git a/app/controllers/api/v1/accounts/conversations/assignments_controller.rb b/app/controllers/api/v1/accounts/conversations/assignments_controller.rb index 0ac927058..49806e97c 100644 --- a/app/controllers/api/v1/accounts/conversations/assignments_controller.rb +++ b/app/controllers/api/v1/accounts/conversations/assignments_controller.rb @@ -34,11 +34,8 @@ class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Account end def set_team - @team = Conversations::AssignmentService.new( - conversation: @conversation, - team_id: params[:team_id] - ).perform - + @team = Current.account.teams.find_by(id: params[:team_id]) + @conversation.update!(team: @team) render json: @team end diff --git a/app/models/conversation.rb b/app/models/conversation.rb index f45323d12..cfde22e70 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -66,7 +66,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 @@ -117,6 +116,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 @@ -166,18 +166,9 @@ 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 @@ -280,12 +271,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? @@ -342,6 +339,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| @@ -349,6 +347,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, diff --git a/app/services/action_service.rb b/app/services/action_service.rb index 13081424b..27f513f24 100644 --- a/app/services/action_service.rb +++ b/app/services/action_service.rb @@ -41,7 +41,7 @@ class ActionService end def assign_agent(agent_ids = []) - return assign_conversation_agent(nil) if agent_ids[0] == 'nil' + return @conversation.update!(assignee_id: 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? - assign_conversation_agent(@agent.id) + @conversation.update!(assignee_id: @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 assign_conversation_team(nil) if should_unassign + return @conversation.update!(team_id: 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) - assign_conversation_team(team_ids[0]) + @conversation.update!(team_id: team_ids[0]) end def remove_assigned_agent(_params) - assign_conversation_agent(nil) + @conversation.update!(assignee_id: nil) end def remove_assigned_team(_params) - assign_conversation_team(nil) + @conversation.update!(team_id: nil) end def send_email_transcript(emails) @@ -99,14 +99,6 @@ 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 diff --git a/app/services/conversations/assignment_service.rb b/app/services/conversations/assignment_service.rb index 743b54be3..c73d41342 100644 --- a/app/services/conversations/assignment_service.rb +++ b/app/services/conversations/assignment_service.rb @@ -1,33 +1,22 @@ class Conversations::AssignmentService - 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) + def initialize(conversation:, assignee_id:, assignee_type: nil) @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, :team_id + attr_reader :conversation, :assignee_id, :assignee_type def assign_agent - bot_handoff = bot_handoff_to_human?(assignee) - conversation.assignee = assignee - conversation.assignee_agent_bot = nil - conversation.mark_bot_handoff if bot_handoff + conversation.assignee_agent_bot = nil if assignee.blank? conversation.save! - conversation.dispatch_bot_handoff if bot_handoff - assignee end @@ -41,20 +30,6 @@ 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 @@ -66,27 +41,4 @@ 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