102 lines
4.6 KiB
Go
102 lines
4.6 KiB
Go
package autoassignment
|
|
|
|
// GORM models for the auto-assignment system.
|
|
//
|
|
// Reference: Chatwoot AutoAssignment pattern
|
|
// - AssignmentPolicy: global policy for how conversations are assigned
|
|
// (round_robin, longest_waiting). Has fair_distribution_limit and
|
|
// fair_distribution_window for rate limiting per agent.
|
|
// - InboxAssignmentPolicy: per-inbox override of the global policy.
|
|
// Each inbox can have its own assignment policy and rate limits.
|
|
//
|
|
// Pattern: gochat models embed model.Base (ID, CreatedAt, UpdatedAt, DeletedAt),
|
|
// use TableName() method, and use gorm struct tags.
|
|
|
|
import (
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
// AssignmentPolicyType defines the type of auto-assignment policy.
|
|
type AssignmentPolicyType string
|
|
|
|
const (
|
|
// PolicyRoundRobin assigns conversations to agents in round-robin order.
|
|
// Reference: Chatwoot InboxRoundRobinService
|
|
PolicyRoundRobin AssignmentPolicyType = "round_robin"
|
|
|
|
// PolicyLongestWaiting assigns conversations to the agent with the
|
|
// longest idle time since their last assignment.
|
|
// Reference: Chatwoot "longest_waiting" policy (planned feature)
|
|
PolicyLongestWaiting AssignmentPolicyType = "longest_waiting"
|
|
|
|
// PolicyLowestLoad assigns conversations to the agent with the
|
|
// fewest currently open conversations.
|
|
// Reference: Chatwoot "least_busy" concept — agent with lowest workload.
|
|
PolicyLowestLoad AssignmentPolicyType = "lowest_load"
|
|
)
|
|
|
|
// AssignmentPolicy represents the global auto-assignment policy for an account.
|
|
// Reference: Chatwoot AssignmentPolicy model
|
|
// - Defines how unassigned conversations are distributed among agents
|
|
// - fair_distribution_limit: max assignments per agent per window (default 5)
|
|
// - fair_distribution_window: time window in seconds for rate limiting (default 300 = 5 min)
|
|
type AssignmentPolicy struct {
|
|
model.Base
|
|
AccountID uint `gorm:"index;not null" json:"account_id"`
|
|
Policy AssignmentPolicyType `gorm:"size:50;default:round_robin" json:"policy"`
|
|
FairDistributionLimit int `gorm:"default:5" json:"fair_distribution_limit"`
|
|
FairDistributionWindow int `gorm:"default:300" json:"fair_distribution_window"` // seconds
|
|
Active bool `gorm:"default:true" json:"active"`
|
|
}
|
|
|
|
func (AssignmentPolicy) TableName() string { return "assignment_policies" }
|
|
|
|
// InboxAssignmentPolicy represents a per-inbox override of the global assignment policy.
|
|
// Reference: Chatwoot InboxAssignmentPolicy model
|
|
// - Each inbox can override the account-level policy
|
|
// - If no inbox-specific policy exists, the account policy is used
|
|
type InboxAssignmentPolicy struct {
|
|
model.Base
|
|
AccountID uint `gorm:"index;not null" json:"account_id"`
|
|
InboxID uint `gorm:"uniqueIndex;not null" json:"inbox_id"`
|
|
Policy AssignmentPolicyType `gorm:"size:50;default:round_robin" json:"policy"`
|
|
FairDistributionLimit int `gorm:"default:5" json:"fair_distribution_limit"`
|
|
FairDistributionWindow int `gorm:"default:300" json:"fair_distribution_window"` // seconds
|
|
Active bool `gorm:"default:true" json:"active"`
|
|
}
|
|
|
|
func (InboxAssignmentPolicy) TableName() string { return "inbox_assignment_policies" }
|
|
|
|
// EffectivePolicy returns the effective assignment policy for a given inbox.
|
|
// If the inbox has a specific policy, it is used; otherwise the account policy is used.
|
|
func EffectivePolicy(accountPolicy *AssignmentPolicy, inboxPolicy *InboxAssignmentPolicy) AssignmentPolicyType {
|
|
if inboxPolicy != nil && inboxPolicy.Active {
|
|
return inboxPolicy.Policy
|
|
}
|
|
if accountPolicy != nil && accountPolicy.Active {
|
|
return accountPolicy.Policy
|
|
}
|
|
return PolicyRoundRobin // default
|
|
}
|
|
|
|
// EffectiveLimit returns the effective fair distribution limit for a given inbox.
|
|
func EffectiveLimit(accountPolicy *AssignmentPolicy, inboxPolicy *InboxAssignmentPolicy) int {
|
|
if inboxPolicy != nil && inboxPolicy.Active && inboxPolicy.FairDistributionLimit > 0 {
|
|
return inboxPolicy.FairDistributionLimit
|
|
}
|
|
if accountPolicy != nil && accountPolicy.FairDistributionLimit > 0 {
|
|
return accountPolicy.FairDistributionLimit
|
|
}
|
|
return 5 // default
|
|
}
|
|
|
|
// EffectiveWindow returns the effective fair distribution window (in seconds).
|
|
func EffectiveWindow(accountPolicy *AssignmentPolicy, inboxPolicy *InboxAssignmentPolicy) int {
|
|
if inboxPolicy != nil && inboxPolicy.Active && inboxPolicy.FairDistributionWindow > 0 {
|
|
return inboxPolicy.FairDistributionWindow
|
|
}
|
|
if accountPolicy != nil && accountPolicy.FairDistributionWindow > 0 {
|
|
return accountPolicy.FairDistributionWindow
|
|
}
|
|
return 300 // default (5 minutes)
|
|
} |