164 lines
5.9 KiB
Go
164 lines
5.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
)
|
|
|
|
// AgentCapacityPolicyService implements business logic for AgentCapacityPolicy operations.
|
|
// Reference: Chatwoot AgentCapacityPolicy + P2B M1 spec
|
|
type AgentCapacityPolicyService struct {
|
|
repo *repository.AgentCapacityPolicyRepo
|
|
}
|
|
|
|
// NewAgentCapacityPolicyService creates a new AgentCapacityPolicy service.
|
|
func NewAgentCapacityPolicyService(repo *repository.AgentCapacityPolicyRepo) *AgentCapacityPolicyService {
|
|
return &AgentCapacityPolicyService{repo: repo}
|
|
}
|
|
|
|
// CreateAgentCapacityPolicyRequest is the DTO for creating an agent capacity policy.
|
|
// Request body uses Chatwoot-style wrapper: { "agent_capacity_policy": { ... } }
|
|
type CreateAgentCapacityPolicyRequest struct {
|
|
Name string `json:"name" validate:"required"`
|
|
Description string `json:"description,omitempty"`
|
|
AssignmentLogic string `json:"assignment_logic" validate:"required"`
|
|
ExclusionRules json.RawMessage `json:"exclusion_rules,omitempty"`
|
|
}
|
|
|
|
// UpdateAgentCapacityPolicyRequest is the DTO for updating an agent capacity policy.
|
|
// Request body uses Chatwoot-style wrapper: { "agent_capacity_policy": { ... } }
|
|
type UpdateAgentCapacityPolicyRequest struct {
|
|
Name string `json:"name,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
AssignmentLogic string `json:"assignment_logic,omitempty"`
|
|
ExclusionRules json.RawMessage `json:"exclusion_rules,omitempty"`
|
|
}
|
|
|
|
// validAssignmentLogic values allowed for AssignmentLogic field.
|
|
var validAssignmentLogic = map[string]bool{
|
|
"round_robin": true,
|
|
"least_busy": true,
|
|
}
|
|
|
|
// validateAssignmentLogic checks that the assignment logic is one of the allowed values.
|
|
func validateAssignmentLogic(logic string) error {
|
|
if !validAssignmentLogic[logic] {
|
|
return fmt.Errorf("invalid assignment_logic: must be one of round_robin, least_busy")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// paginate normalises page/pageSize to sane defaults and computes offset.
|
|
func paginate(page, pageSize int) (offset, normPageSize int) {
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if pageSize < 1 {
|
|
pageSize = 25
|
|
}
|
|
if pageSize > 100 {
|
|
pageSize = 100
|
|
}
|
|
return (page - 1) * pageSize, pageSize
|
|
}
|
|
|
|
// List retrieves all agent capacity policies for an account with pagination.
|
|
func (s *AgentCapacityPolicyService) List(ctx context.Context, accountID uint, page, pageSize int) ([]model.AgentCapacityPolicy, int64, error) {
|
|
offset, pageSize := paginate(page, pageSize)
|
|
|
|
policies, total, err := s.repo.FindByAccount(ctx, accountID, offset, pageSize)
|
|
if err != nil {
|
|
applogger.L().Errorf("List agent capacity policies for account %d: %v", accountID, err)
|
|
return nil, 0, fmt.Errorf("failed to list agent capacity policies: %w", err)
|
|
}
|
|
return policies, total, nil
|
|
}
|
|
|
|
// Create creates a new agent capacity policy within an account.
|
|
func (s *AgentCapacityPolicyService) Create(ctx context.Context, accountID uint, req CreateAgentCapacityPolicyRequest) (*model.AgentCapacityPolicy, error) {
|
|
if err := validateAssignmentLogic(req.AssignmentLogic); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
policy := &model.AgentCapacityPolicy{
|
|
AccountID: accountID,
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
AssignmentLogic: req.AssignmentLogic,
|
|
ExclusionRules: req.ExclusionRules,
|
|
}
|
|
|
|
if err := s.repo.Create(ctx, policy); err != nil {
|
|
applogger.L().Errorf("failed to create agent capacity policy: %v", err)
|
|
return nil, fmt.Errorf("failed to create agent capacity policy: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// Update updates an existing agent capacity policy scoped to an account.
|
|
func (s *AgentCapacityPolicyService) Update(ctx context.Context, id, accountID uint, req UpdateAgentCapacityPolicyRequest) (*model.AgentCapacityPolicy, error) {
|
|
policy, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("agent capacity policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return nil, fmt.Errorf("agent capacity policy not found: policy does not belong to account %d", accountID)
|
|
}
|
|
|
|
// Merge fields: only update non-empty values
|
|
if req.Name != "" {
|
|
policy.Name = req.Name
|
|
}
|
|
if req.Description != "" {
|
|
policy.Description = req.Description
|
|
}
|
|
if req.AssignmentLogic != "" {
|
|
if err := validateAssignmentLogic(req.AssignmentLogic); err != nil {
|
|
return nil, err
|
|
}
|
|
policy.AssignmentLogic = req.AssignmentLogic
|
|
}
|
|
if req.ExclusionRules != nil {
|
|
policy.ExclusionRules = req.ExclusionRules
|
|
}
|
|
|
|
if err := s.repo.Update(ctx, policy); err != nil {
|
|
applogger.L().Errorf("failed to update agent capacity policy %d: %v", id, err)
|
|
return nil, fmt.Errorf("failed to update agent capacity policy: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// Delete deletes an agent capacity policy scoped to an account.
|
|
func (s *AgentCapacityPolicyService) Delete(ctx context.Context, id, accountID uint) error {
|
|
policy, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("agent capacity policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return fmt.Errorf("agent capacity policy not found: policy does not belong to account %d", accountID)
|
|
}
|
|
|
|
if err := s.repo.Delete(ctx, id); err != nil {
|
|
applogger.L().Errorf("failed to delete agent capacity policy %d for account %d: %v", id, accountID, err)
|
|
return fmt.Errorf("failed to delete agent capacity policy: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetByID retrieves a single agent capacity policy scoped to an account.
|
|
func (s *AgentCapacityPolicyService) GetByID(ctx context.Context, id, accountID uint) (*model.AgentCapacityPolicy, error) {
|
|
policy, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("agent capacity policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return nil, fmt.Errorf("agent capacity policy not found: policy does not belong to account %d", accountID)
|
|
}
|
|
return policy, nil
|
|
} |