mirror of
https://github.com/chatwoot/chatwoot.git
synced 2026-06-04 21:02:35 +08:00
## Description Fixes a bug under Assignment V2 where a single conversation could be reassigned dozens of times in a row by the system, producing long stacks of "Assigned to X by Automation System via <policy>" activity messages alternating between agents. After this change each unassigned conversation is assigned exactly once, even on busy inboxes. ## Fixes # (issue) ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? ## How to reproduce 1. Enable `assignment_v2` on an account with at least 2 online agents in an inbox. 2. Generate sustained resolve/snooze activity in the inbox (each one enqueues `AutoAssignment::AssignmentJob` for the whole inbox). 3. Watch any one unassigned conversation while the jobs drain — pre-fix it picks up multiple back-to-back "Assigned to …" activity rows alternating between agents. ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules
50 lines
2.0 KiB
Ruby
50 lines
2.0 KiB
Ruby
module AutoAssignmentHandler
|
|
extend ActiveSupport::Concern
|
|
include Events::Types
|
|
|
|
included do
|
|
after_save :run_auto_assignment
|
|
end
|
|
|
|
private
|
|
|
|
def run_auto_assignment
|
|
# Assignment V2: Also trigger assignment when conversation is resolved or snoozed,
|
|
# bypassing the open-only condition so the AssignmentJob can redistribute capacity.
|
|
return unless conversation_status_changed_to_open? || conversation_status_changed_to_resolved_or_snoozed?
|
|
return unless should_run_auto_assignment?
|
|
|
|
if inbox.auto_assignment_v2_enabled?
|
|
# Coalesces bursts of triggers per inbox. Fine if the job runs even when the
|
|
# surrounding save rolls back: it only scans the inbox's current unassigned
|
|
# conversations, so running it for an uncommitted change is harmless.
|
|
AutoAssignment::AssignmentJob.enqueue_for_inbox(inbox.id)
|
|
else
|
|
# Use legacy assignment system
|
|
# If conversation has a team, only consider team members for assignment
|
|
allowed_agent_ids = team_id.present? ? team_member_ids_with_capacity : inbox.member_ids_with_assignment_capacity
|
|
AutoAssignment::AgentAssignmentService.new(conversation: self, allowed_agent_ids: allowed_agent_ids).perform
|
|
end
|
|
end
|
|
|
|
def conversation_status_changed_to_resolved_or_snoozed?
|
|
inbox.auto_assignment_v2_enabled? && saved_change_to_status? && (resolved? || snoozed?)
|
|
end
|
|
|
|
def team_member_ids_with_capacity
|
|
return [] if team.blank? || team.allow_auto_assign.blank?
|
|
|
|
inbox.member_ids_with_assignment_capacity & team.members.ids
|
|
end
|
|
|
|
def should_run_auto_assignment?
|
|
return false unless inbox.enable_auto_assignment?
|
|
# Assignment V2: Resolved/snoozed conversations still have an assignee, so bypass the
|
|
# assignee-blank check below. The AssignmentJob needs to run to rebalance assignments.
|
|
return true if conversation_status_changed_to_resolved_or_snoozed?
|
|
|
|
# run only if assignee is blank or doesn't have access to inbox
|
|
assignee.blank? || inbox.members.exclude?(assignee)
|
|
end
|
|
end
|