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,45 +73,20 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
|||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
|
||||
var data struct {
|
||||
Success int `json:"success"`
|
||||
Results [][]map[string]interface{} `json:"results"`
|
||||
}
|
||||
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 := []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 _, group := range data.Results {
|
||||
for _, ev := range group {
|
||||
if getString(ev["type"]) != "EV" {
|
||||
continue
|
||||
}
|
||||
|
||||
event := domain.Event{
|
||||
ID: getString(ev["ID"]),
|
||||
SportID: fmt.Sprintf("%d", sportID),
|
||||
MatchName: getString(ev["NA"]),
|
||||
Score: getString(ev["SS"]),
|
||||
MatchMinute: getInt(ev["TM"]),
|
||||
TimerStatus: getString(ev["TT"]),
|
||||
HomeTeamID: getString(ev["HT"]),
|
||||
AwayTeamID: getString(ev["AT"]),
|
||||
HomeKitImage: getString(ev["K1"]),
|
||||
AwayKitImage: getString(ev["K2"]),
|
||||
LeagueName: getString(ev["CT"]),
|
||||
LeagueID: getString(ev["C2"]),
|
||||
LeagueCC: getString(ev["CB"]),
|
||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||
IsLive: true,
|
||||
Status: "live",
|
||||
MatchPeriod: getInt(ev["MD"]),
|
||||
AddedTime: getInt(ev["TA"]),
|
||||
}
|
||||
|
||||
if err := s.store.SaveEvent(ctx, event); err != nil {
|
||||
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
|
||||
}
|
||||
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)
|
||||
|
|
@ -96,20 +95,128 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
|||
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 events
|
||||
}
|
||||
|
||||
for _, group := range data.Results {
|
||||
for _, ev := range group {
|
||||
if getString(ev["type"]) != "EV" {
|
||||
continue
|
||||
}
|
||||
|
||||
event := domain.Event{
|
||||
ID: getString(ev["ID"]),
|
||||
SportID: fmt.Sprintf("%d", sportID),
|
||||
MatchName: getString(ev["NA"]),
|
||||
Score: getString(ev["SS"]),
|
||||
MatchMinute: getInt(ev["TM"]),
|
||||
TimerStatus: getString(ev["TT"]),
|
||||
HomeTeamID: getString(ev["HT"]),
|
||||
AwayTeamID: getString(ev["AT"]),
|
||||
HomeKitImage: getString(ev["K1"]),
|
||||
AwayKitImage: getString(ev["K2"]),
|
||||
LeagueName: getString(ev["CT"]),
|
||||
LeagueID: getString(ev["C2"]),
|
||||
LeagueCC: getString(ev["CB"]),
|
||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||
IsLive: true,
|
||||
Status: "live",
|
||||
MatchPeriod: getInt(ev["MD"]),
|
||||
AddedTime: getInt(ev["TA"]),
|
||||
Source: "bet365",
|
||||
}
|
||||
|
||||
events = append(events, event)
|
||||
}
|
||||
}
|
||||
|
||||
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 _, 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 = 100
|
||||
var count int = 0
|
||||
for _, sportID := range sportIDs {
|
||||
var totalPages int = 1
|
||||
var page int = 0
|
||||
var limit int = 150
|
||||
var count int = 0
|
||||
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 {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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