package repository import ( "context" "time" "eslogad-be/internal/entities" "github.com/google/uuid" "gorm.io/gorm" ) type LetterOutgoingRepository struct{ db *gorm.DB } func NewLetterOutgoingRepository(db *gorm.DB) *LetterOutgoingRepository { return &LetterOutgoingRepository{db: db} } func (r *LetterOutgoingRepository) Create(ctx context.Context, e *entities.LetterOutgoing) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *LetterOutgoingRepository) Get(ctx context.Context, id uuid.UUID) (*entities.LetterOutgoing, error) { db := DBFromContext(ctx, r.db) var e entities.LetterOutgoing if err := db.WithContext(ctx). Preload("Priority"). Preload("ReceiverInstitution"). Preload("Creator"). Preload("ApprovalFlow"). Preload("Recipients"). Preload("Attachments"). Preload("Approvals.Step"). Preload("Approvals.Approver"). Where("id = ? AND deleted_at IS NULL", id). First(&e).Error; err != nil { return nil, err } return &e, nil } func (r *LetterOutgoingRepository) Update(ctx context.Context, e *entities.LetterOutgoing) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.LetterOutgoing{}).Where("id = ? AND deleted_at IS NULL", e.ID).Updates(e).Error } func (r *LetterOutgoingRepository) SoftDelete(ctx context.Context, id uuid.UUID) error { db := DBFromContext(ctx, r.db) now := time.Now() return db.WithContext(ctx).Model(&entities.LetterOutgoing{}).Where("id = ? AND deleted_at IS NULL", id).Update("deleted_at", now).Error } func (r *LetterOutgoingRepository) GetWithRelations(ctx context.Context, id uuid.UUID, relations []string) (*entities.LetterOutgoing, error) { db := DBFromContext(ctx, r.db) query := db.WithContext(ctx).Where("id = ? AND deleted_at IS NULL", id) // Preload all specified relations for _, relation := range relations { query = query.Preload(relation) } var e entities.LetterOutgoing if err := query.First(&e).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, gorm.ErrRecordNotFound } return nil, err } return &e, nil } type ListOutgoingLettersFilter struct { Status *string Query *string CreatedBy *uuid.UUID ReceiverInstitutionID *uuid.UUID FromDate *time.Time ToDate *time.Time } func (r *LetterOutgoingRepository) List(ctx context.Context, filter ListOutgoingLettersFilter, limit, offset int) ([]entities.LetterOutgoing, int64, error) { db := DBFromContext(ctx, r.db) query := db.WithContext(ctx).Model(&entities.LetterOutgoing{}).Where("deleted_at IS NULL") if filter.Status != nil { query = query.Where("status = ?", *filter.Status) } if filter.Query != nil { q := "%" + *filter.Query + "%" query = query.Where("subject ILIKE ? OR reference_number ILIKE ? OR letter_number ILIKE ?", q, q, q) } if filter.CreatedBy != nil { query = query.Where("created_by = ?", *filter.CreatedBy) } if filter.ReceiverInstitutionID != nil { query = query.Where("receiver_institution_id = ?", *filter.ReceiverInstitutionID) } if filter.FromDate != nil { query = query.Where("issue_date >= ?", *filter.FromDate) } if filter.ToDate != nil { query = query.Where("issue_date <= ?", *filter.ToDate) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, 0, err } var list []entities.LetterOutgoing if err := query. Preload("Priority"). Preload("ReceiverInstitution"). Preload("Creator"). Preload("Recipients"). Preload("Attachments"). Preload("Approvals.Step"). Preload("Approvals.Approver"). Order("created_at DESC"). Limit(limit). Offset(offset). Find(&list).Error; err != nil { return nil, 0, err } return list, total, nil } func (r *LetterOutgoingRepository) UpdateStatus(ctx context.Context, id uuid.UUID, status entities.LetterOutgoingStatus) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.LetterOutgoing{}).Where("id = ? AND deleted_at IS NULL", id).Update("status", status).Error } type LetterOutgoingAttachmentRepository struct{ db *gorm.DB } func NewLetterOutgoingAttachmentRepository(db *gorm.DB) *LetterOutgoingAttachmentRepository { return &LetterOutgoingAttachmentRepository{db: db} } func (r *LetterOutgoingAttachmentRepository) Create(ctx context.Context, e *entities.LetterOutgoingAttachment) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *LetterOutgoingAttachmentRepository) CreateBulk(ctx context.Context, list []entities.LetterOutgoingAttachment) error { db := DBFromContext(ctx, r.db) if len(list) == 0 { return nil } return db.WithContext(ctx).Create(&list).Error } func (r *LetterOutgoingAttachmentRepository) ListByLetter(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingAttachment, error) { db := DBFromContext(ctx, r.db) var list []entities.LetterOutgoingAttachment if err := db.WithContext(ctx).Where("letter_id = ?", letterID).Order("uploaded_at ASC").Find(&list).Error; err != nil { return nil, err } return list, nil } func (r *LetterOutgoingAttachmentRepository) Delete(ctx context.Context, id uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("id = ?", id).Delete(&entities.LetterOutgoingAttachment{}).Error } type LetterOutgoingRecipientRepository struct{ db *gorm.DB } func NewLetterOutgoingRecipientRepository(db *gorm.DB) *LetterOutgoingRecipientRepository { return &LetterOutgoingRecipientRepository{db: db} } func (r *LetterOutgoingRecipientRepository) Create(ctx context.Context, e *entities.LetterOutgoingRecipient) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *LetterOutgoingRecipientRepository) CreateBulk(ctx context.Context, list []entities.LetterOutgoingRecipient) error { db := DBFromContext(ctx, r.db) if len(list) == 0 { return nil } return db.WithContext(ctx).Create(&list).Error } func (r *LetterOutgoingRecipientRepository) ListByLetter(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingRecipient, error) { db := DBFromContext(ctx, r.db) var list []entities.LetterOutgoingRecipient if err := db.WithContext(ctx). Preload("User"). Preload("Department"). Where("letter_id = ?", letterID). Order("is_primary DESC, created_at ASC"). Find(&list).Error; err != nil { return nil, err } return list, nil } func (r *LetterOutgoingRecipientRepository) Update(ctx context.Context, e *entities.LetterOutgoingRecipient) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Model(&entities.LetterOutgoingRecipient{}).Where("id = ?", e.ID).Updates(e).Error } func (r *LetterOutgoingRecipientRepository) Delete(ctx context.Context, id uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("id = ?", id).Delete(&entities.LetterOutgoingRecipient{}).Error } func (r *LetterOutgoingRecipientRepository) DeleteByLetter(ctx context.Context, letterID uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("letter_id = ?", letterID).Delete(&entities.LetterOutgoingRecipient{}).Error } type LetterOutgoingDiscussionRepository struct{ db *gorm.DB } func NewLetterOutgoingDiscussionRepository(db *gorm.DB) *LetterOutgoingDiscussionRepository { return &LetterOutgoingDiscussionRepository{db: db} } func (r *LetterOutgoingDiscussionRepository) Create(ctx context.Context, e *entities.LetterOutgoingDiscussion) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *LetterOutgoingDiscussionRepository) Get(ctx context.Context, id uuid.UUID) (*entities.LetterOutgoingDiscussion, error) { db := DBFromContext(ctx, r.db) var e entities.LetterOutgoingDiscussion if err := db.WithContext(ctx). Preload("User"). Preload("Attachments"). Where("id = ?", id). First(&e).Error; err != nil { return nil, err } return &e, nil } func (r *LetterOutgoingDiscussionRepository) ListByLetter(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingDiscussion, error) { db := DBFromContext(ctx, r.db) var list []entities.LetterOutgoingDiscussion if err := db.WithContext(ctx). Preload("User"). Preload("Attachments"). Preload("Replies.User"). Where("letter_id = ? AND parent_id IS NULL", letterID). Order("created_at DESC"). Find(&list).Error; err != nil { return nil, err } return list, nil } func (r *LetterOutgoingDiscussionRepository) Update(ctx context.Context, e *entities.LetterOutgoingDiscussion) error { db := DBFromContext(ctx, r.db) now := time.Now() e.EditedAt = &now return db.WithContext(ctx).Model(&entities.LetterOutgoingDiscussion{}).Where("id = ?", e.ID).Updates(e).Error } func (r *LetterOutgoingDiscussionRepository) Delete(ctx context.Context, id uuid.UUID) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Where("id = ?", id).Delete(&entities.LetterOutgoingDiscussion{}).Error } type LetterOutgoingDiscussionAttachmentRepository struct{ db *gorm.DB } func NewLetterOutgoingDiscussionAttachmentRepository(db *gorm.DB) *LetterOutgoingDiscussionAttachmentRepository { return &LetterOutgoingDiscussionAttachmentRepository{db: db} } func (r *LetterOutgoingDiscussionAttachmentRepository) CreateBulk(ctx context.Context, list []entities.LetterOutgoingDiscussionAttachment) error { db := DBFromContext(ctx, r.db) if len(list) == 0 { return nil } return db.WithContext(ctx).Create(&list).Error } type LetterOutgoingActivityLogRepository struct{ db *gorm.DB } func NewLetterOutgoingActivityLogRepository(db *gorm.DB) *LetterOutgoingActivityLogRepository { return &LetterOutgoingActivityLogRepository{db: db} } func (r *LetterOutgoingActivityLogRepository) Create(ctx context.Context, e *entities.LetterOutgoingActivityLog) error { db := DBFromContext(ctx, r.db) return db.WithContext(ctx).Create(e).Error } func (r *LetterOutgoingActivityLogRepository) ListByLetter(ctx context.Context, letterID uuid.UUID) ([]entities.LetterOutgoingActivityLog, error) { db := DBFromContext(ctx, r.db) var list []entities.LetterOutgoingActivityLog if err := db.WithContext(ctx). Preload("ActorUser"). Preload("ActorDepartment"). Where("letter_id = ?", letterID). Order("occurred_at DESC"). Find(&list).Error; err != nil { return nil, err } return list, nil }