package repository import ( "context" "fmt" "apskel-pos-be/internal/entities" "gorm.io/gorm" ) type RewardRepository interface { Create(ctx context.Context, reward *entities.Reward) error GetByID(ctx context.Context, id string) (*entities.Reward, error) List(ctx context.Context, req *entities.ListRewardsRequest) ([]entities.Reward, int64, error) Update(ctx context.Context, reward *entities.Reward) error Delete(ctx context.Context, id string) error UpdateStock(ctx context.Context, id string, newStock int) error GetByRewardType(ctx context.Context, rewardType entities.RewardType) ([]entities.Reward, error) } type rewardRepository struct { db *gorm.DB } func NewRewardRepository(db *gorm.DB) RewardRepository { return &rewardRepository{ db: db, } } func (r *rewardRepository) Create(ctx context.Context, reward *entities.Reward) error { if err := r.db.WithContext(ctx).Create(reward).Error; err != nil { return fmt.Errorf("failed to create reward: %w", err) } return nil } func (r *rewardRepository) GetByID(ctx context.Context, id string) (*entities.Reward, error) { var reward entities.Reward if err := r.db.WithContext(ctx).Where("id = ?", id).First(&reward).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, fmt.Errorf("reward not found") } return nil, fmt.Errorf("failed to get reward: %w", err) } return &reward, nil } func (r *rewardRepository) List(ctx context.Context, req *entities.ListRewardsRequest) ([]entities.Reward, int64, error) { var rewards []entities.Reward var total int64 query := r.db.WithContext(ctx).Model(&entities.Reward{}) // Apply filters if req.Search != "" { query = query.Where("name ILIKE ?", "%"+req.Search+"%") } if req.RewardType != "" { query = query.Where("reward_type = ?", req.RewardType) } if req.MinPoints != nil { query = query.Where("cost_points >= ?", *req.MinPoints) } if req.MaxPoints != nil { query = query.Where("cost_points <= ?", *req.MaxPoints) } if req.HasStock != nil { if *req.HasStock { query = query.Where("stock > 0 OR stock IS NULL") } else { query = query.Where("stock <= 0") } } // Count total records if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count rewards: %w", err) } // Apply pagination if req.Page > 0 && req.Limit > 0 { offset := (req.Page - 1) * req.Limit query = query.Offset(offset).Limit(req.Limit) } // Apply sorting query = query.Order("created_at DESC") if err := query.Find(&rewards).Error; err != nil { return nil, 0, fmt.Errorf("failed to list rewards: %w", err) } return rewards, total, nil } func (r *rewardRepository) Update(ctx context.Context, reward *entities.Reward) error { if err := r.db.WithContext(ctx).Save(reward).Error; err != nil { return fmt.Errorf("failed to update reward: %w", err) } return nil } func (r *rewardRepository) Delete(ctx context.Context, id string) error { if err := r.db.WithContext(ctx).Where("id = ?", id).Delete(&entities.Reward{}).Error; err != nil { return fmt.Errorf("failed to delete reward: %w", err) } return nil } func (r *rewardRepository) UpdateStock(ctx context.Context, id string, newStock int) error { if err := r.db.WithContext(ctx).Model(&entities.Reward{}).Where("id = ?", id).Update("stock", newStock).Error; err != nil { return fmt.Errorf("failed to update reward stock: %w", err) } return nil } func (r *rewardRepository) GetByRewardType(ctx context.Context, rewardType entities.RewardType) ([]entities.Reward, error) { var rewards []entities.Reward if err := r.db.WithContext(ctx).Where("reward_type = ?", rewardType).Find(&rewards).Error; err != nil { return nil, fmt.Errorf("failed to get rewards by type: %w", err) } return rewards, nil }