optimizations for cashback
This commit is contained in:
parent
b84027ea04
commit
96ea2c8af4
|
|
@ -99,6 +99,11 @@ SELECT *
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
WHERE fast_code = $1
|
WHERE fast_code = $1
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
-- name: GetBetsForCashback :many
|
||||||
|
SELECT *
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE status = 2
|
||||||
|
AND processed = false;
|
||||||
-- name: GetBetOutcomeByEventID :many
|
-- name: GetBetOutcomeByEventID :many
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM bet_outcomes
|
FROM bet_outcomes
|
||||||
|
|
|
||||||
|
|
@ -512,6 +512,52 @@ func (q *Queries) GetBetOutcomeByEventID(ctx context.Context, arg GetBetOutcomeB
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetBetsForCashback = `-- name: GetBetsForCashback :many
|
||||||
|
SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes_hash, fast_code, processed, outcomes
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE status = 2
|
||||||
|
AND processed = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBetsForCashback(ctx context.Context) ([]BetWithOutcome, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetBetsForCashback)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BetWithOutcome
|
||||||
|
for rows.Next() {
|
||||||
|
var i BetWithOutcome
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Amount,
|
||||||
|
&i.TotalOdds,
|
||||||
|
&i.Status,
|
||||||
|
&i.FullName,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.BranchID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.CashedOut,
|
||||||
|
&i.CashoutID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.IsShopBet,
|
||||||
|
&i.OutcomesHash,
|
||||||
|
&i.FastCode,
|
||||||
|
&i.Processed,
|
||||||
|
&i.Outcomes,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :one
|
const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :one
|
||||||
UPDATE bet_outcomes
|
UPDATE bet_outcomes
|
||||||
SET status = $1
|
SET status = $1
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,22 @@ func (s *Store) GetBetByFastCode(ctx context.Context, fastcode string) (domain.G
|
||||||
return convertDBBetWithOutcomes(bet), nil
|
return convertDBBetWithOutcomes(bet), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBetsForCashback(ctx context.Context) ([]domain.GetBet, error) {
|
||||||
|
bets, err := s.queries.GetBetsForCashback(ctx)
|
||||||
|
var res []domain.GetBet
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, bet := range bets {
|
||||||
|
cashbackBet := convertDBBetWithOutcomes(bet)
|
||||||
|
res = append(res, cashbackBet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) GetBetCount(ctx context.Context, UserID int64, outcomesHash string) (int64, error) {
|
func (s *Store) GetBetCount(ctx context.Context, UserID int64, outcomesHash string) (int64, error) {
|
||||||
count, err := s.queries.GetBetCount(ctx, dbgen.GetBetCountParams{
|
count, err := s.queries.GetBetCount(ctx, dbgen.GetBetCountParams{
|
||||||
UserID: pgtype.Int8{Int64: UserID, Valid: true},
|
UserID: pgtype.Int8{Int64: UserID, Valid: true},
|
||||||
|
|
|
||||||
|
|
@ -45,5 +45,6 @@ type BetStore interface {
|
||||||
GetSportDetails(ctx context.Context, filter domain.ReportFilter) (map[string]string, error)
|
GetSportDetails(ctx context.Context, filter domain.ReportFilter) (map[string]string, error)
|
||||||
GetSportMarketPopularity(ctx context.Context, filter domain.ReportFilter) (map[string]string, error)
|
GetSportMarketPopularity(ctx context.Context, filter domain.ReportFilter) (map[string]string, error)
|
||||||
|
|
||||||
|
GetBetsForCashback(ctx context.Context) ([]domain.GetBet, error)
|
||||||
UpdateBetWithCashback(ctx context.Context, betID int64, cashbackStatus bool) error
|
UpdateBetWithCashback(ctx context.Context, betID int64, cashbackStatus bool) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
random "math/rand"
|
random "math/rand"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -908,9 +909,7 @@ func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ProcessBetCashback(ctx context.Context) error {
|
func (s *Service) ProcessBetCashback(ctx context.Context) error {
|
||||||
// TODO: get filterd data from db instead of filtering it here
|
bets, err := s.betStore.GetBetsForCashback(ctx)
|
||||||
// get all bets (status not pending) (processed not true)
|
|
||||||
bets, err := s.GetAllBets(ctx, domain.BetFilter{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to fetch bets",
|
s.mongoLogger.Error("failed to fetch bets",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
|
|
@ -919,35 +918,26 @@ func (s *Service) ProcessBetCashback(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bet := range bets {
|
for _, bet := range bets {
|
||||||
if bet.Status == domain.OUTCOME_STATUS_PENDING {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
loseCount := 0
|
|
||||||
outcomes, err := s.GetBetOutcomeByBetID(ctx, bet.ID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Info("failed to fetch outcomes for a best",
|
|
||||||
zap.Int64("betID", bet.ID),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// bet meets criteria
|
|
||||||
shouldProcess := true
|
shouldProcess := true
|
||||||
for _, outcome := range outcomes {
|
loseCount := 0
|
||||||
|
|
||||||
|
for _, outcome := range bet.Outcomes {
|
||||||
|
// stop if other outcomes exists in bet outcomes
|
||||||
|
if outcome.Status != domain.OUTCOME_STATUS_LOSS && outcome.Status != domain.OUTCOME_STATUS_WIN {
|
||||||
|
shouldProcess = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if outcome.Status == domain.OUTCOME_STATUS_LOSS {
|
if outcome.Status == domain.OUTCOME_STATUS_LOSS {
|
||||||
loseCount++
|
loseCount++
|
||||||
// only process caseback if bet is lost by one
|
// only process caseback if bet is lost by one
|
||||||
if loseCount > 1 {
|
if loseCount > 1 {
|
||||||
shouldProcess = false
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if loseCount != 1 || !shouldProcess {
|
if !shouldProcess || loseCount != 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -968,8 +958,10 @@ func (s *Service) ProcessBetCashback(ctx context.Context) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cashbackAmount := calculateCashbackAmount(bet.Amount.Float32(), bet.TotalOdds)
|
// TODO: get cashback amount cap (currently 1000) from settings in the db
|
||||||
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, domain.ToCurrency(cashbackAmount), domain.ValidInt64{}, domain.TRANSFER_DIRECT,
|
cashbackAmount := math.Min(10, float64(calculateCashbackAmount(bet.Amount.Float32(), bet.TotalOdds)))
|
||||||
|
|
||||||
|
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, domain.ToCurrency(float32(cashbackAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT,
|
||||||
domain.PaymentDetails{}, fmt.Sprintf("cashback amount of %f added to users static wallet", cashbackAmount))
|
domain.PaymentDetails{}, fmt.Sprintf("cashback amount of %f added to users static wallet", cashbackAmount))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user