262 lines
9.4 KiB
Go
262 lines
9.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gochat/gochat/internal/autoassignment"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
pkgvalidator "github.com/gochat/gochat/pkg/validator"
|
|
)
|
|
|
|
// AssignmentPolicyService implements business logic for AssignmentPolicy operations.
|
|
// Reference: Chatwoot app/controllers/api/v1/assignment_policies_controller.rb
|
|
type AssignmentPolicyService struct {
|
|
policyRepo *repository.AssignmentPolicyRepo
|
|
inboxPolicyRepo *repository.InboxAssignmentPolicyRepo
|
|
assignSvc *autoassignment.AssignmentService
|
|
}
|
|
|
|
// NewAssignmentPolicyService creates a new AssignmentPolicy service.
|
|
func NewAssignmentPolicyService(
|
|
policyRepo *repository.AssignmentPolicyRepo,
|
|
inboxPolicyRepo *repository.InboxAssignmentPolicyRepo,
|
|
assignSvc *autoassignment.AssignmentService,
|
|
) *AssignmentPolicyService {
|
|
return &AssignmentPolicyService{policyRepo: policyRepo, inboxPolicyRepo: inboxPolicyRepo, assignSvc: assignSvc}
|
|
}
|
|
|
|
// CreatePolicyRequest is the DTO for creating an assignment policy.
|
|
type CreatePolicyRequest struct {
|
|
Policy string `json:"policy" validate:"required,oneof=round_robin longest_waiting lowest_load"`
|
|
FairDistributionLimit int `json:"fair_distribution_limit,omitempty"`
|
|
FairDistributionWindow int `json:"fair_distribution_window,omitempty"`
|
|
Active *bool `json:"active,omitempty"`
|
|
}
|
|
|
|
// UpdatePolicyRequest is the DTO for updating an assignment policy.
|
|
type UpdatePolicyRequest struct {
|
|
Policy string `json:"policy,omitempty" validate:"omitempty,oneof=round_robin longest_waiting lowest_load"`
|
|
FairDistributionLimit int `json:"fair_distribution_limit,omitempty"`
|
|
FairDistributionWindow int `json:"fair_distribution_window,omitempty"`
|
|
Active *bool `json:"active,omitempty"`
|
|
}
|
|
|
|
// CreateInboxPolicyRequest is the DTO for creating an inbox assignment policy.
|
|
type CreateInboxPolicyRequest struct {
|
|
InboxID uint `json:"inbox_id" validate:"required"`
|
|
Policy string `json:"policy" validate:"required,oneof=round_robin longest_waiting lowest_load"`
|
|
FairDistributionLimit int `json:"fair_distribution_limit,omitempty"`
|
|
FairDistributionWindow int `json:"fair_distribution_window,omitempty"`
|
|
Active *bool `json:"active,omitempty"`
|
|
}
|
|
|
|
// UpdateInboxPolicyRequest is the DTO for updating an inbox assignment policy.
|
|
type UpdateInboxPolicyRequest struct {
|
|
Policy string `json:"policy,omitempty" validate:"omitempty,oneof=round_robin longest_waiting lowest_load"`
|
|
FairDistributionLimit int `json:"fair_distribution_limit,omitempty"`
|
|
FairDistributionWindow int `json:"fair_distribution_window,omitempty"`
|
|
Active *bool `json:"active,omitempty"`
|
|
}
|
|
|
|
// GetAccountPolicy retrieves the account-level assignment policy.
|
|
func (s *AssignmentPolicyService) GetAccountPolicy(ctx context.Context, accountID uint) (*autoassignment.AssignmentPolicy, error) {
|
|
policy, err := s.policyRepo.FindByAccount(ctx, accountID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("assignment policy not found: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// CreateAccountPolicy creates the account-level assignment policy.
|
|
func (s *AssignmentPolicyService) CreateAccountPolicy(ctx context.Context, accountID uint, req CreatePolicyRequest) (*autoassignment.AssignmentPolicy, error) {
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
active := true
|
|
if req.Active != nil {
|
|
active = *req.Active
|
|
}
|
|
|
|
limit := 5
|
|
if req.FairDistributionLimit > 0 {
|
|
limit = req.FairDistributionLimit
|
|
}
|
|
|
|
window := 300
|
|
if req.FairDistributionWindow > 0 {
|
|
window = req.FairDistributionWindow
|
|
}
|
|
|
|
policy := &autoassignment.AssignmentPolicy{
|
|
AccountID: accountID,
|
|
Policy: autoassignment.AssignmentPolicyType(req.Policy),
|
|
FairDistributionLimit: limit,
|
|
FairDistributionWindow: window,
|
|
Active: active,
|
|
}
|
|
|
|
if err := s.policyRepo.Create(ctx, policy); err != nil {
|
|
applogger.L().Errorf("failed to create assignment policy: %v", err)
|
|
return nil, fmt.Errorf("failed to create assignment policy: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// UpdateAccountPolicy updates the account-level assignment policy.
|
|
func (s *AssignmentPolicyService) UpdateAccountPolicy(ctx context.Context, id, accountID uint, req UpdatePolicyRequest) (*autoassignment.AssignmentPolicy, error) {
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
policy, err := s.policyRepo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("assignment policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return nil, fmt.Errorf("assignment policy does not belong to account")
|
|
}
|
|
|
|
if req.Policy != "" {
|
|
policy.Policy = autoassignment.AssignmentPolicyType(req.Policy)
|
|
}
|
|
if req.FairDistributionLimit > 0 {
|
|
policy.FairDistributionLimit = req.FairDistributionLimit
|
|
}
|
|
if req.FairDistributionWindow > 0 {
|
|
policy.FairDistributionWindow = req.FairDistributionWindow
|
|
}
|
|
if req.Active != nil {
|
|
policy.Active = *req.Active
|
|
}
|
|
|
|
if err := s.policyRepo.Update(ctx, policy); err != nil {
|
|
applogger.L().Errorf("failed to update assignment policy: %v", err)
|
|
return nil, fmt.Errorf("failed to update assignment policy: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// DeleteAccountPolicy deletes the account-level assignment policy.
|
|
func (s *AssignmentPolicyService) DeleteAccountPolicy(ctx context.Context, id, accountID uint) error {
|
|
policy, err := s.policyRepo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("assignment policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return fmt.Errorf("assignment policy does not belong to account")
|
|
}
|
|
|
|
if err := s.policyRepo.Delete(ctx, id); err != nil {
|
|
return fmt.Errorf("failed to delete assignment policy: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetInboxPolicy retrieves the inbox-level assignment policy override.
|
|
func (s *AssignmentPolicyService) GetInboxPolicy(ctx context.Context, accountID, inboxID uint) (*autoassignment.InboxAssignmentPolicy, error) {
|
|
policy, err := s.inboxPolicyRepo.FindByInbox(ctx, accountID, inboxID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("inbox assignment policy not found: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// CreateInboxPolicy creates an inbox-level assignment policy override.
|
|
func (s *AssignmentPolicyService) CreateInboxPolicy(ctx context.Context, accountID uint, req CreateInboxPolicyRequest) (*autoassignment.InboxAssignmentPolicy, error) {
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
active := true
|
|
if req.Active != nil {
|
|
active = *req.Active
|
|
}
|
|
|
|
limit := 5
|
|
if req.FairDistributionLimit > 0 {
|
|
limit = req.FairDistributionLimit
|
|
}
|
|
|
|
window := 300
|
|
if req.FairDistributionWindow > 0 {
|
|
window = req.FairDistributionWindow
|
|
}
|
|
|
|
policy := &autoassignment.InboxAssignmentPolicy{
|
|
AccountID: accountID,
|
|
InboxID: req.InboxID,
|
|
Policy: autoassignment.AssignmentPolicyType(req.Policy),
|
|
FairDistributionLimit: limit,
|
|
FairDistributionWindow: window,
|
|
Active: active,
|
|
}
|
|
|
|
if err := s.inboxPolicyRepo.Create(ctx, policy); err != nil {
|
|
applogger.L().Errorf("failed to create inbox assignment policy: %v", err)
|
|
return nil, fmt.Errorf("failed to create inbox assignment policy: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// UpdateInboxPolicy updates an inbox-level assignment policy override.
|
|
func (s *AssignmentPolicyService) UpdateInboxPolicy(ctx context.Context, id, accountID uint, req UpdateInboxPolicyRequest) (*autoassignment.InboxAssignmentPolicy, error) {
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
policy, err := s.inboxPolicyRepo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("inbox assignment policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return nil, fmt.Errorf("inbox assignment policy does not belong to account")
|
|
}
|
|
|
|
if req.Policy != "" {
|
|
policy.Policy = autoassignment.AssignmentPolicyType(req.Policy)
|
|
}
|
|
if req.FairDistributionLimit > 0 {
|
|
policy.FairDistributionLimit = req.FairDistributionLimit
|
|
}
|
|
if req.FairDistributionWindow > 0 {
|
|
policy.FairDistributionWindow = req.FairDistributionWindow
|
|
}
|
|
if req.Active != nil {
|
|
policy.Active = *req.Active
|
|
}
|
|
|
|
if err := s.inboxPolicyRepo.Update(ctx, policy); err != nil {
|
|
applogger.L().Errorf("failed to update inbox assignment policy: %v", err)
|
|
return nil, fmt.Errorf("failed to update inbox assignment policy: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// DeleteInboxPolicy deletes an inbox-level assignment policy override.
|
|
func (s *AssignmentPolicyService) DeleteInboxPolicy(ctx context.Context, id, accountID uint) error {
|
|
policy, err := s.inboxPolicyRepo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("inbox assignment policy not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return fmt.Errorf("inbox assignment policy does not belong to account")
|
|
}
|
|
|
|
if err := s.inboxPolicyRepo.Delete(ctx, id); err != nil {
|
|
return fmt.Errorf("failed to delete inbox assignment policy: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AssignConversation assigns a specific conversation to an agent using auto-assignment.
|
|
func (s *AssignmentPolicyService) AssignConversation(ctx context.Context, conversationID, inboxID, accountID uint) (uint, error) {
|
|
agentID, err := s.assignSvc.AssignConversation(ctx, conversationID, inboxID, accountID)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to assign conversation: %w", err)
|
|
}
|
|
return agentID, nil
|
|
}
|