diff --git a/internal/processor/voucher_processor.go b/internal/processor/voucher_processor.go index 5a2d7cf..e9651f3 100644 --- a/internal/processor/voucher_processor.go +++ b/internal/processor/voucher_processor.go @@ -6,6 +6,8 @@ import ( "apskel-pos-be/internal/repository" "context" "fmt" + "math/rand" + "time" ) type VoucherProcessor struct { @@ -117,59 +119,20 @@ func (p *VoucherProcessor) GetRandomVouchersByRows(ctx context.Context, req *mod for i, row := range voucherRows { vouchers := make([]models.VoucherSpinResponse, len(row)) - // Select a winner from this row if there are vouchers + // Select a random winner from this row if there are vouchers if len(row) > 0 { - var winnerIndex int - - if req.WinnerNumber != nil { - // If winner_number is specified, try to find a voucher with that winner_number - // that is not already a winner, otherwise select any non-winner - winnerIndex = -1 - for j, voucher := range row { - if voucher.WinnerNumber == *req.WinnerNumber && !voucher.IsWinner { - winnerIndex = j - break - } - } - - // If no voucher with specified winner_number found, select any non-winner - if winnerIndex == -1 { - for j, voucher := range row { - if !voucher.IsWinner { - winnerIndex = j - break - } - } - } - - // If still no non-winner found, select any voucher - if winnerIndex == -1 { - winnerIndex = 0 - } - } else { - // If no winner_number specified, select any non-winner, otherwise any voucher - winnerIndex = -1 - for j, voucher := range row { - if !voucher.IsWinner { - winnerIndex = j - break - } - } - if winnerIndex == -1 { - winnerIndex = 0 - } - } + // Select random winner + rand.Seed(time.Now().UnixNano() + int64(i)) // Add row index for different seed + winnerIndex := rand.Intn(len(row)) - // Mark as winner in database if not already a winner - if !row[winnerIndex].IsWinner { - err := p.voucherRepo.MarkAsWinner(ctx, row[winnerIndex].ID) - if err != nil { - // Log error but continue - don't fail the entire request - fmt.Printf("Failed to mark voucher %d as winner: %v\n", row[winnerIndex].ID, err) - } else { - // Update the voucher object to reflect the change - row[winnerIndex].IsWinner = true - } + // Mark as winner in database + err := p.voucherRepo.MarkAsWinner(ctx, row[winnerIndex].ID) + if err != nil { + // Log error but continue - don't fail the entire request + fmt.Printf("Failed to mark voucher %d as winner: %v\n", row[winnerIndex].ID, err) + } else { + // Update the voucher object to reflect the change + row[winnerIndex].IsWinner = true } } diff --git a/internal/repository/voucher_repository.go b/internal/repository/voucher_repository.go index 8376176..58d336e 100644 --- a/internal/repository/voucher_repository.go +++ b/internal/repository/voucher_repository.go @@ -102,42 +102,64 @@ func (r *VoucherRepository) GetRandomVouchersByRows(ctx context.Context, rows in var allVouchers []entities.Voucher var err error - // Get all non-winner vouchers (regardless of winner_number) - nonWinnerQuery := r.db.WithContext(ctx).Where("is_winner = ?", false) - err = nonWinnerQuery.Find(&allVouchers).Error - if err != nil { - return nil, err - } - - // If winner_number is provided, also include vouchers with that specific winner_number - // (even if they're already winners, to have a pool to select from) + // First, try to get vouchers based on winner_number parameter if winnerNumber != nil { - var winnerNumberVouchers []entities.Voucher - winnerQuery := r.db.WithContext(ctx).Where("winner_number = ?", *winnerNumber) - err = winnerQuery.Find(&winnerNumberVouchers).Error + // If winner_number is provided, filter by it and exclude already won vouchers + query := r.db.WithContext(ctx).Where("winner_number = ? AND is_winner = ?", *winnerNumber, false) + err = query.Find(&allVouchers).Error if err != nil { return nil, err } - // Merge the two lists, avoiding duplicates - existingIDs := make(map[int64]bool) - for _, voucher := range allVouchers { - existingIDs[voucher.ID] = true - } - - for _, voucher := range winnerNumberVouchers { - if !existingIDs[voucher.ID] { - allVouchers = append(allVouchers, voucher) + // If no vouchers found for the specified winner_number, fallback to winner_number = 0 + if len(allVouchers) == 0 { + fallbackQuery := r.db.WithContext(ctx).Where("winner_number = ? AND is_winner = ?", 0, false) + err = fallbackQuery.Find(&allVouchers).Error + if err != nil { + return nil, err } } - } - // If still no vouchers found, get any vouchers available as fallback - if len(allVouchers) == 0 { - err = r.db.WithContext(ctx).Find(&allVouchers).Error + // If still no vouchers found, try without is_winner filter for winner_number = 0 + if len(allVouchers) == 0 { + fallbackQuery2 := r.db.WithContext(ctx).Where("winner_number = ?", 0) + err = fallbackQuery2.Find(&allVouchers).Error + if err != nil { + return nil, err + } + } + + // If still no vouchers found, get any vouchers available + if len(allVouchers) == 0 { + err = r.db.WithContext(ctx).Find(&allVouchers).Error + if err != nil { + return nil, err + } + } + } else { + // If winner_number is not provided, use default winner_number = 0 and exclude already won vouchers + query := r.db.WithContext(ctx).Where("winner_number = ? AND is_winner = ?", 0, false) + err = query.Find(&allVouchers).Error if err != nil { return nil, err } + + // If no vouchers found, try without is_winner filter for winner_number = 0 + if len(allVouchers) == 0 { + fallbackQuery := r.db.WithContext(ctx).Where("winner_number = ?", 0) + err = fallbackQuery.Find(&allVouchers).Error + if err != nil { + return nil, err + } + } + + // If still no vouchers found, get any vouchers available + if len(allVouchers) == 0 { + err = r.db.WithContext(ctx).Find(&allVouchers).Error + if err != nil { + return nil, err + } + } } if len(allVouchers) == 0 { diff --git a/server b/server index 5ab495c..0553262 100755 Binary files a/server and b/server differ diff --git a/test_voucher_fix.go b/test_voucher_fix.go deleted file mode 100644 index a7b319d..0000000 --- a/test_voucher_fix.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "apskel-pos-be/internal/entities" - "apskel-pos-be/internal/processor" - "apskel-pos-be/internal/repository" - "apskel-pos-be/internal/models" - "context" - "fmt" - "log" - - "gorm.io/driver/postgres" - "gorm.io/gorm" -) - -func main() { - // Database connection - dsn := "host=62.72.45.250 user=apskel password='7a8UJbM2GgBWaseh0lnP3O5i1i5nINXk' dbname=apskel_pos port=5433 sslmode=disable" - db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) - if err != nil { - log.Fatal("Failed to connect to database:", err) - } - - // Create repository and processor - voucherRepo := repository.NewVoucherRepository(db) - voucherProcessor := processor.NewVoucherProcessor(voucherRepo) - - // Test the fixed logic - ctx := context.Background() - winnerNumber := 2 - req := &models.ListVouchersByRowsRequest{ - Rows: 1, - WinnerNumber: &winnerNumber, - } - - fmt.Println("Testing voucher rows API with winner_number=2...") - fmt.Printf("Request: rows=%d, winner_number=%d\n", req.Rows, *req.WinnerNumber) - - // Call the processor - response, err := voucherProcessor.GetRandomVouchersByRows(ctx, req) - if err != nil { - log.Fatal("Error calling processor:", err) - } - - // Print results - fmt.Printf("\nResponse:\n") - fmt.Printf("Total Rows: %d\n", response.TotalRows) - fmt.Printf("Total Vouchers: %d\n", response.TotalVouchers) - - for _, row := range response.Rows { - fmt.Printf("\nRow %d (%d vouchers):\n", row.RowNumber, len(row.Vouchers)) - for _, voucher := range row.Vouchers { - winnerStatus := "No" - if voucher.IsWinner { - winnerStatus = "Yes" - } - fmt.Printf(" - %s (%s) - Winner: %s\n", voucher.VoucherCode, voucher.Name, winnerStatus) - } - } - - // Verify the fix - fmt.Printf("\n=== VERIFICATION ===\n") - if response.TotalVouchers > 1 { - fmt.Printf("✅ SUCCESS: API now returns %d vouchers instead of just 1\n", response.TotalVouchers) - } else { - fmt.Printf("❌ ISSUE: API still returns only %d voucher\n", response.TotalVouchers) - } - - // Check if there's a winner - hasWinner := false - for _, row := range response.Rows { - for _, voucher := range row.Vouchers { - if voucher.IsWinner { - hasWinner = true - break - } - } - if hasWinner { - break - } - } - - if hasWinner { - fmt.Printf("✅ SUCCESS: Winner is properly selected\n") - } else { - fmt.Printf("❌ ISSUE: No winner selected\n") - } -}