Yimaru-BackEnd/internal/services/transaction/shop_bet.go

207 lines
6.0 KiB
Go

package transaction
import (
"context"
"crypto/rand"
"errors"
"math/big"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
var (
ErrInvalidBetID = errors.New("invalid bet id")
ErrUserHasNotWonBet = errors.New("user has not won bet")
ErrUserHasAlreadyCashoutOut = errors.New("user has already cashout")
ErrTransactionNotVerified = errors.New("transaction hasn't been verified")
)
func (s *Service) GenerateCashoutID() (string, error) {
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
const length int = 13
charLen := big.NewInt(int64(len(chars)))
result := make([]byte, length)
for i := 0; i < length; i++ {
index, err := rand.Int(rand.Reader, charLen)
if err != nil {
// s.mongoLogger.Error("failed to generate random index for cashout ID",
// zap.Int("position", i),
// zap.Error(err),
// )
return "", err
}
result[i] = chars[index.Int64()]
}
return string(result), nil
}
func (s *Service) CreateShopBet(ctx context.Context, userID int64, role domain.Role, userCompanyID domain.ValidInt64, req domain.ShopBetReq) (domain.ShopBet, error) {
branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID, userCompanyID)
if err != nil {
return domain.ShopBet{}, err
}
cashoutID, err := s.GenerateCashoutID()
if err != nil {
return domain.ShopBet{}, err
}
newBet, err := s.betSvc.PlaceBet(ctx, domain.CreateBetReq{
Outcomes: req.Outcomes,
Amount: req.Amount,
}, userID, role, *companyID)
if err != nil {
return domain.ShopBet{}, err
}
newTransaction, err := s.CreateShopTransaction(ctx, domain.CreateShopTransaction{
Amount: domain.ToCurrency(req.Amount),
BranchID: *branchID,
CompanyID: *companyID,
UserID: userID,
Type: domain.TRANSACTION_BET,
FullName: req.FullName,
PhoneNumber: req.PhoneNumber,
PaymentOption: req.PaymentOption,
BankCode: domain.ValidString{
Value: req.BankCode,
Valid: req.BankCode != "",
},
BeneficiaryName: domain.ValidString{
Value: req.BeneficiaryName,
Valid: req.BeneficiaryName != "",
},
AccountName: domain.ValidString{
Value: req.AccountName,
Valid: req.AccountName != "",
},
AccountNumber: domain.ValidString{
Value: req.AccountNumber,
Valid: req.AccountNumber != "",
},
ReferenceNumber: domain.ValidString{
Value: req.ReferenceNumber,
Valid: req.ReferenceNumber != "",
},
Verified: false,
ApprovedBy: domain.ValidInt64{
Value: userID,
Valid: true,
},
})
return s.transactionStore.CreateShopBet(ctx, domain.CreateShopBet{
ShopTransactionID: newTransaction.ID,
CashoutID: cashoutID,
BetID: newBet.ID,
NumberOfOutcomes: int64(len(req.Outcomes)),
})
}
// func (s *Service) CreateShopBet(ctx context.Context, bet domain.CreateShopBet) (domain.ShopBet, error) {
// return s.transactionStore.CreateShopBet(ctx, bet)
// }
func (s *Service) CashoutBet(ctx context.Context, betID int64, userID int64, role domain.Role, req domain.CashoutReq, userCompanyID domain.ValidInt64) (domain.ShopTransaction, error) {
branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID, userCompanyID)
if err != nil {
return domain.ShopTransaction{}, nil
}
bet, err := s.GetShopBetByBetID(ctx, betID)
if err != nil {
// h.logger.Error("CashoutReq failed", "error", err)
return domain.ShopTransaction{}, ErrInvalidBetID
}
if bet.Status != domain.OUTCOME_STATUS_WIN {
// h.logger.Error("CashoutReq failed, bet has not won")
return domain.ShopTransaction{}, ErrUserHasNotWonBet
}
if bet.CashedOut {
// s.logger.Error(("Bet has already been cashed out"))
return domain.ShopTransaction{}, ErrUserHasAlreadyCashoutOut
}
if !bet.TransactionVerified {
return domain.ShopTransaction{}, ErrTransactionNotVerified
}
err = s.UpdateShopBetCashOut(ctx, bet.ID, true)
if err != nil {
return domain.ShopTransaction{}, err
}
return s.CreateShopTransaction(ctx, domain.CreateShopTransaction{
Amount: bet.Amount,
BranchID: *branchID,
CompanyID: *companyID,
UserID: userID,
Type: domain.TRANSACTION_CASHOUT,
FullName: bet.FullName,
PhoneNumber: bet.PhoneNumber,
PaymentOption: req.PaymentOption,
BankCode: domain.ValidString{
Value: req.BankCode,
Valid: req.BankCode != "",
},
BeneficiaryName: domain.ValidString{
Value: req.BeneficiaryName,
Valid: req.BeneficiaryName != "",
},
AccountName: domain.ValidString{
Value: req.AccountName,
Valid: req.AccountName != "",
},
AccountNumber: domain.ValidString{
Value: req.AccountNumber,
Valid: req.AccountNumber != "",
},
ReferenceNumber: domain.ValidString{
Value: req.ReferenceNumber,
Valid: req.ReferenceNumber != "",
},
Verified: false,
ApprovedBy: domain.ValidInt64{
Value: userID,
Valid: true,
},
})
}
func (s *Service) GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter) ([]domain.ShopBetDetail, error) {
return s.transactionStore.GetAllShopBet(ctx, filter)
}
func (s *Service) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error) {
return s.transactionStore.GetShopBetByBetID(ctx, id)
}
func (s *Service) GetShopBetByBetID(ctx context.Context, betID int64) (domain.ShopBetDetail, error) {
return s.transactionStore.GetShopBetByBetID(ctx, betID)
}
func (s *Service) GetShopBetByCashoutID(ctx context.Context, cashoutID string) (domain.ShopBetDetail, error) {
return s.transactionStore.GetShopBetByCashoutID(ctx, cashoutID)
}
func (s *Service) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) {
return s.transactionStore.GetShopBetByShopTransactionID(ctx, shopTransactionID)
}
func (s *Service) UpdateShopBetCashOut(ctx context.Context, id int64, cashedOut bool) error {
return s.transactionStore.UpdateShopBetCashOut(ctx, id, cashedOut)
}
func (s *Service) UpdateShopBetCashoutID(ctx context.Context, id int64, cashoutID string) error {
return s.transactionStore.UpdateShopBetCashoutID(ctx, id, cashoutID)
}