virtual_games wallet service fixes

This commit is contained in:
Yared Yemane 2025-10-29 15:01:39 +03:00
parent 857212d9ba
commit 7575f29386
7 changed files with 188 additions and 216 deletions

View File

@ -11176,10 +11176,8 @@ const docTemplate = `{
"tournament_name": { "tournament_name": {
"type": "string" "type": "string"
}, },
"tournament_stageFK": {
"type": "string"
},
"tournament_stage_name": { "tournament_stage_name": {
"description": "TournamentStageFK string ` + "`" + `json:\"tournament_stageFK\"` + "`" + `",
"type": "string" "type": "string"
}, },
"tournament_templateFK": { "tournament_templateFK": {
@ -11381,10 +11379,8 @@ const docTemplate = `{
"tournament_name": { "tournament_name": {
"type": "string" "type": "string"
}, },
"tournament_stage_fk": {
"type": "string"
},
"tournament_stage_name": { "tournament_stage_name": {
"description": "TournamentStageFK string ` + "`" + `json:\"tournament_stage_fk\"` + "`" + `",
"type": "string" "type": "string"
}, },
"tournament_template_fk": { "tournament_template_fk": {

View File

@ -11168,10 +11168,8 @@
"tournament_name": { "tournament_name": {
"type": "string" "type": "string"
}, },
"tournament_stageFK": {
"type": "string"
},
"tournament_stage_name": { "tournament_stage_name": {
"description": "TournamentStageFK string `json:\"tournament_stageFK\"`",
"type": "string" "type": "string"
}, },
"tournament_templateFK": { "tournament_templateFK": {
@ -11373,10 +11371,8 @@
"tournament_name": { "tournament_name": {
"type": "string" "type": "string"
}, },
"tournament_stage_fk": {
"type": "string"
},
"tournament_stage_name": { "tournament_stage_name": {
"description": "TournamentStageFK string `json:\"tournament_stage_fk\"`",
"type": "string" "type": "string"
}, },
"tournament_template_fk": { "tournament_template_fk": {

View File

@ -838,8 +838,7 @@ definitions:
tournament_name: tournament_name:
type: string type: string
tournament_stage_name: tournament_stage_name:
type: string description: TournamentStageFK string `json:"tournament_stageFK"`
tournament_stageFK:
type: string type: string
tournament_template_name: tournament_template_name:
type: string type: string
@ -975,9 +974,8 @@ definitions:
type: string type: string
tournament_name: tournament_name:
type: string type: string
tournament_stage_fk:
type: string
tournament_stage_name: tournament_stage_name:
description: TournamentStageFK string `json:"tournament_stage_fk"`
type: string type: string
tournament_template_fk: tournament_template_fk:
type: string type: string

View File

@ -116,7 +116,7 @@ func (s *Service) ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*
} }
// 6. Deduct amount from wallet (record transaction) // 6. Deduct amount from wallet (record transaction)
_, err = s.walletSvc.DeductFromWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), "") err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)-req.Amount))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to debit wallet: %w", err) return nil, fmt.Errorf("failed to debit wallet: %w", err)
} }
@ -157,13 +157,13 @@ func (s *Service) ProcessBetWin(ctx context.Context, req domain.AtlasBetWinReque
} }
// 6. Deduct amount from wallet (record transaction) // 6. Deduct amount from wallet (record transaction)
_, err = s.walletSvc.DeductFromWallet(ctx, wallet.ID, domain.Currency(req.BetAmount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), "") err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)-req.BetAmount))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to debit wallet: %w", err) return nil, fmt.Errorf("failed to debit wallet: %w", err)
} }
if req.WinAmount > 0 { if req.WinAmount > 0 {
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.WinAmount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+req.WinAmount))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to credit wallet: %w", err) return nil, fmt.Errorf("failed to credit wallet: %w", err)
} }
@ -172,7 +172,7 @@ func (s *Service) ProcessBetWin(ctx context.Context, req domain.AtlasBetWinReque
// 8. Build response // 8. Build response
res := &domain.AtlasBetWinResponse{ res := &domain.AtlasBetWinResponse{
PlayerID: req.PlayerID, PlayerID: req.PlayerID,
Balance: float64(wallet.RegularBalance) - req.BetAmount + req.WinAmount, Balance: float64(wallet.RegularBalance),
} }
return res, nil return res, nil
@ -196,7 +196,7 @@ func (s *Service) ProcessRoundResult(ctx context.Context, req domain.RoundResult
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
} }
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+req.Amount))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to credit wallet: %w", err) return nil, fmt.Errorf("failed to credit wallet: %w", err)
} }
@ -228,7 +228,7 @@ func (s *Service) ProcessRollBack(ctx context.Context, req domain.RollbackReques
return nil, fmt.Errorf("failed to fetch transfer for reference %s: %w", req.BetTransactionID, err) return nil, fmt.Errorf("failed to fetch transfer for reference %s: %w", req.BetTransactionID, err)
} }
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(transfer.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+float64(transfer.Amount)))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to credit wallet: %w", err) return nil, fmt.Errorf("failed to credit wallet: %w", err)
} }
@ -283,7 +283,7 @@ func (s *Service) ProcessFreeSpinResult(ctx context.Context, req domain.FreeSpin
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
} }
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") err = s.walletSvc.UpdateBalance(ctx, wallet.RegularID, domain.Currency(float64(wallet.RegularBalance)+req.Amount))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to credit wallet: %w", err) return nil, fmt.Errorf("failed to credit wallet: %w", err)
} }
@ -312,7 +312,7 @@ func (s *Service) ProcessJackPot(ctx context.Context, req domain.JackpotRequest)
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
} }
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") _, err = s.walletSvc.AddToWallet(ctx, wallet.RegularID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to credit wallet: %w", err) return nil, fmt.Errorf("failed to credit wallet: %w", err)
} }

