mongoLogger to bet service
This commit is contained in:
parent
6dbce0725d
commit
788e3ee9a6
|
|
@ -10,10 +10,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
// "github.com/gofiber/fiber/v2"
|
// "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||||
customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger"
|
customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"
|
||||||
|
|
||||||
// mongologger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"
|
// mongologger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"
|
||||||
|
|
||||||
|
|
@ -80,7 +83,8 @@ func main() {
|
||||||
|
|
||||||
logger := customlogger.NewLogger(cfg.Env, cfg.LogLevel)
|
logger := customlogger.NewLogger(cfg.Env, cfg.LogLevel)
|
||||||
|
|
||||||
// mongologger.Init()
|
mongoLogger.Init()
|
||||||
|
mongoDBLogger := zap.L()
|
||||||
|
|
||||||
// client := mongoLogger.InitDB()
|
// client := mongoLogger.InitDB()
|
||||||
// defer func() {
|
// defer func() {
|
||||||
|
|
@ -139,7 +143,7 @@ func main() {
|
||||||
branchSvc := branch.NewService(store)
|
branchSvc := branch.NewService(store)
|
||||||
companySvc := company.NewService(store)
|
companySvc := company.NewService(store)
|
||||||
leagueSvc := league.New(store)
|
leagueSvc := league.New(store)
|
||||||
betSvc := bet.NewService(store, eventSvc, oddsSvc, *walletSvc, *branchSvc, logger)
|
betSvc := bet.NewService(store, eventSvc, oddsSvc, *walletSvc, *branchSvc, logger, mongoDBLogger)
|
||||||
resultSvc := result.NewService(store, cfg, logger, *betSvc)
|
resultSvc := result.NewService(store, cfg, logger, *betSvc)
|
||||||
referalRepo := repository.NewReferralRepository(store)
|
referalRepo := repository.NewReferralRepository(store)
|
||||||
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,6 @@ func Init() {
|
||||||
|
|
||||||
defer logger.Sync()
|
defer logger.Sync()
|
||||||
|
|
||||||
logger.Info("Application started", zap.String("module", "main"))
|
// logger.Info("Application started", zap.String("module", "main"))
|
||||||
logger.Error("Something went wrong", zap.String("error_code", "E123"))
|
// logger.Error("Something went wrong", zap.String("error_code", "E123"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,13 @@ import (
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger *slog.Logger
|
var (
|
||||||
|
logger *slog.Logger
|
||||||
|
mongoLogger *zap.Logger
|
||||||
|
)
|
||||||
|
|
||||||
func convertDBBet(bet dbgen.Bet) domain.Bet {
|
func convertDBBet(bet dbgen.Bet) domain.Bet {
|
||||||
return domain.Bet{
|
return domain.Bet{
|
||||||
|
|
@ -151,9 +155,14 @@ func (s *Store) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBe
|
||||||
for _, outcome := range outcomes {
|
for _, outcome := range outcomes {
|
||||||
dbParams = append(dbParams, convertDBCreateBetOutcome(outcome))
|
dbParams = append(dbParams, convertDBCreateBetOutcome(outcome))
|
||||||
}
|
}
|
||||||
rows, err := s.queries.CreateBetOutcome(ctx, dbParams)
|
|
||||||
|
|
||||||
|
rows, err := s.queries.CreateBetOutcome(ctx, dbParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to create bet outcomes in DB",
|
||||||
|
zap.Int("outcome_count", len(outcomes)),
|
||||||
|
zap.Any("bet_id", outcomes[0].BetID), // assumes all outcomes have same BetID
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return rows, err
|
return rows, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,8 +171,11 @@ func (s *Store) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBe
|
||||||
|
|
||||||
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
|
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
|
||||||
bet, err := s.queries.GetBetByID(ctx, id)
|
bet, err := s.queries.GetBetByID(ctx, id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to get bet by ID",
|
||||||
|
zap.Int64("bet_id", id),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.GetBet{}, err
|
return domain.GetBet{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,8 +184,11 @@ func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error)
|
||||||
|
|
||||||
func (s *Store) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) {
|
func (s *Store) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) {
|
||||||
bet, err := s.queries.GetBetByCashoutID(ctx, id)
|
bet, err := s.queries.GetBetByCashoutID(ctx, id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to get bet by cashout ID",
|
||||||
|
zap.String("cashout_id", id),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.GetBet{}, err
|
return domain.GetBet{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,6 +211,10 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to get all bets",
|
||||||
|
zap.Any("filter", filter),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,8 +231,11 @@ func (s *Store) GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.
|
||||||
Int64: BranchID,
|
Int64: BranchID,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to get bets by branch ID",
|
||||||
|
zap.Int64("branch_id", BranchID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,6 +270,13 @@ func (s *Store) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) err
|
||||||
ID: id,
|
ID: id,
|
||||||
CashedOut: cashedOut,
|
CashedOut: cashedOut,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to update cashout",
|
||||||
|
zap.Int64("id", id),
|
||||||
|
zap.Bool("cashed_out", cashedOut),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,16 +285,27 @@ func (s *Store) UpdateStatus(ctx context.Context, id int64, status domain.Outcom
|
||||||
ID: id,
|
ID: id,
|
||||||
Status: int32(status),
|
Status: int32(status),
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to update status",
|
||||||
|
zap.Int64("id", id),
|
||||||
|
zap.Int32("status", int32(status)),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]domain.BetOutcome, error) {
|
func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]domain.BetOutcome, error) {
|
||||||
outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, eventID)
|
outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
mongoLogger.Error("failed to get bet outcomes by event ID",
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
|
|
||||||
|
|
||||||
|
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
|
||||||
for _, outcome := range outcomes {
|
for _, outcome := range outcomes {
|
||||||
result = append(result, convertDBBetOutcomes(outcome))
|
result = append(result, convertDBBetOutcomes(outcome))
|
||||||
}
|
}
|
||||||
|
|
@ -275,22 +315,36 @@ func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]do
|
||||||
func (s *Store) GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error) {
|
func (s *Store) GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error) {
|
||||||
outcomes, err := s.queries.GetBetOutcomeByBetID(ctx, betID)
|
outcomes, err := s.queries.GetBetOutcomeByBetID(ctx, betID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
mongoLogger.Error("failed to get bet outcomes by bet ID",
|
||||||
|
zap.Int64("bet_id", betID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
|
|
||||||
|
|
||||||
|
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
|
||||||
for _, outcome := range outcomes {
|
for _, outcome := range outcomes {
|
||||||
result = append(result, convertDBBetOutcomes(outcome))
|
result = append(result, convertDBBetOutcomes(outcome))
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) {
|
func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) {
|
||||||
update, err := s.queries.UpdateBetOutcomeStatus(ctx, dbgen.UpdateBetOutcomeStatusParams{
|
update, err := s.queries.UpdateBetOutcomeStatus(ctx, dbgen.UpdateBetOutcomeStatusParams{
|
||||||
Status: int32(status),
|
Status: int32(status),
|
||||||
ID: id,
|
ID: id,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to update bet outcome status",
|
||||||
|
zap.Int64("id", id),
|
||||||
|
zap.Int32("status", int32(status)),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return domain.BetOutcome{}, err
|
||||||
|
}
|
||||||
|
|
||||||
res := convertDBBetOutcomes(update)
|
res := convertDBBetOutcomes(update)
|
||||||
return res, err
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
||||||
|
|
@ -374,9 +428,24 @@ func (s *Store) GetBetSummary(ctx context.Context, filter domain.ReportFilter) (
|
||||||
row := s.conn.QueryRow(ctx, query, args...)
|
row := s.conn.QueryRow(ctx, query, args...)
|
||||||
err = row.Scan(&totalStakes, &totalBets, &activeBets, &totalWins, &totalLosses, &winBalance)
|
err = row.Scan(&totalStakes, &totalBets, &activeBets, &totalWins, &totalLosses, &winBalance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to get bet summary",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return 0, 0, 0, 0, 0, 0, fmt.Errorf("failed to get bet summary: %w", err)
|
return 0, 0, 0, 0, 0, 0, fmt.Errorf("failed to get bet summary: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetBetSummary executed successfully",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Float64("totalStakes", float64(totalStakes)), // convert if needed
|
||||||
|
zap.Int64("totalBets", totalBets),
|
||||||
|
zap.Int64("activeBets", activeBets),
|
||||||
|
zap.Int64("totalWins", totalWins),
|
||||||
|
zap.Int64("totalLosses", totalLosses),
|
||||||
|
zap.Float64("winBalance", float64(winBalance)), // convert if needed
|
||||||
|
)
|
||||||
return totalStakes, totalBets, activeBets, totalWins, totalLosses, winBalance, nil
|
return totalStakes, totalBets, activeBets, totalWins, totalLosses, winBalance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,6 +519,11 @@ func (s *Store) GetBetStats(ctx context.Context, filter domain.ReportFilter) ([]
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query bet stats",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query bet stats: %w", err)
|
return nil, fmt.Errorf("failed to query bet stats: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -465,15 +539,26 @@ func (s *Store) GetBetStats(ctx context.Context, filter domain.ReportFilter) ([]
|
||||||
&stat.TotalPayouts,
|
&stat.TotalPayouts,
|
||||||
&stat.AverageOdds,
|
&stat.AverageOdds,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan bet stat",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to scan bet stat: %w", err)
|
return nil, fmt.Errorf("failed to scan bet stat: %w", err)
|
||||||
}
|
}
|
||||||
stats = append(stats, stat)
|
stats = append(stats, stat)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetBetStats executed successfully",
|
||||||
|
zap.Int("result_count", len(stats)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -530,6 +615,11 @@ func (s *Store) GetSportPopularity(ctx context.Context, filter domain.ReportFilt
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query sport popularity",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query sport popularity: %w", err)
|
return nil, fmt.Errorf("failed to query sport popularity: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -539,15 +629,26 @@ func (s *Store) GetSportPopularity(ctx context.Context, filter domain.ReportFilt
|
||||||
var date time.Time
|
var date time.Time
|
||||||
var sportID string
|
var sportID string
|
||||||
if err := rows.Scan(&date, &sportID); err != nil {
|
if err := rows.Scan(&date, &sportID); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan sport popularity",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to scan sport popularity: %w", err)
|
return nil, fmt.Errorf("failed to scan sport popularity: %w", err)
|
||||||
}
|
}
|
||||||
popularity[date] = sportID
|
popularity[date] = sportID
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetSportPopularity executed successfully",
|
||||||
|
zap.Int("result_count", len(popularity)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return popularity, nil
|
return popularity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -604,6 +705,11 @@ func (s *Store) GetMarketPopularity(ctx context.Context, filter domain.ReportFil
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query market popularity",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query market popularity: %w", err)
|
return nil, fmt.Errorf("failed to query market popularity: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -613,15 +719,26 @@ func (s *Store) GetMarketPopularity(ctx context.Context, filter domain.ReportFil
|
||||||
var date time.Time
|
var date time.Time
|
||||||
var marketName string
|
var marketName string
|
||||||
if err := rows.Scan(&date, &marketName); err != nil {
|
if err := rows.Scan(&date, &marketName); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan market popularity",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to scan market popularity: %w", err)
|
return nil, fmt.Errorf("failed to scan market popularity: %w", err)
|
||||||
}
|
}
|
||||||
popularity[date] = marketName
|
popularity[date] = marketName
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetMarketPopularity executed successfully",
|
||||||
|
zap.Int("result_count", len(popularity)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return popularity, nil
|
return popularity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -692,6 +809,11 @@ func (s *Store) GetExtremeValues(ctx context.Context, filter domain.ReportFilter
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query extreme values",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query extreme values: %w", err)
|
return nil, fmt.Errorf("failed to query extreme values: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -701,15 +823,26 @@ func (s *Store) GetExtremeValues(ctx context.Context, filter domain.ReportFilter
|
||||||
var date time.Time
|
var date time.Time
|
||||||
var extreme domain.ExtremeValues
|
var extreme domain.ExtremeValues
|
||||||
if err := rows.Scan(&date, &extreme.HighestStake, &extreme.HighestPayout); err != nil {
|
if err := rows.Scan(&date, &extreme.HighestStake, &extreme.HighestPayout); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan extreme values",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to scan extreme values: %w", err)
|
return nil, fmt.Errorf("failed to scan extreme values: %w", err)
|
||||||
}
|
}
|
||||||
extremes[date] = extreme
|
extremes[date] = extreme
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetExtremeValues executed successfully",
|
||||||
|
zap.Int("result_count", len(extremes)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return extremes, nil
|
return extremes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -766,6 +899,11 @@ func (s *Store) GetCustomerBetActivity(ctx context.Context, filter domain.Report
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query customer bet activity",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query customer bet activity: %w", err)
|
return nil, fmt.Errorf("failed to query customer bet activity: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -783,15 +921,26 @@ func (s *Store) GetCustomerBetActivity(ctx context.Context, filter domain.Report
|
||||||
&activity.LastBetDate,
|
&activity.LastBetDate,
|
||||||
&activity.AverageOdds,
|
&activity.AverageOdds,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan customer bet activity",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to scan customer bet activity: %w", err)
|
return nil, fmt.Errorf("failed to scan customer bet activity: %w", err)
|
||||||
}
|
}
|
||||||
activities = append(activities, activity)
|
activities = append(activities, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetCustomerBetActivity executed successfully",
|
||||||
|
zap.Int("result_count", len(activities)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return activities, nil
|
return activities, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,6 +989,11 @@ func (s *Store) GetBranchBetActivity(ctx context.Context, filter domain.ReportFi
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query branch bet activity",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query branch bet activity: %w", err)
|
return nil, fmt.Errorf("failed to query branch bet activity: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -854,15 +1008,22 @@ func (s *Store) GetBranchBetActivity(ctx context.Context, filter domain.ReportFi
|
||||||
&activity.TotalWins,
|
&activity.TotalWins,
|
||||||
&activity.TotalPayouts,
|
&activity.TotalPayouts,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan branch bet activity", zap.Error(err))
|
||||||
return nil, fmt.Errorf("failed to scan branch bet activity: %w", err)
|
return nil, fmt.Errorf("failed to scan branch bet activity: %w", err)
|
||||||
}
|
}
|
||||||
activities = append(activities, activity)
|
activities = append(activities, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration", zap.Error(err))
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetBranchBetActivity executed successfully",
|
||||||
|
zap.Int("result_count", len(activities)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return activities, nil
|
return activities, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -882,7 +1043,6 @@ func (s *Store) GetSportBetActivity(ctx context.Context, filter domain.ReportFil
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
argPos := 1
|
argPos := 1
|
||||||
|
|
||||||
// Add filters if provided
|
|
||||||
if filter.CompanyID.Valid {
|
if filter.CompanyID.Valid {
|
||||||
query += fmt.Sprintf(" AND b.company_id = $%d", argPos)
|
query += fmt.Sprintf(" AND b.company_id = $%d", argPos)
|
||||||
args = append(args, filter.CompanyID.Value)
|
args = append(args, filter.CompanyID.Value)
|
||||||
|
|
@ -918,6 +1078,11 @@ func (s *Store) GetSportBetActivity(ctx context.Context, filter domain.ReportFil
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query sport bet activity",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query sport bet activity: %w", err)
|
return nil, fmt.Errorf("failed to query sport bet activity: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -933,15 +1098,22 @@ func (s *Store) GetSportBetActivity(ctx context.Context, filter domain.ReportFil
|
||||||
&activity.TotalPayouts,
|
&activity.TotalPayouts,
|
||||||
&activity.AverageOdds,
|
&activity.AverageOdds,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan sport bet activity", zap.Error(err))
|
||||||
return nil, fmt.Errorf("failed to scan sport bet activity: %w", err)
|
return nil, fmt.Errorf("failed to scan sport bet activity: %w", err)
|
||||||
}
|
}
|
||||||
activities = append(activities, activity)
|
activities = append(activities, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration", zap.Error(err))
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetSportBetActivity executed successfully",
|
||||||
|
zap.Int("result_count", len(activities)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
return activities, nil
|
return activities, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -950,12 +1122,27 @@ func (s *Store) GetSportDetails(ctx context.Context, filter domain.ReportFilter)
|
||||||
query := `SELECT DISTINCT bo.sport_id, e.match_name
|
query := `SELECT DISTINCT bo.sport_id, e.match_name
|
||||||
FROM bet_outcomes bo
|
FROM bet_outcomes bo
|
||||||
JOIN events e ON bo.event_id = e.id::bigint
|
JOIN events e ON bo.event_id = e.id::bigint
|
||||||
|
JOIN bets b ON b.id = bo.bet_id
|
||||||
WHERE bo.sport_id IS NOT NULL`
|
WHERE bo.sport_id IS NOT NULL`
|
||||||
|
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
argPos := 1
|
argPos := 1
|
||||||
|
|
||||||
// Add filters if provided
|
if filter.CompanyID.Valid {
|
||||||
|
query += fmt.Sprintf(" AND b.company_id = $%d", argPos)
|
||||||
|
args = append(args, filter.CompanyID.Value)
|
||||||
|
argPos++
|
||||||
|
}
|
||||||
|
if filter.BranchID.Valid {
|
||||||
|
query += fmt.Sprintf(" AND b.branch_id = $%d", argPos)
|
||||||
|
args = append(args, filter.BranchID.Value)
|
||||||
|
argPos++
|
||||||
|
}
|
||||||
|
if filter.UserID.Valid {
|
||||||
|
query += fmt.Sprintf(" AND b.user_id = $%d", argPos)
|
||||||
|
args = append(args, filter.UserID.Value)
|
||||||
|
argPos++
|
||||||
|
}
|
||||||
if filter.StartTime.Valid {
|
if filter.StartTime.Valid {
|
||||||
query += fmt.Sprintf(" AND bo.created_at >= $%d", argPos)
|
query += fmt.Sprintf(" AND bo.created_at >= $%d", argPos)
|
||||||
args = append(args, filter.StartTime.Value)
|
args = append(args, filter.StartTime.Value)
|
||||||
|
|
@ -969,6 +1156,11 @@ func (s *Store) GetSportDetails(ctx context.Context, filter domain.ReportFilter)
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query sport details",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query sport details: %w", err)
|
return nil, fmt.Errorf("failed to query sport details: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -977,15 +1169,23 @@ func (s *Store) GetSportDetails(ctx context.Context, filter domain.ReportFilter)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var sportID, matchName string
|
var sportID, matchName string
|
||||||
if err := rows.Scan(&sportID, &matchName); err != nil {
|
if err := rows.Scan(&sportID, &matchName); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan sport detail", zap.Error(err))
|
||||||
return nil, fmt.Errorf("failed to scan sport detail: %w", err)
|
return nil, fmt.Errorf("failed to scan sport detail: %w", err)
|
||||||
}
|
}
|
||||||
details[sportID] = matchName
|
details[sportID] = matchName
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration", zap.Error(err))
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetSportDetails executed successfully",
|
||||||
|
zap.Int("result_count", len(details)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
|
|
||||||
return details, nil
|
return details, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -995,7 +1195,7 @@ func (s *Store) GetSportMarketPopularity(ctx context.Context, filter domain.Repo
|
||||||
SELECT
|
SELECT
|
||||||
bo.sport_id,
|
bo.sport_id,
|
||||||
bo.market_name,
|
bo.market_name,
|
||||||
COUNT(*) as bet_count,
|
COUNT(*) AS bet_count,
|
||||||
ROW_NUMBER() OVER (PARTITION BY bo.sport_id ORDER BY COUNT(*) DESC) as rank
|
ROW_NUMBER() OVER (PARTITION BY bo.sport_id ORDER BY COUNT(*) DESC) as rank
|
||||||
FROM bets b
|
FROM bets b
|
||||||
JOIN bet_outcomes bo ON b.id = bo.bet_id
|
JOIN bet_outcomes bo ON b.id = bo.bet_id
|
||||||
|
|
@ -1004,7 +1204,6 @@ func (s *Store) GetSportMarketPopularity(ctx context.Context, filter domain.Repo
|
||||||
args := []interface{}{}
|
args := []interface{}{}
|
||||||
argPos := 1
|
argPos := 1
|
||||||
|
|
||||||
// Add filters if provided
|
|
||||||
if filter.CompanyID.Valid {
|
if filter.CompanyID.Valid {
|
||||||
query += fmt.Sprintf(" AND b.company_id = $%d", argPos)
|
query += fmt.Sprintf(" AND b.company_id = $%d", argPos)
|
||||||
args = append(args, filter.CompanyID.Value)
|
args = append(args, filter.CompanyID.Value)
|
||||||
|
|
@ -1042,6 +1241,11 @@ func (s *Store) GetSportMarketPopularity(ctx context.Context, filter domain.Repo
|
||||||
|
|
||||||
rows, err := s.conn.Query(ctx, query, args...)
|
rows, err := s.conn.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mongoLogger.Error("failed to query sport market popularity",
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return nil, fmt.Errorf("failed to query sport market popularity: %w", err)
|
return nil, fmt.Errorf("failed to query sport market popularity: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
@ -1050,14 +1254,22 @@ func (s *Store) GetSportMarketPopularity(ctx context.Context, filter domain.Repo
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var sportID, marketName string
|
var sportID, marketName string
|
||||||
if err := rows.Scan(&sportID, &marketName); err != nil {
|
if err := rows.Scan(&sportID, &marketName); err != nil {
|
||||||
|
mongoLogger.Error("failed to scan sport market popularity", zap.Error(err))
|
||||||
return nil, fmt.Errorf("failed to scan sport market popularity: %w", err)
|
return nil, fmt.Errorf("failed to scan sport market popularity: %w", err)
|
||||||
}
|
}
|
||||||
popularity[sportID] = marketName
|
popularity[sportID] = marketName
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
|
mongoLogger.Error("rows error after iteration", zap.Error(err))
|
||||||
return nil, fmt.Errorf("rows error: %w", err)
|
return nil, fmt.Errorf("rows error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mongoLogger.Info("GetSportMarketPopularity executed successfully",
|
||||||
|
zap.Int("result_count", len(popularity)),
|
||||||
|
zap.String("query", query),
|
||||||
|
zap.Any("args", args),
|
||||||
|
)
|
||||||
|
|
||||||
return popularity, nil
|
return popularity, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -33,9 +34,10 @@ type Service struct {
|
||||||
walletSvc wallet.Service
|
walletSvc wallet.Service
|
||||||
branchSvc branch.Service
|
branchSvc branch.Service
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
|
mongoLogger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(betStore BetStore, eventSvc event.Service, prematchSvc odds.Service, walletSvc wallet.Service, branchSvc branch.Service, logger *slog.Logger) *Service {
|
func NewService(betStore BetStore, eventSvc event.Service, prematchSvc odds.Service, walletSvc wallet.Service, branchSvc branch.Service, logger *slog.Logger, mongoLogger *zap.Logger) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
betStore: betStore,
|
betStore: betStore,
|
||||||
eventSvc: eventSvc,
|
eventSvc: eventSvc,
|
||||||
|
|
@ -43,6 +45,7 @@ func NewService(betStore BetStore, eventSvc event.Service, prematchSvc odds.Serv
|
||||||
walletSvc: walletSvc,
|
walletSvc: walletSvc,
|
||||||
branchSvc: branchSvc,
|
branchSvc: branchSvc,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
mongoLogger: mongoLogger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,37 +61,56 @@ func (s *Service) GenerateCashoutID() (string, error) {
|
||||||
const length int = 13
|
const length int = 13
|
||||||
charLen := big.NewInt(int64(len(chars)))
|
charLen := big.NewInt(int64(len(chars)))
|
||||||
result := make([]byte, length)
|
result := make([]byte, length)
|
||||||
|
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
index, err := rand.Int(rand.Reader, charLen)
|
index, err := rand.Int(rand.Reader, charLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to generate random index for cashout ID",
|
||||||
|
zap.Int("position", i),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
result[i] = chars[index.Int64()]
|
result[i] = chars[index.Int64()]
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(result), nil
|
return string(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketID int64, oddID int64) (domain.CreateBetOutcome, 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)
|
eventIDStr := strconv.FormatInt(eventID, 10)
|
||||||
marketIDStr := strconv.FormatInt(marketID, 10)
|
marketIDStr := strconv.FormatInt(marketID, 10)
|
||||||
oddIDStr := strconv.FormatInt(oddID, 10)
|
oddIDStr := strconv.FormatInt(oddID, 10)
|
||||||
|
|
||||||
event, err := s.eventSvc.GetUpcomingEventByID(ctx, eventIDStr)
|
event, err := s.eventSvc.GetUpcomingEventByID(ctx, eventIDStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to fetch upcoming event by ID",
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetOutcome{}, ErrEventHasBeenRemoved
|
return domain.CreateBetOutcome{}, ErrEventHasBeenRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
if event.StartTime.Before(currentTime) {
|
if event.StartTime.Before(currentTime) {
|
||||||
|
s.mongoLogger.Error("event has already started",
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
zap.Time("event_start_time", event.StartTime),
|
||||||
|
zap.Time("current_time", currentTime),
|
||||||
|
)
|
||||||
return domain.CreateBetOutcome{}, ErrEventHasNotEnded
|
return domain.CreateBetOutcome{}, ErrEventHasNotEnded
|
||||||
}
|
}
|
||||||
|
|
||||||
odds, err := s.prematchSvc.GetRawOddsByMarketID(ctx, marketIDStr, eventIDStr)
|
odds, err := s.prematchSvc.GetRawOddsByMarketID(ctx, marketIDStr, eventIDStr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get raw odds by market ID",
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
zap.Int64("market_id", marketID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetOutcome{}, err
|
return domain.CreateBetOutcome{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type rawOddType struct {
|
type rawOddType struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
|
|
@ -98,29 +120,51 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedOdd rawOddType
|
var selectedOdd rawOddType
|
||||||
var isOddFound bool = false
|
var isOddFound bool
|
||||||
|
|
||||||
for _, raw := range odds.RawOdds {
|
for _, raw := range odds.RawOdds {
|
||||||
var rawOdd rawOddType
|
var rawOdd rawOddType
|
||||||
rawBytes, err := json.Marshal(raw)
|
rawBytes, err := json.Marshal(raw)
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to marshal raw odd",
|
||||||
|
zap.Any("raw", raw),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
err = json.Unmarshal(rawBytes, &rawOdd)
|
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to unmarshal raw odd %v", err)
|
s.mongoLogger.Error("failed to unmarshal raw odd",
|
||||||
|
zap.ByteString("raw_bytes", rawBytes),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if rawOdd.ID == oddIDStr {
|
if rawOdd.ID == oddIDStr {
|
||||||
selectedOdd = rawOdd
|
selectedOdd = rawOdd
|
||||||
isOddFound = true
|
isOddFound = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !isOddFound {
|
if !isOddFound {
|
||||||
|
s.mongoLogger.Error("odd ID not found in raw odds",
|
||||||
|
zap.Int64("odd_id", oddID),
|
||||||
|
zap.Int64("market_id", marketID),
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
)
|
||||||
return domain.CreateBetOutcome{}, ErrRawOddInvalid
|
return domain.CreateBetOutcome{}, ErrRawOddInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to parse selected odd value",
|
||||||
|
zap.String("odd", selectedOdd.Odds),
|
||||||
|
zap.Int64("odd_id", oddID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetOutcome{}, err
|
return domain.CreateBetOutcome{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newOutcome := domain.CreateBetOutcome{
|
newOutcome := domain.CreateBetOutcome{
|
||||||
EventID: eventID,
|
EventID: eventID,
|
||||||
OddID: oddID,
|
OddID: oddID,
|
||||||
|
|
@ -137,13 +181,14 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
|
||||||
}
|
}
|
||||||
|
|
||||||
return newOutcome, nil
|
return newOutcome, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID int64, role domain.Role) (domain.CreateBetRes, error) {
|
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 {
|
if len(req.Outcomes) > 30 {
|
||||||
|
s.mongoLogger.Error("too many outcomes",
|
||||||
|
zap.Int("count", len(req.Outcomes)),
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, ErrOutcomeLimit
|
return domain.CreateBetRes{}, ErrOutcomeLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,17 +198,25 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
||||||
for _, outcomeReq := range req.Outcomes {
|
for _, outcomeReq := range req.Outcomes {
|
||||||
newOutcome, err := s.GenerateBetOutcome(ctx, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID)
|
newOutcome, err := s.GenerateBetOutcome(ctx, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to generate outcome",
|
||||||
|
zap.Int64("event_id", outcomeReq.EventID),
|
||||||
|
zap.Int64("market_id", outcomeReq.MarketID),
|
||||||
|
zap.Int64("odd_id", outcomeReq.OddID),
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
totalOdds = totalOdds * float32(newOutcome.Odd)
|
totalOdds *= float32(newOutcome.Odd)
|
||||||
outcomes = append(outcomes, newOutcome)
|
outcomes = append(outcomes, newOutcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle role-specific logic and wallet deduction if needed.
|
|
||||||
var cashoutID string
|
|
||||||
cashoutID, err := s.GenerateCashoutID()
|
cashoutID, err := s.GenerateCashoutID()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to generate cashout ID",
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,106 +228,117 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
||||||
PhoneNumber: req.PhoneNumber,
|
PhoneNumber: req.PhoneNumber,
|
||||||
CashoutID: cashoutID,
|
CashoutID: cashoutID,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch role {
|
switch role {
|
||||||
case domain.RoleCashier:
|
case domain.RoleCashier:
|
||||||
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get branch by cashier",
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
// Deduct from wallet:
|
|
||||||
// TODO: Make this percentage come from the company
|
deductedAmount := req.Amount / 10
|
||||||
var deductedAmount = req.Amount / 10
|
|
||||||
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to deduct from wallet",
|
||||||
|
zap.Int64("wallet_id", branch.WalletID),
|
||||||
|
zap.Float32("amount", deductedAmount),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
newBet.BranchID = domain.ValidInt64{
|
|
||||||
Value: branch.ID,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
newBet.CompanyID = domain.ValidInt64{
|
newBet.BranchID = domain.ValidInt64{Value: branch.ID, Valid: true}
|
||||||
Value: branch.CompanyID,
|
newBet.CompanyID = domain.ValidInt64{Value: branch.CompanyID, Valid: true}
|
||||||
Valid: true,
|
newBet.UserID = domain.ValidInt64{Value: userID, Valid: true}
|
||||||
}
|
|
||||||
newBet.UserID = domain.ValidInt64{
|
|
||||||
Value: userID,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
newBet.IsShopBet = true
|
newBet.IsShopBet = true
|
||||||
// bet, err = s.betStore.CreateBet(ctx)
|
|
||||||
case domain.RoleBranchManager, domain.RoleAdmin, domain.RoleSuperAdmin:
|
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 {
|
if req.BranchID == nil {
|
||||||
|
s.mongoLogger.Error("branch ID required for admin/manager",
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, ErrBranchIDRequired
|
return domain.CreateBetRes{}, ErrBranchIDRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
branch, err := s.branchSvc.GetBranchByID(ctx, *req.BranchID)
|
branch, err := s.branchSvc.GetBranchByID(ctx, *req.BranchID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get branch by ID",
|
||||||
|
zap.Int64("branch_id", *req.BranchID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
// Deduct from wallet:
|
|
||||||
// TODO: Make this percentage come from the company
|
deductedAmount := req.Amount / 10
|
||||||
var deductedAmount = req.Amount / 10
|
|
||||||
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("wallet deduction failed",
|
||||||
|
zap.Int64("wallet_id", branch.WalletID),
|
||||||
|
zap.Float32("amount", deductedAmount),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newBet.BranchID = domain.ValidInt64{
|
newBet.BranchID = domain.ValidInt64{Value: branch.ID, Valid: true}
|
||||||
Value: branch.ID,
|
newBet.CompanyID = domain.ValidInt64{Value: branch.CompanyID, Valid: true}
|
||||||
Valid: true,
|
newBet.UserID = domain.ValidInt64{Value: userID, Valid: true}
|
||||||
}
|
|
||||||
newBet.CompanyID = domain.ValidInt64{
|
|
||||||
Value: branch.CompanyID,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
newBet.UserID = domain.ValidInt64{
|
|
||||||
Value: userID,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
newBet.IsShopBet = true
|
newBet.IsShopBet = true
|
||||||
|
|
||||||
case domain.RoleCustomer:
|
case domain.RoleCustomer:
|
||||||
// Get User Wallet
|
wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID)
|
||||||
|
|
||||||
wallet, err := s.walletSvc.GetWalletsByUser(ctx, userID)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get customer wallets",
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userWallet := wallet[0]
|
userWallet := wallets[0]
|
||||||
|
|
||||||
err = s.walletSvc.DeductFromWallet(ctx, userWallet.ID, domain.ToCurrency(req.Amount))
|
err = s.walletSvc.DeductFromWallet(ctx, userWallet.ID, domain.ToCurrency(req.Amount))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("wallet deduction failed for customer",
|
||||||
|
zap.Int64("wallet_id", userWallet.ID),
|
||||||
|
zap.Float32("amount", req.Amount),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newBet.UserID = domain.ValidInt64{
|
newBet.UserID = domain.ValidInt64{Value: userID, Valid: true}
|
||||||
Value: userID,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
newBet.IsShopBet = false
|
newBet.IsShopBet = false
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
s.mongoLogger.Error("unknown role type",
|
||||||
|
zap.String("role", string(role)),
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, fmt.Errorf("Unknown Role Type")
|
return domain.CreateBetRes{}, fmt.Errorf("Unknown Role Type")
|
||||||
}
|
}
|
||||||
|
|
||||||
bet, err := s.CreateBet(ctx, newBet)
|
bet, err := s.CreateBet(ctx, newBet)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to create bet",
|
||||||
|
zap.Int64("user_id", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Associate outcomes with the bet.
|
|
||||||
for i := range outcomes {
|
for i := range outcomes {
|
||||||
outcomes[i].BetID = bet.ID
|
outcomes[i].BetID = bet.ID
|
||||||
}
|
}
|
||||||
rows, err := s.betStore.CreateBetOutcome(ctx, outcomes)
|
rows, err := s.betStore.CreateBetOutcome(ctx, outcomes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to create bet outcomes",
|
||||||
|
zap.Int64("bet_id", bet.ID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,14 +353,24 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
|
||||||
var totalOdds float32 = 1
|
var totalOdds float32 = 1
|
||||||
|
|
||||||
markets, err := s.prematchSvc.GetPrematchOddsByUpcomingID(ctx, eventID)
|
markets, err := s.prematchSvc.GetPrematchOddsByUpcomingID(ctx, eventID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to get odds for event", "event id", eventID, "error", err)
|
s.logger.Error("failed to get odds for event", "event id", eventID, "error", err)
|
||||||
|
s.mongoLogger.Error("failed to get odds for event",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.Int32("sportID", sportID),
|
||||||
|
zap.String("homeTeam", HomeTeam),
|
||||||
|
zap.String("awayTeam", AwayTeam),
|
||||||
|
zap.Error(err))
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(markets) == 0 {
|
if len(markets) == 0 {
|
||||||
s.logger.Error("empty odds for event", "event id", eventID)
|
s.logger.Error("empty odds for event", "event id", eventID)
|
||||||
|
s.mongoLogger.Warn("empty odds for event",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.Int32("sportID", sportID),
|
||||||
|
zap.String("homeTeam", HomeTeam),
|
||||||
|
zap.String("awayTeam", AwayTeam))
|
||||||
return nil, 0, fmt.Errorf("empty odds or event %v", eventID)
|
return nil, 0, fmt.Errorf("empty odds or event %v", eventID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,35 +399,55 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
|
||||||
err = json.Unmarshal(rawBytes, &selectedOdd)
|
err = json.Unmarshal(rawBytes, &selectedOdd)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to unmarshal raw odd %v", err)
|
s.logger.Error("Failed to unmarshal raw odd", "error", err)
|
||||||
|
s.mongoLogger.Warn("Failed to unmarshal raw odd",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.Int32("sportID", sportID),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse odd", "error", err)
|
s.logger.Error("Failed to parse odd", "error", err)
|
||||||
|
s.mongoLogger.Warn("Failed to parse odd",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.String("oddValue", selectedOdd.Odds),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
eventID, err := strconv.ParseInt(eventID, 10, 64)
|
|
||||||
|
eventIDInt, err := strconv.ParseInt(eventID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get event id", "error", err)
|
s.logger.Error("Failed to parse eventID", "error", err)
|
||||||
|
s.mongoLogger.Warn("Failed to parse eventID",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
oddID, err := strconv.ParseInt(selectedOdd.ID, 10, 64)
|
oddID, err := strconv.ParseInt(selectedOdd.ID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get odd id", "error", err)
|
s.logger.Error("Failed to parse oddID", "error", err)
|
||||||
|
s.mongoLogger.Warn("Failed to parse oddID",
|
||||||
|
zap.String("oddID", selectedOdd.ID),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
marketID, err := strconv.ParseInt(market.MarketID, 10, 64)
|
marketID, err := strconv.ParseInt(market.MarketID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get odd id", "error", err)
|
s.logger.Error("Failed to parse marketID", "error", err)
|
||||||
|
s.mongoLogger.Warn("Failed to parse marketID",
|
||||||
|
zap.String("marketID", market.MarketID),
|
||||||
|
zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
marketName := market.MarketName
|
marketName := market.MarketName
|
||||||
|
|
||||||
newOdds = append(newOdds, domain.CreateBetOutcome{
|
newOdds = append(newOdds, domain.CreateBetOutcome{
|
||||||
EventID: eventID,
|
EventID: eventIDInt,
|
||||||
OddID: oddID,
|
OddID: oddID,
|
||||||
MarketID: marketID,
|
MarketID: marketID,
|
||||||
SportID: int64(sportID),
|
SportID: int64(sportID),
|
||||||
|
|
@ -367,15 +461,27 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
|
||||||
Expires: StartTime,
|
Expires: StartTime,
|
||||||
})
|
})
|
||||||
|
|
||||||
totalOdds = totalOdds * float32(parsedOdd)
|
totalOdds *= float32(parsedOdd)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(newOdds) == 0 {
|
if len(newOdds) == 0 {
|
||||||
s.logger.Error("Bet Outcomes is empty for market", "selectedMarket", selectedMarkets[0].MarketName)
|
s.logger.Error("Bet Outcomes is empty for market", "selectedMarkets", len(selectedMarkets))
|
||||||
|
s.mongoLogger.Error("Bet Outcomes is empty for market",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.Int32("sportID", sportID),
|
||||||
|
zap.String("homeTeam", HomeTeam),
|
||||||
|
zap.String("awayTeam", AwayTeam),
|
||||||
|
zap.Int("selectedMarkets", len(selectedMarkets)))
|
||||||
return nil, 0, ErrGenerateRandomOutcome
|
return nil, 0, ErrGenerateRandomOutcome
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ Final success log (optional)
|
||||||
|
s.mongoLogger.Info("Random bet outcomes generated successfully",
|
||||||
|
zap.String("eventID", eventID),
|
||||||
|
zap.Int32("sportID", sportID),
|
||||||
|
zap.Int("numOutcomes", len(newOdds)),
|
||||||
|
zap.Float32("totalOdds", totalOdds))
|
||||||
|
|
||||||
return newOdds, totalOdds, nil
|
return newOdds, totalOdds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,10 +493,17 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
domain.ValidInt64{}, domain.ValidInt64{}, leagueID, sportID, firstStartTime, lastStartTime)
|
domain.ValidInt64{}, domain.ValidInt64{}, leagueID, sportID, firstStartTime, lastStartTime)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get paginated upcoming events",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID),
|
||||||
|
zap.Error(err))
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(events) == 0 {
|
if len(events) == 0 {
|
||||||
|
s.mongoLogger.Warn("no events available for random bet",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID))
|
||||||
return domain.CreateBetRes{}, ErrNoEventsAvailable
|
return domain.CreateBetRes{}, ErrNoEventsAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,6 +530,11 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("failed to generate random bet outcome", "event id", event.ID, "error", err)
|
s.logger.Error("failed to generate random bet outcome", "event id", event.ID, "error", err)
|
||||||
|
s.mongoLogger.Error("failed to generate random bet outcome",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID),
|
||||||
|
zap.String("eventID", event.ID),
|
||||||
|
zap.String("error", fmt.Sprintf("%v", err)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -426,6 +544,9 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
}
|
}
|
||||||
if len(randomOdds) == 0 {
|
if len(randomOdds) == 0 {
|
||||||
s.logger.Error("Failed to generate random any outcomes for all events")
|
s.logger.Error("Failed to generate random any outcomes for all events")
|
||||||
|
s.mongoLogger.Error("Failed to generate random any outcomes for all events",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID))
|
||||||
return domain.CreateBetRes{}, ErrGenerateRandomOutcome
|
return domain.CreateBetRes{}, ErrGenerateRandomOutcome
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,6 +556,9 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
|
|
||||||
cashoutID, err = s.GenerateCashoutID()
|
cashoutID, err = s.GenerateCashoutID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("Failed to generate cash out ID",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID))
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -452,6 +576,10 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
|
|
||||||
bet, err := s.CreateBet(ctx, newBet)
|
bet, err := s.CreateBet(ctx, newBet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("Failed to create a new random bet",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID),
|
||||||
|
zap.String("bet", fmt.Sprintf("%+v", newBet)))
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,11 +589,19 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
|
|
||||||
rows, err := s.betStore.CreateBetOutcome(ctx, randomOdds)
|
rows, err := s.betStore.CreateBetOutcome(ctx, randomOdds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("Failed to create a new random bet outcome",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID),
|
||||||
|
zap.String("randomOdds", fmt.Sprintf("%+v", randomOdds)))
|
||||||
return domain.CreateBetRes{}, err
|
return domain.CreateBetRes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := domain.ConvertCreateBet(bet, rows)
|
res := domain.ConvertCreateBet(bet, rows)
|
||||||
|
|
||||||
|
s.mongoLogger.Info("Random bets placed successfully",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int64("branchID", branchID),
|
||||||
|
zap.String("response", fmt.Sprintf("%+v", res)))
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,10 +636,12 @@ func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
|
||||||
bet, err := s.GetBetByID(ctx, id)
|
bet, err := s.GetBetByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update bet status. Invalid bet id")
|
s.mongoLogger.Error("failed to update bet status: invalid bet ID",
|
||||||
|
zap.Int64("bet_id", id),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -516,22 +654,30 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
|
||||||
|
|
||||||
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, id)
|
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update bet status. Invalid customer wallet id")
|
s.mongoLogger.Error("failed to get customer wallet",
|
||||||
|
zap.Int64("bet_id", id),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var amount domain.Currency
|
var amount domain.Currency
|
||||||
if status == domain.OUTCOME_STATUS_WIN {
|
switch status {
|
||||||
|
case domain.OUTCOME_STATUS_WIN:
|
||||||
amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds)
|
amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds)
|
||||||
} else if status == domain.OUTCOME_STATUS_HALF {
|
case domain.OUTCOME_STATUS_HALF:
|
||||||
amount = (domain.CalculateWinnings(bet.Amount, bet.TotalOdds)) / 2
|
amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds) / 2
|
||||||
} else {
|
default:
|
||||||
amount = bet.Amount
|
amount = bet.Amount
|
||||||
}
|
}
|
||||||
err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount)
|
|
||||||
|
|
||||||
|
err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update bet status. Failed to update user wallet")
|
s.mongoLogger.Error("failed to add winnings to wallet",
|
||||||
|
zap.Int64("wallet_id", customerWallet.RegularID),
|
||||||
|
zap.Float32("amount", float32(amount)),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,92 +687,89 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
|
||||||
func (s *Service) CheckBetOutcomeForBet(ctx context.Context, betID int64) (domain.OutcomeStatus, error) {
|
func (s *Service) CheckBetOutcomeForBet(ctx context.Context, betID int64) (domain.OutcomeStatus, error) {
|
||||||
betOutcomes, err := s.betStore.GetBetOutcomeByBetID(ctx, betID)
|
betOutcomes, err := s.betStore.GetBetOutcomeByBetID(ctx, betID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get bet outcomes",
|
||||||
|
zap.Int64("bet_id", betID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.OUTCOME_STATUS_PENDING, err
|
return domain.OUTCOME_STATUS_PENDING, err
|
||||||
}
|
}
|
||||||
|
|
||||||
status := domain.OUTCOME_STATUS_PENDING
|
status := domain.OUTCOME_STATUS_PENDING
|
||||||
|
|
||||||
for _, betOutcome := range betOutcomes {
|
for _, betOutcome := range betOutcomes {
|
||||||
// If any of the bet outcomes are pending return
|
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_PENDING {
|
if betOutcome.Status == domain.OUTCOME_STATUS_PENDING {
|
||||||
|
s.mongoLogger.Info("outcome still pending",
|
||||||
|
zap.Int64("bet_id", betID),
|
||||||
|
)
|
||||||
return domain.OUTCOME_STATUS_PENDING, ErrOutcomesNotCompleted
|
return domain.OUTCOME_STATUS_PENDING, ErrOutcomesNotCompleted
|
||||||
}
|
}
|
||||||
|
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_ERROR {
|
if betOutcome.Status == domain.OUTCOME_STATUS_ERROR {
|
||||||
|
s.mongoLogger.Info("outcome contains error",
|
||||||
|
zap.Int64("bet_id", betID),
|
||||||
|
)
|
||||||
return domain.OUTCOME_STATUS_ERROR, nil
|
return domain.OUTCOME_STATUS_ERROR, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The bet status can only be updated if its not lost or error
|
|
||||||
// If all the bet outcomes are a win, then set the bet status to win
|
|
||||||
// If even one of the bet outcomes is a loss then set the bet status to loss
|
|
||||||
// If even one of the bet outcomes is an error, then set the bet status to error
|
|
||||||
switch status {
|
switch status {
|
||||||
case domain.OUTCOME_STATUS_PENDING:
|
case domain.OUTCOME_STATUS_PENDING:
|
||||||
status = betOutcome.Status
|
status = betOutcome.Status
|
||||||
case domain.OUTCOME_STATUS_WIN:
|
case domain.OUTCOME_STATUS_WIN:
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
switch betOutcome.Status {
|
||||||
|
case domain.OUTCOME_STATUS_LOSS:
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
case domain.OUTCOME_STATUS_HALF:
|
||||||
status = domain.OUTCOME_STATUS_HALF
|
status = domain.OUTCOME_STATUS_HALF
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
case domain.OUTCOME_STATUS_VOID:
|
||||||
status = domain.OUTCOME_STATUS_WIN
|
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
|
||||||
status = domain.OUTCOME_STATUS_VOID
|
status = domain.OUTCOME_STATUS_VOID
|
||||||
} else {
|
case domain.OUTCOME_STATUS_WIN:
|
||||||
|
// remain win
|
||||||
|
default:
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
status = domain.OUTCOME_STATUS_ERROR
|
||||||
}
|
}
|
||||||
case domain.OUTCOME_STATUS_LOSS:
|
case domain.OUTCOME_STATUS_LOSS:
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
// stay as LOSS regardless of others
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
|
||||||
} else {
|
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
|
||||||
}
|
|
||||||
case domain.OUTCOME_STATUS_VOID:
|
case domain.OUTCOME_STATUS_VOID:
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_VOID ||
|
switch betOutcome.Status {
|
||||||
betOutcome.Status == domain.OUTCOME_STATUS_WIN ||
|
case domain.OUTCOME_STATUS_LOSS:
|
||||||
betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
|
||||||
status = domain.OUTCOME_STATUS_VOID
|
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
|
case domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_HALF, domain.OUTCOME_STATUS_VOID:
|
||||||
} else {
|
// remain VOID
|
||||||
|
default:
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
status = domain.OUTCOME_STATUS_ERROR
|
||||||
}
|
}
|
||||||
case domain.OUTCOME_STATUS_HALF:
|
case domain.OUTCOME_STATUS_HALF:
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_HALF ||
|
switch betOutcome.Status {
|
||||||
betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
case domain.OUTCOME_STATUS_LOSS:
|
||||||
status = domain.OUTCOME_STATUS_HALF
|
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
case domain.OUTCOME_STATUS_VOID:
|
||||||
status = domain.OUTCOME_STATUS_VOID
|
status = domain.OUTCOME_STATUS_VOID
|
||||||
} else {
|
case domain.OUTCOME_STATUS_HALF, domain.OUTCOME_STATUS_WIN:
|
||||||
|
// remain HALF
|
||||||
|
default:
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
status = domain.OUTCOME_STATUS_ERROR
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// If the status is not pending, win, loss or error, then set the status to error
|
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
status = domain.OUTCOME_STATUS_ERROR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if status == domain.OUTCOME_STATUS_PENDING || status == domain.OUTCOME_STATUS_ERROR {
|
if status == domain.OUTCOME_STATUS_PENDING || status == domain.OUTCOME_STATUS_ERROR {
|
||||||
// If the status is pending or error, then we don't need to update the bet
|
s.mongoLogger.Info("bet status not updated due to status",
|
||||||
s.logger.Info("bet not updated", "bet id", betID, "status", status)
|
zap.Int64("bet_id", betID),
|
||||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("Error when processing bet outcomes")
|
zap.String("final_status", string(status)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) {
|
func (s *Service) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) {
|
||||||
betOutcome, err := s.betStore.UpdateBetOutcomeStatus(ctx, id, status)
|
betOutcome, err := s.betStore.UpdateBetOutcomeStatus(ctx, id, status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to update bet outcome status",
|
||||||
|
zap.Int64("betID", id),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return domain.BetOutcome{}, err
|
return domain.BetOutcome{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package mongoLogger
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -52,7 +52,14 @@ func (h *Handler) GetDashboardReport(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).JSON(summary)
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
|
Message: "Dashboard reports generated successfully",
|
||||||
|
Success: true,
|
||||||
|
StatusCode: 200,
|
||||||
|
Data: summary,
|
||||||
|
})
|
||||||
|
|
||||||
|
// return c.Status(fiber.StatusOK).JSON(summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseReportFilter parses query parameters into ReportFilter
|
// parseReportFilter parses query parameters into ReportFilter
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
_ "github.com/SamuelTariku/FortuneBet-Backend/docs"
|
_ "github.com/SamuelTariku/FortuneBet-Backend/docs"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"
|
// "github.com/SamuelTariku/FortuneBet-Backend/internal/logger/mongoLogger"
|
||||||
|
|
||||||
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet/monitor"
|
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet/monitor"
|
||||||
|
|
||||||
|
|
@ -230,7 +230,7 @@ func (a *App) initAppRoutes() {
|
||||||
|
|
||||||
//mongoDB logs
|
//mongoDB logs
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
group.Get("/logs", mongoLogger.GetLogsHandler(ctx))
|
group.Get("/logs", handlers.GetLogsHandler(ctx))
|
||||||
|
|
||||||
// Recommendation Routes
|
// Recommendation Routes
|
||||||
group.Get("/virtual-games/recommendations/:userID", h.GetRecommendations)
|
group.Get("/virtual-games/recommendations/:userID", h.GetRecommendations)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user