create random bet
This commit is contained in:
parent
8e271559ae
commit
b7b17fa8d2
|
|
@ -70,14 +70,13 @@ func main() {
|
|||
|
||||
eventSvc := event.New(cfg.Bet365Token, store)
|
||||
oddsSvc := odds.New(store, cfg, logger)
|
||||
resultSvc := result.NewService(store, cfg, logger)
|
||||
ticketSvc := ticket.NewService(store)
|
||||
betSvc := bet.NewService(store)
|
||||
walletSvc := wallet.NewService(store, store)
|
||||
transactionSvc := transaction.NewService(store)
|
||||
branchSvc := branch.NewService(store)
|
||||
companySvc := company.NewService(store)
|
||||
|
||||
betSvc := bet.NewService(store, eventSvc, oddsSvc, *walletSvc, *branchSvc, logger)
|
||||
resultSvc := result.NewService(store, cfg, logger, *betSvc)
|
||||
notificationRepo := repository.NewNotificationRepository(store)
|
||||
referalRepo := repository.NewReferralRepository(store)
|
||||
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
||||
|
|
|
|||
|
|
@ -62,16 +62,16 @@ WHERE branch_id = $1;
|
|||
SELECT *
|
||||
FROM bet_outcomes
|
||||
WHERE event_id = $1;
|
||||
|
||||
-- name: UpdateCashOut :exec
|
||||
UPDATE bets
|
||||
SET cashed_out = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
-- name: UpdateBetOutcomeStatus :exec
|
||||
-- name: UpdateBetOutcomeStatus :one
|
||||
UPDATE bet_outcomes
|
||||
SET status = $1
|
||||
WHERE id = $2;
|
||||
WHERE id = $2
|
||||
RETURNING *;
|
||||
-- name: UpdateStatus :exec
|
||||
UPDATE bets
|
||||
SET status = $2,
|
||||
|
|
|
|||
|
|
@ -285,10 +285,11 @@ func (q *Queries) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :exec
|
||||
const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :one
|
||||
UPDATE bet_outcomes
|
||||
SET status = $1
|
||||
WHERE id = $2
|
||||
RETURNING id, bet_id, sport_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires
|
||||
`
|
||||
|
||||
type UpdateBetOutcomeStatusParams struct {
|
||||
|
|
@ -296,9 +297,27 @@ type UpdateBetOutcomeStatusParams struct {
|
|||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateBetOutcomeStatus(ctx context.Context, arg UpdateBetOutcomeStatusParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateBetOutcomeStatus, arg.Status, arg.ID)
|
||||
return err
|
||||
func (q *Queries) UpdateBetOutcomeStatus(ctx context.Context, arg UpdateBetOutcomeStatusParams) (BetOutcome, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateBetOutcomeStatus, arg.Status, arg.ID)
|
||||
var i BetOutcome
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.BetID,
|
||||
&i.SportID,
|
||||
&i.EventID,
|
||||
&i.OddID,
|
||||
&i.HomeTeamName,
|
||||
&i.AwayTeamName,
|
||||
&i.MarketID,
|
||||
&i.MarketName,
|
||||
&i.Odd,
|
||||
&i.OddName,
|
||||
&i.OddHeader,
|
||||
&i.OddHandicap,
|
||||
&i.Status,
|
||||
&i.Expires,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateCashOut = `-- name: UpdateCashOut :exec
|
||||
|
|
|
|||
|
|
@ -80,3 +80,82 @@ type CreateBet struct {
|
|||
IsShopBet bool
|
||||
CashoutID string
|
||||
}
|
||||
|
||||
type CreateBetOutcomeReq struct {
|
||||
EventID int64 `json:"event_id" example:"1"`
|
||||
OddID int64 `json:"odd_id" example:"1"`
|
||||
MarketID int64 `json:"market_id" example:"1"`
|
||||
}
|
||||
|
||||
type CreateBetReq struct {
|
||||
Outcomes []CreateBetOutcomeReq `json:"outcomes"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
Status OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
type RandomBetReq struct {
|
||||
BranchID int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
type CreateBetRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||
Status OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID int64 `json:"branch_id" example:"2"`
|
||||
UserID int64 `json:"user_id" example:"2"`
|
||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||
CreatedNumber int64 `json:"created_number" example:"2"`
|
||||
CashedID string `json:"cashed_id" example:"21234"`
|
||||
}
|
||||
type BetRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Outcomes []BetOutcome `json:"outcomes"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||
Status OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID int64 `json:"branch_id" example:"2"`
|
||||
UserID int64 `json:"user_id" example:"2"`
|
||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||
CashedOut bool `json:"cashed_out" example:"false"`
|
||||
CashedID string `json:"cashed_id" example:"21234"`
|
||||
}
|
||||
|
||||
func ConvertCreateBet(bet Bet, createdNumber int64) CreateBetRes {
|
||||
return CreateBetRes{
|
||||
ID: bet.ID,
|
||||
Amount: bet.Amount.Float32(),
|
||||
TotalOdds: bet.TotalOdds,
|
||||
Status: bet.Status,
|
||||
FullName: bet.FullName,
|
||||
PhoneNumber: bet.PhoneNumber,
|
||||
BranchID: bet.BranchID.Value,
|
||||
UserID: bet.UserID.Value,
|
||||
CreatedNumber: createdNumber,
|
||||
CashedID: bet.CashoutID,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertBet(bet GetBet) BetRes {
|
||||
return BetRes{
|
||||
ID: bet.ID,
|
||||
Amount: bet.Amount.Float32(),
|
||||
TotalOdds: bet.TotalOdds,
|
||||
Status: bet.Status,
|
||||
FullName: bet.FullName,
|
||||
PhoneNumber: bet.PhoneNumber,
|
||||
BranchID: bet.BranchID.Value,
|
||||
UserID: bet.UserID.Value,
|
||||
Outcomes: bet.Outcomes,
|
||||
IsShopBet: bet.IsShopBet,
|
||||
CashedOut: bet.CashedOut,
|
||||
CashedID: bet.CashoutID,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,12 +225,13 @@ func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]do
|
|||
}
|
||||
return result, nil
|
||||
}
|
||||
func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||
err := s.queries.UpdateBetOutcomeStatus(ctx, dbgen.UpdateBetOutcomeStatusParams{
|
||||
func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) {
|
||||
update, err := s.queries.UpdateBetOutcomeStatus(ctx, dbgen.UpdateBetOutcomeStatusParams{
|
||||
Status: int32(status),
|
||||
ID: id,
|
||||
})
|
||||
return err
|
||||
res := convertDBBetOutcomes(update)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ type BetStore interface {
|
|||
GetBetByID(ctx context.Context, id int64) (domain.GetBet, error)
|
||||
GetAllBets(ctx context.Context) ([]domain.GetBet, error)
|
||||
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
|
||||
GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]domain.BetOutcome, error)
|
||||
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
|
||||
UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
|
||||
DeleteBet(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,21 +3,50 @@ package bet
|
|||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math/big"
|
||||
random "math/rand"
|
||||
"slices"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
betStore BetStore
|
||||
betStore BetStore
|
||||
eventSvc event.Service
|
||||
prematchSvc odds.Service
|
||||
walletSvc wallet.Service
|
||||
branchSvc branch.Service
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewService(betStore BetStore) *Service {
|
||||
func NewService(betStore BetStore, eventSvc event.Service, prematchSvc odds.Service, walletSvc wallet.Service, branchSvc branch.Service, logger *slog.Logger) *Service {
|
||||
return &Service{
|
||||
betStore: betStore,
|
||||
betStore: betStore,
|
||||
eventSvc: eventSvc,
|
||||
prematchSvc: prematchSvc,
|
||||
walletSvc: walletSvc,
|
||||
branchSvc: branchSvc,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ErrEventHasNotEnded = errors.New("Event has not ended yet")
|
||||
ErrRawOddInvalid = errors.New("Prematch Raw Odd is Invalid")
|
||||
ErrBranchIDRequired = errors.New("Branch ID required for this role")
|
||||
ErrOutcomeLimit = errors.New("Too many outcomes on a single bet")
|
||||
)
|
||||
|
||||
func (s *Service) GenerateCashoutID() (string, error) {
|
||||
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
const length int = 13
|
||||
|
|
@ -33,8 +62,365 @@ func (s *Service) GenerateCashoutID() (string, error) {
|
|||
return string(result), nil
|
||||
}
|
||||
|
||||
func (s *Service) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
|
||||
func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketID int64, oddID int64) (domain.CreateBetOutcome, error) {
|
||||
// TODO: Change this when you refactor the database code
|
||||
eventIDStr := strconv.FormatInt(eventID, 10)
|
||||
marketIDStr := strconv.FormatInt(marketID, 10)
|
||||
oddIDStr := strconv.FormatInt(oddID, 10)
|
||||
|
||||
event, err := s.eventSvc.GetUpcomingEventByID(ctx, eventIDStr)
|
||||
if err != nil {
|
||||
return domain.CreateBetOutcome{}, err
|
||||
}
|
||||
|
||||
currentTime := time.Now()
|
||||
if event.StartTime.Before(currentTime) {
|
||||
return domain.CreateBetOutcome{}, ErrEventHasNotEnded
|
||||
}
|
||||
|
||||
odds, err := s.prematchSvc.GetRawOddsByMarketID(ctx, marketIDStr, eventIDStr)
|
||||
|
||||
if err != nil {
|
||||
return domain.CreateBetOutcome{}, err
|
||||
}
|
||||
type rawOddType struct {
|
||||
ID string
|
||||
Name string
|
||||
Odds string
|
||||
Header string
|
||||
Handicap string
|
||||
}
|
||||
|
||||
var selectedOdd rawOddType
|
||||
var isOddFound bool = false
|
||||
|
||||
for _, raw := range odds.RawOdds {
|
||||
var rawOdd rawOddType
|
||||
rawBytes, err := json.Marshal(raw)
|
||||
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to unmarshal raw odd %v", err)
|
||||
continue
|
||||
}
|
||||
if rawOdd.ID == oddIDStr {
|
||||
selectedOdd = rawOdd
|
||||
isOddFound = true
|
||||
}
|
||||
}
|
||||
if !isOddFound {
|
||||
return domain.CreateBetOutcome{}, ErrRawOddInvalid
|
||||
}
|
||||
|
||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||
if err != nil {
|
||||
return domain.CreateBetOutcome{}, err
|
||||
}
|
||||
sportID, err := strconv.ParseInt(event.SportID, 10, 64)
|
||||
if err != nil {
|
||||
return domain.CreateBetOutcome{}, err
|
||||
}
|
||||
newOutcome := domain.CreateBetOutcome{
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
SportID: sportID,
|
||||
HomeTeamName: event.HomeTeam,
|
||||
AwayTeamName: event.AwayTeam,
|
||||
MarketName: odds.MarketName,
|
||||
Odd: float32(parsedOdd),
|
||||
OddName: selectedOdd.Name,
|
||||
OddHeader: selectedOdd.Header,
|
||||
OddHandicap: selectedOdd.Handicap,
|
||||
Expires: event.StartTime,
|
||||
}
|
||||
|
||||
return newOutcome, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID int64, role domain.Role) (domain.CreateBetRes, error) {
|
||||
// You can move the loop over req.Outcomes and all the business logic here.
|
||||
|
||||
if len(req.Outcomes) > 30 {
|
||||
return domain.CreateBetRes{}, ErrOutcomeLimit
|
||||
}
|
||||
|
||||
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
||||
var totalOdds float32 = 1
|
||||
|
||||
for _, outcomeReq := range req.Outcomes {
|
||||
newOutcome, err := s.GenerateBetOutcome(ctx, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID)
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
totalOdds = totalOdds * float32(newOutcome.Odd)
|
||||
outcomes = append(outcomes, newOutcome)
|
||||
}
|
||||
|
||||
// Handle role-specific logic and wallet deduction if needed.
|
||||
var cashoutID string
|
||||
cashoutID, err := s.GenerateCashoutID()
|
||||
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
newBet := domain.CreateBet{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
TotalOdds: totalOdds,
|
||||
Status: req.Status,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
CashoutID: cashoutID,
|
||||
}
|
||||
switch role {
|
||||
case domain.RoleCashier:
|
||||
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
// Deduct from wallet:
|
||||
// TODO: Make this percentage come from the company
|
||||
var deductedAmount = req.Amount / 10
|
||||
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
||||
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
newBet.BranchID = domain.ValidInt64{
|
||||
Value: branch.ID,
|
||||
Valid: true,
|
||||
}
|
||||
newBet.UserID = domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
}
|
||||
newBet.IsShopBet = true
|
||||
// bet, err = s.betStore.CreateBet(ctx)
|
||||
case domain.RoleBranchManager, domain.RoleAdmin, domain.RoleSuperAdmin:
|
||||
// TODO: restrict the Branch ID of Admin and Branch Manager to only the branches within their own company
|
||||
// If a non cashier wants to create a bet, they will need to provide the Branch ID
|
||||
if req.BranchID == nil {
|
||||
return domain.CreateBetRes{}, ErrBranchIDRequired
|
||||
}
|
||||
|
||||
newBet.BranchID = domain.ValidInt64{
|
||||
Value: *req.BranchID,
|
||||
Valid: true,
|
||||
}
|
||||
newBet.UserID = domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
}
|
||||
newBet.IsShopBet = true
|
||||
case domain.RoleCustomer:
|
||||
return domain.CreateBetRes{}, fmt.Errorf("Not yet implemented")
|
||||
default:
|
||||
return domain.CreateBetRes{}, fmt.Errorf("Unknown Role Type")
|
||||
}
|
||||
|
||||
bet, err := s.CreateBet(ctx, newBet)
|
||||
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
// Associate outcomes with the bet.
|
||||
for i := range outcomes {
|
||||
outcomes[i].BetID = bet.ID
|
||||
}
|
||||
rows, err := s.betStore.CreateBetOutcome(ctx, outcomes)
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
res := domain.ConvertCreateBet(bet, rows)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID, sportID, HomeTeam, AwayTeam string, StartTime time.Time) ([]domain.CreateBetOutcome, float32, error) {
|
||||
|
||||
var newOdds []domain.CreateBetOutcome
|
||||
var totalOdds float32 = 1
|
||||
|
||||
markets, err := s.prematchSvc.GetPrematchOdds(ctx, eventID)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error("failed to get odds for event", "event id", eventID, "error", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if len(markets) == 0 {
|
||||
s.logger.Error("empty odds for event", "event id", eventID)
|
||||
return nil, 0, fmt.Errorf("empty odds or event", "event id", eventID)
|
||||
}
|
||||
|
||||
var numMarkets = min(5, len(markets))
|
||||
var randIndex []int = make([]int, numMarkets)
|
||||
for i := 0; i < numMarkets; i++ {
|
||||
// Guarantee that the odd is unique
|
||||
var newRandMarket int
|
||||
count := 0
|
||||
for {
|
||||
newRandMarket = random.Intn(len(markets))
|
||||
if !slices.Contains(randIndex, newRandMarket) {
|
||||
break
|
||||
}
|
||||
// just in case
|
||||
if count >= 5 {
|
||||
s.logger.Warn("market overload", "event id", eventID)
|
||||
break
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
randIndex[i] = newRandMarket
|
||||
|
||||
rawOdds := markets[i].RawOdds
|
||||
randomRawOdd := rawOdds[random.Intn(len(rawOdds))]
|
||||
|
||||
type rawOddType struct {
|
||||
ID string
|
||||
Name string
|
||||
Odds string
|
||||
Header string
|
||||
Handicap string
|
||||
}
|
||||
|
||||
var selectedOdd rawOddType
|
||||
rawBytes, err := json.Marshal(randomRawOdd)
|
||||
err = json.Unmarshal(rawBytes, &selectedOdd)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to unmarshal raw odd %v", err)
|
||||
continue
|
||||
}
|
||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse odd", "error", err)
|
||||
continue
|
||||
}
|
||||
sportID, err := strconv.ParseInt(sportID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get sport id", "error", err)
|
||||
continue
|
||||
}
|
||||
eventID, err := strconv.ParseInt(eventID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get event id", "error", err)
|
||||
continue
|
||||
}
|
||||
oddID, err := strconv.ParseInt(selectedOdd.ID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get odd id", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
marketID, err := strconv.ParseInt(markets[i].MarketID, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get odd id", "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
marketName := markets[i].MarketName
|
||||
|
||||
newOdds = append(newOdds, domain.CreateBetOutcome{
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
SportID: sportID,
|
||||
HomeTeamName: HomeTeam,
|
||||
AwayTeamName: AwayTeam,
|
||||
MarketName: marketName,
|
||||
Odd: float32(parsedOdd),
|
||||
OddName: selectedOdd.Name,
|
||||
OddHeader: selectedOdd.Header,
|
||||
OddHandicap: selectedOdd.Handicap,
|
||||
Expires: StartTime,
|
||||
})
|
||||
|
||||
totalOdds = totalOdds * float32(parsedOdd)
|
||||
|
||||
}
|
||||
|
||||
if len(newOdds) == 0 {
|
||||
s.logger.Error("Failed to generate random outcomes")
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
return newOdds, totalOdds, nil
|
||||
}
|
||||
|
||||
func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64) (domain.CreateBetRes, error) {
|
||||
|
||||
// Get a unexpired event id
|
||||
events, _, err := s.eventSvc.GetPaginatedUpcomingEvents(ctx, 5, 0, domain.ValidString{}, domain.ValidString{})
|
||||
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
// Get market and odds for that
|
||||
var randomOdds []domain.CreateBetOutcome
|
||||
var totalOdds float32 = 1
|
||||
for _, event := range events {
|
||||
|
||||
newOdds, total, err := s.GenerateRandomBetOutcomes(ctx, event.ID, event.SportID, event.HomeTeam, event.AwayTeam, event.StartTime)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error("failed to generate random bet outcome", "event id", event.ID, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
randomOdds = append(randomOdds, newOdds...)
|
||||
totalOdds = totalOdds * total
|
||||
|
||||
}
|
||||
if len(randomOdds) == 0 {
|
||||
s.logger.Error("Failed to generate random outcomes")
|
||||
return domain.CreateBetRes{}, nil
|
||||
}
|
||||
|
||||
var cashoutID string
|
||||
|
||||
cashoutID, err = s.GenerateCashoutID()
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
randomNumber := strconv.FormatInt(int64(random.Intn(10)), 10)
|
||||
newBet := domain.CreateBet{
|
||||
Amount: 123,
|
||||
TotalOdds: totalOdds,
|
||||
Status: domain.OUTCOME_STATUS_PENDING,
|
||||
FullName: "test" + randomNumber,
|
||||
PhoneNumber: randomNumber,
|
||||
CashoutID: cashoutID,
|
||||
BranchID: domain.ValidInt64{Valid: true, Value: branchID},
|
||||
UserID: domain.ValidInt64{Valid: true, Value: userID},
|
||||
}
|
||||
|
||||
bet, err := s.CreateBet(ctx, newBet)
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
for i := range randomOdds {
|
||||
randomOdds[i].BetID = bet.ID
|
||||
}
|
||||
|
||||
rows, err := s.betStore.CreateBetOutcome(ctx, randomOdds)
|
||||
if err != nil {
|
||||
return domain.CreateBetRes{}, err
|
||||
}
|
||||
|
||||
res := domain.ConvertCreateBet(bet, rows)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Service) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
|
||||
return s.betStore.CreateBet(ctx, bet)
|
||||
}
|
||||
|
||||
|
|
@ -64,8 +450,43 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
|
|||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
}
|
||||
|
||||
func (s *Service) checkBetOutcomeForBet(ctx context.Context, eventID int64) error {
|
||||
betOutcomes, err := s.betStore.GetBetOutcomeByEventID(ctx, eventID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status := domain.OUTCOME_STATUS_PENDING
|
||||
|
||||
for _, betOutcome := range betOutcomes {
|
||||
// Check if any of them are pending
|
||||
if betOutcome.Status == domain.OUTCOME_STATUS_PENDING {
|
||||
return nil
|
||||
}
|
||||
|
||||
if status == domain.OUTCOME_STATUS_PENDING {
|
||||
status = betOutcome.Status
|
||||
} else if status == domain.OUTCOME_STATUS_WIN {
|
||||
status = betOutcome.Status
|
||||
} else if status == domain.OUTCOME_STATUS_LOSS {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if status != domain.OUTCOME_STATUS_PENDING {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.UpdateStatus(ctx, eventID, status)
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||
return s.betStore.UpdateBetOutcomeStatus(ctx, id, status)
|
||||
betOutcome, err := s.betStore.UpdateBetOutcomeStatus(ctx, id, status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.checkBetOutcomeForBet(ctx, betOutcome.EventID)
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
|
|
@ -20,14 +21,16 @@ type Service struct {
|
|||
config *config.Config
|
||||
logger *slog.Logger
|
||||
client *http.Client
|
||||
betSvc bet.Service
|
||||
}
|
||||
|
||||
func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger) *Service {
|
||||
func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger, betSvc bet.Service) *Service {
|
||||
return &Service{
|
||||
repo: repo,
|
||||
config: cfg,
|
||||
logger: logger,
|
||||
client: &http.Client{Timeout: 10 * time.Second},
|
||||
betSvc: betSvc,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +88,7 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
// continue
|
||||
// }
|
||||
|
||||
err = s.repo.UpdateBetOutcomeStatus(ctx, outcome.ID, result.Status)
|
||||
_, err = s.repo.UpdateBetOutcomeStatus(ctx, outcome.ID, result.Status)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
|
|
@ -10,88 +8,13 @@ import (
|
|||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type CreateBetOutcomeReq struct {
|
||||
EventID int64 `json:"event_id" example:"1"`
|
||||
OddID int64 `json:"odd_id" example:"1"`
|
||||
MarketID int64 `json:"market_id" example:"1"`
|
||||
}
|
||||
|
||||
type CreateBetReq struct {
|
||||
Outcomes []CreateBetOutcomeReq `json:"outcomes"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
Status domain.OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
type CreateBetRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||
Status domain.OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID int64 `json:"branch_id" example:"2"`
|
||||
UserID int64 `json:"user_id" example:"2"`
|
||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||
CreatedNumber int64 `json:"created_number" example:"2"`
|
||||
CashedID string `json:"cashed_id" example:"21234"`
|
||||
}
|
||||
type BetRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Outcomes []domain.BetOutcome `json:"outcomes"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||
Status domain.OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID int64 `json:"branch_id" example:"2"`
|
||||
UserID int64 `json:"user_id" example:"2"`
|
||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||
CashedOut bool `json:"cashed_out" example:"false"`
|
||||
CashedID string `json:"cashed_id" example:"21234"`
|
||||
}
|
||||
|
||||
func convertCreateBet(bet domain.Bet, createdNumber int64) CreateBetRes {
|
||||
return CreateBetRes{
|
||||
ID: bet.ID,
|
||||
Amount: bet.Amount.Float32(),
|
||||
TotalOdds: bet.TotalOdds,
|
||||
Status: bet.Status,
|
||||
FullName: bet.FullName,
|
||||
PhoneNumber: bet.PhoneNumber,
|
||||
BranchID: bet.BranchID.Value,
|
||||
UserID: bet.UserID.Value,
|
||||
CreatedNumber: createdNumber,
|
||||
CashedID: bet.CashoutID,
|
||||
}
|
||||
}
|
||||
|
||||
func convertBet(bet domain.GetBet) BetRes {
|
||||
return BetRes{
|
||||
ID: bet.ID,
|
||||
Amount: bet.Amount.Float32(),
|
||||
TotalOdds: bet.TotalOdds,
|
||||
Status: bet.Status,
|
||||
FullName: bet.FullName,
|
||||
PhoneNumber: bet.PhoneNumber,
|
||||
BranchID: bet.BranchID.Value,
|
||||
UserID: bet.UserID.Value,
|
||||
Outcomes: bet.Outcomes,
|
||||
IsShopBet: bet.IsShopBet,
|
||||
CashedOut: bet.CashedOut,
|
||||
CashedID: bet.CashoutID,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateBet godoc
|
||||
// @Summary Create a bet
|
||||
// @Description Creates a bet
|
||||
// @Tags bet
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param createBet body CreateBetReq true "Creates bet"
|
||||
// @Param createBet body domain.CreateBetReq true "Creates bet"
|
||||
// @Success 200 {object} BetRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
|
|
@ -102,7 +25,7 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
|||
userID := c.Locals("user_id").(int64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
|
||||
var req CreateBetReq
|
||||
var req domain.CreateBetReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("Failed to parse CreateBet request", "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
|
|
@ -113,199 +36,52 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
|||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||
// Validation for creating tickets
|
||||
if len(req.Outcomes) > 30 {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||
}
|
||||
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
||||
var totalOdds float32 = 1
|
||||
for _, outcome := range req.Outcomes {
|
||||
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||
event, err := h.eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||
}
|
||||
|
||||
// Checking to make sure the event hasn't already started
|
||||
// currentTime := time.Now()
|
||||
// if event.StartTime.Before(currentTime) {
|
||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||
// }
|
||||
|
||||
odds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||
}
|
||||
type rawOddType struct {
|
||||
ID string
|
||||
Name string
|
||||
Odds string
|
||||
Header string
|
||||
Handicap string
|
||||
}
|
||||
var selectedOdd rawOddType
|
||||
var isOddFound bool = false
|
||||
for _, raw := range odds.RawOdds {
|
||||
var rawOdd rawOddType
|
||||
rawBytes, err := json.Marshal(raw)
|
||||
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to unmarshal raw odd", "error", err)
|
||||
continue
|
||||
}
|
||||
if rawOdd.ID == oddIDStr {
|
||||
selectedOdd = rawOdd
|
||||
isOddFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isOddFound {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||
}
|
||||
|
||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||
totalOdds = totalOdds * float32(parsedOdd)
|
||||
|
||||
sportID, err := strconv.ParseInt(event.SportID, 10, 64)
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid sport id", nil, nil)
|
||||
}
|
||||
|
||||
h.logger.Info("Create Bet", slog.Int64("sportId", sportID))
|
||||
|
||||
outcomes = append(outcomes, domain.CreateBetOutcome{
|
||||
EventID: outcome.EventID,
|
||||
OddID: outcome.OddID,
|
||||
MarketID: outcome.MarketID,
|
||||
SportID: sportID,
|
||||
HomeTeamName: event.HomeTeam,
|
||||
AwayTeamName: event.AwayTeam,
|
||||
MarketName: odds.MarketName,
|
||||
Odd: float32(parsedOdd),
|
||||
OddName: selectedOdd.Name,
|
||||
OddHeader: selectedOdd.Header,
|
||||
OddHandicap: selectedOdd.Handicap,
|
||||
Expires: event.StartTime,
|
||||
})
|
||||
}
|
||||
|
||||
// Validating user by role
|
||||
// Differentiating between offline and online bets
|
||||
cashoutID, err := h.betSvc.GenerateCashoutID()
|
||||
if err != nil {
|
||||
h.logger.Error("CreateBetReq failed, unable to create cashout id")
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Invalid request", err, nil)
|
||||
}
|
||||
var bet domain.Bet
|
||||
if role == domain.RoleCashier {
|
||||
|
||||
// Get the branch from the branch ID
|
||||
branch, err := h.branchSvc.GetBranchByCashier(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("CreateBetReq failed, branch id invalid")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
// Deduct a percentage of the amount
|
||||
// TODO move to service layer. Make it fetch dynamically from company
|
||||
var deductedAmount = req.Amount / 10
|
||||
err = h.walletSvc.DeductFromWallet(c.Context(), branch.WalletID, domain.ToCurrency(deductedAmount))
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("CreateBetReq failed, unable to deduct from WalletID")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
bet, err = h.betSvc.CreateBet(c.Context(), domain.CreateBet{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
TotalOdds: totalOdds,
|
||||
Status: req.Status,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
|
||||
BranchID: domain.ValidInt64{
|
||||
Value: branch.ID,
|
||||
Valid: true,
|
||||
},
|
||||
UserID: domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: false,
|
||||
},
|
||||
IsShopBet: true,
|
||||
CashoutID: cashoutID,
|
||||
})
|
||||
} else if role == domain.RoleSuperAdmin || role == domain.RoleAdmin || role == domain.RoleBranchManager {
|
||||
// If a non cashier wants to create a bet, they will need to provide the Branch ID
|
||||
// TODO: restrict the Branch ID of Admin and Branch Manager to only the branches within their own company
|
||||
if req.BranchID == nil {
|
||||
h.logger.Error("CreateBetReq failed, Branch ID is required for this type of user")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID is required for this type of user", nil, nil)
|
||||
}
|
||||
// h.logger.Info("Branch ID", slog.Int64("branch_id", *req.BranchID))
|
||||
bet, err = h.betSvc.CreateBet(c.Context(), domain.CreateBet{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
TotalOdds: totalOdds,
|
||||
Status: req.Status,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
BranchID: domain.ValidInt64{
|
||||
Value: *req.BranchID,
|
||||
Valid: true,
|
||||
},
|
||||
UserID: domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
},
|
||||
IsShopBet: true,
|
||||
CashoutID: cashoutID,
|
||||
})
|
||||
} else {
|
||||
// TODO if user is customer, get id from the token then get the wallet id from there and reduce the amount
|
||||
bet, err = h.betSvc.CreateBet(c.Context(), domain.CreateBet{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
TotalOdds: totalOdds,
|
||||
Status: req.Status,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
|
||||
BranchID: domain.ValidInt64{
|
||||
Value: 0,
|
||||
Valid: false,
|
||||
},
|
||||
UserID: domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
},
|
||||
IsShopBet: false,
|
||||
CashoutID: cashoutID,
|
||||
})
|
||||
}
|
||||
res, err := h.betSvc.PlaceBet(c.Context(), req, userID, role)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("CreateBetReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||
h.logger.Error("PlaceBet failed", "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Unable to create bet")
|
||||
}
|
||||
|
||||
// Updating the bet id for outcomes
|
||||
for index := range outcomes {
|
||||
outcomes[index].BetID = bet.ID
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
|
||||
|
||||
}
|
||||
|
||||
// RandomBet godoc
|
||||
// @Summary Generate a random bet
|
||||
// @Description Generate a random bet
|
||||
// @Tags bet
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param createBet body domain.RandomBetReq true "Create Random bet"
|
||||
// @Success 200 {object} BetRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /random/bet [post]
|
||||
func (h *Handler) RandomBet(c *fiber.Ctx) error {
|
||||
|
||||
// Get user_id from middleware
|
||||
userID := c.Locals("user_id").(int64)
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
|
||||
var req domain.RandomBetReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("Failed to parse RandomBet request", "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
rows, err := h.betSvc.CreateBetOutcome(c.Context(), outcomes)
|
||||
valErrs, ok := h.validator.Validate(c, req)
|
||||
if !ok {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
res, err := h.betSvc.PlaceRandomBet(c.Context(), userID, req.BranchID)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("CreateBetReq failed to create outcomes", "error", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": "Internal server error",
|
||||
})
|
||||
h.logger.Error("Random Bet failed", "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Unable to create random bet")
|
||||
}
|
||||
|
||||
res := convertCreateBet(bet, rows)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
|
||||
|
||||
}
|
||||
|
|
@ -327,9 +103,9 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
|||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets")
|
||||
}
|
||||
|
||||
res := make([]BetRes, len(bets))
|
||||
res := make([]domain.BetRes, len(bets))
|
||||
for i, bet := range bets {
|
||||
res[i] = convertBet(bet)
|
||||
res[i] = domain.ConvertBet(bet)
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "All bets retrieved successfully", res, nil)
|
||||
|
|
@ -360,7 +136,7 @@ func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
|||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bet")
|
||||
}
|
||||
|
||||
res := convertBet(bet)
|
||||
res := domain.ConvertBet(bet)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil)
|
||||
|
||||
|
|
@ -392,7 +168,7 @@ func (h *Handler) GetBetByCashoutID(c *fiber.Ctx) error {
|
|||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bet", err, nil)
|
||||
}
|
||||
|
||||
res := convertBet(bet)
|
||||
res := domain.ConvertBet(bet)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil)
|
||||
|
||||
|
|
|
|||
|
|
@ -517,9 +517,9 @@ func (h *Handler) GetBetByBranchID(c *fiber.Ctx) error {
|
|||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bets", err, nil)
|
||||
}
|
||||
|
||||
var res []BetRes = make([]BetRes, 0, len(bets))
|
||||
var res []domain.BetRes = make([]domain.BetRes, 0, len(bets))
|
||||
for _, bet := range bets {
|
||||
res = append(res, convertBet(bet))
|
||||
res = append(res, domain.ConvertBet(bet))
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Branch Bets Retrieved", res, nil)
|
||||
|
|
|
|||
|
|
@ -149,7 +149,9 @@ func (a *App) initAppRoutes() {
|
|||
a.fiber.Get("/bet/cashout/:id", a.authMiddleware, h.GetBetByCashoutID)
|
||||
a.fiber.Patch("/bet/:id", a.authMiddleware, h.UpdateCashOut)
|
||||
a.fiber.Delete("/bet/:id", a.authMiddleware, h.DeleteBet)
|
||||
|
||||
|
||||
a.fiber.Post("/random/bet", a.authMiddleware, h.RandomBet)
|
||||
|
||||
// Wallet
|
||||
a.fiber.Get("/wallet", h.GetAllWallets)
|
||||
a.fiber.Get("/wallet/:id", h.GetWalletByID)
|
||||
|
|
@ -176,6 +178,7 @@ func (a *App) initAppRoutes() {
|
|||
// Virtual Game Routes
|
||||
a.fiber.Post("/virtual-game/launch", a.authMiddleware, h.LaunchVirtualGame)
|
||||
a.fiber.Post("/virtual-game/callback", h.HandleVirtualGameCallback)
|
||||
|
||||
}
|
||||
|
||||
///user/profile get
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user