package repository import ( "enaklo-pos-be/internal/common/logger" "enaklo-pos-be/internal/common/mycontext" "enaklo-pos-be/internal/entity" "fmt" "time" "go.uber.org/zap" "gorm.io/gorm" ) type UndianRepo interface { GetUndianEventByID(ctx mycontext.Context, id int64) (*entity.UndianEventDB, error) GetActiveUndianEvents(ctx mycontext.Context) ([]*entity.UndianEventDB, error) GetActiveUndianEventsWithPrizes(ctx mycontext.Context, customerID int64) ([]*entity.UndianEventDB, error) GetCustomerVouchersByEventIDs(ctx mycontext.Context, customerID int64, eventIDs []int64) ([]*entity.UndianVoucherDB, error) CreateUndianVouchers(ctx mycontext.Context, vouchers []*entity.UndianVoucherDB) error GetNextVoucherSequence(ctx mycontext.Context) (int64, error) GetNextVoucherSequenceBatch(ctx mycontext.Context, count int) (int64, error) } type undianRepository struct { db *gorm.DB } func NewUndianRepository(db *gorm.DB) UndianRepo { return &undianRepository{ db: db, } } func (r *undianRepository) GetUndianEventByID(ctx mycontext.Context, id int64) (*entity.UndianEventDB, error) { event := new(entity.UndianEventDB) if err := r.db.WithContext(ctx).First(event, id).Error; err != nil { logger.ContextLogger(ctx).Error("error when get undian event by id", zap.Error(err)) return nil, err } return event, nil } func (r *undianRepository) GetActiveUndianEvents(ctx mycontext.Context) ([]*entity.UndianEventDB, error) { var events []*entity.UndianEventDB now := time.Now() if err := r.db.WithContext(ctx). Where("status = 'active' AND start_date <= ? AND end_date >= ?", now, now). Order("created_at DESC"). Find(&events).Error; err != nil { logger.ContextLogger(ctx).Error("error when get active undian events", zap.Error(err)) return nil, err } return events, nil } func (r *undianRepository) GetActiveUndianEventsWithPrizes(ctx mycontext.Context, customerID int64) ([]*entity.UndianEventDB, error) { var events []*entity.UndianEventDB now := time.Now() query := r.db.WithContext(ctx). Preload("Prizes", func(db *gorm.DB) *gorm.DB { return db.Order("rank ASC") }). Where("status = 'active' AND start_date <= ? AND end_date >= ?", now, now). Order("created_at DESC") // If customer ID is provided, preload only that customer's vouchers if customerID > 0 { query = query.Preload("Vouchers", func(db *gorm.DB) *gorm.DB { return db.Where("customer_id = ?", customerID).Order("created_at ASC") }) } else { // If no customer ID, don't load any vouchers (or load all if needed) query = query.Preload("Vouchers", func(db *gorm.DB) *gorm.DB { return db.Where("1 = 0") // This loads no vouchers }) } if err := query.Find(&events).Error; err != nil { logger.ContextLogger(ctx).Error("error when get active undian events with prizes", zap.Int64("customerID", customerID), zap.Error(err)) return nil, err } return events, nil } func (r *undianRepository) GetCustomerVouchersByEventIDs(ctx mycontext.Context, customerID int64, eventIDs []int64) ([]*entity.UndianVoucherDB, error) { var vouchers []*entity.UndianVoucherDB if err := r.db.WithContext(ctx). Where("customer_id = ? AND undian_event_id IN ?", customerID, eventIDs). Order("undian_event_id ASC, created_at ASC"). Find(&vouchers).Error; err != nil { logger.ContextLogger(ctx).Error("error when get customer vouchers by event IDs", zap.Int64("customerID", customerID), zap.Int64s("eventIDs", eventIDs), zap.Error(err)) return nil, err } return vouchers, nil } func (r *undianRepository) CreateUndianVouchers(ctx mycontext.Context, vouchers []*entity.UndianVoucherDB) error { err := r.db.WithContext(ctx).Create(&vouchers).Error if err != nil { logger.ContextLogger(ctx).Error("error when create undian vouchers", zap.Error(err)) return err } return nil } func (r *undianRepository) GetNextVoucherSequence(ctx mycontext.Context) (int64, error) { var sequence int64 err := r.db.WithContext(ctx).Raw("SELECT nextval('voucher_sequence')").Scan(&sequence).Error if err != nil { logger.ContextLogger(ctx).Error("error when get next voucher sequence", zap.Error(err)) return 0, err } return sequence, nil } func (r *undianRepository) GetNextVoucherSequenceBatch(ctx mycontext.Context, count int) (int64, error) { var startSequence int64 query := fmt.Sprintf("SELECT nextval('voucher_sequence') + %d - %d", count-1, count-1) err := r.db.WithContext(ctx).Raw(query).Scan(&startSequence).Error if err != nil { logger.ContextLogger(ctx).Error("error when get batch voucher sequence", zap.Error(err)) return 0, err } return startSequence, nil }