diff --git a/internal/processor/voucher_processor.go b/internal/processor/voucher_processor.go index e9651f3..5a2d7cf 100644 --- a/internal/processor/voucher_processor.go +++ b/internal/processor/voucher_processor.go @@ -6,8 +6,6 @@ import ( "apskel-pos-be/internal/repository" "context" "fmt" - "math/rand" - "time" ) type VoucherProcessor struct { @@ -119,20 +117,59 @@ func (p *VoucherProcessor) GetRandomVouchersByRows(ctx context.Context, req *mod for i, row := range voucherRows { vouchers := make([]models.VoucherSpinResponse, len(row)) - // Select a random winner from this row if there are vouchers + // Select a winner from this row if there are vouchers if len(row) > 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 - 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) + 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 { - // Update the voucher object to reflect the change - row[winnerIndex].IsWinner = true + // 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 + } + } + + // 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 + } } } diff --git a/internal/repository/voucher_repository.go b/internal/repository/voucher_repository.go index 58d336e..8376176 100644 --- a/internal/repository/voucher_repository.go +++ b/internal/repository/voucher_repository.go @@ -102,64 +102,42 @@ func (r *VoucherRepository) GetRandomVouchersByRows(ctx context.Context, rows in var allVouchers []entities.Voucher var err error - // First, try to get vouchers based on winner_number parameter + // 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) if winnerNumber != nil { - // 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 + var winnerNumberVouchers []entities.Voucher + winnerQuery := r.db.WithContext(ctx).Where("winner_number = ?", *winnerNumber) + err = winnerQuery.Find(&winnerNumberVouchers).Error if err != nil { return nil, err } - // 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 - } + // Merge the two lists, avoiding duplicates + existingIDs := make(map[int64]bool) + for _, voucher := range allVouchers { + existingIDs[voucher.ID] = true } - // 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 + for _, voucher := range winnerNumberVouchers { + if !existingIDs[voucher.ID] { + allVouchers = append(allVouchers, voucher) } } + } - // 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 still no vouchers found, get any vouchers available as fallback + if len(allVouchers) == 0 { + err = r.db.WithContext(ctx).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 0553262..5ab495c 100755 Binary files a/server and b/server differ diff --git a/test_voucher_fix.go b/test_voucher_fix.go new file mode 100644 index 0000000..a7b319d --- /dev/null +++ b/test_voucher_fix.go @@ -0,0 +1,88 @@ +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") + } +}