View File

@ -224,16 +224,16 @@ func (s *service) GetPlayerInfo(ctx context.Context, req *domain.PopOKPlayerInfo
return nil, fmt.Errorf("invalid token") return nil, fmt.Errorf("invalid token")
} }
wallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) wallet, err := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
if err != nil || len(wallets) == 0 { if err != nil {
s.logger.Error("No wallets found for user", "userID", claims.UserID) s.logger.Error("No wallets found for user", "userID", claims.UserID)
return nil, fmt.Errorf("no wallet found") return nil, err
} }
return &domain.PopOKPlayerInfoResponse{ return &domain.PopOKPlayerInfoResponse{
Country: "ET", Country: "ET",
Currency: claims.Currency, Currency: claims.Currency,
Balance: float64(wallets[0].Balance), // Convert cents to currency Balance: float64(wallet.RegularBalance), // Convert cents to currency
PlayerID: fmt.Sprintf("%d", claims.UserID), PlayerID: fmt.Sprintf("%d", claims.UserID),
}, nil }, nil
} }
@ -246,17 +246,17 @@ func (s *service) ProcessBet(ctx context.Context, req *domain.PopOKBetRequest) (
} }
// Convert amount to cents (assuming wallet uses cents) // Convert amount to cents (assuming wallet uses cents)
amountCents := int64(req.Amount) // amount := int64(req.Amount)
// Deduct from wallet // Deduct from wallet
userWallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) wallet, err := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
if err != nil { if err != nil {
return &domain.PopOKBetResponse{}, fmt.Errorf("Failed to read user wallets") return &domain.PopOKBetResponse{}, fmt.Errorf("Failed to read user wallets")
} }
_, err = s.walletSvc.DeductFromWallet(ctx, claims.UserID, domain.Currency(amountCents), _, err = s.walletSvc.DeductFromWallet(ctx, wallet.RegularID, domain.Currency(req.Amount),
domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.ValidInt64{}, domain.TRANSFER_DIRECT,
fmt.Sprintf("Deducted %v amount from wallet by system while placing virtual game bet", amountCents)) fmt.Sprintf("Deducted %v amount from wallet by system while placing virtual game bet", req.Amount))
if err != nil { if err != nil {
return nil, fmt.Errorf("insufficient balance") return nil, fmt.Errorf("insufficient balance")
} }
@ -268,7 +268,7 @@ func (s *service) ProcessBet(ctx context.Context, req *domain.PopOKBetRequest) (
Provider: string(domain.PROVIDER_POPOK), Provider: string(domain.PROVIDER_POPOK),
GameID: req.GameID, GameID: req.GameID,
TransactionType: "BET", TransactionType: "BET",
Amount: amountCents, // Negative for bets Amount: int64(req.Amount), // Negative for bets
Currency: req.Currency, Currency: req.Currency,
ExternalTransactionID: req.TransactionID, ExternalTransactionID: req.TransactionID,
Status: "COMPLETED", Status: "COMPLETED",
@ -283,7 +283,7 @@ func (s *service) ProcessBet(ctx context.Context, req *domain.PopOKBetRequest) (
return &domain.PopOKBetResponse{ return &domain.PopOKBetResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", tx.ID), // Your internal transaction ID ExternalTrxID: fmt.Sprintf("%v", tx.ID), // Your internal transaction ID
Balance: float64(userWallets[0].Balance), Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
@ -319,10 +319,15 @@ func (s *service) ProcessWin(ctx context.Context, req *domain.PopOKWinRequest) (
} }
// 3. Convert amount to cents // 3. Convert amount to cents
amountCents := int64(req.Amount) // amountCents := int64(req.Amount)
wallet, err := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
if err != nil {
return nil, fmt.Errorf("Failed to read user wallets")
}
// 4. Credit to wallet // 4. Credit to wallet
_, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, _, err = s.walletSvc.AddToWallet(ctx, wallet.RegularID, domain.Currency(req.Amount), domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.PaymentDetails{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to wallet for winning PopOkBet", req.Amount), fmt.Sprintf("Added %v to wallet for winning PopOkBet", req.Amount),
) )
@ -331,10 +336,10 @@ func (s *service) ProcessWin(ctx context.Context, req *domain.PopOKWinRequest) (
return nil, fmt.Errorf("wallet credit failed") return nil, fmt.Errorf("wallet credit failed")
} }
userWallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // userWallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID)
if err != nil { // if err != nil {
return &domain.PopOKWinResponse{}, fmt.Errorf("Failed to read user wallets") // return &domain.PopOKWinResponse{}, fmt.Errorf("Failed to read user wallets")
} // }
// 5. Create transaction record // 5. Create transaction record
tx := &domain.VirtualGameTransaction{ tx := &domain.VirtualGameTransaction{
UserID: claims.UserID, UserID: claims.UserID,
@ -342,7 +347,7 @@ func (s *service) ProcessWin(ctx context.Context, req *domain.PopOKWinRequest) (
Provider: string(domain.PROVIDER_POPOK), Provider: string(domain.PROVIDER_POPOK),
GameID: req.GameID, GameID: req.GameID,
TransactionType: "WIN", TransactionType: "WIN",
Amount: amountCents, Amount: int64(req.Amount),
Currency: req.Currency, Currency: req.Currency,
ExternalTransactionID: req.TransactionID, ExternalTransactionID: req.TransactionID,
Status: "COMPLETED", Status: "COMPLETED",
@ -354,12 +359,12 @@ func (s *service) ProcessWin(ctx context.Context, req *domain.PopOKWinRequest) (
return nil, fmt.Errorf("transaction recording failed") return nil, fmt.Errorf("transaction recording failed")
} }
fmt.Printf("\n\n Win balance is:%v\n\n", float64(userWallets[0].Balance)) fmt.Printf("\n\n Win balance is:%v\n\n", float64(wallet.RegularBalance))
return &domain.PopOKWinResponse{ return &domain.PopOKWinResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", tx.ID), ExternalTrxID: fmt.Sprintf("%v", tx.ID),
Balance: float64(userWallets[0].Balance), Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
@ -371,6 +376,11 @@ func (s *service) ProcessTournamentWin(ctx context.Context, req *domain.PopOKWin
return nil, fmt.Errorf("invalid token") return nil, fmt.Errorf("invalid token")
} }
wallet, err := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
if err != nil {
return nil, fmt.Errorf("Failed to read user wallets")
}
// 2. Check for duplicate tournament win transaction // 2. Check for duplicate tournament win transaction
existingTx, err := s.repo.GetVirtualGameTransactionByExternalID(ctx, req.TransactionID) existingTx, err := s.repo.GetVirtualGameTransactionByExternalID(ctx, req.TransactionID)
if err != nil { if err != nil {
@ -379,15 +389,15 @@ func (s *service) ProcessTournamentWin(ctx context.Context, req *domain.PopOKWin
} }
if existingTx != nil && existingTx.TransactionType == "TOURNAMENT_WIN" { if existingTx != nil && existingTx.TransactionType == "TOURNAMENT_WIN" {
s.logger.Warn("Duplicate tournament win", "transactionID", req.TransactionID) s.logger.Warn("Duplicate tournament win", "transactionID", req.TransactionID)
wallets, _ := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // wallet, _ := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
balance := 0.0 // balance := 0.0
if len(wallets) > 0 { // if len(wallets) > 0 {
balance = float64(wallets[0].Balance) // balance = float64(wallets[0].Balance)
} // }
return &domain.PopOKWinResponse{ return &domain.PopOKWinResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", existingTx.ID), ExternalTrxID: fmt.Sprintf("%v", existingTx.ID),
Balance: balance, Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
@ -395,7 +405,7 @@ func (s *service) ProcessTournamentWin(ctx context.Context, req *domain.PopOKWin
amountCents := int64(req.Amount) amountCents := int64(req.Amount)
// 4. Credit user wallet // 4. Credit user wallet
_, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, _, err = s.walletSvc.AddToWallet(ctx, wallet.RegularID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to wallet for winning Popok Tournament", req.Amount)) fmt.Sprintf("Added %v to wallet for winning Popok Tournament", req.Amount))
if err != nil { if err != nil {
s.logger.Error("Failed to credit wallet for tournament", "userID", claims.UserID, "error", err) s.logger.Error("Failed to credit wallet for tournament", "userID", claims.UserID, "error", err)
@ -419,15 +429,15 @@ func (s *service) ProcessTournamentWin(ctx context.Context, req *domain.PopOKWin
} }
// 6. Fetch updated balance // 6. Fetch updated balance
wallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // wallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID)
if err != nil { // if err != nil {
return nil, fmt.Errorf("Failed to get wallet balance") // return nil, fmt.Errorf("Failed to get wallet balance")
} // }
return &domain.PopOKWinResponse{ return &domain.PopOKWinResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", tx.ID), ExternalTrxID: fmt.Sprintf("%v", tx.ID),
Balance: float64(wallets[0].Balance), Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
@ -438,6 +448,11 @@ func (s *service) ProcessPromoWin(ctx context.Context, req *domain.PopOKWinReque
return nil, fmt.Errorf("invalid token") return nil, fmt.Errorf("invalid token")
} }
wallet, err := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
if err != nil {
return nil, fmt.Errorf("Failed to read user wallets")
}
existingTx, err := s.repo.GetVirtualGameTransactionByExternalID(ctx, req.TransactionID) existingTx, err := s.repo.GetVirtualGameTransactionByExternalID(ctx, req.TransactionID)
if err != nil { if err != nil {
s.logger.Error("Failed to check existing promo transaction", "error", err) s.logger.Error("Failed to check existing promo transaction", "error", err)
@ -445,20 +460,20 @@ func (s *service) ProcessPromoWin(ctx context.Context, req *domain.PopOKWinReque
} }
if existingTx != nil && existingTx.TransactionType == "PROMO_WIN" { if existingTx != nil && existingTx.TransactionType == "PROMO_WIN" {
s.logger.Warn("Duplicate promo win", "transactionID", req.TransactionID) s.logger.Warn("Duplicate promo win", "transactionID", req.TransactionID)
wallets, _ := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // wallets, _ := s.walletSvc.GetWalletsByUser(ctx, claims.UserID)
balance := 0.0 // balance := 0.0
if len(wallets) > 0 { // if len(wallets) > 0 {
balance = float64(wallets[0].Balance) // balance = float64(wallets[0].Balance)
} // }
return &domain.PopOKWinResponse{ return &domain.PopOKWinResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", existingTx.ID), ExternalTrxID: fmt.Sprintf("%v", existingTx.ID),
Balance: balance, Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
amountCents := int64(req.Amount * 100) // amountCents := int64(req.Amount * 100)
_, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, _, err = s.walletSvc.AddToWallet(ctx, wallet.RegularID, domain.Currency(req.Amount), domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet for winning PopOk Promo Win", req.Amount)) domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet for winning PopOk Promo Win", req.Amount))
if err != nil { if err != nil {
s.logger.Error("Failed to credit wallet for promo", "userID", claims.UserID, "error", err) s.logger.Error("Failed to credit wallet for promo", "userID", claims.UserID, "error", err)
@ -468,7 +483,7 @@ func (s *service) ProcessPromoWin(ctx context.Context, req *domain.PopOKWinReque
tx := &domain.VirtualGameTransaction{ tx := &domain.VirtualGameTransaction{
UserID: claims.UserID, UserID: claims.UserID,
TransactionType: "PROMO_WIN", TransactionType: "PROMO_WIN",
Amount: amountCents, Amount: int64(wallet.RegularBalance),
Currency: req.Currency, Currency: req.Currency,
ExternalTransactionID: req.TransactionID, ExternalTransactionID: req.TransactionID,
Status: "COMPLETED", Status: "COMPLETED",
@ -480,15 +495,15 @@ func (s *service) ProcessPromoWin(ctx context.Context, req *domain.PopOKWinReque
return nil, fmt.Errorf("transaction recording failed") return nil, fmt.Errorf("transaction recording failed")
} }
wallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // wallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID)
if err != nil { // if err != nil {
return nil, fmt.Errorf("failed to read wallets") // return nil, fmt.Errorf("failed to read wallets")
} // }
return &domain.PopOKWinResponse{ return &domain.PopOKWinResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", tx.ID), ExternalTrxID: fmt.Sprintf("%v", tx.ID),
Balance: float64(wallets[0].Balance), Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
@ -535,6 +550,11 @@ func (s *service) ProcessCancel(ctx context.Context, req *domain.PopOKCancelRequ
// return nil, fmt.Errorf("invalid token") // return nil, fmt.Errorf("invalid token")
// } // }
wallet, err := s.walletSvc.GetCustomerWallet(ctx, claims.UserID)
if err != nil {
return nil, fmt.Errorf("Failed to read user wallets")
}
// 2. Find the original bet transaction // 2. Find the original bet transaction
originalBet, err := s.repo.GetVirtualGameTransactionByExternalID(ctx, req.TransactionID) originalBet, err := s.repo.GetVirtualGameTransactionByExternalID(ctx, req.TransactionID)
if err != nil { if err != nil {
@ -551,21 +571,21 @@ func (s *service) ProcessCancel(ctx context.Context, req *domain.PopOKCancelRequ
// 4. Check if already cancelled // 4. Check if already cancelled
if originalBet.Status == "CANCELLED" { if originalBet.Status == "CANCELLED" {
s.logger.Warn("Transaction already cancelled", "transactionID", req.TransactionID) s.logger.Warn("Transaction already cancelled", "transactionID", req.TransactionID)
wallets, _ := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // wallets, _ := s.walletSvc.GetWalletsByUser(ctx, claims.UserID)
balance := 0.0 // balance := 0.0
if len(wallets) > 0 { // if len(wallets) > 0 {
balance = float64(wallets[0].Balance) // balance = float64(wallets[0].Balance)
} // }
return &domain.PopOKCancelResponse{ return &domain.PopOKCancelResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", originalBet.ID), ExternalTrxID: fmt.Sprintf("%v", originalBet.ID),
Balance: balance, Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }
// 5. Refund the bet amount (absolute value since bet amount is negative) // 5. Refund the bet amount (absolute value since bet amount is negative)
refundAmount := -originalBet.Amount refundAmount := -originalBet.Amount
_, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(refundAmount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, _, err = s.walletSvc.AddToWallet(ctx, wallet.RegularID, domain.Currency(refundAmount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to wallet as refund for cancelling PopOk bet", refundAmount), fmt.Sprintf("Added %v to wallet as refund for cancelling PopOk bet", refundAmount),
) )
if err != nil { if err != nil {
@ -573,10 +593,10 @@ func (s *service) ProcessCancel(ctx context.Context, req *domain.PopOKCancelRequ
return nil, fmt.Errorf("refund failed") return nil, fmt.Errorf("refund failed")
} }
userWallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID) // userWallets, err := s.walletSvc.GetWalletsByUser(ctx, claims.UserID)
if err != nil { // if err != nil {
return &domain.PopOKCancelResponse{}, fmt.Errorf("Failed to read user wallets") // return &domain.PopOKCancelResponse{}, fmt.Errorf("Failed to read user wallets")
} // }
// 6. Mark original bet as cancelled and create cancel record // 6. Mark original bet as cancelled and create cancel record
cancelTx := &domain.VirtualGameTransaction{ cancelTx := &domain.VirtualGameTransaction{
@ -615,7 +635,7 @@ func (s *service) ProcessCancel(ctx context.Context, req *domain.PopOKCancelRequ
return &domain.PopOKCancelResponse{ return &domain.PopOKCancelResponse{
TransactionID: req.TransactionID, TransactionID: req.TransactionID,
ExternalTrxID: fmt.Sprintf("%v", cancelTx.ID), ExternalTrxID: fmt.Sprintf("%v", cancelTx.ID),
Balance: float64(userWallets[0].Balance), Balance: float64(wallet.RegularBalance),
}, nil }, nil
} }

View File

@ -1 +0,0 @@
package veli

View File

@ -218,23 +218,24 @@ func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*d
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid PlayerID: %w", err) return nil, fmt.Errorf("invalid PlayerID: %w", err)
} }
playerWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64) // playerWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64)
// if err != nil {
// return nil, fmt.Errorf("failed to get real balance: %w", err)
// }
// if len(playerWallets) == 0 {
// return nil, fmt.Errorf("PLAYER_NOT_FOUND: no wallet found for player %s", req.PlayerID)
// }
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt64)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get real balance: %w", err) return nil, fmt.Errorf("failed to read user wallets")
}
if len(playerWallets) == 0 {
return nil, fmt.Errorf("PLAYER_NOT_FOUND: no wallet found for player %s", req.PlayerID)
} }
realBalance := playerWallets[0].Balance // realBalance := playerWallets[0].Balance
// Retrieve bonus balance if applicable // Retrieve bonus balance if applicable
var bonusBalance float64 // var bonusBalance float64
if len(playerWallets) > 1 { // bonusBalance := float64(wallet.StaticBalance)
bonusBalance = float64(playerWallets[1].Balance)
} else {
bonusBalance = 0
}
// Build the response // Build the response
res := &domain.BalanceResponse{ res := &domain.BalanceResponse{
@ -243,19 +244,19 @@ func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*d
Amount float64 `json:"amount"` Amount float64 `json:"amount"`
}{ }{
Currency: req.Currency, Currency: req.Currency,
Amount: float64(realBalance), Amount: float64(wallet.RegularBalance),
}, },
} }
if bonusBalance > 0 { // if bonusBalance > 0 {
res.Bonus = &struct { // res.Bonus = &struct {
Currency string `json:"currency"` // Currency string `json:"currency"`
Amount float64 `json:"amount"` // Amount float64 `json:"amount"`
}{ // }{
Currency: req.Currency, // Currency: req.Currency,
Amount: bonusBalance, // Amount: bonusBalance,
} // }
} // }
return res, nil return res, nil
} }
@ -280,91 +281,64 @@ func (s *Service) ProcessBet(ctx context.Context, req domain.BetRequest) (*domai
// } // }
// --- 3. Get player wallets --- // --- 3. Get player wallets ---
playerWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64) // playerWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64)
// if err != nil {
// return nil, fmt.Errorf("failed to get real balance: %w", err)
// }
// if len(playerWallets) == 0 {
// return nil, fmt.Errorf("no wallets found for player %s", req.PlayerID)
// }
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt64)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get real balance: %w", err) return nil, fmt.Errorf("failed to read user wallets")
}
if len(playerWallets) == 0 {
return nil, fmt.Errorf("no wallets found for player %s", req.PlayerID)
} }
realWallet := playerWallets[0] // realWallet := playerWallets[0]
realBalance := float64(realWallet.Balance) // realBalance := float64(realWallet.Balance)
var bonusBalance float64 // var bonusBalance float64
if len(playerWallets) > 1 { // if len(playerWallets) > 1 {
bonusBalance = float64(playerWallets[1].Balance) // bonusBalance = float64(playerWallets[1].Balance)
} // }
bonusBalance := float64(wallet.StaticBalance)
// --- 4. Check sufficient balance --- // --- 4. Check sufficient balance ---
totalBalance := realBalance + bonusBalance // totalBalance := float64(wallet.RegularBalance) + bonusBalance
if totalBalance < req.Amount.Amount { if float64(wallet.RegularBalance) < req.Amount.Amount {
return nil, fmt.Errorf("INSUFFICIENT_BALANCE") return nil, fmt.Errorf("INSUFFICIENT_BALANCE")
} }
// --- 5. Deduct funds (bonus first, then real) --- // --- 5. Deduct funds (bonus first, then real) ---
remaining := req.Amount.Amount remaining := req.Amount.Amount
var usedBonus, usedReal float64 // var usedBonus, usedReal float64
if bonusBalance > 0 { if remaining > float64(wallet.RegularBalance) {
if bonusBalance >= remaining {
// fully cover from bonus
usedBonus = remaining
bonusBalance -= remaining
remaining = 0
} else {
// partially cover from bonus
usedBonus = bonusBalance
remaining -= bonusBalance
bonusBalance = 0
}
}
if remaining > 0 {
if realBalance >= remaining {
usedReal = remaining
realBalance -= remaining
remaining = 0
} else {
// should never happen because of totalBalance check
return nil, fmt.Errorf("INSUFFICIENT_BALANCE") return nil, fmt.Errorf("INSUFFICIENT_BALANCE")
} }
}
// --- 6. Persist wallet deductions --- // --- 6. Persist wallet deductions ---
if usedBonus > 0 && len(playerWallets) > 1 {
_, err = s.walletSvc.DeductFromWallet(ctx, playerWallets[1].ID, _, err = s.walletSvc.DeductFromWallet(ctx, wallet.RegularID,
domain.Currency(usedBonus), domain.Currency(req.Amount.Amount),
domain.ValidInt64{}, domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.TRANSFER_DIRECT,
fmt.Sprintf("Deduct bonus %.2f for bet %s", usedBonus, req.TransactionID), fmt.Sprintf("Deduct amount %.2f for bet %s", req.Amount.Amount, req.TransactionID),
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("bonus deduction failed: %w", err) return nil, fmt.Errorf("bonus deduction failed: %w", err)
} }
}
if usedReal > 0 {
_, err = s.walletSvc.DeductFromWallet(ctx, realWallet.ID,
domain.Currency(usedReal),
domain.ValidInt64{},
domain.TRANSFER_DIRECT,
fmt.Sprintf("Deduct real %.2f for bet %s", usedReal, req.TransactionID),
)
if err != nil {
return nil, fmt.Errorf("real deduction failed: %w", err)
}
}
// --- 7. Build response --- // --- 7. Build response ---
res := &domain.BetResponse{ res := &domain.BetResponse{
Real: domain.BalanceDetail{ Real: domain.BalanceDetail{
Currency: "ETB", Currency: "ETB",
Amount: realBalance, Amount: float64(wallet.RegularBalance),
}, },
WalletTransactionID: req.TransactionID, WalletTransactionID: req.TransactionID,
UsedRealAmount: usedReal, UsedRealAmount: req.Amount.Amount,
UsedBonusAmount: usedBonus, UsedBonusAmount: 0,
} }
if bonusBalance > 0 { if bonusBalance > 0 {
@ -385,21 +359,19 @@ func (s *Service) ProcessWin(ctx context.Context, req domain.WinRequest) (*domai
} }
// --- 2. Get player wallets --- // --- 2. Get player wallets ---
playerWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64) wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt64)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get wallets: %w", err) return nil, fmt.Errorf("failed to read user wallets")
}
if len(playerWallets) == 0 {
return nil, fmt.Errorf("PLAYER_NOT_FOUND: no wallets for player %s", req.PlayerID)
} }
realWallet := playerWallets[0] // realWallet := playerWallets[0]
realBalance := float64(realWallet.Balance) realBalance := float64(wallet.RegularBalance)
var bonusBalance float64 // var bonusBalance float64
if len(playerWallets) > 1 { // if len(playerWallets) > 1 {
bonusBalance = float64(playerWallets[1].Balance) // bonusBalance = float64(playerWallets[1].Balance)
} // }
bonusBalance := float64(wallet.StaticBalance)
// --- 3. Apply winnings (for now, everything goes to real wallet) --- // --- 3. Apply winnings (for now, everything goes to real wallet) ---
winAmount := req.Amount.Amount winAmount := req.Amount.Amount
@ -411,7 +383,7 @@ func (s *Service) ProcessWin(ctx context.Context, req domain.WinRequest) (*domai
_, err = s.walletSvc.AddToWallet( _, err = s.walletSvc.AddToWallet(
ctx, ctx,
realWallet.ID, wallet.RegularID,
domain.Currency(winAmount), domain.Currency(winAmount),
domain.ValidInt64{}, domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.TRANSFER_DIRECT,
@ -422,18 +394,18 @@ func (s *Service) ProcessWin(ctx context.Context, req domain.WinRequest) (*domai
return nil, fmt.Errorf("failed to credit real wallet: %w", err) return nil, fmt.Errorf("failed to credit real wallet: %w", err)
} }
// --- 4. Reload balances after credit --- // // --- 4. Reload balances after credit ---
updatedWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64) // updatedWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64)
if err != nil { // if err != nil {
return nil, fmt.Errorf("failed to reload balances: %w", err) // return nil, fmt.Errorf("failed to reload balances: %w", err)
} // }
updatedReal := updatedWallets[0] // updatedReal := updatedWallets[0]
realBalance = float64(updatedReal.Balance) // realBalance = float64(wallet.RegularBalance)
if len(updatedWallets) > 1 { // if len(updatedWallets) > 1 {
bonusBalance = float64(updatedWallets[1].Balance) // bonusBalance = float64(updatedWallets[1].Balance)
} // }
// --- 5. Build response --- // --- 5. Build response ---
res := &domain.WinResponse{ res := &domain.WinResponse{
@ -464,21 +436,18 @@ func (s *Service) ProcessCancel(ctx context.Context, req domain.CancelRequest) (
} }
// --- 2. Get player wallets --- // --- 2. Get player wallets ---
playerWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64) wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt64)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get wallets: %w", err) return nil, fmt.Errorf("failed to read user wallets")
}
if len(playerWallets) == 0 {
return nil, fmt.Errorf("no wallets for player %s", req.PlayerID)
} }
realWallet := playerWallets[0] // realWallet := playerWallets[0]
realBalance := float64(realWallet.Balance) realBalance := float64(wallet.RegularBalance)
var bonusBalance float64 // var bonusBalance float64
if len(playerWallets) > 1 { // if len(playerWallets) > 1 {
bonusBalance = float64(playerWallets[1].Balance) bonusBalance := float64(wallet.StaticBalance)
} // }
// --- 3. Determine refund amount based on IsAdjustment --- // --- 3. Determine refund amount based on IsAdjustment ---
var refundAmount float64 var refundAmount float64
@ -502,7 +471,7 @@ func (s *Service) ProcessCancel(ctx context.Context, req domain.CancelRequest) (
_, err = s.walletSvc.AddToWallet( _, err = s.walletSvc.AddToWallet(
ctx, ctx,
realWallet.ID, wallet.RegularID,
domain.Currency(refundAmount), domain.Currency(refundAmount),
domain.ValidInt64{}, domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.TRANSFER_DIRECT,
@ -520,23 +489,23 @@ func (s *Service) ProcessCancel(ctx context.Context, req domain.CancelRequest) (
} }
// --- 5. Reload balances after refund --- // --- 5. Reload balances after refund ---
updatedWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64) // updatedWallets, err := s.walletSvc.GetWalletsByUser(ctx, playerIDInt64)
if err != nil { // if err != nil {
return nil, fmt.Errorf("failed to reload balances: %w", err) // return nil, fmt.Errorf("failed to reload balances: %w", err)
} // }
updatedReal := updatedWallets[0] // updatedReal := updatedWallets[0]
realBalance = float64(updatedReal.Balance) // realBalance = float64(wallet.RegularBalance)
if len(updatedWallets) > 1 { // if len(updatedWallets) > 1 {
bonusBalance = float64(updatedWallets[1].Balance) // bonusBalance = float64(updatedWallets[1].Balance)
} // }
// --- 6. Build response --- // --- 6. Build response ---
res := &domain.CancelResponse{ res := &domain.CancelResponse{
WalletTransactionID: req.TransactionID, WalletTransactionID: req.TransactionID,
Real: domain.BalanceDetail{ Real: domain.BalanceDetail{
Currency: "ETB", Currency: req.AdjustmentRefund.Currency,
Amount: realBalance, Amount: realBalance,
}, },
UsedRealAmount: usedReal, UsedRealAmount: usedReal,
@ -545,7 +514,7 @@ func (s *Service) ProcessCancel(ctx context.Context, req domain.CancelRequest) (
if bonusBalance > 0 { if bonusBalance > 0 {
res.Bonus = &domain.BalanceDetail{ res.Bonus = &domain.BalanceDetail{
Currency: "ETB", Currency: req.AdjustmentRefund.Currency,
Amount: bonusBalance, Amount: bonusBalance,
} }
} }
@ -553,12 +522,6 @@ func (s *Service) ProcessCancel(ctx context.Context, req domain.CancelRequest) (
return res, nil return res, nil
} }
// Example helper to fetch original bet
// func (s *Service) getOriginalBet(ctx context.Context, transactionID string) (*domain.BetRecord, error) {
// // TODO: implement actual lookup
// return &domain.BetRecord{Amount: 50}, nil
// }
func (s *Service) GetGamingActivity(ctx context.Context, req domain.GamingActivityRequest) (*domain.GamingActivityResponse, error) { func (s *Service) GetGamingActivity(ctx context.Context, req domain.GamingActivityRequest) (*domain.GamingActivityResponse, error) {
// --- Signature Params (flattened strings for signing) --- // --- Signature Params (flattened strings for signing) ---
sigParams := map[string]any{ sigParams := map[string]any{