merge conflixt fix
This commit is contained in:
commit
eb8abfc963
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
// "context"
|
||||
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
|
|
|||
|
|
@ -202,7 +202,8 @@ CREATE TABLE events (
|
|||
match_period INT,
|
||||
is_live BOOLEAN,
|
||||
status TEXT,
|
||||
fetched_at TIMESTAMP DEFAULT now()
|
||||
fetched_at TIMESTAMP DEFAULT now(),
|
||||
source TEXT DEFAULT 'b365api'
|
||||
);
|
||||
CREATE TABLE odds (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ INSERT INTO events (
|
|||
added_time,
|
||||
match_period,
|
||||
is_live,
|
||||
status
|
||||
status,
|
||||
source
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
|
|
@ -41,7 +42,8 @@ VALUES (
|
|||
$17,
|
||||
$18,
|
||||
$19,
|
||||
$20
|
||||
$20,
|
||||
$21
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
|
|
@ -63,6 +65,7 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
match_period = EXCLUDED.match_period,
|
||||
is_live = EXCLUDED.is_live,
|
||||
status = EXCLUDED.status,
|
||||
source = EXCLUDED.source,
|
||||
fetched_at = now();
|
||||
-- name: InsertUpcomingEvent :exec
|
||||
INSERT INTO events (
|
||||
|
|
@ -80,7 +83,8 @@ INSERT INTO events (
|
|||
league_cc,
|
||||
start_time,
|
||||
is_live,
|
||||
status
|
||||
status,
|
||||
source
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
|
|
@ -97,7 +101,8 @@ VALUES (
|
|||
$12,
|
||||
$13,
|
||||
false,
|
||||
'upcoming'
|
||||
'upcoming',
|
||||
$14
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
|
|
@ -114,6 +119,7 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
start_time = EXCLUDED.start_time,
|
||||
is_live = false,
|
||||
status = 'upcoming',
|
||||
source = EXCLUDED.source,
|
||||
fetched_at = now();
|
||||
-- name: ListLiveEvents :many
|
||||
SELECT id
|
||||
|
|
@ -135,6 +141,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
|
|
@ -156,6 +163,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE start_time < now()
|
||||
|
|
@ -197,6 +205,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
|
|
@ -235,6 +244,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE id = $1
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: auth.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: bet.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: branch.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: company.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: copyfrom.go
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
|
||||
package dbgen
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: events.sql
|
||||
|
||||
package dbgen
|
||||
|
|
@ -37,6 +37,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
|
|
@ -60,6 +61,7 @@ type GetAllUpcomingEventsRow struct {
|
|||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
}
|
||||
|
||||
|
|
@ -88,6 +90,7 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]GetAllUpcomingEve
|
|||
&i.StartTime,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.Source,
|
||||
&i.FetchedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -116,6 +119,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE start_time < now()
|
||||
|
|
@ -138,6 +142,7 @@ type GetExpiredUpcomingEventsRow struct {
|
|||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +171,7 @@ func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context) ([]GetExpiredUpc
|
|||
&i.StartTime,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.Source,
|
||||
&i.FetchedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -194,6 +200,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
|
|
@ -243,6 +250,7 @@ type GetPaginatedUpcomingEventsRow struct {
|
|||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +286,7 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat
|
|||
&i.StartTime,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.Source,
|
||||
&i.FetchedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -348,6 +357,7 @@ SELECT id,
|
|||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
source,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE id = $1
|
||||
|
|
@ -372,6 +382,7 @@ type GetUpcomingByIDRow struct {
|
|||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
}
|
||||
|
||||
|
|
@ -394,6 +405,7 @@ func (q *Queries) GetUpcomingByID(ctx context.Context, id string) (GetUpcomingBy
|
|||
&i.StartTime,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.Source,
|
||||
&i.FetchedAt,
|
||||
)
|
||||
return i, err
|
||||
|
|
@ -420,7 +432,8 @@ INSERT INTO events (
|
|||
added_time,
|
||||
match_period,
|
||||
is_live,
|
||||
status
|
||||
status,
|
||||
source
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
|
|
@ -442,7 +455,8 @@ VALUES (
|
|||
$17,
|
||||
$18,
|
||||
$19,
|
||||
$20
|
||||
$20,
|
||||
$21
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
|
|
@ -464,6 +478,7 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
match_period = EXCLUDED.match_period,
|
||||
is_live = EXCLUDED.is_live,
|
||||
status = EXCLUDED.status,
|
||||
source = EXCLUDED.source,
|
||||
fetched_at = now()
|
||||
`
|
||||
|
||||
|
|
@ -488,6 +503,7 @@ type InsertEventParams struct {
|
|||
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
}
|
||||
|
||||
func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error {
|
||||
|
|
@ -512,6 +528,7 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error
|
|||
arg.MatchPeriod,
|
||||
arg.IsLive,
|
||||
arg.Status,
|
||||
arg.Source,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -532,7 +549,8 @@ INSERT INTO events (
|
|||
league_cc,
|
||||
start_time,
|
||||
is_live,
|
||||
status
|
||||
status,
|
||||
source
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
|
|
@ -549,7 +567,8 @@ VALUES (
|
|||
$12,
|
||||
$13,
|
||||
false,
|
||||
'upcoming'
|
||||
'upcoming',
|
||||
$14
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
|
|
@ -566,6 +585,7 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
start_time = EXCLUDED.start_time,
|
||||
is_live = false,
|
||||
status = 'upcoming',
|
||||
source = EXCLUDED.source,
|
||||
fetched_at = now()
|
||||
`
|
||||
|
||||
|
|
@ -583,6 +603,7 @@ type InsertUpcomingEventParams struct {
|
|||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
}
|
||||
|
||||
func (q *Queries) InsertUpcomingEvent(ctx context.Context, arg InsertUpcomingEventParams) error {
|
||||
|
|
@ -600,6 +621,7 @@ func (q *Queries) InsertUpcomingEvent(ctx context.Context, arg InsertUpcomingEve
|
|||
arg.LeagueName,
|
||||
arg.LeagueCc,
|
||||
arg.StartTime,
|
||||
arg.Source,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
|
||||
package dbgen
|
||||
|
||||
|
|
@ -196,6 +196,7 @@ type Event struct {
|
|||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: notification.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: odds.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: otp.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: referal.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: result.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: ticket.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: transactions.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: transfer.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: user.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: virtual_games.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
// sqlc v1.29.0
|
||||
// source: wallet.sql
|
||||
|
||||
package dbgen
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -18,6 +18,8 @@ require (
|
|||
golang.org/x/crypto v0.36.0
|
||||
)
|
||||
|
||||
require github.com/gorilla/websocket v1.5.3 // indirect
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
|
|
|
|||
|
|
@ -23,7 +23,35 @@ type Event struct {
|
|||
MatchPeriod int
|
||||
IsLive bool
|
||||
Status string
|
||||
Source string
|
||||
}
|
||||
|
||||
type BetResult struct {
|
||||
Success int `json:"success"`
|
||||
Pager struct {
|
||||
Page int `json:"page"`
|
||||
PerPage int `json:"per_page"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
Results []struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"home"`
|
||||
Away *struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"away"`
|
||||
} `json:"results"`
|
||||
}
|
||||
|
||||
type UpcomingEvent struct {
|
||||
ID string // Event ID
|
||||
SportID string // Sport ID
|
||||
|
|
@ -38,6 +66,7 @@ type UpcomingEvent struct {
|
|||
LeagueName string // League name
|
||||
LeagueCC string // League country code
|
||||
StartTime time.Time // Converted from "time" field in UNIX format
|
||||
Source string // bet api provider (bet365, betfair)
|
||||
}
|
||||
type MatchResult struct {
|
||||
EventID string
|
||||
|
|
|
|||
|
|
@ -151,3 +151,142 @@ type IceHockeyResultResponse struct {
|
|||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type CricketResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
NumberOfPeriods string `json:"numberofperiods"`
|
||||
PeriodLength string `json:"periodlength"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
} `json:"extra"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type VolleyballResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstSet Score `json:"1"`
|
||||
SecondSet Score `json:"2"`
|
||||
ThirdSet Score `json:"3"`
|
||||
FourthSet Score `json:"4"`
|
||||
FivethSet Score `json:"5"`
|
||||
} `json:"scores"`
|
||||
Stats struct {
|
||||
PointsWonOnServe []string `json:"points_won_on_serve"`
|
||||
LongestStreak []string `json:"longest_streak"`
|
||||
} `json:"stats"`
|
||||
InplayCreatedAt string `json:"inplay_created_at"`
|
||||
InplayUpdatedAt string `json:"inplay_updated_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type DartsResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
InplayCreatedAt string `json:"inplay_created_at"`
|
||||
InplayUpdatedAt string `json:"inplay_updated_at"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type FutsalResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstPeriod Score `json:"1"`
|
||||
SecondPeriod Score `json:"2"`
|
||||
ThirdPeriod Score `json:"3"`
|
||||
TotalScore Score `json:"4"`
|
||||
} `json:"scores"`
|
||||
Events []map[string]string `json:"events"`
|
||||
InplayCreatedAt string `json:"inplay_created_at"`
|
||||
InplayUpdatedAt string `json:"inplay_updated_at"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,72 @@ const (
|
|||
ICE_HOCKEY_ALTERNATIVE_TOTAL_TWO_WAY IceHockeyMarket = 170240
|
||||
)
|
||||
|
||||
type CricketMarket int64
|
||||
|
||||
const (
|
||||
// Main
|
||||
CRICKET_TO_WIN_THE_MATCH CricketMarket = 1246
|
||||
CRICKET_TEAM_TOP_BATTER CricketMarket = 1241
|
||||
CRICKET_TEAM_TOP_BOWLE CricketMarket = 1242
|
||||
CRICKET_PLAYER_OF_THE_MATCH CricketMarket = 346
|
||||
CRICKET_FIRST_WICKET_METHOD CricketMarket = 30205
|
||||
|
||||
// First Over
|
||||
CRICKET_FIRST_OVER_TOTAL_RUNS CricketMarket = 300336
|
||||
CRICKET_FIRST_OVER_TOTAL_RUNS_Odd_Even CricketMarket = 300118
|
||||
|
||||
// Inninigs 1
|
||||
CRICKET_FIRST_INNINIGS_SCORE CricketMarket = 300338
|
||||
CRICKET_INNINGS_OF_MATCH_BOWLED_OUT CricketMarket = 300108
|
||||
|
||||
// Match
|
||||
CRICKET_TOP_MATCH_BATTER CricketMarket = 30245
|
||||
CRICKET_TOP_MATCH_BOWLER CricketMarket = 30246
|
||||
)
|
||||
|
||||
type VolleyballMarket int64
|
||||
|
||||
const (
|
||||
VOLLEYBALL_GAME_LINES VolleyballMarket = 910000
|
||||
VOLLEYBALL_CORRECT_SET_SCORE VolleyballMarket = 910201
|
||||
VOLLEYBALL_MATCH_TOTAL_ODD_EVEN VolleyballMarket = 910217
|
||||
VOLLEYBALL_SET_ONE_LINES VolleyballMarket = 910204
|
||||
VOLLEYBALL_SET_ONE_TO_GO_TO_EXTRA_POINTS VolleyballMarket = 910209
|
||||
VOLLEYBALL_SET_ONE_TOTAL_ODD_EVEN VolleyballMarket = 910218
|
||||
)
|
||||
|
||||
type DartsMarket int64
|
||||
|
||||
const (
|
||||
// Main
|
||||
DARTS_MATCH_WINNER DartsMarket = 703 // match_winner
|
||||
DARTS_MATCH_DOUBLE DartsMarket = 150228 // match_double
|
||||
DARTS_MATCH_TREBLE DartsMarket = 150230 // match_treble
|
||||
DARTS_CORRECT_LEG_SCORE DartsMarket = 150015 // correct_leg_score
|
||||
DARTS_TOTAL_LEGS DartsMarket = 150117 // total_legs
|
||||
|
||||
DARTS_MOST_HUNDERED_EIGHTYS DartsMarket = 150030 // "most_180s"
|
||||
DARTS_TOTAL_HUNDERED_EIGHTYS DartsMarket = 150012 // total_180s
|
||||
DARTS_MOST_HUNDERED_EIGHTYS_HANDICAP DartsMarket = 150227 // most_180s_handicap
|
||||
DARTS_PLAYER_HUNDERED_EIGHTYS DartsMarket = 150121 // player_180s
|
||||
DARTS_FIRST_DART DartsMarket = 150125 // first_dart
|
||||
)
|
||||
|
||||
type FutsalMarket int64
|
||||
|
||||
const (
|
||||
// Main
|
||||
FUTSAL_GAME_LINES FutsalMarket = 830001
|
||||
FUTSAL_MONEY_LINE FutsalMarket = 830130
|
||||
|
||||
// Others
|
||||
FUTSAL_DOUBLE_RESULT_9_WAY FutsalMarket = 830124
|
||||
|
||||
// Score
|
||||
FUTSAL_TEAM_TO_SCORE_FIRST FutsalMarket = 830141
|
||||
FUTSAL_RACE_TO_GOALS FutsalMarket = 830142
|
||||
)
|
||||
|
||||
type AmericanFootballMarket int64
|
||||
|
||||
const (
|
||||
|
|
@ -214,6 +280,50 @@ var SupportedMarkets = map[int64]bool{
|
|||
int64(ICE_HOCKEY_ALTERNATIVE_PUCK_LINE_TWO_WAY): false,
|
||||
int64(ICE_HOCKEY_ALTERNATIVE_TOTAL_TWO_WAY): false,
|
||||
|
||||
// Cricket Markets
|
||||
int64(CRICKET_TO_WIN_THE_MATCH): true,
|
||||
|
||||
int64(CRICKET_FIRST_OVER_TOTAL_RUNS_Odd_Even): false,
|
||||
int64(CRICKET_FIRST_INNINIGS_SCORE): false,
|
||||
int64(CRICKET_INNINGS_OF_MATCH_BOWLED_OUT): false,
|
||||
int64(CRICKET_FIRST_OVER_TOTAL_RUNS): false,
|
||||
int64(CRICKET_TEAM_TOP_BATTER): false,
|
||||
int64(CRICKET_TEAM_TOP_BOWLE): false,
|
||||
int64(CRICKET_PLAYER_OF_THE_MATCH): false,
|
||||
int64(CRICKET_FIRST_WICKET_METHOD): false,
|
||||
int64(CRICKET_TOP_MATCH_BATTER): false,
|
||||
int64(CRICKET_TOP_MATCH_BOWLER): false,
|
||||
|
||||
// Volleyball Markets
|
||||
int64(VOLLEYBALL_GAME_LINES): true,
|
||||
int64(VOLLEYBALL_CORRECT_SET_SCORE): true,
|
||||
int64(VOLLEYBALL_MATCH_TOTAL_ODD_EVEN): true,
|
||||
|
||||
int64(VOLLEYBALL_SET_ONE_LINES): false,
|
||||
int64(VOLLEYBALL_SET_ONE_TO_GO_TO_EXTRA_POINTS): false,
|
||||
int64(VOLLEYBALL_SET_ONE_TOTAL_ODD_EVEN): false,
|
||||
|
||||
// Darts Markets
|
||||
int64(DARTS_MATCH_WINNER): true,
|
||||
int64(DARTS_TOTAL_LEGS): true,
|
||||
int64(DARTS_CORRECT_LEG_SCORE): false,
|
||||
int64(DARTS_MATCH_DOUBLE): false,
|
||||
int64(DARTS_MATCH_TREBLE): false,
|
||||
|
||||
int64(DARTS_MOST_HUNDERED_EIGHTYS): false,
|
||||
int64(DARTS_TOTAL_HUNDERED_EIGHTYS): false,
|
||||
int64(DARTS_MOST_HUNDERED_EIGHTYS_HANDICAP): false,
|
||||
int64(DARTS_PLAYER_HUNDERED_EIGHTYS): false,
|
||||
int64(DARTS_FIRST_DART): false,
|
||||
|
||||
// Futsal Markets
|
||||
int64(FUTSAL_MONEY_LINE): true,
|
||||
int64(FUTSAL_GAME_LINES): true,
|
||||
int64(FUTSAL_TEAM_TO_SCORE_FIRST): true,
|
||||
|
||||
int64(FUTSAL_DOUBLE_RESULT_9_WAY): false,
|
||||
int64(FUTSAL_RACE_TO_GOALS): false,
|
||||
|
||||
// American Football Markets
|
||||
int64(AMERICAN_FOOTBALL_MONEY_LINE): true,
|
||||
int64(AMERICAN_FOOTBALL_SPREAD): true,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
|
|||
MatchPeriod: pgtype.Int4{Int32: int32(e.MatchPeriod), Valid: true},
|
||||
IsLive: pgtype.Bool{Bool: e.IsLive, Valid: true},
|
||||
Status: pgtype.Text{String: e.Status, Valid: true},
|
||||
Source: pgtype.Text{String: e.Source, Valid: true},
|
||||
})
|
||||
}
|
||||
func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
|
||||
|
|
@ -57,6 +58,7 @@ func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) e
|
|||
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
|
||||
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
|
||||
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
|
||||
Source: pgtype.Text{String: e.Source, Valid: true},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -85,6 +87,7 @@ func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEven
|
|||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
Source: e.Source.String,
|
||||
}
|
||||
}
|
||||
return upcomingEvents, nil
|
||||
|
|
@ -112,6 +115,7 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.Upcoming
|
|||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
Source: e.Source.String,
|
||||
}
|
||||
}
|
||||
return upcomingEvents, nil
|
||||
|
|
@ -165,6 +169,7 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.Val
|
|||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
Source: e.Source.String,
|
||||
}
|
||||
}
|
||||
totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
|
||||
|
|
@ -212,6 +217,7 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
|||
LeagueName: event.LeagueName.String,
|
||||
LeagueCC: event.LeagueCc.String,
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: event.Source.String,
|
||||
}, nil
|
||||
}
|
||||
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore, status string) error {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,30 @@ func New(token string, store *repository.Store) Service {
|
|||
}
|
||||
|
||||
func (s *service) FetchLiveEvents(ctx context.Context) error {
|
||||
var wg sync.WaitGroup
|
||||
urls := []struct {
|
||||
name string
|
||||
source string
|
||||
}{
|
||||
{"https://api.b365api.com/v1/bet365/inplay?sport_id=%d&token=%s", "bet365"},
|
||||
{"https://api.b365api.com/v1/betfair/sb/inplay?sport_id=%d&token=%s", "betfair"},
|
||||
{"https://api.b365api.com/v1/1xbet/inplay?sport_id=%d&token=%s", "1xbet"},
|
||||
}
|
||||
|
||||
for _, url := range urls {
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
s.fetchLiveEvents(ctx, url.name, url.source)
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) fetchLiveEvents(ctx context.Context, url, source string) error {
|
||||
sportIDs := []int{1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4, 83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90, 95, 110, 107, 151, 162, 148}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
|
@ -39,7 +63,7 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
|||
go func(sportID int) {
|
||||
defer wg.Done()
|
||||
|
||||
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/inplay?sport_id=%d&token=%s", sportID, s.token)
|
||||
url := fmt.Sprintf(url, sportID, s.token)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Printf(" Failed request for sport_id=%d: %v\n", sportID, err)
|
||||
|
|
@ -49,13 +73,41 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
|||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
|
||||
events := []domain.Event{}
|
||||
switch source {
|
||||
case "bet365":
|
||||
events = handleBet365prematch(body, sportID)
|
||||
case "betfair":
|
||||
events = handleBetfairprematch(body, sportID, source)
|
||||
case "1xbet":
|
||||
// betfair and 1xbet have the same result structure
|
||||
events = handleBetfairprematch(body, sportID, source)
|
||||
}
|
||||
|
||||
for _, event := range events {
|
||||
if err := s.store.SaveEvent(ctx, event); err != nil {
|
||||
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
|
||||
}
|
||||
}
|
||||
}(sportID)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
fmt.Println("All live events fetched and stored.")
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func handleBet365prematch(body []byte, sportID int) []domain.Event {
|
||||
var data struct {
|
||||
Success int `json:"success"`
|
||||
Results [][]map[string]interface{} `json:"results"`
|
||||
}
|
||||
|
||||
events := []domain.Event{}
|
||||
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))
|
||||
return
|
||||
return events
|
||||
}
|
||||
|
||||
for _, group := range data.Results {
|
||||
|
|
@ -83,33 +135,88 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
|||
Status: "live",
|
||||
MatchPeriod: getInt(ev["MD"]),
|
||||
AddedTime: getInt(ev["TA"]),
|
||||
Source: "bet365",
|
||||
}
|
||||
|
||||
if err := s.store.SaveEvent(ctx, event); err != nil {
|
||||
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
|
||||
events = append(events, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}(sportID)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
fmt.Println("All live events fetched and stored.")
|
||||
return nil
|
||||
return events
|
||||
}
|
||||
|
||||
func handleBetfairprematch(body []byte, sportID int, source string) []domain.Event {
|
||||
var data struct {
|
||||
Success int `json:"success"`
|
||||
Results []map[string]interface{} `json:"results"`
|
||||
}
|
||||
|
||||
events := []domain.Event{}
|
||||
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))
|
||||
return events
|
||||
}
|
||||
|
||||
for _, ev := range data.Results {
|
||||
homeRaw, _ := ev["home"].(map[string]interface{})
|
||||
homeId, _ := homeRaw["id"].(string)
|
||||
|
||||
awayRaw, _ := ev["home"].(map[string]interface{})
|
||||
awayId, _ := awayRaw["id"].(string)
|
||||
|
||||
event := domain.Event{
|
||||
ID: getString(ev["id"]),
|
||||
SportID: fmt.Sprintf("%d", sportID),
|
||||
TimerStatus: getString(ev["time_status"]),
|
||||
HomeTeamID: homeId,
|
||||
AwayTeamID: awayId,
|
||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||
IsLive: true,
|
||||
Status: "live",
|
||||
Source: source,
|
||||
}
|
||||
|
||||
events = append(events, event)
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||
sportIDs := []int{1, 18, 17}
|
||||
var wg sync.WaitGroup
|
||||
urls := []struct {
|
||||
name string
|
||||
source string
|
||||
}{
|
||||
{"https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", "bet365"},
|
||||
{"https://api.b365api.com/v1/betfair/sb/upcoming?sport_id=%d&token=%s&page=%d", "betfair"},
|
||||
{"https://api.b365api.com/v1/1xbet/upcoming?sport_id=%d&token=%s&page=%d", "1xbet"},
|
||||
}
|
||||
|
||||
for _, sportID := range sportIDs {
|
||||
for _, url := range urls {
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
s.fetchUpcomingEventsFromProvider(ctx, url.name, url.source)
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, source string) {
|
||||
sportIDs := []int{1, 18, 17}
|
||||
var totalPages int = 1
|
||||
var page int = 0
|
||||
var limit int = 150
|
||||
var limit int = 100
|
||||
var count int = 0
|
||||
for _, sportID := range sportIDs {
|
||||
for page <= totalPages {
|
||||
page = page + 1
|
||||
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", sportID, s.token, page)
|
||||
log.Printf("📡 Fetching data for sport %d event data page %d/%d", sportID, page, min(limit, totalPages))
|
||||
log.Printf("📡 Fetching data for event data page %d", page)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch event data for page %d: %v", page, err)
|
||||
|
|
@ -118,31 +225,8 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
|||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
var data struct {
|
||||
Success int `json:"success"`
|
||||
Pager struct {
|
||||
Page int `json:"page"`
|
||||
PerPage int `json:"per_page"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
Results []struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"home"`
|
||||
Away *struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"away"`
|
||||
} `json:"results"`
|
||||
}
|
||||
var data domain.BetResult
|
||||
|
||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||
log.Printf("❌ Failed to parse json data")
|
||||
continue
|
||||
|
|
@ -182,6 +266,7 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
|||
LeagueName: ev.League.Name,
|
||||
LeagueCC: "",
|
||||
StartTime: time.Unix(startUnix, 0).UTC(),
|
||||
Source: source,
|
||||
}
|
||||
|
||||
if ev.Away != nil {
|
||||
|
|
@ -209,8 +294,6 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
|||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getString(v interface{}) string {
|
||||
|
|
|
|||
|
|
@ -182,32 +182,33 @@ func evaluateAsianHandicap(outcome domain.BetOutcome, score struct{ Home, Away i
|
|||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
fmt.Printf("multi outcome check error")
|
||||
return domain.OUTCOME_STATUS_PENDING, err
|
||||
}
|
||||
}
|
||||
continue
|
||||
} else if adjustedHomeScore < adjustedAwayScore {
|
||||
if outcome.OddHeader == "2" {
|
||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_WIN)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
fmt.Printf("multi outcome check error")
|
||||
return domain.OUTCOME_STATUS_PENDING, err
|
||||
}
|
||||
continue
|
||||
} else if adjustedHomeScore == adjustedAwayScore {
|
||||
}
|
||||
}
|
||||
if newOutcome == domain.OUTCOME_STATUS_PENDING {
|
||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_VOID)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, err
|
||||
fmt.Printf("multi outcome check error")
|
||||
return domain.OUTCOME_STATUS_PENDING, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
return newOutcome, nil
|
||||
|
|
@ -498,9 +499,33 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
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
|
||||
// the outcome of a match and whether the total number of points scored will be over or under a specified number.
|
||||
func evaluateResultAndTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
totalLegs := float64(score.Home + score.Away)
|
||||
|
||||
switch outcome.OddHeader {
|
||||
case "Over":
|
||||
if totalLegs > total {
|
||||
return domain.OUTCOME_STATUS_WIN, nil
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
case "Under":
|
||||
if totalLegs < total {
|
||||
return domain.OUTCOME_STATUS_WIN, nil
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||
}
|
||||
|
||||
// Result and Total betting is a type of bet where the bettor predicts
|
||||
// the outcome of a match and whether the total number of points scored will be over or under a specified number.
|
||||
func evaluateResultAndTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
|
||||
// The handicap will be in the format "U {float}" or "O {float}"
|
||||
// U and O denoting over and under for this case
|
||||
|
|
@ -548,11 +573,11 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
default:
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("failed to parse over and under: %s", outcome.OddName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Team Total betting is a type of bet where the bettor predicts the total number of points scored by a specific team in a match
|
||||
// is over or under a specified number.
|
||||
func evaluateTeamTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Team Total betting is a type of bet where the bettor predicts the total number of points scored by a specific team in a match
|
||||
// is over or under a specified number.
|
||||
func evaluateTeamTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
|
||||
// The handicap will be in the format "U {float}" or "O {float}"
|
||||
// U and O denoting over and under for this case
|
||||
|
|
@ -594,11 +619,11 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
default:
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("failed to parse over and under: %s", outcome.OddName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Result and Both Teams To Score X Points is a type of bet where the bettor predicts whether both teams will score a certain number of points
|
||||
// and also the result fo the match
|
||||
func evaluateResultAndBTTSX(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Result and Both Teams To Score X Points is a type of bet where the bettor predicts whether both teams will score a certain number of points
|
||||
// and also the result fo the match
|
||||
func evaluateResultAndBTTSX(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
|
||||
// The name parameter will hold value "name": "{team_name} and {Yes | No}"
|
||||
// The best way to do this is to evaluate backwards since there might be
|
||||
|
|
@ -623,6 +648,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid threshold: %s", outcome.OddHeader)
|
||||
}
|
||||
|
||||
// above code removes any space from team name, so do the same for outcome.HomeTeamName and outcome.AwayTeamName
|
||||
outcome.HomeTeamName = strings.Join(strings.Split(outcome.HomeTeamName, " "), "")
|
||||
outcome.AwayTeamName = strings.Join(strings.Split(outcome.AwayTeamName, " "), "")
|
||||
|
||||
switch teamName {
|
||||
case outcome.HomeTeamName:
|
||||
if score.Home > score.Away {
|
||||
|
|
@ -646,10 +675,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Both Teams To Score X Points is a type of bet where the bettor predicts whether both teams will score a certain number of points.
|
||||
func evaluateBTTSX(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Both Teams To Score X Points is a type of bet where the bettor predicts whether both teams will score a certain number of points.
|
||||
func evaluateBTTSX(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
threshold, err := strconv.ParseInt(outcome.OddName, 10, 64)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid threshold: %s", outcome.OddName)
|
||||
|
|
@ -670,10 +699,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Money Line 3 Way betting is a type of bet where the bettor predicts the outcome of a match with three possible outcomes: home win, away win, or draw.
|
||||
func evaluateMoneyLine3Way(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Money Line 3 Way betting is a type of bet where the bettor predicts the outcome of a match with three possible outcomes: home win, away win, or draw.
|
||||
func evaluateMoneyLine3Way(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
switch outcome.OddName {
|
||||
case "1": // Home win
|
||||
if score.Home > score.Away {
|
||||
|
|
@ -693,22 +722,21 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
default:
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Double Result betting is a type of bet where the bettor predicts the outcome of a match at both half-time and full-time.
|
||||
func evaluateDoubleResult(outcome domain.BetOutcome, firstHalfScore struct{ Home, Away int }, secondHalfScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
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_ERROR, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
}
|
||||
firstHalfWinner := strings.TrimSpace(halfWins[0])
|
||||
secondHalfWinner := strings.TrimSpace(halfWins[1])
|
||||
fullTimeWinner := strings.TrimSpace(halfWins[1])
|
||||
|
||||
if firstHalfWinner != outcome.HomeTeamName && firstHalfWinner != outcome.AwayTeamName && firstHalfWinner != "Tie" {
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", firstHalfWinner)
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", firstHalfWinner)
|
||||
}
|
||||
if secondHalfWinner != outcome.HomeTeamName && secondHalfWinner != outcome.AwayTeamName && secondHalfWinner != "Tie" {
|
||||
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)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
|
@ -721,19 +749,19 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
}
|
||||
|
||||
switch {
|
||||
case secondHalfWinner == outcome.HomeTeamName && firstHalfScore.Home < firstHalfScore.Away:
|
||||
case fullTimeWinner == outcome.HomeTeamName && fullTimeScore.Home < fullTimeScore.Away:
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
case secondHalfWinner == outcome.AwayTeamName && firstHalfScore.Away < firstHalfScore.Home:
|
||||
case fullTimeWinner == outcome.AwayTeamName && fullTimeScore.Away < fullTimeScore.Home:
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
case secondHalfWinner == "Tie" && firstHalfScore.Home != firstHalfScore.Away:
|
||||
case fullTimeWinner == "Tie" && fullTimeScore.Home != fullTimeScore.Away:
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_WIN, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Highest Scoring Half betting is a type of bet where the bettor predicts which half of the match will have the highest total score.
|
||||
func evaluateHighestScoringHalf(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Highest Scoring Half betting is a type of bet where the bettor predicts which half of the match will have the highest total score.
|
||||
func evaluateHighestScoringHalf(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
firstHalfTotal := firstScore.Home + firstScore.Away
|
||||
secondHalfTotal := secondScore.Home + secondScore.Away
|
||||
switch outcome.OddName {
|
||||
|
|
@ -753,10 +781,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Highest Scoring Quarter betting is a type of bet where the bettor predicts which quarter of the match will have the highest score.
|
||||
func evaluateHighestScoringQuarter(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }, fourthScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Highest Scoring Quarter betting is a type of bet where the bettor predicts which quarter of the match will have the highest score.
|
||||
func evaluateHighestScoringQuarter(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }, fourthScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
firstQuarterTotal := firstScore.Home + firstScore.Away
|
||||
secondQuarterTotal := secondScore.Home + secondScore.Away
|
||||
thirdQuarterTotal := thirdScore.Home + thirdScore.Away
|
||||
|
|
@ -787,10 +815,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Team With Highest Scoring Quarter betting is a type of bet where the bettor predicts which team will have the highest score in a specific quarter.
|
||||
func evaluateTeamWithHighestScoringQuarter(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }, fourthScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Team With Highest Scoring Quarter betting is a type of bet where the bettor predicts which team will have the highest score in a specific quarter.
|
||||
func evaluateTeamWithHighestScoringQuarter(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }, fourthScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
homeTeamHighestQuarter := max(firstScore.Home, secondScore.Home, thirdScore.Home, fourthScore.Home)
|
||||
awayTeamHighestQuarter := max(firstScore.Away, secondScore.Away, thirdScore.Away, fourthScore.Away)
|
||||
|
||||
|
|
@ -811,11 +839,11 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Handicap and Total betting is a combination of spread betting and total points betting
|
||||
// where the bettor predicts the outcome of a match with a point spread and the total number of points scored is over or under a specified number.
|
||||
func evaluateHandicapAndTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Handicap and Total betting is a combination of spread betting and total points betting
|
||||
// where the bettor predicts the outcome of a match with a point spread and the total number of points scored is over or under a specified number.
|
||||
func evaluateHandicapAndTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
|
||||
nameSplit := strings.Split(outcome.OddName, " ")
|
||||
// Evaluate from bottom to get the threshold and find out if its over or under
|
||||
|
|
@ -843,10 +871,12 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
}
|
||||
|
||||
teamName := strings.TrimSpace(strings.Join(nameSplit[:len(nameSplit)-4], ""))
|
||||
|
||||
adjustedHomeScore := float64(score.Home)
|
||||
adjustedAwayScore := float64(score.Away)
|
||||
|
||||
outcome.HomeTeamName = strings.Join(strings.Split(outcome.HomeTeamName, " "), "")
|
||||
outcome.AwayTeamName = strings.Join(strings.Split(outcome.AwayTeamName, " "), "")
|
||||
|
||||
switch teamName {
|
||||
case outcome.HomeTeamName:
|
||||
adjustedHomeScore += handicap
|
||||
|
|
@ -864,25 +894,25 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("failed parsing team name: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Winning Margin betting is a type of bet where the bettor predicts the margin of victory in a match.
|
||||
func evaluateWinningMargin(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
|
||||
marginSplit := strings.Split(outcome.OddName, "")
|
||||
if len(marginSplit) < 1 {
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
margin, err := strconv.ParseInt(marginSplit[0], 10, 64)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
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)
|
||||
}
|
||||
|
||||
isGtr := false
|
||||
if len(marginSplit) == 2 {
|
||||
isGtr = marginSplit[1] == "+"
|
||||
idx := len(outcome.OddName)
|
||||
if outcome.OddName[idx-1] == '+' {
|
||||
isGtr = true
|
||||
idx--
|
||||
}
|
||||
|
||||
margin, err := strconv.ParseInt(outcome.OddName[:idx], 10, 64)
|
||||
if err != nil {
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
switch outcome.OddHeader {
|
||||
case "1":
|
||||
if score.Home == (score.Away + int(margin)) {
|
||||
|
|
@ -892,19 +922,19 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
case "2":
|
||||
if (score.Home + int(margin)) == score.Away {
|
||||
if score.Away == (score.Home + int(margin)) {
|
||||
return domain.OUTCOME_STATUS_WIN, nil
|
||||
} else if isGtr && (score.Home+int(margin)) > score.Away {
|
||||
} else if isGtr && score.Away > (score.Home+int(margin)) {
|
||||
return domain.OUTCOME_STATUS_WIN, nil
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddheader: %s", outcome.OddHeader)
|
||||
}
|
||||
}
|
||||
|
||||
// Highest Scoring Period betting is a type of bet where the bettor predicts which period of the match will have the highest total score.
|
||||
func evaluateHighestScoringPeriod(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Highest Scoring Period betting is a type of bet where the bettor predicts which period of the match will have the highest total score.
|
||||
func evaluateHighestScoringPeriod(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
firstPeriodTotal := firstScore.Home + firstScore.Away
|
||||
secondPeriodTotal := secondScore.Home + secondScore.Away
|
||||
thirdPeriodTotal := thirdScore.Home + thirdScore.Away
|
||||
|
|
@ -930,10 +960,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Tied After Regulation is a type of bet where the bettor predicts whether the match will end in a tie after regulation time.
|
||||
func evaluateTiedAfterRegulation(outcome domain.BetOutcome, scores []struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
// Tied After Regulation is a type of bet where the bettor predicts whether the match will end in a tie after regulation time.
|
||||
func evaluateTiedAfterRegulation(outcome domain.BetOutcome, scores []struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
totalScore := struct{ Home, Away int }{0, 0}
|
||||
for _, score := range scores {
|
||||
totalScore.Home += score.Home
|
||||
|
|
@ -952,11 +982,10 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
return domain.OUTCOME_STATUS_LOSS, nil
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||
}
|
||||
|
||||
// evaluateRugbyOutcome evaluates the outcome of a Rugby bet
|
||||
func evaluateRugbyOutcome(outcome domain.BetOutcome, result *domain.RugbyResultResponse) (domain.OutcomeStatus, error) {
|
||||
func evaluateRugbyOutcome(outcome domain.BetOutcome, result *domain.RugbyResultResponse) (domain.OutcomeStatus, error) {
|
||||
finalScore := parseSS(result.SS)
|
||||
|
||||
switch outcome.MarketName {
|
||||
|
|
@ -969,10 +998,9 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
default:
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported rugby market: %s", outcome.MarketName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// evaluateBaseballOutcome evaluates the outcome of a Baseball bet
|
||||
func evaluateBaseballOutcome(outcome domain.BetOutcome, result *domain.BaseballResultResponse) (domain.OutcomeStatus, error) {
|
||||
func evaluateBaseballOutcome(outcome domain.BetOutcome, result *domain.BaseballResultResponse) (domain.OutcomeStatus, error) {
|
||||
finalScore := parseSS(result.SS)
|
||||
|
||||
switch outcome.MarketName {
|
||||
|
|
@ -985,4 +1013,13 @@ func evaluateTotalOverUnder(outcome domain.BetOutcome, score struct{ Home, Away
|
|||
default:
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported baseball market: %s", outcome.MarketName)
|
||||
}
|
||||
}
|
||||
|
||||
func evaluateVolleyballGamelines(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
switch outcome.OddName {
|
||||
case "Total":
|
||||
return evaluateTotalOverUnder(outcome, score)
|
||||
default:
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd name: %s", outcome.OddName)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,7 +227,9 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
// }
|
||||
|
||||
func (s *Service) fetchResult(ctx context.Context, eventID, oddID, marketID, sportID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
||||
// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
||||
url := fmt.Sprintf("https://api.b365api.com/v1/event/view?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to create request", "event_id", eventID, "error", err)
|
||||
|
|
@ -261,18 +263,70 @@ func (s *Service) fetchResult(ctx context.Context, eventID, oddID, marketID, spo
|
|||
switch sportID {
|
||||
case domain.FOOTBALL:
|
||||
result, err = s.parseFootball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse football", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.BASKETBALL:
|
||||
result, err = s.parseBasketball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse basketball", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.ICE_HOCKEY:
|
||||
result, err = s.parseIceHockey(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse ice hockey", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.CRICKET:
|
||||
result, err = s.parseCricket(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse cricket", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.VOLLEYBALL:
|
||||
result, err = s.parseVolleyball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse volleyball", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.DARTS:
|
||||
result, err = s.parseDarts(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse darts", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.FUTSAL:
|
||||
result, err = s.parseFutsal(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse futsal", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.AMERICAN_FOOTBALL:
|
||||
result, err = s.parseNFL(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse american football", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.RUGBY_UNION:
|
||||
result, err = s.parseRugbyUnion(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse rugby_union", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.RUGBY_LEAGUE:
|
||||
result, err = s.parseRugbyLeague(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse rugby_league", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
case domain.BASEBALL:
|
||||
result, err = s.parseBaseball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to parse baseball", "event id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
default:
|
||||
s.logger.Error("Unsupported sport", "sport", sportID)
|
||||
return domain.CreateResult{}, fmt.Errorf("unsupported sport: %v", sportID)
|
||||
|
|
@ -352,6 +406,7 @@ func (s *Service) parseFootball(resultRes json.RawMessage, eventID, oddID, marke
|
|||
|
||||
func (s *Service) parseBasketball(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
var basketBallRes domain.BasketballResultResponse
|
||||
|
||||
if err := json.Unmarshal(response, &basketBallRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal basketball result", "event_id", eventID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
|
|
@ -416,6 +471,121 @@ func (s *Service) parseIceHockey(response json.RawMessage, eventID, oddID, marke
|
|||
|
||||
}
|
||||
|
||||
func (s *Service) parseCricket(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
var cricketRes domain.CricketResultResponse
|
||||
|
||||
if err := json.Unmarshal(response, &cricketRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
if cricketRes.TimeStatus != "3" {
|
||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
||||
}
|
||||
|
||||
status, err := s.evaluateCricketOutcome(outcome, cricketRes)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
|
||||
return domain.CreateResult{
|
||||
BetOutcomeID: 0,
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
Status: status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) parseVolleyball(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
var volleyballRes domain.VolleyballResultResponse
|
||||
|
||||
if err := json.Unmarshal(response, &volleyballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
if volleyballRes.TimeStatus != "3" {
|
||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
||||
}
|
||||
|
||||
status, err := s.evaluateVolleyballOutcome(outcome, volleyballRes)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
|
||||
return domain.CreateResult{
|
||||
BetOutcomeID: 0,
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
Status: status,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) parseDarts(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
var dartsRes domain.DartsResultResponse
|
||||
|
||||
if err := json.Unmarshal(response, &dartsRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
|
||||
if dartsRes.TimeStatus != "3" {
|
||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
||||
}
|
||||
|
||||
// result for dart is limited
|
||||
// only ss is given, format with 2-4
|
||||
status, err := s.evaluateDartsOutcome(outcome, dartsRes)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
|
||||
return domain.CreateResult{
|
||||
BetOutcomeID: 0,
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
Status: status,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) parseFutsal(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
var futsalRes domain.FutsalResultResponse
|
||||
|
||||
if err := json.Unmarshal(response, &futsalRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
|
||||
if futsalRes.TimeStatus != "3" {
|
||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
||||
}
|
||||
|
||||
status, err := s.evaluateFutsalOutcome(outcome, futsalRes)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
|
||||
return domain.CreateResult{}, err
|
||||
}
|
||||
|
||||
return domain.CreateResult{
|
||||
BetOutcomeID: 0,
|
||||
EventID: eventID,
|
||||
OddID: oddID,
|
||||
MarketID: marketID,
|
||||
Status: status,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) parseNFL(resultRes json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||
var nflResp domain.NFLResultResponse
|
||||
if err := json.Unmarshal(resultRes, &nflResp); err != nil {
|
||||
|
|
@ -730,6 +900,92 @@ func (s *Service) evaluateIceHockeyOutcome(outcome domain.BetOutcome, res domain
|
|||
return domain.OUTCOME_STATUS_PENDING, nil
|
||||
}
|
||||
|
||||
func (s *Service) evaluateCricketOutcome(outcome domain.BetOutcome, res domain.CricketResultResponse) (domain.OutcomeStatus, error) {
|
||||
if !domain.SupportedMarkets[outcome.MarketID] {
|
||||
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
|
||||
}
|
||||
|
||||
score := parseSS(res.SS)
|
||||
|
||||
switch outcome.MarketID {
|
||||
case int64(domain.CRICKET_TO_WIN_THE_MATCH):
|
||||
return evaluateFullTimeResult(outcome, score)
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, nil
|
||||
}
|
||||
|
||||
func (s *Service) evaluateVolleyballOutcome(outcome domain.BetOutcome, res domain.VolleyballResultResponse) (domain.OutcomeStatus, error) {
|
||||
if !domain.SupportedMarkets[outcome.MarketID] {
|
||||
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
|
||||
}
|
||||
|
||||
score := parseSS(res.SS)
|
||||
|
||||
// res.SS example: { 2-3 } is the win count not actuall score of sets
|
||||
// for total score we need every set's score
|
||||
firstSet := parseScore(res.Scores.FirstSet.Home, res.Scores.FirstSet.Away)
|
||||
secondSet := parseScore(res.Scores.SecondSet.Home, res.Scores.SecondSet.Away)
|
||||
thirdSet := parseScore(res.Scores.ThirdSet.Home, res.Scores.ThirdSet.Away)
|
||||
fourthSet := parseScore(res.Scores.FourthSet.Home, res.Scores.FourthSet.Away)
|
||||
fivethSet := parseScore(res.Scores.FivethSet.Home, res.Scores.FivethSet.Away)
|
||||
|
||||
totalScore := struct{ Home, Away int }{Home: 0, Away: 0}
|
||||
totalScore.Home = firstSet.Home + secondSet.Home + thirdSet.Home + fourthSet.Home + fivethSet.Home
|
||||
totalScore.Away = firstSet.Away + secondSet.Away + thirdSet.Away + fourthSet.Away + fivethSet.Away
|
||||
|
||||
switch outcome.MarketID {
|
||||
case int64(domain.VOLLEYBALL_GAME_LINES):
|
||||
return evaluateVolleyballGamelines(outcome, totalScore)
|
||||
case int64(domain.VOLLEYBALL_MATCH_TOTAL_ODD_EVEN):
|
||||
return evaluateGoalsOddEven(outcome, totalScore)
|
||||
case int64(domain.VOLLEYBALL_CORRECT_SET_SCORE):
|
||||
return evaluateCorrectScore(outcome, score)
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, nil
|
||||
}
|
||||
|
||||
func (s *Service) evaluateDartsOutcome(outcome domain.BetOutcome, res domain.DartsResultResponse) (domain.OutcomeStatus, error) {
|
||||
if !domain.SupportedMarkets[outcome.MarketID] {
|
||||
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
|
||||
}
|
||||
|
||||
score := parseSS(res.SS)
|
||||
|
||||
switch outcome.MarketID {
|
||||
case int64(domain.DARTS_MATCH_WINNER):
|
||||
return evaluateFullTimeResult(outcome, score)
|
||||
case int64(domain.DARTS_TOTAL_LEGS):
|
||||
return evaluateTotalLegs(outcome, score)
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, nil
|
||||
}
|
||||
|
||||
func (s *Service) evaluateFutsalOutcome(outcome domain.BetOutcome, res domain.FutsalResultResponse) (domain.OutcomeStatus, error) {
|
||||
if !domain.SupportedMarkets[outcome.MarketID] {
|
||||
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
|
||||
}
|
||||
|
||||
score := parseSS(res.SS)
|
||||
|
||||
switch outcome.MarketID {
|
||||
case int64(domain.FUTSAL_GAME_LINES):
|
||||
return evaluateGameLines(outcome, score)
|
||||
case int64(domain.FUTSAL_MONEY_LINE):
|
||||
return evaluateMoneyLine(outcome, score)
|
||||
case int64(domain.FUTSAL_TEAM_TO_SCORE_FIRST):
|
||||
return evaluateFirstTeamToScore(outcome, res.Events)
|
||||
}
|
||||
|
||||
return domain.OUTCOME_STATUS_PENDING, nil
|
||||
}
|
||||
|
||||
func (s *Service) EvaluateNFLOutcome(outcome domain.BetOutcome, finalScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||
if !domain.SupportedMarkets[outcome.MarketID] {
|
||||
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
||||
|
|
|
|||
|
|
@ -1,49 +1 @@
|
|||
package result
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
func TestEvaluateFootballOutcome(t *testing.T) {
|
||||
service := &Service{} // or your real logger
|
||||
|
||||
// Mock outcome
|
||||
outcome := domain.BetOutcome{
|
||||
ID: 1,
|
||||
BetID: 1,
|
||||
EventID: 1001,
|
||||
OddID: 2001,
|
||||
SportID: 1, // Assuming 1 = Football
|
||||
HomeTeamName: "Manchester",
|
||||
AwayTeamName: "Liverpool",
|
||||
MarketID: int64(domain.FOOTBALL_FULL_TIME_RESULT),
|
||||
MarketName: "Full Time Result",
|
||||
Odd: 1.75,
|
||||
OddName: "2", // Home win
|
||||
OddHeader: "1",
|
||||
OddHandicap: "",
|
||||
Status: domain.OUTCOME_STATUS_PENDING, // Initial status
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
// Parsed result (simulate Bet365 JSON)
|
||||
finalScore := struct{ Home, Away int }{Home: 2, Away: 1}
|
||||
firstHalfScore := struct{ Home, Away int }{Home: 1, Away: 1}
|
||||
secondHalfScore := struct{ Home, Away int }{Home: 1, Away: 0}
|
||||
corners := struct{ Home, Away int }{Home: 5, Away: 3}
|
||||
halfTimeCorners := struct{ Home, Away int }{Home: 2, Away: 2}
|
||||
events := []map[string]string{
|
||||
{"type": "goal", "team": "home", "minute": "23"},
|
||||
{"type": "goal", "team": "away", "minute": "34"},
|
||||
}
|
||||
|
||||
// Act
|
||||
status, _ := service.evaluateFootballOutcome(outcome, finalScore, firstHalfScore, secondHalfScore, corners, halfTimeCorners, events)
|
||||
|
||||
fmt.Printf("\n\nBet Outcome: %v\n\n", &status)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package result
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -301,3 +303,678 @@ func TestBaseballMarkets(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateFootballOutcome(t *testing.T) {
|
||||
service := &Service{} // or your real logger
|
||||
|
||||
// Mock outcome
|
||||
outcome := domain.BetOutcome{
|
||||
ID: 1,
|
||||
BetID: 1,
|
||||
EventID: 1001,
|
||||
OddID: 2001,
|
||||
SportID: 1, // Assuming 1 = Football
|
||||
HomeTeamName: "Manchester",
|
||||
AwayTeamName: "Liverpool",
|
||||
MarketID: int64(domain.FOOTBALL_FULL_TIME_RESULT),
|
||||
MarketName: "Full Time Result",
|
||||
Odd: 1.75,
|
||||
OddName: "2", // Home win
|
||||
OddHeader: "1",
|
||||
OddHandicap: "",
|
||||
Status: domain.OUTCOME_STATUS_PENDING, // Initial status
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
// Parsed result (simulate Bet365 JSON)
|
||||
finalScore := struct{ Home, Away int }{Home: 2, Away: 1}
|
||||
firstHalfScore := struct{ Home, Away int }{Home: 1, Away: 1}
|
||||
secondHalfScore := struct{ Home, Away int }{Home: 1, Away: 0}
|
||||
corners := struct{ Home, Away int }{Home: 5, Away: 3}
|
||||
halfTimeCorners := struct{ Home, Away int }{Home: 2, Away: 2}
|
||||
events := []map[string]string{
|
||||
{"type": "goal", "team": "home", "minute": "23"},
|
||||
{"type": "goal", "team": "away", "minute": "34"},
|
||||
}
|
||||
|
||||
// Act
|
||||
status, _ := service.evaluateFootballOutcome(outcome, finalScore, firstHalfScore, secondHalfScore, corners, halfTimeCorners, events)
|
||||
|
||||
fmt.Printf("\n\nBet Outcome: %v\n\n", &status)
|
||||
|
||||
}
|
||||
func TestEvaluateTotalLegs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"OverTotalLegs", domain.BetOutcome{OddName: "3", OddHeader: "Over"}, struct{ Home, Away int }{2, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"OverTotalLegs", domain.BetOutcome{OddName: "3", OddHeader: "Under"}, struct{ Home, Away int }{2, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"UnderTotalLegs", domain.BetOutcome{OddName: "7", OddHeader: "Under"}, struct{ Home, Away int }{2, 3}, domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateTotalLegs(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateGameLines(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"GameLines - Total", domain.BetOutcome{OddName: "Total", OddHandicap: "O 5.5"}, struct{ Home, Away int }{2, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"GameLines - Total", domain.BetOutcome{OddName: "Total", OddHandicap: "O 5.5"}, struct{ Home, Away int }{2, 3}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"GameLines - Money Line", domain.BetOutcome{OddName: "Money Line", OddHeader: "1"}, struct{ Home, Away int }{2, 3}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"GameLines - Money Line", domain.BetOutcome{OddName: "Money Line", OddHeader: "1"}, struct{ Home, Away int }{3, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateGameLines(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateFirstTeamToScore(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
events []map[string]string
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"HomeScoreFirst", domain.BetOutcome{OddName: "1", HomeTeamName: "Team A", AwayTeamName: "Team B"}, []map[string]string{
|
||||
{"text": "1st Goal - Team A"},
|
||||
}, domain.OUTCOME_STATUS_WIN},
|
||||
{"AwayScoreFirst", domain.BetOutcome{OddName: "2", HomeTeamName: "Team A", AwayTeamName: "Team B"}, []map[string]string{
|
||||
{"text": "1st Goal - Team A"},
|
||||
}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"AwayScoreFirst", domain.BetOutcome{OddName: "2", HomeTeamName: "Team A", AwayTeamName: "Team B"}, []map[string]string{
|
||||
{"text": "1st Goal - Team B"},
|
||||
}, domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateFirstTeamToScore(tt.outcome, tt.events)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateGoalsOverUnder(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"LosingGoalsOver", domain.BetOutcome{OddHeader: "Over", OddName: "13"}, struct{ Home, Away int }{7, 5}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"WinningGoalsOver", domain.BetOutcome{OddHeader: "Over", OddName: "11"}, struct{ Home, Away int }{7, 5}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningGoalsUnder", domain.BetOutcome{OddHeader: "Under", OddName: "12"}, struct{ Home, Away int }{6, 5}, domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateGoalsOverUnder(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateGoalsOddEven(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningOddGoals", domain.BetOutcome{OddName: "Odd"}, struct{ Home, Away int }{7, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingEvenGoals", domain.BetOutcome{OddName: "Even"}, struct{ Home, Away int }{7, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"WinningEvenGoals", domain.BetOutcome{OddName: "Even"}, struct{ Home, Away int }{6, 6}, domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateGoalsOddEven(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateCorrectScore(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"CorrectScore", domain.BetOutcome{OddName: "7-4"}, struct{ Home, Away int }{7, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"CorrectScore", domain.BetOutcome{OddName: "6-6"}, struct{ Home, Away int }{6, 6}, domain.OUTCOME_STATUS_WIN},
|
||||
{"IncorrectScore", domain.BetOutcome{OddName: "2-3"}, struct{ Home, Away int }{7, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateCorrectScore(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateHighestScoringHalf(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
firstScore struct{ Home, Away int }
|
||||
secondScore struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"Winning1stHalf", domain.BetOutcome{OddName: "1st Half"}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"Losing1stHalf", domain.BetOutcome{OddName: "1st Half"}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{2, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Losing2ndHalf", domain.BetOutcome{OddName: "2nd Half"}, struct{ Home, Away int }{0, 0}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Winning2ndHalf", domain.BetOutcome{OddName: "2nd Half"}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{2, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateHighestScoringHalf(tt.outcome, tt.firstScore, tt.secondScore)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEvaluateHighestScoringQuarter(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
firstScore struct{ Home, Away int }
|
||||
secondScore struct{ Home, Away int }
|
||||
thirdScore struct{ Home, Away int }
|
||||
fourthScore struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"Winning1stQuarter", domain.BetOutcome{OddName: "1st Quarter"},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
struct{ Home, Away int }{1, 0},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
domain.OUTCOME_STATUS_WIN},
|
||||
{"Losing1stQuarter", domain.BetOutcome{OddName: "1st Quarter"},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
domain.OUTCOME_STATUS_LOSS},
|
||||
{"Losing2ndQuarter", domain.BetOutcome{OddName: "2nd Quarter"},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
domain.OUTCOME_STATUS_LOSS},
|
||||
{"Winning3rdQuarter", domain.BetOutcome{OddName: "3rd Quarter"},
|
||||
struct{ Home, Away int }{1, 0},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
domain.OUTCOME_STATUS_WIN},
|
||||
{"Wining4thQuarter", domain.BetOutcome{OddName: "4th Quarter"},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{0, 0},
|
||||
struct{ Home, Away int }{1, 1},
|
||||
struct{ Home, Away int }{2, 2},
|
||||
domain.OUTCOME_STATUS_WIN},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateHighestScoringQuarter(tt.outcome, tt.firstScore, tt.secondScore, tt.thirdScore, tt.fourthScore)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEvaluateWinningMargin(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningMargin", domain.BetOutcome{OddHeader: "1", OddName: "12"}, struct{ Home, Away int }{12, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningMargin", domain.BetOutcome{OddHeader: "2", OddName: "3"}, struct{ Home, Away int }{1, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningMargin", domain.BetOutcome{OddHeader: "1", OddName: "3+"}, struct{ Home, Away int }{4, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningMargin", domain.BetOutcome{OddHeader: "2", OddName: "12+"}, struct{ Home, Away int }{0, 13}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingMargin", domain.BetOutcome{OddHeader: "2", OddName: "3"}, struct{ Home, Away int }{0, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingMargin", domain.BetOutcome{OddHeader: "2", OddName: "3+"}, struct{ Home, Away int }{1, 3}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateWinningMargin(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateDoubleResult(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
firstHalfScore struct{ Home, Away int }
|
||||
fullTimeScore struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHomeAway", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A - Team B"}, struct{ Home, Away int }{1, 0}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAwayHome", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B - Team A"}, struct{ Home, Away int }{0, 1}, struct{ Home, Away int }{2, 1}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningTie", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Tie - Tie"}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{2, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningTieAway", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Tie - Team B"}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingHomeAway", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A - Team B"}, struct{ Home, Away int }{1, 0}, struct{ Home, Away int }{2, 0}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingTie", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Tie - Tie"}, struct{ Home, Away int }{1, 0}, struct{ Home, Away int }{1, 1}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingTieAway", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Tie - Team A"}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"BadInput", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A - "}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_PENDING},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateDoubleResult(tt.outcome, tt.firstHalfScore, tt.fullTimeScore)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateHighestScoringPeriod(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
firstScore struct{ Home, Away int }
|
||||
secondScore struct{ Home, Away int }
|
||||
thirdScore struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"Winning1stPeriod", domain.BetOutcome{OddName: "Period 1"}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{1, 1}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"Winning2ndPeriod", domain.BetOutcome{OddName: "Period 2"}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{2, 3}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"Winning3rdPeriod", domain.BetOutcome{OddName: "Period 3"}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{2, 3}, struct{ Home, Away int }{3, 3}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningTie", domain.BetOutcome{OddName: "Tie"}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"Losing1stPeriod", domain.BetOutcome{OddName: "Period 1"}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{2, 3}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Losing3rdPeriod", domain.BetOutcome{OddName: "Period 3"}, struct{ Home, Away int }{2, 2}, struct{ Home, Away int }{2, 3}, struct{ Home, Away int }{0, 0}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateHighestScoringPeriod(tt.outcome, tt.firstScore, tt.secondScore, tt.thirdScore)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalauteTiedAfterRegulation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score []struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningTied", domain.BetOutcome{OddName: "Yes"}, []struct{ Home, Away int }{{1, 0}, {0, 1}, {2, 2}}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningTied", domain.BetOutcome{OddName: "Yes"}, []struct{ Home, Away int }{{1, 1}, {0, 1}, {2, 2}, {2, 1}}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningNotTied", domain.BetOutcome{OddName: "No"}, []struct{ Home, Away int }{{0, 0}, {0, 0}, {0, 0}, {1, 0}}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingTied", domain.BetOutcome{OddName: "Yes"}, []struct{ Home, Away int }{{0, 2}, {0, 0}, {0, 0}, {0, 0}}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingNotTied", domain.BetOutcome{OddName: "No"}, []struct{ Home, Away int }{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateTiedAfterRegulation(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateTeamTotal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHomeUnder", domain.BetOutcome{OddHandicap: "Under 3", OddHeader: "1"}, struct{ Home, Away int }{2, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningHomeOver", domain.BetOutcome{OddHandicap: "Over 2", OddHeader: "1"}, struct{ Home, Away int }{3, 1}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAwayOver", domain.BetOutcome{OddHandicap: "Over 2", OddHeader: "2"}, struct{ Home, Away int }{1, 3}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingHomeOver", domain.BetOutcome{OddHandicap: "Over 2", OddHeader: "1"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingAwayOver", domain.BetOutcome{OddHandicap: "Over 2", OddHeader: "2"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateTeamTotal(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDrawNoBet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHome", domain.BetOutcome{OddName: "1"}, struct{ Home, Away int }{1, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAway", domain.BetOutcome{OddName: "2"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingHome", domain.BetOutcome{OddName: "1"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Tie", domain.BetOutcome{OddName: "1"}, struct{ Home, Away int }{1, 1}, domain.OUTCOME_STATUS_VOID},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateDrawNoBet(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateMoneyLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHome", domain.BetOutcome{OddHeader: "1"}, struct{ Home, Away int }{1, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAway", domain.BetOutcome{OddHeader: "2"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningTie", domain.BetOutcome{OddHeader: "Tie"}, struct{ Home, Away int }{2, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingTie", domain.BetOutcome{OddHeader: "1"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingAway", domain.BetOutcome{OddHeader: "2"}, struct{ Home, Away int }{3, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateMoneyLine(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateDoubleChance(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHomeOrDraw", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "1 or Draw"}, struct{ Home, Away int }{1, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningHomeOrDraw", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A or Draw"}, struct{ Home, Away int }{1, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAwayOrDraw", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Draw or Team B"}, struct{ Home, Away int }{0, 1}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingHomeorAway", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "1 or 2"}, struct{ Home, Away int }{1, 1}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingAwayOrDraw", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Draw or 2"}, struct{ Home, Away int }{2, 1}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateDoubleChance(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateResultAndTotal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHomeOver", domain.BetOutcome{OddHeader: "1", OddHandicap: "Over 4"}, struct{ Home, Away int }{3, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningHomeUnder", domain.BetOutcome{OddHeader: "1", OddHandicap: "Under 4"}, struct{ Home, Away int }{2, 1}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAwayUnder", domain.BetOutcome{OddHeader: "2", OddHandicap: "Under 4"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingHomeOver", domain.BetOutcome{OddHeader: "1", OddHandicap: "Under 4"}, struct{ Home, Away int }{3, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingAwayUnder", domain.BetOutcome{OddHeader: "2", OddHandicap: "Under 4"}, struct{ Home, Away int }{2, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateResultAndTotal(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckMultiOutcome(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.OutcomeStatus
|
||||
secondOutcome domain.OutcomeStatus
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"Win-Win", domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_WIN},
|
||||
{"Win-Void", domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_VOID, domain.OUTCOME_STATUS_HALF},
|
||||
{"Win-Loss", domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_LOSS, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Loss-Loss", domain.OUTCOME_STATUS_LOSS, domain.OUTCOME_STATUS_LOSS, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Loss-Void", domain.OUTCOME_STATUS_LOSS, domain.OUTCOME_STATUS_VOID, domain.OUTCOME_STATUS_VOID},
|
||||
{"Loss-Win", domain.OUTCOME_STATUS_LOSS, domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_LOSS},
|
||||
{"Void-Win", domain.OUTCOME_STATUS_VOID, domain.OUTCOME_STATUS_WIN, domain.OUTCOME_STATUS_VOID},
|
||||
{"Void-Loss", domain.OUTCOME_STATUS_VOID, domain.OUTCOME_STATUS_LOSS, domain.OUTCOME_STATUS_VOID},
|
||||
{"Void-Void", domain.OUTCOME_STATUS_VOID, domain.OUTCOME_STATUS_VOID, domain.OUTCOME_STATUS_VOID},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := checkMultiOutcome(tt.outcome, tt.secondOutcome)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateBTTSX(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningBothScoreX", domain.BetOutcome{OddName: "3", OddHeader: "Yes"}, struct{ Home, Away int }{3, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningBothScoreLess", domain.BetOutcome{OddName: "3", OddHeader: "No"}, struct{ Home, Away int }{2, 1}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingBothScoreX", domain.BetOutcome{OddName: "3", OddHeader: "Yes"}, struct{ Home, Away int }{2, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingBothScoreLess", domain.BetOutcome{OddName: "3", OddHeader: "No"}, struct{ Home, Away int }{2, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateBTTSX(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateResultAndBTTSX(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHomeAndBothScoreX", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A and Yes", OddHeader: "3"}, struct{ Home, Away int }{4, 3}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningHomeAndBothScoreLess", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A and No", OddHeader: "3"}, struct{ Home, Away int }{2, 1}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAwayAndBothScoreX", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B and Yes", OddHeader: "3"}, struct{ Home, Away int }{3, 4}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAwayAndBothScoreLess", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B and No", OddHeader: "3"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingHomeAndBothScoreX", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A and Yes", OddHeader: "3"}, struct{ Home, Away int }{3, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingHomeAndBothScoreX", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B and Yes", OddHeader: "3"}, struct{ Home, Away int }{4, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingAwayAndBothScoreX", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B and Yes", OddHeader: "3"}, struct{ Home, Away int }{2, 4}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateResultAndBTTSX(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateMoneyLine3Way(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"WinningHome", domain.BetOutcome{OddName: "1"}, struct{ Home, Away int }{1, 0}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningAway", domain.BetOutcome{OddName: "2"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"WinningTie", domain.BetOutcome{OddName: "Tie"}, struct{ Home, Away int }{2, 2}, domain.OUTCOME_STATUS_WIN},
|
||||
{"LosingTie", domain.BetOutcome{OddName: "1"}, struct{ Home, Away int }{1, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
{"LosingAway", domain.BetOutcome{OddName: "2"}, struct{ Home, Away int }{3, 2}, domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateMoneyLine3Way(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateAsianHandicap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{
|
||||
name: "Home -1 Win",
|
||||
outcome: domain.BetOutcome{OddHeader: "1", OddHandicap: "-1"},
|
||||
score: struct{ Home, Away int }{Home: 2, Away: 0},
|
||||
expected: domain.OUTCOME_STATUS_WIN,
|
||||
},
|
||||
{
|
||||
name: "Home -0.5 Win",
|
||||
outcome: domain.BetOutcome{OddHeader: "1", OddHandicap: "-0.5"},
|
||||
score: struct{ Home, Away int }{Home: 1, Away: 0},
|
||||
expected: domain.OUTCOME_STATUS_WIN,
|
||||
},
|
||||
{
|
||||
name: "Home -1 Void",
|
||||
outcome: domain.BetOutcome{OddHeader: "1", OddHandicap: "-1"},
|
||||
score: struct{ Home, Away int }{Home: 1, Away: 0},
|
||||
expected: domain.OUTCOME_STATUS_VOID,
|
||||
},
|
||||
{
|
||||
name: "Away +3 Win",
|
||||
outcome: domain.BetOutcome{OddHeader: "2", OddHandicap: "3"},
|
||||
score: struct{ Home, Away int }{Home: 1, Away: 2},
|
||||
expected: domain.OUTCOME_STATUS_WIN,
|
||||
},
|
||||
{
|
||||
name: "Split Handicap Home -0.5,-1 Win/Win",
|
||||
outcome: domain.BetOutcome{OddHeader: "1", OddHandicap: "-0.5,-1"},
|
||||
score: struct{ Home, Away int }{Home: 2, Away: 0},
|
||||
expected: domain.OUTCOME_STATUS_WIN,
|
||||
},
|
||||
{
|
||||
name: "Split Handicap Home -0.5,-1 Win/Void",
|
||||
outcome: domain.BetOutcome{OddHeader: "1", OddHandicap: "-0.5,-1"},
|
||||
score: struct{ Home, Away int }{Home: 1, Away: 0},
|
||||
expected: domain.OUTCOME_STATUS_WIN,
|
||||
},
|
||||
{
|
||||
name: "Invalid Handicap",
|
||||
outcome: domain.BetOutcome{OddHeader: "1", OddHandicap: "invalid"},
|
||||
score: struct{ Home, Away int }{Home: 1, Away: 0},
|
||||
expected: domain.OUTCOME_STATUS_ERROR,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateAsianHandicap(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluateHandicapAndTotal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outcome domain.BetOutcome
|
||||
score struct{ Home, Away int }
|
||||
expected domain.OutcomeStatus
|
||||
}{
|
||||
{"Home +2.5 Over 3", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A +2.5 & Over 3"},
|
||||
struct{ Home, Away int }{4, 0},
|
||||
domain.OUTCOME_STATUS_WIN},
|
||||
{"Away +2.5 Over 4", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B +2.5 & Over 4"},
|
||||
struct{ Home, Away int }{1, 5},
|
||||
domain.OUTCOME_STATUS_WIN},
|
||||
{"Home +2.5 Over 3", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A +2.5 & Over 3"},
|
||||
struct{ Home, Away int }{2, 0},
|
||||
domain.OUTCOME_STATUS_LOSS},
|
||||
{"Home -3.5 Over 3", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team A -2.5 & Over 3"},
|
||||
struct{ Home, Away int }{4, 3},
|
||||
domain.OUTCOME_STATUS_LOSS},
|
||||
{"Away -3 Over 4", domain.BetOutcome{HomeTeamName: "Team A", AwayTeamName: "Team B", OddName: "Team B -3 & Over 4"},
|
||||
struct{ Home, Away int }{3, 5},
|
||||
domain.OUTCOME_STATUS_LOSS},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
status, _ := evaluateHandicapAndTotal(tt.outcome, tt.score)
|
||||
if status != tt.expected {
|
||||
t.Errorf("expected %d, got %d", tt.expected, status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user