Merge: resolved conflicts
This commit is contained in:
commit
354989e6e1
10
cmd/main.go
10
cmd/main.go
|
|
@ -110,8 +110,8 @@ func main() {
|
|||
|
||||
authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
|
||||
userSvc := user.NewService(store, store, messengerSvc, cfg)
|
||||
eventSvc := event.New(cfg.Bet365Token, store)
|
||||
oddsSvc := odds.New(store, cfg, logger)
|
||||
eventSvc := event.New(cfg.Bet365Token, store, domain.MongoDBLogger)
|
||||
oddsSvc := odds.New(store, cfg, logger, domain.MongoDBLogger)
|
||||
notificationRepo := repository.NewNotificationRepository(store)
|
||||
virtuaGamesRepo := repository.NewVirtualGameRepository(store)
|
||||
notificationSvc := notificationservice.New(notificationRepo, domain.MongoDBLogger, logger, cfg, messengerSvc, userSvc)
|
||||
|
|
@ -141,7 +141,7 @@ func main() {
|
|||
leagueSvc := league.New(store)
|
||||
ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger, *settingSvc, notificationSvc)
|
||||
betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, *companySvc, *settingSvc, *userSvc, notificationSvc, logger, domain.MongoDBLogger)
|
||||
resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc)
|
||||
resultSvc := result.NewService(store, cfg, logger, domain.MongoDBLogger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc, *userSvc)
|
||||
bonusSvc := bonus.NewService(store)
|
||||
referalRepo := repository.NewReferralRepository(store)
|
||||
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
||||
|
|
@ -221,8 +221,8 @@ func main() {
|
|||
defer exchangeWorker.Stop()
|
||||
go walletMonitorSvc.Start()
|
||||
|
||||
httpserver.StartDataFetchingCrons(eventSvc, *oddsSvc, resultSvc)
|
||||
httpserver.StartTicketCrons(*ticketSvc)
|
||||
httpserver.StartDataFetchingCrons(eventSvc, *oddsSvc, resultSvc, domain.MongoDBLogger)
|
||||
httpserver.StartTicketCrons(*ticketSvc, domain.MongoDBLogger)
|
||||
|
||||
issueReportingRepo := repository.NewReportedIssueRepository(store)
|
||||
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ INSERT INTO wallets (
|
|||
is_transferable,
|
||||
user_id,
|
||||
is_active,
|
||||
type
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
|
|
@ -231,6 +232,7 @@ VALUES (
|
|||
TRUE,
|
||||
2,
|
||||
TRUE,
|
||||
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
|
@ -242,6 +244,7 @@ INSERT INTO branches (
|
|||
branch_manager_id,
|
||||
company_id,
|
||||
is_self_owned,
|
||||
profit_percent,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
|
|
@ -253,6 +256,7 @@ values (
|
|||
2,
|
||||
1,
|
||||
TRUE,
|
||||
0.1,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,12 +5,20 @@ CREATE TABLE IF NOT EXISTS notifications (
|
|||
type IN (
|
||||
'cash_out_success',
|
||||
'deposit_success',
|
||||
'withdraw_success',
|
||||
'bet_placed',
|
||||
'daily_report',
|
||||
'high_loss_on_bet',
|
||||
'bet_overload',
|
||||
'signup_welcome',
|
||||
'otp_sent'
|
||||
'otp_sent',
|
||||
'wallet_threshold',
|
||||
'transfer_failed',
|
||||
'transfer_success',
|
||||
'admin_alert',
|
||||
'bet_result',
|
||||
'transfer_rejected',
|
||||
'approval_required'
|
||||
)
|
||||
),
|
||||
level TEXT NOT NULL CHECK (level IN ('info', 'error', 'warning', 'success')),
|
||||
|
|
@ -29,19 +37,13 @@ CREATE TABLE IF NOT EXISTS notifications (
|
|||
timestamp TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
metadata JSONB
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wallet_threshold_notifications (
|
||||
company_id BIGINT NOT NULL,
|
||||
threshold FLOAT NOT NULL,
|
||||
notified_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (company_id, threshold)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_wallet_threshold_notifications_company ON wallet_threshold_notifications(company_id);
|
||||
|
||||
CREATE INDEX idx_notifications_recipient_id ON notifications (recipient_id);
|
||||
|
||||
CREATE INDEX idx_notifications_timestamp ON notifications (timestamp);
|
||||
|
||||
CREATE INDEX idx_notifications_type ON notifications (type);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
-- Settings Initial Data
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('sms_provider', '30'),
|
||||
<<<<<<< HEAD
|
||||
('max_number_of_outcomes', '30'),
|
||||
('bet_amount_limit', '100000'),
|
||||
=======
|
||||
('max_number_of_outcomes', '30'),
|
||||
('bet_amount_limit', '10000000'),
|
||||
>>>>>>> 7d8d824a94381bd82c40398654c3bd78218c5950
|
||||
('daily_ticket_limit', '50'),
|
||||
('total_winnings_limit', '1000000'),
|
||||
('amount_for_bet_referral', '1000000'),
|
||||
('cashback_amount_cap', '1000') ON CONFLICT (key) DO
|
||||
UPDATE
|
||||
<<<<<<< HEAD
|
||||
SET value = EXCLUDED.value;
|
||||
=======
|
||||
SET value = EXCLUDED.value;
|
||||
>>>>>>> 7d8d824a94381bd82c40398654c3bd78218c5950
|
||||
|
|
|
|||
19
db/query/events_stat.sql
Normal file
19
db/query/events_stat.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
-- name: GetTotalMontlyEventStat :many
|
||||
SELECT DATE_TRUNC('month', start_time) AS month,
|
||||
COUNT(*) AS event_count
|
||||
FROM events
|
||||
JOIN leagues ON leagues.id = events.league_id
|
||||
WHERE (
|
||||
events.is_featured = sqlc.narg('is_event_featured')
|
||||
OR sqlc.narg('is_event_featured') IS NULL
|
||||
)
|
||||
AND (
|
||||
leagues.is_featured = sqlc.narg('is_league_featured')
|
||||
OR sqlc.narg('is_league_featured') IS NULL
|
||||
)
|
||||
AND (
|
||||
events.league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
GROUP BY month
|
||||
ORDER BY month;
|
||||
64
gen/db/events_stat.sql.go
Normal file
64
gen/db/events_stat.sql.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: events_stat.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const GetTotalMontlyEventStat = `-- name: GetTotalMontlyEventStat :many
|
||||
SELECT DATE_TRUNC('month', start_time) AS month,
|
||||
COUNT(*) AS event_count
|
||||
FROM events
|
||||
JOIN leagues ON leagues.id = events.league_id
|
||||
WHERE (
|
||||
events.is_featured = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
leagues.is_featured = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
events.league_id = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
GROUP BY month
|
||||
ORDER BY month
|
||||
`
|
||||
|
||||
type GetTotalMontlyEventStatParams struct {
|
||||
IsEventFeatured pgtype.Bool `json:"is_event_featured"`
|
||||
IsLeagueFeatured pgtype.Bool `json:"is_league_featured"`
|
||||
LeagueID pgtype.Int4 `json:"league_id"`
|
||||
}
|
||||
|
||||
type GetTotalMontlyEventStatRow struct {
|
||||
Month pgtype.Interval `json:"month"`
|
||||
EventCount int64 `json:"event_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTotalMontlyEventStat(ctx context.Context, arg GetTotalMontlyEventStatParams) ([]GetTotalMontlyEventStatRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetTotalMontlyEventStat, arg.IsEventFeatured, arg.IsLeagueFeatured, arg.LeagueID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetTotalMontlyEventStatRow
|
||||
for rows.Next() {
|
||||
var i GetTotalMontlyEventStatRow
|
||||
if err := rows.Scan(&i.Month, &i.EventCount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
|
@ -93,3 +95,73 @@ type Pagination struct {
|
|||
|
||||
func PtrFloat64(v float64) *float64 { return &v }
|
||||
func PtrInt64(v int64) *int64 { return &v }
|
||||
|
||||
type Int64JSON int64
|
||||
|
||||
// func (i *Int64JSON) Parse() (int64, error) {
|
||||
// var asString string
|
||||
// if err := json.Unmarshal(i, &asString); err == nil {
|
||||
// // Try to parse the string to int64
|
||||
// return strconv.ParseInt(strings.TrimSpace(asString), 10, 64)
|
||||
// }
|
||||
|
||||
// var asInt int64
|
||||
// if err := json.Unmarshal(i, &asInt); err == nil {
|
||||
// return asInt, nil
|
||||
// }
|
||||
|
||||
// // Neither string nor int worked
|
||||
// return 0, fmt.Errorf("invalid int64 value: %s", string(i))
|
||||
// }
|
||||
|
||||
func (i *Int64JSON) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err == nil {
|
||||
// it was a string, parse it
|
||||
v, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*i = Int64JSON(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
var v int64
|
||||
if err := json.Unmarshal(data, &v); err == nil {
|
||||
*i = Int64JSON(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid int64 value: %s", string(data))
|
||||
}
|
||||
|
||||
type NullableInt64JSON struct {
|
||||
Int64 int64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (n *NullableInt64JSON) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err == nil {
|
||||
if s == "" {
|
||||
n.Valid = false
|
||||
return nil
|
||||
}
|
||||
v, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.Int64, n.Valid = v, true
|
||||
return nil
|
||||
}
|
||||
|
||||
var v int64
|
||||
if err := json.Unmarshal(data, &v); err == nil {
|
||||
n.Int64, n.Valid = v, true
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid int64 value: %s", string(data))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,19 @@ type Notification struct {
|
|||
Timestamp time.Time `json:"timestamp"`
|
||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||
}
|
||||
type CreateNotification struct {
|
||||
RecipientID int64 `json:"recipient_id"`
|
||||
Type NotificationType `json:"type"`
|
||||
Level NotificationLevel `json:"level"`
|
||||
ErrorSeverity *NotificationErrorSeverity `json:"error_severity"`
|
||||
Reciever NotificationRecieverSide `json:"reciever"`
|
||||
IsRead bool `json:"is_read"`
|
||||
DeliveryStatus NotificationDeliveryStatus `json:"delivery_status,omitempty"`
|
||||
DeliveryChannel DeliveryChannel `json:"delivery_channel,omitempty"`
|
||||
Payload NotificationPayload `json:"payload"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func (n *Notification) ToJSON() ([]byte, error) {
|
||||
return json.Marshal(n)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ type RawOdd struct {
|
|||
|
||||
// The Market ID for the json data can be either string / int which is causing problems when UnMarshalling
|
||||
type OddsMarket struct {
|
||||
ID json.RawMessage `json:"id"`
|
||||
ID NullableInt64JSON `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Odds []json.RawMessage `json:"odds"`
|
||||
Header string `json:"header,omitempty"`
|
||||
|
|
|
|||
|
|
@ -82,3 +82,23 @@ const (
|
|||
TIME_STATUS_DECIDED_BY_FA TimeStatus = 11
|
||||
TIME_STATUS_REMOVED TimeStatus = 99
|
||||
)
|
||||
|
||||
type ResultStatusCounts struct {
|
||||
IsNotFinished int `json:"is_not_finished"`
|
||||
IsNotFinishedBets int `json:"is_not_finished_bets"`
|
||||
IsToBeFixed int `json:"is_to_be_fixed"`
|
||||
IsToBeFixedBets int `json:"is_to_be_fixed_bets"`
|
||||
IsPostponed int `json:"is_postponed"`
|
||||
IsPostponedBets int `json:"is_postponed_bets"`
|
||||
IsEnded int `json:"is_ended"`
|
||||
IsEndedBets int `json:"is_ended_bets"`
|
||||
IsRemoved int `json:"is_removed"`
|
||||
IsRemovedBets int `json:"is_removed_bets"`
|
||||
}
|
||||
type ResultStatusBets struct {
|
||||
IsNotFinished []int64 `json:"is_not_finished"`
|
||||
IsToBeFixed []int64 `json:"is_to_be_fixed"`
|
||||
IsPostponed []int64 `json:"is_postponed"`
|
||||
IsEnded []int64 `json:"is_ended"`
|
||||
IsRemoved []int64 `json:"is_removed"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ type LeagueRes struct {
|
|||
}
|
||||
|
||||
type Team struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID NullableInt64JSON `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
}
|
||||
|
||||
type Score struct {
|
||||
|
|
@ -28,14 +28,14 @@ type Score struct {
|
|||
}
|
||||
|
||||
type CommonResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League LeagueRes `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus NullableInt64JSON `json:"time_status"`
|
||||
League LeagueRes `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
}
|
||||
|
||||
type FootballResultResponse struct {
|
||||
|
|
|
|||
|
|
@ -32,3 +32,81 @@ const (
|
|||
MMA = 162
|
||||
SURFING = 148
|
||||
)
|
||||
|
||||
func (s Sport) String() string {
|
||||
switch s {
|
||||
case FOOTBALL:
|
||||
return "FOOTBALL"
|
||||
case BASKETBALL:
|
||||
return "BASKETBALL"
|
||||
case VOLLEYBALL:
|
||||
return "VOLLEYBALL"
|
||||
case HANDBALL:
|
||||
return "HANDBALL"
|
||||
case BASEBALL:
|
||||
return "BASEBALL"
|
||||
case HORSE_RACING:
|
||||
return "HORSE_RACING"
|
||||
case GREYHOUNDS:
|
||||
return "GREYHOUNDS"
|
||||
case ICE_HOCKEY:
|
||||
return "ICE_HOCKEY"
|
||||
case SNOOKER:
|
||||
return "SNOOKER"
|
||||
case AMERICAN_FOOTBALL:
|
||||
return "AMERICAN_FOOTBALL"
|
||||
case CRICKET:
|
||||
return "CRICKET"
|
||||
case FUTSAL:
|
||||
return "FUTSAL"
|
||||
case DARTS:
|
||||
return "DARTS"
|
||||
case TABLE_TENNIS:
|
||||
return "TABLE_TENNIS"
|
||||
case BADMINTON:
|
||||
return "BADMINTON"
|
||||
case RUGBY_UNION:
|
||||
return "RUGBY_UNION"
|
||||
case RUGBY_LEAGUE:
|
||||
return "RUGBY_LEAGUE"
|
||||
case AUSTRALIAN_RULES:
|
||||
return "AUSTRALIAN_RULES"
|
||||
case BOWLS:
|
||||
return "BOWLS"
|
||||
case BOXING:
|
||||
return "BOXING"
|
||||
case GAELIC_SPORTS:
|
||||
return "GAELIC_SPORTS"
|
||||
case FLOORBALL:
|
||||
return "FLOORBALL"
|
||||
case BEACH_VOLLEYBALL:
|
||||
return "BEACH_VOLLEYBALL"
|
||||
case WATER_POLO:
|
||||
return "WATER_POLO"
|
||||
case SQUASH:
|
||||
return "SQUASH"
|
||||
case E_SPORTS:
|
||||
return "E_SPORTS"
|
||||
case MMA:
|
||||
return "MMA"
|
||||
case SURFING:
|
||||
return "SURFING"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func IsValidSport(s Sport) bool {
|
||||
switch s {
|
||||
case
|
||||
FOOTBALL, BASKETBALL, VOLLEYBALL, HANDBALL, BASEBALL,
|
||||
HORSE_RACING, GREYHOUNDS, ICE_HOCKEY, SNOOKER, AMERICAN_FOOTBALL,
|
||||
CRICKET, FUTSAL, DARTS, TABLE_TENNIS, BADMINTON,
|
||||
RUGBY_UNION, RUGBY_LEAGUE, AUSTRALIAN_RULES, BOWLS, BOXING,
|
||||
GAELIC_SPORTS, FLOORBALL, BEACH_VOLLEYBALL, WATER_POLO,
|
||||
SQUASH, E_SPORTS, MMA, SURFING:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
|||
}, nil
|
||||
}
|
||||
func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
|
||||
fmt.Printf("\n\nuser_filter %v \n\n", filter)
|
||||
users, err := s.queries.GetAllUsers(ctx, dbgen.GetAllUsersParams{
|
||||
Role: filter.Role,
|
||||
CompanyID: pgtype.Int8{
|
||||
|
|
|
|||
|
|
@ -874,6 +874,10 @@ func (s *Service) GetBetOutcomeByBetID(ctx context.Context, UserID int64) ([]dom
|
|||
return s.betStore.GetBetOutcomeByBetID(ctx, UserID)
|
||||
}
|
||||
|
||||
func (s *Service) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) {
|
||||
return s.betStore.GetBetOutcomeByEventID(ctx, eventID, is_filtered)
|
||||
}
|
||||
|
||||
func (s *Service) GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error) {
|
||||
return s.betStore.GetBetByFastCode(ctx, fastcode)
|
||||
}
|
||||
|
|
@ -900,22 +904,19 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
|
|||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case bet.IsShopBet:
|
||||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
case status == domain.OUTCOME_STATUS_ERROR, status == domain.OUTCOME_STATUS_PENDING:
|
||||
s.SendErrorStatusNotification(ctx, status, bet.UserID, "")
|
||||
if status == domain.OUTCOME_STATUS_ERROR || status == domain.OUTCOME_STATUS_PENDING {
|
||||
s.SendAdminErrorAlertNotification(ctx, status, "")
|
||||
s.SendErrorStatusNotification(ctx, status, bet.UserID, "")
|
||||
s.mongoLogger.Error("Bet Status is error",
|
||||
zap.Int64("bet_id", id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
case status == domain.OUTCOME_STATUS_LOSS:
|
||||
s.SendLosingStatusNotification(ctx, status, bet.UserID, "")
|
||||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
}
|
||||
|
||||
if bet.IsShopBet {
|
||||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
}
|
||||
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, id)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error("failed to get customer wallet",
|
||||
|
|
@ -927,6 +928,9 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
|
|||
|
||||
var amount domain.Currency
|
||||
switch status {
|
||||
case domain.OUTCOME_STATUS_LOSS:
|
||||
s.SendLosingStatusNotification(ctx, status, bet.UserID, "")
|
||||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
case domain.OUTCOME_STATUS_WIN:
|
||||
amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds)
|
||||
s.SendWinningStatusNotification(ctx, status, bet.UserID, amount, "")
|
||||
|
|
@ -1120,7 +1124,19 @@ func (s *Service) SendAdminErrorAlertNotification(ctx context.Context, status do
|
|||
}`, status, extra),
|
||||
}
|
||||
|
||||
users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
||||
super_admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
||||
Role: string(domain.RoleSuperAdmin),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
s.mongoLogger.Error("failed to get super_admin recipients",
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
||||
Role: string(domain.RoleAdmin),
|
||||
})
|
||||
|
||||
|
|
@ -1132,6 +1148,8 @@ func (s *Service) SendAdminErrorAlertNotification(ctx context.Context, status do
|
|||
return err
|
||||
}
|
||||
|
||||
users := append(super_admin_users, admin_users...)
|
||||
|
||||
for _, user := range users {
|
||||
betNotification.RecipientID = user.ID
|
||||
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
|
||||
|
|
|
|||
|
|
@ -14,18 +14,21 @@ import (
|
|||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||
"go.uber.org/zap"
|
||||
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
token string
|
||||
store *repository.Store
|
||||
token string
|
||||
store *repository.Store
|
||||
mongoLogger *zap.Logger
|
||||
}
|
||||
|
||||
func New(token string, store *repository.Store) Service {
|
||||
func New(token string, store *repository.Store, mongoLogger *zap.Logger) Service {
|
||||
return &service{
|
||||
token: token,
|
||||
store: store,
|
||||
token: token,
|
||||
store: store,
|
||||
mongoLogger: mongoLogger,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +205,7 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, source string) {
|
||||
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_url, source string) {
|
||||
sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91}
|
||||
// sportIDs := []int{1}
|
||||
// TODO: Add the league skipping again when we have dynamic leagues
|
||||
|
|
@ -217,14 +220,24 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
var page int = 0
|
||||
var limit int = 200
|
||||
var count int = 0
|
||||
var skippedLeague []string
|
||||
var totalEvents = 0
|
||||
for page <= totalPages {
|
||||
page = page + 1
|
||||
url := fmt.Sprintf(url, sportID, s.token, page)
|
||||
url := fmt.Sprintf(source_url, sportID, s.token, page)
|
||||
log.Printf("📡 Fetching data from %s - sport %d (%d/%d), for event data page (%d/%d)",
|
||||
source, sportID, sportIndex+1, len(sportIDs), page, totalPages)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch event data for page %d: %v", page, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to fetch event data for page",
|
||||
zap.String("source", source),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
|
@ -233,21 +246,42 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
var data domain.BetResult
|
||||
|
||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||
log.Printf("❌ Failed to parse json data")
|
||||
s.mongoLogger.Error(
|
||||
"Failed to parse event json data",
|
||||
zap.String("source", source),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
var skippedLeague []string
|
||||
for _, ev := range data.Results {
|
||||
startUnix, _ := strconv.ParseInt(ev.Time, 10, 64)
|
||||
// eventID, err := strconv.ParseInt(ev.ID, 10, 64)
|
||||
// if err != nil {
|
||||
// log.Panicf("❌ Invalid event id, eventID %v", ev.ID)
|
||||
// continue
|
||||
// }
|
||||
|
||||
for _, ev := range data.Results {
|
||||
startUnix, err := strconv.ParseInt(ev.Time, 10, 64)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error(
|
||||
"Invalid time",
|
||||
zap.String("time", ev.Time),
|
||||
zap.String("source", source),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
leagueID, err := strconv.ParseInt(ev.League.ID, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("❌ Invalid league id, leagueID %v", ev.League.ID)
|
||||
s.mongoLogger.Error(
|
||||
"Invalid league id",
|
||||
zap.String("leagueID", ev.League.ID),
|
||||
zap.String("source", source),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -264,13 +298,26 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("❌ Error Saving League on %v", ev.League.Name)
|
||||
log.Printf("err:%v", err)
|
||||
s.mongoLogger.Error(
|
||||
"error while saving league",
|
||||
zap.String("leagueID", ev.League.ID),
|
||||
zap.String("leagueName", ev.League.Name),
|
||||
zap.String("source", source),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if supported, err := s.store.CheckLeagueSupport(ctx, leagueID); !supported || err != nil {
|
||||
log.Printf("Skipping league %v", ev.League.Name)
|
||||
s.mongoLogger.Warn(
|
||||
"Skipping league",
|
||||
zap.String("league", ev.League.Name),
|
||||
zap.Bool("is_supported", supported),
|
||||
zap.Error(err),
|
||||
)
|
||||
skippedLeague = append(skippedLeague, ev.League.Name)
|
||||
continue
|
||||
}
|
||||
|
|
@ -300,12 +347,23 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
|
||||
err = s.store.SaveUpcomingEvent(ctx, event)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to save upcoming event %s", event.ID)
|
||||
s.mongoLogger.Error(
|
||||
"failed to save upcoming event",
|
||||
zap.String("leagueID", ev.League.ID),
|
||||
zap.String("leagueName", ev.League.Name),
|
||||
zap.String("source", source),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
totalEvents += 1
|
||||
}
|
||||
|
||||
log.Printf("⚠️ Skipped leagues %v", len(skippedLeague))
|
||||
log.Printf("⚠️ Total pages %v", data.Pager.Total/data.Pager.PerPage)
|
||||
// log.Printf("⚠️ Skipped leagues %v", len(skippedLeague))
|
||||
// log.Printf("⚠️ Total pages %v", data.Pager.Total/data.Pager.PerPage)
|
||||
|
||||
totalPages = data.Pager.Total / data.Pager.PerPage
|
||||
|
||||
if count >= limit {
|
||||
|
|
@ -316,6 +374,17 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
|||
}
|
||||
count++
|
||||
}
|
||||
s.mongoLogger.Info(
|
||||
"Successfully fetched upcoming events",
|
||||
zap.String("source", source),
|
||||
zap.Int("totalEvents", totalEvents),
|
||||
zap.Int("sport_id", sportID),
|
||||
zap.String("sport_name", domain.Sport(sportID).String()),
|
||||
zap.Int("page", page),
|
||||
zap.Int("total_pages", totalPages),
|
||||
zap.Int("Skipped leagues", len(skippedLeague)),
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ func (s *Service) addConnection(recipientID int64, c *websocket.Conn) error {
|
|||
}
|
||||
|
||||
func (s *Service) SendNotification(ctx context.Context, notification *domain.Notification) error {
|
||||
|
||||
notification.ID = helpers.GenerateID()
|
||||
notification.Timestamp = time.Now()
|
||||
notification.DeliveryStatus = domain.DeliveryStatusPending
|
||||
|
|
@ -642,5 +643,3 @@ func (s *Service) GetLiveMetrics(ctx context.Context) (domain.LiveMetric, error)
|
|||
// // Broadcast over WebSocket
|
||||
// s.Hub.Broadcast <- event
|
||||
// }
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,21 +16,24 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type ServiceImpl struct {
|
||||
store *repository.Store
|
||||
config *config.Config
|
||||
logger *slog.Logger
|
||||
client *http.Client
|
||||
store *repository.Store
|
||||
config *config.Config
|
||||
logger *slog.Logger
|
||||
mongoLogger *zap.Logger
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func New(store *repository.Store, cfg *config.Config, logger *slog.Logger) *ServiceImpl {
|
||||
func New(store *repository.Store, cfg *config.Config, logger *slog.Logger, mongoLogger *zap.Logger) *ServiceImpl {
|
||||
return &ServiceImpl{
|
||||
store: store,
|
||||
config: cfg,
|
||||
logger: logger,
|
||||
client: &http.Client{Timeout: 10 * time.Second},
|
||||
store: store,
|
||||
config: cfg,
|
||||
logger: logger,
|
||||
mongoLogger: mongoLogger,
|
||||
client: &http.Client{Timeout: 10 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +78,10 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
|||
func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
|
||||
eventIDs, err := s.store.GetAllUpcomingEvents(ctx)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch upcoming event IDs: %v", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to fetch upcoming event IDs",
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -86,34 +92,59 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
|
|||
|
||||
oddsData, err := s.FetchNonLiveOddsByEventID(ctx, event.ID)
|
||||
if err != nil || oddsData.Success != 1 {
|
||||
s.logger.Error("Failed to fetch prematch odds", "eventID", event.ID, "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to fetch prematch odds",
|
||||
zap.String("eventID", event.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, fmt.Errorf("failed to fetch prematch odds for event %v: %w", event.ID, err))
|
||||
continue
|
||||
}
|
||||
|
||||
parsedOddSections, err := s.ParseOddSections(ctx, oddsData.Results[0], event.SportID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse odd section", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to parse odd section",
|
||||
zap.String("eventID", event.ID),
|
||||
zap.Int32("sportID", event.SportID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, fmt.Errorf("failed to parse odd section for event %v: %w", event.ID, err))
|
||||
continue
|
||||
}
|
||||
|
||||
if parsedOddSections.EventFI == "" {
|
||||
s.logger.Error("Skipping result with no valid Event FI field", "fi", parsedOddSections.EventFI)
|
||||
s.mongoLogger.Error(
|
||||
"Skipping result with no valid Event FI field",
|
||||
zap.String("FI", parsedOddSections.EventFI),
|
||||
zap.String("eventID", event.ID),
|
||||
zap.Int32("sportID", event.SportID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, errors.New("event FI is empty"))
|
||||
continue
|
||||
}
|
||||
|
||||
for oddCategory, section := range parsedOddSections.Sections {
|
||||
if err := s.storeSection(ctx, event.ID, parsedOddSections.EventFI, oddCategory, section); err != nil {
|
||||
s.logger.Error("Error storing odd section", "eventID", event.ID, "odd", oddCategory)
|
||||
log.Printf("⚠️ Error when storing %v", err)
|
||||
s.mongoLogger.Error(
|
||||
"Error storing odd section",
|
||||
zap.String("eventID", event.ID),
|
||||
zap.String("odd", oddCategory),
|
||||
zap.Int32("sportID", event.SportID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
for _, section := range parsedOddSections.OtherRes {
|
||||
if err := s.storeSection(ctx, event.ID, parsedOddSections.EventFI, "others", section); err != nil {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
s.mongoLogger.Error(
|
||||
"Error storing odd other section",
|
||||
zap.String("eventID", event.ID),
|
||||
zap.Int32("sportID", event.SportID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
|
@ -138,20 +169,32 @@ func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
|
|||
url := fmt.Sprintf("https://api.b365api.com/v1/bwin/prematch?sport_id=%d&token=%s", sportId, s.config.Bet365Token)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to create request for sportId %d: %v", sportId, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to create request for sportId",
|
||||
zap.Int("sportID", sportId),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch request for sportId %d: %v", sportId, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to fetch request for sportId",
|
||||
zap.Int("sportID", sportId),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to read response body for sportId %d: %v", sportId, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to read response body for sportId",
|
||||
zap.Int("sportID", sportId),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +205,11 @@ func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
|
|||
|
||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||
fmt.Printf("Decode failed for sport_id=%d\nRaw: %s\n", sportId, string(body))
|
||||
s.mongoLogger.Error(
|
||||
"Failed to decode BWin response body",
|
||||
zap.Int("sportID", sportId),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -188,6 +236,12 @@ func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
|
|||
|
||||
if err := s.store.SaveEvent(ctx, event); err != nil {
|
||||
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
|
||||
s.mongoLogger.Error(
|
||||
"Could not store live event",
|
||||
zap.Int("sportID", sportId),
|
||||
zap.String("eventID", event.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +276,11 @@ func (s *ServiceImpl) FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr
|
|||
eventID, err := strconv.ParseInt(eventIDStr, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse event id")
|
||||
s.mongoLogger.Error(
|
||||
"Failed to parse event id",
|
||||
zap.String("eventID", eventIDStr),
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.BaseNonLiveOddResponse{}, err
|
||||
}
|
||||
|
||||
|
|
@ -229,26 +288,42 @@ func (s *ServiceImpl) FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr
|
|||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to create request for event %d: %v", eventID, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to create request for event",
|
||||
zap.String("eventID", eventIDStr),
|
||||
zap.Error(err),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch prematch odds for event %d: %v", eventID, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to fetch prematch odds for event",
|
||||
zap.String("eventID", eventIDStr),
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.BaseNonLiveOddResponse{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to read response body for event %d: %v", eventID, err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to read response body for event",
|
||||
zap.String("eventID", eventIDStr),
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.BaseNonLiveOddResponse{}, err
|
||||
}
|
||||
var oddsData domain.BaseNonLiveOddResponse
|
||||
|
||||
if err := json.Unmarshal(body, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
||||
log.Printf("❌ Invalid prematch data for event %d", eventID)
|
||||
s.mongoLogger.Error(
|
||||
"Invalid prematch data for event",
|
||||
zap.String("eventID", eventIDStr),
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.BaseNonLiveOddResponse{}, err
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +338,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.FOOTBALL:
|
||||
var footballRes domain.FootballOddsResponse
|
||||
if err := json.Unmarshal(res, &footballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal football result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = footballRes.FI
|
||||
|
|
@ -276,7 +354,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.BASKETBALL:
|
||||
var basketballRes domain.BasketballOddsResponse
|
||||
if err := json.Unmarshal(res, &basketballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal basketball result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal basketball result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = basketballRes.FI
|
||||
|
|
@ -291,7 +372,11 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.ICE_HOCKEY:
|
||||
var iceHockeyRes domain.IceHockeyOddsResponse
|
||||
if err := json.Unmarshal(res, &iceHockeyRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal ice hockey result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = iceHockeyRes.FI
|
||||
|
|
@ -304,7 +389,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.CRICKET:
|
||||
var cricketRes domain.CricketOddsResponse
|
||||
if err := json.Unmarshal(res, &cricketRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal cricket result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = cricketRes.FI
|
||||
|
|
@ -320,7 +408,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.VOLLEYBALL:
|
||||
var volleyballRes domain.VolleyballOddsResponse
|
||||
if err := json.Unmarshal(res, &volleyballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal volleyball result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = volleyballRes.FI
|
||||
|
|
@ -331,7 +422,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.DARTS:
|
||||
var dartsRes domain.DartsOddsResponse
|
||||
if err := json.Unmarshal(res, &dartsRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal darts result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = dartsRes.FI
|
||||
|
|
@ -345,7 +439,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.FUTSAL:
|
||||
var futsalRes domain.FutsalOddsResponse
|
||||
if err := json.Unmarshal(res, &futsalRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal futsal result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = futsalRes.FI
|
||||
|
|
@ -357,7 +454,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.AMERICAN_FOOTBALL:
|
||||
var americanFootballRes domain.AmericanFootballOddsResponse
|
||||
if err := json.Unmarshal(res, &americanFootballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal american football result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = americanFootballRes.FI
|
||||
|
|
@ -370,7 +470,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.RUGBY_LEAGUE:
|
||||
var rugbyLeagueRes domain.RugbyLeagueOddsResponse
|
||||
if err := json.Unmarshal(res, &rugbyLeagueRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal rugby league result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = rugbyLeagueRes.FI
|
||||
|
|
@ -386,7 +489,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.RUGBY_UNION:
|
||||
var rugbyUnionRes domain.RugbyUnionOddsResponse
|
||||
if err := json.Unmarshal(res, &rugbyUnionRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal rugby union result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = rugbyUnionRes.FI
|
||||
|
|
@ -401,7 +507,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage,
|
|||
case domain.BASEBALL:
|
||||
var baseballRes domain.BaseballOddsResponse
|
||||
if err := json.Unmarshal(res, &baseballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"Failed to unmarshal baseball result",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.ParseOddSectionsRes{}, err
|
||||
}
|
||||
eventFI = baseballRes.FI
|
||||
|
|
@ -433,23 +542,19 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
|||
}
|
||||
|
||||
// Check if the market id is a string
|
||||
var marketIDstr string
|
||||
err := json.Unmarshal(market.ID, &marketIDstr)
|
||||
var marketIDint int64
|
||||
if err != nil {
|
||||
// check if its int
|
||||
err := json.Unmarshal(market.ID, &marketIDint)
|
||||
if err != nil {
|
||||
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
marketIDint, err = strconv.ParseInt(marketIDstr, 10, 64)
|
||||
if err != nil {
|
||||
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
marketIDint := market.ID.Int64
|
||||
// if err != nil {
|
||||
// s.mongoLogger.Error(
|
||||
// "Invalid market id",
|
||||
// zap.Int64("market_id", marketIDint),
|
||||
// zap.String("market_name", market.Name),
|
||||
// zap.String("eventID", eventID),
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// continue
|
||||
// }
|
||||
|
||||
marketIDstr := strconv.FormatInt(marketIDint, 10)
|
||||
|
||||
isSupported, ok := domain.SupportedMarkets[marketIDint]
|
||||
|
||||
|
|
@ -460,7 +565,13 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
|||
|
||||
marketOdds, err := convertRawMessage(market.Odds)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to conver json.RawMessage to []map[string]interface{} for market_id: ", market.ID)
|
||||
s.mongoLogger.Error(
|
||||
"failed to convert market.Odds to json.RawMessage to []map[string]interface{}",
|
||||
zap.String("market_id", marketIDstr),
|
||||
zap.String("market_name", market.Name),
|
||||
zap.String("eventID", eventID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
|
@ -480,7 +591,13 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
|||
|
||||
err = s.store.SaveNonLiveMarket(ctx, marketRecord)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to save market", "market_id", market.ID, "error", err)
|
||||
s.mongoLogger.Error(
|
||||
"failed to save market",
|
||||
zap.String("market_id", marketIDstr),
|
||||
zap.String("market_name", market.Name),
|
||||
zap.String("eventID", eventID),
|
||||
zap.Error(err),
|
||||
)
|
||||
errs = append(errs, fmt.Errorf("market %s: %w", market.ID, err))
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ func evaluateAsianHandicap(outcome domain.BetOutcome, score struct{ Home, Away i
|
|||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
||||
if err != nil {
|
||||
fmt.Printf("multi outcome check error")
|
||||
return domain.OUTCOME_STATUS_PENDING, err
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
}
|
||||
}
|
||||
} else if adjustedHomeScore < adjustedAwayScore {
|
||||
|
|
@ -203,7 +203,7 @@ func evaluateAsianHandicap(outcome domain.BetOutcome, score struct{ Home, Away i
|
|||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
||||
if err != nil {
|
||||
fmt.Printf("multi outcome check error")
|
||||
return domain.OUTCOME_STATUS_PENDING, err
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ func evaluateAsianHandicap(outcome domain.BetOutcome, score struct{ Home, Away i
|
|||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_VOID)
|
||||
if err != nil {
|
||||
fmt.Printf("multi outcome check error")
|
||||
return domain.OUTCOME_STATUS_PENDING, err
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -510,7 +510,7 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
func evaluateTotalLegs(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
total, err := strconv.ParseFloat(outcome.OddName, 64)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid : %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid : %s", outcome.OddName)
|
||||
}
|
||||
|
||||
totalLegs := float64(score.Home + score.Away)
|
||||
|
|
@ -528,7 +528,7 @@ func evaluateTotalLegs(outcome domain.BetOutcome, score struct{ Home, Away int }
|
|||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||
}
|
||||
|
||||
// Result and Total betting is a type of bet where the bettor predicts
|
||||
|
|
@ -736,16 +736,16 @@ func evaluateMoneyLine3Way(outcome domain.BetOutcome, score struct{ Home, Away i
|
|||
func evaluateDoubleResult(outcome domain.BetOutcome, firstHalfScore struct{ Home, Away int }, fullTimeScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
halfWins := strings.Split(outcome.OddName, "-")
|
||||
if len(halfWins) != 2 {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
}
|
||||
firstHalfWinner := strings.TrimSpace(halfWins[0])
|
||||
fullTimeWinner := strings.TrimSpace(halfWins[1])
|
||||
|
||||
if firstHalfWinner != outcome.HomeTeamName && firstHalfWinner != outcome.AwayTeamName && firstHalfWinner != "Tie" {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", firstHalfWinner)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", firstHalfWinner)
|
||||
}
|
||||
if fullTimeWinner != outcome.HomeTeamName && fullTimeWinner != outcome.AwayTeamName && fullTimeWinner != "Tie" {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", firstHalfWinner)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", firstHalfWinner)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
|
@ -908,7 +908,7 @@ func evaluateHandicapAndTotal(outcome domain.BetOutcome, score struct{ Home, Awa
|
|||
|
||||
func evaluateWinningMargin(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
if len(outcome.OddName) < 1 {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
isGtr := false
|
||||
|
|
@ -920,7 +920,7 @@ func evaluateWinningMargin(outcome domain.BetOutcome, score struct{ Home, Away i
|
|||
|
||||
margin, err := strconv.ParseInt(outcome.OddName[:idx], 10, 64)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
switch outcome.OddHeader {
|
||||
|
|
@ -992,7 +992,7 @@ func evaluateTiedAfterRegulation(outcome domain.BetOutcome, scores []struct{ Hom
|
|||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
func evaluateVolleyballGamelines(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
|
|
@ -1000,7 +1000,7 @@ func evaluateVolleyballGamelines(outcome domain.BetOutcome, score struct{ Home,
|
|||
case "Total":
|
||||
return evaluateTotalOverUnder(outcome, score)
|
||||
default:
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -304,8 +304,12 @@ func (s *Service) GetAdminNotificationRecipients(ctx context.Context, walletID i
|
|||
}
|
||||
|
||||
func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWallet domain.Wallet) error {
|
||||
errorSeverity := domain.NotificationErrorSeverityLow
|
||||
// Send notification to admin team
|
||||
adminNotification := &domain.Notification{
|
||||
ErrorSeverity: &errorSeverity,
|
||||
IsRead: false,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
RecipientID: adminWallet.UserID,
|
||||
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
||||
Level: domain.NotificationLevelWarning,
|
||||
|
|
@ -363,8 +367,12 @@ func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWalle
|
|||
|
||||
func (s *Service) SendAdminWalletInsufficientNotification(ctx context.Context, adminWallet domain.Wallet, amount domain.Currency) error {
|
||||
|
||||
errorSeverity := domain.NotificationErrorSeverityLow
|
||||
// Send notification to admin team
|
||||
adminNotification := &domain.Notification{
|
||||
ErrorSeverity: &errorSeverity,
|
||||
IsRead: false,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
RecipientID: adminWallet.UserID,
|
||||
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
||||
Level: domain.NotificationLevelError,
|
||||
|
|
@ -423,8 +431,12 @@ func (s *Service) SendAdminWalletInsufficientNotification(ctx context.Context, a
|
|||
}
|
||||
|
||||
func (s *Service) SendCustomerWalletInsufficientNotification(ctx context.Context, customerWallet domain.Wallet, amount domain.Currency) error {
|
||||
errorSeverity := domain.NotificationErrorSeverityLow
|
||||
// Send notification to admin team
|
||||
customerNotification := &domain.Notification{
|
||||
ErrorSeverity: &errorSeverity,
|
||||
IsRead: false,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
RecipientID: customerWallet.UserID,
|
||||
Type: domain.NOTIFICATION_TYPE_WALLET,
|
||||
Level: domain.NotificationLevelError,
|
||||
|
|
|
|||
|
|
@ -15,69 +15,85 @@ import (
|
|||
resultsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||
"github.com/robfig/cron/v3"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.ServiceImpl, resultService *resultsvc.Service) {
|
||||
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.ServiceImpl, resultService *resultsvc.Service, mongoLogger *zap.Logger) {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
|
||||
schedule := []struct {
|
||||
spec string
|
||||
task func()
|
||||
}{
|
||||
{
|
||||
spec: "0 0 * * * *", // Every 1 hour
|
||||
task: func() {
|
||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||
log.Printf("FetchUpcomingEvents error: %v", err)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
|
||||
task: func() {
|
||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||
log.Printf("FetchNonLiveOdds error: %v", err)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 */5 * * * *", // Every 5 Minutes
|
||||
task: func() {
|
||||
log.Println("Updating expired events status...")
|
||||
|
||||
if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil {
|
||||
log.Printf("Failed to update events: %v", err)
|
||||
} else {
|
||||
log.Printf("Successfully updated expired events")
|
||||
}
|
||||
},
|
||||
},
|
||||
// {
|
||||
// spec: "0 0 * * * *", // Every 1 hour
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began fetching upcoming events")
|
||||
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to fetch upcoming events",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Successfully fetched upcoming events")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began fetching non live odds")
|
||||
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to fetch non live odds",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Successfully fetched non live odds")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 */5 * * * *", // Every 5 Minutes
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began updating all expired events status")
|
||||
// if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to update expired events status",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Successfully updated expired events")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
{
|
||||
spec: "0 */15 * * * *", // Every 15 Minutes
|
||||
task: func() {
|
||||
log.Println("Fetching results for upcoming events...")
|
||||
|
||||
mongoLogger.Info("Fetching results for upcoming events")
|
||||
if err := resultService.FetchAndProcessResults(context.Background()); err != nil {
|
||||
log.Printf("Failed to process result: %v", err)
|
||||
mongoLogger.Error("Failed to process result",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
log.Printf("Successfully processed all outcomes")
|
||||
mongoLogger.Info("Successfully processed all event result outcomes")
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, job := range schedule {
|
||||
// job.task()
|
||||
job.task()
|
||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||
mongoLogger.Error("Failed to schedule data fetching cron job",
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
c.Start()
|
||||
log.Println("Cron jobs started for event and odds services")
|
||||
mongoLogger.Info("Cron jobs started for event and odds services")
|
||||
}
|
||||
|
||||
func StartTicketCrons(ticketService ticket.Service) {
|
||||
func StartTicketCrons(ticketService ticket.Service, mongoLogger *zap.Logger) {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
|
||||
schedule := []struct {
|
||||
|
|
@ -87,11 +103,13 @@ func StartTicketCrons(ticketService ticket.Service) {
|
|||
{
|
||||
spec: "0 0 * * * *", // Every hour
|
||||
task: func() {
|
||||
log.Println("Deleting old tickets...")
|
||||
mongoLogger.Info("Deleting old tickets")
|
||||
if err := ticketService.DeleteOldTickets(context.Background()); err != nil {
|
||||
log.Printf("Failed to remove old ticket: %v", err)
|
||||
mongoLogger.Error("Failed to remove old ticket",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
log.Printf("Successfully deleted old tickets")
|
||||
mongoLogger.Info("Successfully deleted old tickets")
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -99,12 +117,14 @@ func StartTicketCrons(ticketService ticket.Service) {
|
|||
|
||||
for _, job := range schedule {
|
||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||
mongoLogger.Error("Failed to schedule ticket cron job",
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
c.Start()
|
||||
log.Println("Cron jobs started for ticket service")
|
||||
mongoLogger.Info("Cron jobs started for ticket service")
|
||||
}
|
||||
|
||||
func SetupReportCronJobs(ctx context.Context, reportService *report.Service) {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,8 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
|||
|
||||
rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to get raw odds by market ID",
|
||||
// Lets turn this into a warn because this is constantly going off
|
||||
h.mongoLoggerSvc.Warn("Failed to get raw odds by market ID",
|
||||
zap.String("marketID", marketID),
|
||||
zap.String("upcomingID", upcomingID),
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user