create bet with fast code

This commit is contained in:
Asher Samuel 2025-07-02 16:57:36 +03:00
parent 163dae4e44
commit d9f7cde114
7 changed files with 219 additions and 10 deletions

View File

@ -94,6 +94,11 @@ WHERE branch_id = $1;
SELECT *
FROM bet_with_outcomes
WHERE user_id = $1;
-- name: GetBetByFastCode :one
SELECT *
FROM bet_with_outcomes
WHERE fast_code = $1
LIMIT 1;
-- name: GetBetOutcomeByEventID :many
SELECT *
FROM bet_outcomes

View File

@ -283,6 +283,38 @@ func (q *Queries) GetBetByCashoutID(ctx context.Context, cashoutID string) (BetW
return i, err
}
const GetBetByFastCode = `-- name: GetBetByFastCode :one
SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes_hash, fast_code, outcomes
FROM bet_with_outcomes
WHERE fast_code = $1
LIMIT 1
`
func (q *Queries) GetBetByFastCode(ctx context.Context, fastCode string) (BetWithOutcome, error) {
row := q.db.QueryRow(ctx, GetBetByFastCode, fastCode)
var i BetWithOutcome
err := row.Scan(
&i.ID,
&i.Amount,
&i.TotalOdds,
&i.Status,
&i.FullName,
&i.PhoneNumber,
&i.CompanyID,
&i.BranchID,
&i.UserID,
&i.CashedOut,
&i.CashoutID,
&i.CreatedAt,
&i.UpdatedAt,
&i.IsShopBet,
&i.OutcomesHash,
&i.FastCode,
&i.Outcomes,
)
return i, err
}
const GetBetByID = `-- name: GetBetByID :one
SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes_hash, fast_code, outcomes
FROM bet_with_outcomes

View File

@ -282,6 +282,16 @@ func (s *Store) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetB
return result, nil
}
func (s *Store) GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error) {
bet, err := s.queries.GetBetByFastCode(ctx, fastcode)
if err != nil {
return domain.GetBet{}, err
}
return convertDBBetWithOutcomes(bet), nil
}
func (s *Store) GetBetCount(ctx context.Context, UserID int64, outcomesHash string) (int64, error) {
count, err := s.queries.GetBetCount(ctx, dbgen.GetBetCountParams{
UserID: pgtype.Int8{Int64: UserID},

View File

@ -15,6 +15,7 @@ type BetStore interface {
GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error)
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error)
GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error)
GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error)
GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error)
GetBetCount(ctx context.Context, userID int64, outcomesHash string) (int64, error)

View File

@ -711,6 +711,14 @@ func (s *Service) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.Ge
return s.betStore.GetBetByUserID(ctx, UserID)
}
func (s *Service) GetBetOutcomeByBetID(ctx context.Context, UserID int64) ([]domain.BetOutcome, error) {
return s.betStore.GetBetOutcomeByBetID(ctx, UserID)
}
func (s *Service) GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error) {
return s.betStore.GetBetByFastCode(ctx, fastcode)
}
func (s *Service) GetBetCount(ctx context.Context, UserID int64, outcomesHash string) (int64, error) {
return s.betStore.GetBetCount(ctx, UserID, outcomesHash)
}

View File

@ -1,6 +1,7 @@
package handlers
import (
"fmt"
"strconv"
"time"
@ -37,6 +38,163 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
}
res, err := h.CreateBetInternal(c, req, userID, role)
if err != nil {
h.mongoLoggerSvc.Error("Failed to create bet",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", userID),
zap.Time("timestamp", time.Now()),
)
}
h.mongoLoggerSvc.Info("Bet created successfully",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", userID),
zap.Time("timestamp", time.Now()),
)
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
}
// CreateBetWithFastCode godoc
// @Summary Create a bet with fast code
// @Description Creates a bet with fast code
// @Tags bet
// @Accept json
// @Produce json
// @Param createBetWithFastCode body domain.CreateBetReq true "Creates bet"
// @Success 200 {object} domain.BetRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /sport/bet/fastcode [post]
func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error {
userID := c.Locals("user_id").(int64)
role := c.Locals("role").(domain.Role)
var req struct {
FastCode string `json:"fast_code"`
}
if err := c.BodyParser(&req); err != nil {
h.mongoLoggerSvc.Error("Failed to parse CreateBet request",
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
}
bet, err := h.betSvc.GetBetByFastCode(c.Context(), req.FastCode)
if err != nil {
h.mongoLoggerSvc.Error("falied to get bet with fast code",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "falied to get bet with fast code")
}
outcomes, err := h.betSvc.GetBetOutcomeByBetID(c.Context(), bet.ID)
if err != nil {
h.mongoLoggerSvc.Error("falied to get BetOutcomes by BetID",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "falied to get BetOutcomes by BetID")
}
bet_outcomes := []domain.CreateBetOutcomeReq{}
for _, outcome := range outcomes {
bet_outcomes = append(bet_outcomes, domain.CreateBetOutcomeReq{
EventID: outcome.EventID,
OddID: outcome.OddID,
MarketID: outcome.MarketID,
})
}
user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil {
h.mongoLoggerSvc.Error("falied to get user information",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "falied to get user information")
}
branch, err := h.branchSvc.GetBranchByID(c.Context(), user.CompanyID.Value)
if err != nil {
h.mongoLoggerSvc.Error("falied to get branch of user",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "falied to get branch of user")
}
newReq := domain.CreateBetReq{
Amount: float32(bet.Amount),
Status: bet.Status,
Outcomes: bet_outcomes,
BranchID: &branch.ID,
FullName: user.FirstName,
PhoneNumber: user.PhoneNumber,
}
res, err := h.CreateBetInternal(c, newReq, userID, role)
if err != nil {
h.mongoLoggerSvc.Error("Failed to create bet",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", userID),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to create bet")
}
wallets, err := h.walletSvc.GetWalletsByUser(c.Context(), bet.UserID.Value)
var staticWallet domain.Wallet
var staticFound bool
for _, wallet := range wallets {
if !wallet.IsWithdraw {
staticWallet = wallet
staticFound = true
break
}
}
if err != nil || staticFound == false {
fmt.Println("wallet error: ", err)
h.mongoLoggerSvc.Error("Failed to get static wallet of user",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", user.ID),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to get wallets of user")
}
// amount added for fast code owner can be fetched from settings in db
amount := domain.Currency(100)
_, err = h.walletSvc.AddToWallet(c.Context(), staticWallet.ID, amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
if err != nil {
h.mongoLoggerSvc.Error("Failed to add reward to static bet",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", userID),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to add reward to static bet")
}
h.mongoLoggerSvc.Info("Bet created successfully",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", userID),
zap.Time("timestamp", time.Now()),
)
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
}
func (h *Handler) CreateBetInternal(c *fiber.Ctx, req domain.CreateBetReq, userID int64, role domain.Role) (domain.CreateBetRes, error) {
valErrs, ok := h.validator.Validate(c, req)
if !ok {
h.mongoLoggerSvc.Error("CreateBet validation failed",
@ -44,7 +202,7 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
zap.Any("validation_errors", valErrs),
zap.Time("timestamp", time.Now()),
)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return domain.CreateBetRes{}, fmt.Errorf("%s", valErrs)
}
res, err := h.betSvc.PlaceBet(c.Context(), req, userID, role)
@ -57,19 +215,13 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
switch err {
case bet.ErrEventHasBeenRemoved, bet.ErrEventHasNotEnded, bet.ErrRawOddInvalid, wallet.ErrBalanceInsufficient:
return fiber.NewError(fiber.StatusBadRequest, err.Error())
return domain.CreateBetRes{}, fiber.NewError(fiber.StatusBadRequest, err.Error())
}
return fiber.NewError(fiber.StatusInternalServerError, "Unable to create bet")
return domain.CreateBetRes{}, fiber.NewError(fiber.StatusInternalServerError, "Unable to create bet")
}
h.mongoLoggerSvc.Info("Bet created successfully",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", userID),
zap.Time("timestamp", time.Now()),
)
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
return res, nil
}
// RandomBet godoc

View File

@ -192,6 +192,7 @@ func (a *App) initAppRoutes() {
// Bet Routes
a.fiber.Post("/sport/bet", a.authMiddleware, h.CreateBet)
a.fiber.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode)
a.fiber.Get("/sport/bet", a.authMiddleware, h.GetAllBet)
a.fiber.Get("/sport/bet/:id", h.GetBetByID)
a.fiber.Get("/sport/bet/cashout/:id", a.authMiddleware, h.GetBetByCashoutID)