306 lines
10 KiB
Go
306 lines
10 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"gorm.io/datatypes"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
// SlaPolicyRepo implements GORM repository for SlaPolicy.
|
|
type SlaPolicyRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewSlaPolicyRepo creates a new SlaPolicy repository.
|
|
func NewSlaPolicyRepo(db *gorm.DB) *SlaPolicyRepo {
|
|
return &SlaPolicyRepo{db: db}
|
|
}
|
|
|
|
// Create creates a new SLA policy.
|
|
func (r *SlaPolicyRepo) Create(ctx context.Context, policy *model.SlaPolicy) error {
|
|
return r.db.WithContext(ctx).Create(policy).Error
|
|
}
|
|
|
|
// FindByID retrieves a SLA policy by primary key.
|
|
func (r *SlaPolicyRepo) FindByID(ctx context.Context, id uint) (*model.SlaPolicy, error) {
|
|
var policy model.SlaPolicy
|
|
if err := r.db.WithContext(ctx).First(&policy, id).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &policy, nil
|
|
}
|
|
|
|
// FindByAccount retrieves all SLA policies for an account.
|
|
func (r *SlaPolicyRepo) FindByAccount(ctx context.Context, accountID uint) ([]model.SlaPolicy, error) {
|
|
var policies []model.SlaPolicy
|
|
if err := r.db.WithContext(ctx).Where("account_id = ?", accountID).Find(&policies).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return policies, nil
|
|
}
|
|
|
|
// Update updates a SLA policy.
|
|
func (r *SlaPolicyRepo) Update(ctx context.Context, policy *model.SlaPolicy) error {
|
|
return r.db.WithContext(ctx).Save(policy).Error
|
|
}
|
|
|
|
// Delete soft-deletes a SLA policy.
|
|
func (r *SlaPolicyRepo) Delete(ctx context.Context, id uint) error {
|
|
return r.db.WithContext(ctx).Delete(&model.SlaPolicy{}, id).Error
|
|
}
|
|
|
|
// AppliedSlaRepo implements GORM repository for AppliedSLA.
|
|
type AppliedSlaRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// DB returns the underlying gorm.DB for serializer/report queries.
|
|
func (r *AppliedSlaRepo) DB() *gorm.DB {
|
|
return r.db
|
|
}
|
|
|
|
// NewAppliedSlaRepo creates a new AppliedSLA repository.
|
|
func NewAppliedSlaRepo(db *gorm.DB) *AppliedSlaRepo {
|
|
return &AppliedSlaRepo{db: db}
|
|
}
|
|
|
|
// FindByConversation retrieves the applied SLA for a conversation.
|
|
func (r *AppliedSlaRepo) FindByConversation(ctx context.Context, conversationID uint) (*model.AppliedSLA, error) {
|
|
var applied model.AppliedSLA
|
|
if err := r.db.WithContext(ctx).
|
|
Where("conversation_id = ?", conversationID).
|
|
First(&applied).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &applied, nil
|
|
}
|
|
|
|
// FindByAccount retrieves all applied SLAs for an account.
|
|
func (r *AppliedSlaRepo) FindByAccount(ctx context.Context, accountID uint) ([]model.AppliedSLA, error) {
|
|
var applied []model.AppliedSLA
|
|
if err := r.db.WithContext(ctx).
|
|
Preload("SlaPolicy").
|
|
Preload("SlaEvents").
|
|
Where("account_id = ?", accountID).
|
|
Find(&applied).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return applied, nil
|
|
}
|
|
|
|
// AppliedSlaReportFilter contains Chatwoot applied_slas report filters.
|
|
type AppliedSlaReportFilter struct {
|
|
Since *time.Time
|
|
Until *time.Time
|
|
InboxID *uint
|
|
TeamID *uint
|
|
SlaPolicyID *uint
|
|
LabelList string
|
|
AssignedAgentID *uint
|
|
SLAStatus string
|
|
}
|
|
|
|
// FindReport returns filtered applied SLAs with report preloads.
|
|
func (r *AppliedSlaRepo) FindReport(ctx context.Context, accountID uint, filter AppliedSlaReportFilter, missedOnly bool, offset, limit int) ([]model.AppliedSLA, int64, error) {
|
|
base := r.reportQuery(ctx, accountID, filter, missedOnly)
|
|
|
|
var total int64
|
|
if err := base.Session(&gorm.Session{}).Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
query := base.Preload("SlaPolicy").Preload("SlaEvents").Order("applied_slas.created_at DESC")
|
|
if limit > 0 {
|
|
query = query.Offset(offset).Limit(limit)
|
|
}
|
|
|
|
var applied []model.AppliedSLA
|
|
if err := query.Find(&applied).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return applied, total, nil
|
|
}
|
|
|
|
// CountReport returns total and missed counts for Chatwoot SLA report metrics.
|
|
func (r *AppliedSlaRepo) CountReport(ctx context.Context, accountID uint, filter AppliedSlaReportFilter) (int64, int64, error) {
|
|
var total int64
|
|
if err := r.reportQuery(ctx, accountID, filter, false).Count(&total).Error; err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
var missed int64
|
|
if err := r.reportQuery(ctx, accountID, filter, true).Count(&missed).Error; err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return total, missed, nil
|
|
}
|
|
|
|
func (r *AppliedSlaRepo) reportQuery(ctx context.Context, accountID uint, filter AppliedSlaReportFilter, missedOnly bool) *gorm.DB {
|
|
query := r.db.WithContext(ctx).Model(&model.AppliedSLA{}).
|
|
Where("applied_slas.account_id = ?", accountID)
|
|
|
|
if filter.Since != nil {
|
|
query = query.Where("applied_slas.created_at >= ?", *filter.Since)
|
|
}
|
|
if filter.Until != nil {
|
|
query = query.Where("applied_slas.created_at <= ?", *filter.Until)
|
|
}
|
|
if filter.SlaPolicyID != nil && *filter.SlaPolicyID != 0 {
|
|
query = query.Where("applied_slas.sla_policy_id = ?", *filter.SlaPolicyID)
|
|
}
|
|
if filter.SLAStatus != "" {
|
|
query = query.Where("applied_slas.sla_status = ?", filter.SLAStatus)
|
|
}
|
|
if missedOnly {
|
|
query = query.Where("applied_slas.sla_status IN ?", []model.SLAStatus{model.SLAStatusMissed, model.SLAStatusActiveWithMisses})
|
|
}
|
|
|
|
needsConversation := filter.InboxID != nil || filter.TeamID != nil || filter.AssignedAgentID != nil || filter.LabelList != ""
|
|
if needsConversation {
|
|
query = query.Joins("JOIN conversations ON conversations.id = applied_slas.conversation_id")
|
|
if filter.InboxID != nil && *filter.InboxID != 0 {
|
|
query = query.Where("conversations.inbox_id = ?", *filter.InboxID)
|
|
}
|
|
if filter.TeamID != nil && *filter.TeamID != 0 {
|
|
query = query.Where("conversations.team_id = ?", *filter.TeamID)
|
|
}
|
|
if filter.AssignedAgentID != nil && *filter.AssignedAgentID != 0 {
|
|
query = query.Where("conversations.assignee_id = ?", *filter.AssignedAgentID)
|
|
}
|
|
if filter.LabelList != "" {
|
|
query = query.Where("conversations.labels LIKE ?", "%"+filter.LabelList+"%")
|
|
}
|
|
}
|
|
|
|
return query
|
|
}
|
|
|
|
// Create creates a new applied SLA record.
|
|
func (r *AppliedSlaRepo) Create(ctx context.Context, applied *model.AppliedSLA) error {
|
|
return r.db.WithContext(ctx).Create(applied).Error
|
|
}
|
|
|
|
// FindByID retrieves an applied SLA by primary key.
|
|
func (r *AppliedSlaRepo) FindByID(ctx context.Context, id uint) (*model.AppliedSLA, error) {
|
|
var applied model.AppliedSLA
|
|
if err := r.db.WithContext(ctx).First(&applied, id).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &applied, nil
|
|
}
|
|
|
|
// Update persists changes to an existing AppliedSLA record.
|
|
func (r *AppliedSlaRepo) Update(ctx context.Context, applied *model.AppliedSLA) error {
|
|
return r.db.WithContext(ctx).Save(applied).Error
|
|
}
|
|
|
|
// Delete soft-deletes an applied SLA.
|
|
func (r *AppliedSlaRepo) Delete(ctx context.Context, id uint) error {
|
|
return r.db.WithContext(ctx).Delete(&model.AppliedSLA{}, id).Error
|
|
}
|
|
|
|
// SlaEventRepo implements GORM repository for SlaEvent.
|
|
type SlaEventRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewSlaEventRepo creates a new SlaEvent repository.
|
|
func NewSlaEventRepo(db *gorm.DB) *SlaEventRepo {
|
|
return &SlaEventRepo{db: db}
|
|
}
|
|
|
|
// FindByAppliedSla retrieves all SLA events for an applied SLA.
|
|
func (r *SlaEventRepo) FindByAppliedSla(ctx context.Context, appliedSlaID uint) ([]model.SlaEvent, error) {
|
|
var events []model.SlaEvent
|
|
if err := r.db.WithContext(ctx).
|
|
Where("applied_sla_id = ?", appliedSlaID).
|
|
Find(&events).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return events, nil
|
|
}
|
|
|
|
// ExistsByAppliedSlaEventAndMeta checks whether a missed SLA threshold was already recorded.
|
|
func (r *SlaEventRepo) ExistsByAppliedSlaEventAndMeta(ctx context.Context, appliedSlaID uint, eventType model.SLAEventType, meta datatypes.JSON) (bool, error) {
|
|
var count int64
|
|
query := r.db.WithContext(ctx).Model(&model.SlaEvent{}).
|
|
Where("applied_sla_id = ? AND event_type = ?", appliedSlaID, eventType)
|
|
if len(meta) > 0 {
|
|
query = query.Where("meta = ?", meta)
|
|
}
|
|
if err := query.Count(&count).Error; err != nil {
|
|
return false, err
|
|
}
|
|
return count > 0, nil
|
|
}
|
|
|
|
// Create creates a new SLA event.
|
|
func (r *SlaEventRepo) Create(ctx context.Context, event *model.SlaEvent) error {
|
|
return r.db.WithContext(ctx).Create(event).Error
|
|
}
|
|
|
|
// Delete soft-deletes a SLA event.
|
|
func (r *SlaEventRepo) Delete(ctx context.Context, id uint) error {
|
|
return r.db.WithContext(ctx).Delete(&model.SlaEvent{}, id).Error
|
|
}
|
|
|
|
// SlaPolicyInboxRepo implements GORM repository for SlaPolicyInbox (join table).
|
|
type SlaPolicyInboxRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewSlaPolicyInboxRepo creates a new SlaPolicyInbox repository.
|
|
func NewSlaPolicyInboxRepo(db *gorm.DB) *SlaPolicyInboxRepo {
|
|
return &SlaPolicyInboxRepo{db: db}
|
|
}
|
|
|
|
// Create creates a new SLA policy inbox association.
|
|
func (r *SlaPolicyInboxRepo) Create(ctx context.Context, spi *model.SlaPolicyInbox) error {
|
|
return r.db.WithContext(ctx).Create(spi).Error
|
|
}
|
|
|
|
// FindBySlaPolicy retrieves all inbox associations for a SLA policy.
|
|
func (r *SlaPolicyInboxRepo) FindBySlaPolicy(ctx context.Context, slaPolicyID uint) ([]model.SlaPolicyInbox, error) {
|
|
var spInboxes []model.SlaPolicyInbox
|
|
if err := r.db.WithContext(ctx).
|
|
Where("sla_policy_id = ?", slaPolicyID).
|
|
Find(&spInboxes).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return spInboxes, nil
|
|
}
|
|
|
|
// FindByInbox retrieves the SLA policy inbox association for a specific inbox.
|
|
func (r *SlaPolicyInboxRepo) FindByInbox(ctx context.Context, inboxID uint) (*model.SlaPolicyInbox, error) {
|
|
var spi model.SlaPolicyInbox
|
|
if err := r.db.WithContext(ctx).
|
|
Where("inbox_id = ?", inboxID).
|
|
First(&spi).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &spi, nil
|
|
}
|
|
|
|
// Delete soft-deletes a SLA policy inbox association.
|
|
func (r *SlaPolicyInboxRepo) Delete(ctx context.Context, id uint) error {
|
|
return r.db.WithContext(ctx).Delete(&model.SlaPolicyInbox{}, id).Error
|
|
}
|
|
|
|
// DeleteBySlaPolicy removes all inbox associations for a SLA policy.
|
|
func (r *SlaPolicyInboxRepo) DeleteBySlaPolicy(ctx context.Context, slaPolicyID uint) error {
|
|
return r.db.WithContext(ctx).
|
|
Where("sla_policy_id = ?", slaPolicyID).
|
|
Delete(&model.SlaPolicyInbox{}).Error
|
|
}
|
|
|
|
// DeleteByInbox removes the SLA policy association for a specific inbox.
|
|
func (r *SlaPolicyInboxRepo) DeleteByInbox(ctx context.Context, inboxID uint) error {
|
|
return r.db.WithContext(ctx).
|
|
Where("inbox_id = ?", inboxID).
|
|
Delete(&model.SlaPolicyInbox{}).Error
|
|
}
|