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, FullName: req.FullName, PhoneNumber: req.PhoneNumber, BranchID: branchID, }, userID, role) 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) (domain.ShopTransaction, error) { branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID) 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) 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) }