feat: Add agent capacity controllers (#12200)

## Linear reference:
https://linear.app/chatwoot/issue/CW-4649/re-imagine-assignments

## Description
This PR introduces the foundation for Assignment V2 system by
implementing agent_capacity and their association with inboxes and
users.

## Type of change

- [ ] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Test Coverage:
-  Controller specs for assignment policies CRUD operations
-  Enterprise-specific specs for balanced assignment order
-  Model specs for community/enterprise separation

## 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

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
Tanmay Deep Sharma
2025-08-27 09:12:58 +07:00
committed by GitHub
parent 39dfa35229
commit ad90deb709
26 changed files with 679 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
class Api::V1::Accounts::AgentCapacityPolicies::InboxLimitsController < Api::V1::Accounts::EnterpriseAccountsController
before_action -> { check_authorization(AgentCapacityPolicy) }
before_action :fetch_policy
before_action :fetch_inbox, only: [:create]
before_action :fetch_inbox_limit, only: [:update, :destroy]
before_action :validate_no_duplicate, only: [:create]
def create
@inbox_limit = @agent_capacity_policy.inbox_capacity_limits.create!(
inbox: @inbox,
conversation_limit: permitted_params[:conversation_limit]
)
end
def update
@inbox_limit.update!(conversation_limit: permitted_params[:conversation_limit])
end
def destroy
@inbox_limit.destroy!
head :no_content
end
private
def fetch_policy
@agent_capacity_policy = Current.account.agent_capacity_policies.find(params[:agent_capacity_policy_id])
end
def fetch_inbox
@inbox = Current.account.inboxes.find(permitted_params[:inbox_id])
end
def fetch_inbox_limit
@inbox_limit = @agent_capacity_policy.inbox_capacity_limits.find(params[:id])
end
def validate_no_duplicate
return unless @agent_capacity_policy.inbox_capacity_limits.exists?(inbox: @inbox)
render_could_not_create_error(I18n.t('agent_capacity_policy.inbox_already_assigned'))
end
def permitted_params
params.permit(:inbox_id, :conversation_limit)
end
end

View File

@@ -0,0 +1,35 @@
class Api::V1::Accounts::AgentCapacityPolicies::UsersController < Api::V1::Accounts::EnterpriseAccountsController
before_action -> { check_authorization(AgentCapacityPolicy) }
before_action :fetch_policy
before_action :fetch_user, only: [:destroy]
def index
@users = Current.account.users.joins(:account_users)
.where(account_users: { agent_capacity_policy_id: @agent_capacity_policy.id })
end
def create
@account_user = Current.account.account_users.find_by!(user_id: permitted_params[:user_id])
@account_user.update!(agent_capacity_policy: @agent_capacity_policy)
@user = @account_user.user
end
def destroy
@account_user.update!(agent_capacity_policy: nil)
head :ok
end
private
def fetch_policy
@agent_capacity_policy = Current.account.agent_capacity_policies.find(params[:agent_capacity_policy_id])
end
def fetch_user
@account_user = Current.account.account_users.find_by!(user_id: params[:id])
end
def permitted_params
params.permit(:user_id)
end
end

View File

@@ -0,0 +1,37 @@
class Api::V1::Accounts::AgentCapacityPoliciesController < Api::V1::Accounts::EnterpriseAccountsController
before_action :check_authorization
before_action :fetch_policy, only: [:show, :update, :destroy]
def index
@agent_capacity_policies = Current.account.agent_capacity_policies
end
def show; end
def create
@agent_capacity_policy = Current.account.agent_capacity_policies.create!(permitted_params)
end
def update
@agent_capacity_policy.update!(permitted_params)
end
def destroy
@agent_capacity_policy.destroy!
head :ok
end
private
def permitted_params
params.require(:agent_capacity_policy).permit(
:name,
:description,
exclusion_rules: [:overall_capacity, { hours: [], days: [] }]
)
end
def fetch_policy
@agent_capacity_policy = Current.account.agent_capacity_policies.find(params[:id])
end
end