package repository import ( "context" "eslogad-be/internal/entities" "github.com/google/uuid" "gorm.io/gorm" ) type ApprovalFlowRepository struct{ db *gorm.DB } func NewApprovalFlowRepository(db *gorm.DB) *ApprovalFlowRepository { return &ApprovalFlowRepository{db: db} } func (r *ApprovalFlowRepository) Create(ctx context.Context, e *entities.ApprovalFlow) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *ApprovalFlowRepository) Get(ctx context.Context, id uuid.UUID) (*entities.ApprovalFlow, error) { db := DBFromContext(ctx, r.db) var e entities.ApprovalFlow if err := db.WithContext(ctx). Preload("Department"). Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step_order ASC, parallel_group ASC") }). Preload("Steps.ApproverRole"). Preload("Steps.ApproverUser"). Where("id = ?", id). First(&e).Error; err != nil { return nil, err } return &e, nil } func (r *ApprovalFlowRepository) GetByDepartment(ctx context.Context, departmentID uuid.UUID) (*entities.ApprovalFlow, error) { db := DBFromContext(ctx, r.db) var e entities.ApprovalFlow if err := db.WithContext(ctx). Preload("Department"). Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step_order ASC, parallel_group ASC") }). Preload("Steps.ApproverRole"). Preload("Steps.ApproverUser"). Where("department_id = ? AND is_active = true", departmentID). First(&e).Error; err != nil { return nil, err } return &e, nil } func (r *ApprovalFlowRepository) Update(ctx context.Context, e *entities.ApprovalFlow) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.ApprovalFlow{}).Where("id = ?", e.ID).Updates(e).Error } func (r *ApprovalFlowRepository) Delete(ctx context.Context, id uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("id = ?", id).Delete(&entities.ApprovalFlow{}).Error } type ListApprovalFlowsFilter struct { DepartmentID *uuid.UUID IsActive *bool } func (r *ApprovalFlowRepository) List(ctx context.Context, filter ListApprovalFlowsFilter, limit, offset int) ([]entities.ApprovalFlow, int64, error) { db := DBFromContext(ctx, r.db) query := db.WithContext(ctx).Model(&entities.ApprovalFlow{}) if filter.DepartmentID != nil { query = query.Where("department_id = ?", *filter.DepartmentID) } if filter.IsActive != nil { query = query.Where("is_active = ?", *filter.IsActive) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, 0, err } var list []entities.ApprovalFlow if err := query. Preload("Department"). Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step_order ASC, parallel_group ASC") }). Order("created_at DESC"). Limit(limit). Offset(offset). Find(&list).Error; err != nil { return nil, 0, err } return list, total, nil } type ApprovalFlowStepRepository struct{ db *gorm.DB } func NewApprovalFlowStepRepository(db *gorm.DB) *ApprovalFlowStepRepository { return &ApprovalFlowStepRepository{db: db} } func (r *ApprovalFlowStepRepository) Create(ctx context.Context, e *entities.ApprovalFlowStep) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *ApprovalFlowStepRepository) CreateBulk(ctx context.Context, list []entities.ApprovalFlowStep) error { db := DBFromContext(ctx, r.db) if len(list) == 0 { return nil } return db.WithContext(ctx).Create(&list).Error } func (r *ApprovalFlowStepRepository) Update(ctx context.Context, e *entities.ApprovalFlowStep) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.ApprovalFlowStep{}).Where("id = ?", e.ID).Updates(e).Error } func (r *ApprovalFlowStepRepository) Delete(ctx context.Context, id uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("id = ?", id).Delete(&entities.ApprovalFlowStep{}).Error } func (r *ApprovalFlowStepRepository) DeleteByFlow(ctx context.Context, flowID uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("flow_id = ?", flowID).Delete(&entities.ApprovalFlowStep{}).Error } func (r *ApprovalFlowStepRepository) ListByFlow(ctx context.Context, flowID uuid.UUID) ([]entities.ApprovalFlowStep, error) { db := DBFromContext(ctx, r.db) var list []entities.ApprovalFlowStep if err := db.WithContext(ctx). Preload("ApproverRole"). Preload("ApproverUser"). Where("flow_id = ?", flowID). Order("step_order ASC, parallel_group ASC"). Find(&list).Error; err != nil { return nil, err } return list, nil } type LetterOutgoingApprovalRepository struct{ db *gorm.DB } func NewLetterOutgoingApprovalRepository(db *gorm.DB) *LetterOutgoingApprovalRepository { return &LetterOutgoingApprovalRepository{db: db} } func (r *LetterOutgoingApprovalRepository) Create(ctx context.Context, e *entities.LetterOutgoingApproval) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *LetterOutgoingApprovalRepository) CreateBulk(ctx context.Context, list []entities.LetterOutgoingApproval) error { db := DBFromContext(ctx, r.db) if len(list) == 0 { return nil } return db.WithContext(ctx).Create(&list).Error } func (r *LetterOutgoingApprovalRepository) Get(ctx context.Context, id uuid.UUID) (*entities.LetterOutgoingApproval, error) { db := DBFromContext(ctx, r.db) var e entities.LetterOutgoingApproval if err := db.WithContext(ctx). Preload("Letter"). Preload("Step"). Preload("Approver"). Where("id = ?", id). First(&e).Error; err != nil { return nil, err } return &e, nil } func (r *LetterOutgoingApprovalRepository) GetByLetterAndStep(ctx context.Context, letterID, stepID uuid.UUID) (*entities.LetterOutgoingApproval, error) { db := DBFromContext(ctx, r.db) var e entities.LetterOutgoingApproval if err := db.WithContext(ctx). Where("letter_id = ? AND step_id = ?", letterID, stepID). First(&e).Error; err != nil { return nil, err } return &e, nil } func (r *LetterOutgoingApprovalRepository) Update(ctx context.Context, e *entities.LetterOutgoingApproval) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.LetterOutgoingApproval{}).Where("id = ?", e.ID).Updates(e).Error } func (r *LetterOutgoingApprovalRepository) ListByLetter(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingApproval, error) { db := DBFromContext(ctx, r.db) var list []entities.LetterOutgoingApproval if err := db.WithContext(ctx). Preload("Step.ApproverRole"). Preload("Step.ApproverUser"). Preload("Approver"). Where("letter_id = ?", letterID). Order("created_at ASC"). Find(&list).Error; err != nil { return nil, err } return list, nil } func (r *LetterOutgoingApprovalRepository) GetPendingApprovals(ctx context.Context, userID uuid.UUID) ([]entities.LetterOutgoingApproval, error) { db := DBFromContext(ctx, r.db) var list []entities.LetterOutgoingApproval if err := db.WithContext(ctx). Preload("Letter"). Preload("Step"). Joins("JOIN approval_flow_steps afs ON afs.id = letter_outgoing_approvals.step_id"). Where("letter_outgoing_approvals.status = ? AND (afs.approver_user_id = ? OR afs.approver_role_id IN (SELECT role_id FROM user_roles WHERE user_id = ?))", entities.ApprovalStatusPending, userID, userID). Find(&list).Error; err != nil { return nil, err } return list, nil }