feat: Enable Capacity Config UI (#5164)
- Enables Capacity Config in UI - Rewrite auto assignment Logic to consider only online agents fixes: #4990
This commit is contained in:
38
app/services/auto_assignment/agent_assignment_service.rb
Normal file
38
app/services/auto_assignment/agent_assignment_service.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
class AutoAssignment::AgentAssignmentService
|
||||
# Allowed agent ids: array
|
||||
# This is the list of agents from which an agent can be assigned to this conversation
|
||||
# examples: Agents with assignment capacity, Agents who are members of a team etc
|
||||
pattr_initialize [:conversation!, :allowed_agent_ids!]
|
||||
|
||||
def find_assignee
|
||||
round_robin_manage_service.available_agent(allowed_agent_ids: allowed_online_agent_ids)
|
||||
end
|
||||
|
||||
def perform
|
||||
new_assignee = find_assignee
|
||||
conversation.update(assignee: new_assignee) if new_assignee
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def online_agent_ids
|
||||
online_agents = OnlineStatusTracker.get_available_users(conversation.account_id)
|
||||
online_agents.select { |_key, value| value.eql?('online') }.keys if online_agents.present?
|
||||
end
|
||||
|
||||
def allowed_online_agent_ids
|
||||
# We want to perform roundrobin only over online agents
|
||||
# Hence taking an intersection of online agents and allowed member ids
|
||||
|
||||
# the online user ids are string, since its from redis, allowed member ids are integer, since its from active record
|
||||
@allowed_online_agent_ids ||= online_agent_ids & allowed_agent_ids&.map(&:to_s)
|
||||
end
|
||||
|
||||
def round_robin_manage_service
|
||||
@round_robin_manage_service ||= AutoAssignment::InboxRoundRobinService.new(inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
def round_robin_key
|
||||
format(::Redis::Alfred::ROUND_ROBIN_AGENTS, inbox_id: conversation.inbox_id)
|
||||
end
|
||||
end
|
||||
62
app/services/auto_assignment/inbox_round_robin_service.rb
Normal file
62
app/services/auto_assignment/inbox_round_robin_service.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
class AutoAssignment::InboxRoundRobinService
|
||||
pattr_initialize [:inbox!]
|
||||
|
||||
# called on inbox delete
|
||||
def clear_queue
|
||||
::Redis::Alfred.delete(round_robin_key)
|
||||
end
|
||||
|
||||
# called on inbox member create
|
||||
def add_agent_to_queue(user_id)
|
||||
::Redis::Alfred.lpush(round_robin_key, user_id)
|
||||
end
|
||||
|
||||
# called on inbox member delete
|
||||
def remove_agent_from_queue(user_id)
|
||||
::Redis::Alfred.lrem(round_robin_key, user_id)
|
||||
end
|
||||
|
||||
def reset_queue
|
||||
clear_queue
|
||||
add_agent_to_queue(inbox.inbox_members.map(&:user_id))
|
||||
end
|
||||
|
||||
# end of queue management functions
|
||||
|
||||
# allowed member ids = [assignable online agents supplied by the assignement service]
|
||||
# the values of allowed member ids should be in string format
|
||||
def available_agent(allowed_agent_ids: [])
|
||||
reset_queue unless validate_queue?
|
||||
user_id = get_member_from_allowed_agent_ids(allowed_agent_ids)
|
||||
inbox.inbox_members.find_by(user_id: user_id)&.user if user_id.present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_member_from_allowed_agent_ids(allowed_agent_ids)
|
||||
return nil if allowed_agent_ids.blank?
|
||||
|
||||
user_id = queue.intersection(allowed_agent_ids).pop
|
||||
pop_push_to_queue(user_id)
|
||||
user_id
|
||||
end
|
||||
|
||||
def pop_push_to_queue(user_id)
|
||||
return if user_id.blank?
|
||||
|
||||
remove_agent_from_queue(user_id)
|
||||
add_agent_to_queue(user_id)
|
||||
end
|
||||
|
||||
def validate_queue?
|
||||
return true if inbox.inbox_members.map(&:user_id).sort == queue.map(&:to_i).sort
|
||||
end
|
||||
|
||||
def queue
|
||||
::Redis::Alfred.lrange(round_robin_key)
|
||||
end
|
||||
|
||||
def round_robin_key
|
||||
format(::Redis::Alfred::ROUND_ROBIN_AGENTS, inbox_id: inbox.id)
|
||||
end
|
||||
end
|
||||
@@ -1,28 +0,0 @@
|
||||
class RoundRobin::AssignmentService
|
||||
pattr_initialize [:conversation, { allowed_member_ids: [] }]
|
||||
|
||||
def find_assignee
|
||||
round_robin_manage_service.available_agent(priority_list: online_agents)
|
||||
end
|
||||
|
||||
def perform
|
||||
# online agents will get priority
|
||||
new_assignee = find_assignee
|
||||
conversation.update(assignee: new_assignee) if new_assignee
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def online_agents
|
||||
online_agents = OnlineStatusTracker.get_available_users(conversation.account_id)
|
||||
online_agents.select { |_key, value| value.eql?('online') }.keys if online_agents.present?
|
||||
end
|
||||
|
||||
def round_robin_manage_service
|
||||
@round_robin_manage_service ||= RoundRobin::ManageService.new(inbox: conversation.inbox, allowed_member_ids: allowed_member_ids)
|
||||
end
|
||||
|
||||
def round_robin_key
|
||||
format(::Redis::Alfred::ROUND_ROBIN_AGENTS, inbox_id: conversation.inbox_id)
|
||||
end
|
||||
end
|
||||
@@ -1,85 +0,0 @@
|
||||
# NOTE: available agent method now expect allowed_member_ids to be passed in always because of inbox limits feature
|
||||
# need to refactor this class and split the queue managment into a seperate class
|
||||
|
||||
# If allowed_member_ids are supplied round robin service will only fetch a member from member id
|
||||
# This is used in case of team assignment
|
||||
class RoundRobin::ManageService
|
||||
pattr_initialize [:inbox!, { allowed_member_ids: [] }]
|
||||
|
||||
# called on inbox delete
|
||||
def clear_queue
|
||||
::Redis::Alfred.delete(round_robin_key)
|
||||
end
|
||||
|
||||
# called on inbox member create
|
||||
def add_agent_to_queue(user_id)
|
||||
::Redis::Alfred.lpush(round_robin_key, user_id)
|
||||
end
|
||||
|
||||
# called on inbox member delete
|
||||
def remove_agent_from_queue(user_id)
|
||||
::Redis::Alfred.lrem(round_robin_key, user_id)
|
||||
end
|
||||
|
||||
def reset_queue
|
||||
clear_queue
|
||||
add_agent_to_queue(inbox.inbox_members.map(&:user_id))
|
||||
end
|
||||
|
||||
# end of queue management functions
|
||||
|
||||
def available_agent(priority_list: [])
|
||||
reset_queue unless validate_queue?
|
||||
user_id = get_member_via_priority_list(priority_list)
|
||||
# incase priority list was empty or inbox members weren't present
|
||||
user_id ||= fetch_user_id
|
||||
inbox.inbox_members.find_by(user_id: user_id)&.user if user_id.present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_user_id
|
||||
return nil if allowed_member_ids_in_str.blank?
|
||||
|
||||
user_id = queue.intersection(allowed_member_ids_in_str).pop
|
||||
pop_push_to_queue(user_id)
|
||||
user_id
|
||||
end
|
||||
|
||||
# priority list is usually the members who are online passed from assignment service
|
||||
def get_member_via_priority_list(priority_list)
|
||||
return if priority_list.blank?
|
||||
|
||||
# When allowed member ids is passed we will be looking to get members from that list alone
|
||||
priority_list = priority_list.intersection(allowed_member_ids_in_str)
|
||||
return if priority_list.blank?
|
||||
|
||||
user_id = queue.intersection(priority_list.map(&:to_s)).pop
|
||||
pop_push_to_queue(user_id)
|
||||
user_id
|
||||
end
|
||||
|
||||
def pop_push_to_queue(user_id)
|
||||
return if user_id.blank?
|
||||
|
||||
remove_agent_from_queue(user_id)
|
||||
add_agent_to_queue(user_id)
|
||||
end
|
||||
|
||||
def validate_queue?
|
||||
return true if inbox.inbox_members.map(&:user_id).sort == queue.map(&:to_i).sort
|
||||
end
|
||||
|
||||
def queue
|
||||
::Redis::Alfred.lrange(round_robin_key)
|
||||
end
|
||||
|
||||
def round_robin_key
|
||||
format(::Redis::Alfred::ROUND_ROBIN_AGENTS, inbox_id: inbox.id)
|
||||
end
|
||||
|
||||
def allowed_member_ids_in_str
|
||||
# NOTE: the values which are returned from redis for priority list are string
|
||||
@allowed_member_ids_in_str ||= allowed_member_ids.map(&:to_s)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user