diff --git a/cmd/main.go b/cmd/main.go index b15f76b..4008087 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -110,7 +110,13 @@ func main() { v := customvalidator.NewCustomValidator(validator.New()) // Initialize services - settingSvc := settings.NewService(repository.NewSettingStore(store)) + settingRepo := repository.NewSettingStore(store) + + if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil { + log.Fatalf("failed to ensure settings: %v", err) + } + settingSvc := settings.NewService(settingRepo) + messengerSvc := messenger.NewService(settingSvc, cfg) statSvc := stats.NewService( repository.NewCompanyStatStore(store), @@ -142,13 +148,21 @@ func main() { cfg, ) + marketSettingRepo := repository.NewMarketSettingStore(store) + + if err := marketSettingRepo.EnsureAllMarketSettingsExist(context.Background()); err != nil { + log.Fatalf("failed to ensure market settings: %v", err) + } + oddsSvc := odds.New( repository.NewOddStore(store), + marketSettingRepo, cfg, eventSvc, logger, domain.MongoDBLogger, ) + // virtuaGamesRepo := repository.NewVirtualGameRepository(store) // Initialize producer diff --git a/db/data/001_initial_seed_data.sql b/db/data/001_initial_seed_data.sql index ba8937c..1671b2b 100644 --- a/db/data/001_initial_seed_data.sql +++ b/db/data/001_initial_seed_data.sql @@ -81,8 +81,8 @@ VALUES ('sms_provider', 'afro_message'), ('max_unsettled_bets', '100'), ('bet_amount_limit', '10000000'), ('daily_ticket_limit', '50'), - ('total_winnings_limit', '100000000000'), - ('total_winnings_notify', '100000000'), + ('total_winnings_limit', '100000000'), + ('total_winnings_notify', '10000000'), ('amount_for_bet_referral', '1000000'), ('cashback_amount_cap', '1000'), ('default_winning_limit', '5000000'), diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index b94a01e..37f53b7 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -438,6 +438,21 @@ CREATE TABLE company_odd_settings ( updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE (company_id, odds_market_id) ); +CREATE TABLE global_odd_market_settings ( + market_id BIGINT NOT NULL, + market_name TEXT NOT NULL, + is_active BOOLEAN NOT NULL DEFAULT true, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE (market_id) +); +CREATE TABLE company_odd_market_settings ( + market_id BIGINT NOT NULL, + market_name TEXT NOT NULL, + company_id BIGINT NOT NULL, + is_active BOOLEAN, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE (company_id, market_id) +); CREATE TABLE result_log ( id BIGSERIAL PRIMARY KEY, status_not_finished_count INT NOT NULL, @@ -750,7 +765,7 @@ FROM customer_wallets cw LEFT JOIN LATERAL ( SELECT * FROM wallet_stats s - WHERE s.wallet_id = cw.regular_wallet + WHERE s.wallet_id = cw.regular_wallet_id ORDER BY s.interval_start DESC LIMIT 1 ) cs ON true; @@ -884,10 +899,12 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o - LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id; + LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id + LEFT JOIN company_odd_market_settings cms ON o.id = cms.market_id; CREATE VIEW report_request_detail AS SELECT r.*, c.name AS company_name, diff --git a/db/query/branch_stats.sql b/db/query/branch_stats.sql index 89d6814..23c42d7 100644 --- a/db/query/branch_stats.sql +++ b/db/query/branch_stats.sql @@ -5,7 +5,7 @@ bet_stats AS ( COUNT(*) AS total_bets, COALESCE(SUM(amount), 0) AS total_stake, COALESCE( - SUM(amount) * MAX(companies.deducted_percentage), + SUM(amount) * MAX(profit_percent), 0 ) AS deducted_stake, COALESCE( @@ -71,18 +71,18 @@ SELECT br.id AS branch_id, c.name AS company_name, c.slug AS company_slug, DATE_TRUNC('day', NOW() AT TIME ZONE 'UTC') AS interval_start, - COALESCE(b.total_bets, 0) AS total_bets, - COALESCE(b.total_stake, 0) AS total_stake, - COALESCE(b.deducted_stake, 0) AS deducted_stake, - COALESCE(b.total_cash_out, 0) AS total_cash_out, - COALESCE(b.total_cash_backs, 0) AS total_cash_backs, - COALESCE(b.number_of_unsettled, 0) AS number_of_unsettled, - COALESCE(b.total_unsettled_amount, 0) AS total_unsettled_amount, + COALESCE(bs.total_bets, 0) AS total_bets, + COALESCE(bs.total_stake, 0) AS total_stake, + COALESCE(bs.deducted_stake, 0) AS deducted_stake, + COALESCE(bs.total_cash_out, 0) AS total_cash_out, + COALESCE(bs.total_cash_backs, 0) AS total_cash_backs, + COALESCE(bs.number_of_unsettled, 0) AS number_of_unsettled, + COALESCE(bs.total_unsettled_amount, 0) AS total_unsettled_amount, COALESCE(bc.total_cashiers, 0) AS total_cashiers, NOW() AS updated_at FROM branches br LEFT JOIN companies c ON c.id = br.company_id - LEFT JOIN bet_stats bs ON b.branch_id = br.id + LEFT JOIN bet_stats bs ON bs.branch_id = br.id LEFT JOIN cashier_stats bc ON bc.branch_id = br.id ON CONFLICT (branch_id, interval_start) DO UPDATE SET total_bets = EXCLUDED.total_bets, diff --git a/db/query/company_stats.sql b/db/query/company_stats.sql index a588ec2..df202ab 100644 --- a/db/query/company_stats.sql +++ b/db/query/company_stats.sql @@ -122,7 +122,7 @@ SET total_bets = EXCLUDED.total_bets, total_unsettled_amount = EXCLUDED.total_unsettled_amount, total_admins = EXCLUDED.total_admins, total_managers = EXCLUDED.total_managers, - SETtotal_cashiers = EXCLUDED.total_cashiers, + total_cashiers = EXCLUDED.total_cashiers, total_customers = EXCLUDED.total_customers, total_approvers = EXCLUDED.total_approvers, total_branches = EXCLUDED.total_branches, diff --git a/db/query/events_with_settings.sql b/db/query/events_with_settings.sql index c9bbb34..8444ee2 100644 --- a/db/query/events_with_settings.sql +++ b/db/query/events_with_settings.sql @@ -83,7 +83,7 @@ SELECT e.*, FROM events e LEFT JOIN company_event_settings ces ON e.id = ces.event_id AND ces.company_id = $1 - LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id + LEFT JOIN event_bet_stats ebs ON ebs.event_id = e.id JOIN leagues l ON l.id = e.league_id LEFT JOIN ( SELECT event_id, @@ -157,9 +157,9 @@ SELECT e.*, COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount, COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings FROM events e - LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id - AND ces.company_id = $2 LEFT JOIN company_event_settings ces ON e.id = ces.event_id + AND ces.company_id = $2 + LEFT JOIN event_bet_stats ebs ON ebs.event_id = e.id JOIN leagues l ON l.id = e.league_id LEFT JOIN ( SELECT event_id, diff --git a/db/query/market_settings.sql b/db/query/market_settings.sql new file mode 100644 index 0000000..da8e138 --- /dev/null +++ b/db/query/market_settings.sql @@ -0,0 +1,57 @@ +-- name: InsertGlobalMarketSettings :exec +INSERT INTO global_odd_market_settings (market_id, market_name, is_active) +VALUES ($1, $2, $3) ON CONFLICT (market_id) DO +UPDATE +SET is_active = EXCLUDED.is_active, + updated_at = CURRENT_TIMESTAMP; +-- name: InsertCompanyMarketSettings :exec +INSERT INTO company_odd_market_settings (company_id, market_id, market_name, is_active) +VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, market_id) DO +UPDATE +SET is_active = EXCLUDED.is_active, + updated_at = CURRENT_TIMESTAMP; +-- name: GetAllGlobalMarketSettings :many +SELECT * +FROM global_odd_market_settings +LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); +-- name: GetGlobalMarketSettingsByID :one +SELECT * +FROM global_odd_market_settings +WHERE market_id = $1; +-- name: GetAllCompanyMarketSettings :many +SELECT * +FROM company_odd_market_settings +WHERE ( + company_id = sqlc.narg('company_id') + OR sqlc.narg('company_id') IS NULL + ) +LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); +-- name: GetCompanyMarketSettingsByID :one +SELECT * +FROM company_odd_market_settings +WHERE market_id = $1; +-- name: GetAllOverrideMarketSettings :many +SELECT gdm.market_id, + gdm.market_name, + COALESCE(cdm.is_active, gdm.is_active) AS is_active, + COALESCE(cdm.updated_at, gdm.updated_at) AS updated_at +FROM global_odd_market_settings gdm + LEFT JOIN company_odd_market_settings cdm ON cdm.market_id = gdm.market_id + AND company_id = $1 +LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); +-- name: GetOverrideMarketSettingByID :one +SELECT gdm.market_id, + gdm.market_name, + COALESCE(cdm.is_active, gdm.is_active) AS is_active, + COALESCE(cdm.updated_at, gdm.updated_at) AS updated_at +FROM global_odd_market_settings gdm + LEFT JOIN company_odd_market_settings cdm ON cdm.market_id = gdm.market_id + AND company_id = $1 +WHERE gdm.market_id = $2; +-- name: DeleteAllMarketSettingsForCompany :exec +DELETE FROM company_odd_market_settings +WHERE company_id = $1; +-- name: DeleteCompanyMarketSettings :exec +DELETE FROM company_odd_market_settings +WHERE market_id = $1 + AND company_id = $2; \ No newline at end of file diff --git a/db/query/odds.sql b/db/query/odds.sql index 6979426..e865522 100644 --- a/db/query/odds.sql +++ b/db/query/odds.sql @@ -18,7 +18,7 @@ VALUES ( $5, $6, $7, - $8, + $8, $9 ) ON CONFLICT (event_id, market_id) DO UPDATE @@ -57,11 +57,14 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $1 + AND cos.company_id = $1 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $1 LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); -- name: GetOddByID :one SELECT * @@ -85,12 +88,15 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $3 -WHERE market_id = $1 + AND cos.company_id = $3 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $3 +WHERE o.market_id = $1 AND event_id = $2; -- name: GetOddsWithSettingsByID :one SELECT o.id, @@ -105,11 +111,14 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $2 + AND cos.company_id = $2 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $2 WHERE o.id = $1; -- name: GetOddsByEventID :many SELECT * @@ -141,11 +150,14 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $2 + AND cos.company_id = $2 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $2 WHERE event_id = $1 LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); -- name: DeleteOddsForEvent :exec diff --git a/db/query/settings.sql b/db/query/settings.sql index e51c1ff..44e4691 100644 --- a/db/query/settings.sql +++ b/db/query/settings.sql @@ -1,3 +1,8 @@ +-- name: InsertGlobalSetting :exec +INSERT INTO global_settings (key, value) +VALUES ($1, $2) ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; -- name: GetGlobalSettings :many SELECT * FROM global_settings; diff --git a/gen/db/branch_stats.sql.go b/gen/db/branch_stats.sql.go index c39740d..781478c 100644 --- a/gen/db/branch_stats.sql.go +++ b/gen/db/branch_stats.sql.go @@ -150,7 +150,7 @@ bet_stats AS ( COUNT(*) AS total_bets, COALESCE(SUM(amount), 0) AS total_stake, COALESCE( - SUM(amount) * MAX(companies.deducted_percentage), + SUM(amount) * MAX(profit_percent), 0 ) AS deducted_stake, COALESCE( @@ -216,18 +216,18 @@ SELECT br.id AS branch_id, c.name AS company_name, c.slug AS company_slug, DATE_TRUNC('day', NOW() AT TIME ZONE 'UTC') AS interval_start, - COALESCE(b.total_bets, 0) AS total_bets, - COALESCE(b.total_stake, 0) AS total_stake, - COALESCE(b.deducted_stake, 0) AS deducted_stake, - COALESCE(b.total_cash_out, 0) AS total_cash_out, - COALESCE(b.total_cash_backs, 0) AS total_cash_backs, - COALESCE(b.number_of_unsettled, 0) AS number_of_unsettled, - COALESCE(b.total_unsettled_amount, 0) AS total_unsettled_amount, + COALESCE(bs.total_bets, 0) AS total_bets, + COALESCE(bs.total_stake, 0) AS total_stake, + COALESCE(bs.deducted_stake, 0) AS deducted_stake, + COALESCE(bs.total_cash_out, 0) AS total_cash_out, + COALESCE(bs.total_cash_backs, 0) AS total_cash_backs, + COALESCE(bs.number_of_unsettled, 0) AS number_of_unsettled, + COALESCE(bs.total_unsettled_amount, 0) AS total_unsettled_amount, COALESCE(bc.total_cashiers, 0) AS total_cashiers, NOW() AS updated_at FROM branches br LEFT JOIN companies c ON c.id = br.company_id - LEFT JOIN bet_stats bs ON b.branch_id = br.id + LEFT JOIN bet_stats bs ON bs.branch_id = br.id LEFT JOIN cashier_stats bc ON bc.branch_id = br.id ON CONFLICT (branch_id, interval_start) DO UPDATE SET total_bets = EXCLUDED.total_bets, diff --git a/gen/db/company_stats.sql.go b/gen/db/company_stats.sql.go index 72c1d83..1c4b6f8 100644 --- a/gen/db/company_stats.sql.go +++ b/gen/db/company_stats.sql.go @@ -272,7 +272,7 @@ SET total_bets = EXCLUDED.total_bets, total_unsettled_amount = EXCLUDED.total_unsettled_amount, total_admins = EXCLUDED.total_admins, total_managers = EXCLUDED.total_managers, - SETtotal_cashiers = EXCLUDED.total_cashiers, + total_cashiers = EXCLUDED.total_cashiers, total_customers = EXCLUDED.total_customers, total_approvers = EXCLUDED.total_approvers, total_branches = EXCLUDED.total_branches, diff --git a/gen/db/events_with_settings.sql.go b/gen/db/events_with_settings.sql.go index c320e67..c207058 100644 --- a/gen/db/events_with_settings.sql.go +++ b/gen/db/events_with_settings.sql.go @@ -28,9 +28,9 @@ SELECT e.id, e.source_event_id, e.sport_id, e.match_name, e.home_team, e.away_te COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount, COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings FROM events e - LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id - AND ces.company_id = $2 LEFT JOIN company_event_settings ces ON e.id = ces.event_id + AND ces.company_id = $2 + LEFT JOIN event_bet_stats ebs ON ebs.event_id = e.id JOIN leagues l ON l.id = e.league_id LEFT JOIN ( SELECT event_id, @@ -153,7 +153,7 @@ SELECT e.id, e.source_event_id, e.sport_id, e.match_name, e.home_team, e.away_te FROM events e LEFT JOIN company_event_settings ces ON e.id = ces.event_id AND ces.company_id = $1 - LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id + LEFT JOIN event_bet_stats ebs ON ebs.event_id = e.id JOIN leagues l ON l.id = e.league_id LEFT JOIN ( SELECT event_id, diff --git a/gen/db/market_settings.sql.go b/gen/db/market_settings.sql.go new file mode 100644 index 0000000..d8a58d4 --- /dev/null +++ b/gen/db/market_settings.sql.go @@ -0,0 +1,281 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: market_settings.sql + +package dbgen + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const DeleteAllMarketSettingsForCompany = `-- name: DeleteAllMarketSettingsForCompany :exec +DELETE FROM company_odd_market_settings +WHERE company_id = $1 +` + +func (q *Queries) DeleteAllMarketSettingsForCompany(ctx context.Context, companyID int64) error { + _, err := q.db.Exec(ctx, DeleteAllMarketSettingsForCompany, companyID) + return err +} + +const DeleteCompanyMarketSettings = `-- name: DeleteCompanyMarketSettings :exec +DELETE FROM company_odd_market_settings +WHERE market_id = $1 + AND company_id = $2 +` + +type DeleteCompanyMarketSettingsParams struct { + MarketID int64 `json:"market_id"` + CompanyID int64 `json:"company_id"` +} + +func (q *Queries) DeleteCompanyMarketSettings(ctx context.Context, arg DeleteCompanyMarketSettingsParams) error { + _, err := q.db.Exec(ctx, DeleteCompanyMarketSettings, arg.MarketID, arg.CompanyID) + return err +} + +const GetAllCompanyMarketSettings = `-- name: GetAllCompanyMarketSettings :many +SELECT market_id, market_name, company_id, is_active, updated_at +FROM company_odd_market_settings +WHERE ( + company_id = $1 + OR $1 IS NULL + ) +LIMIT $3 OFFSET $2 +` + +type GetAllCompanyMarketSettingsParams struct { + CompanyID pgtype.Int8 `json:"company_id"` + Offset pgtype.Int4 `json:"offset"` + Limit pgtype.Int4 `json:"limit"` +} + +func (q *Queries) GetAllCompanyMarketSettings(ctx context.Context, arg GetAllCompanyMarketSettingsParams) ([]CompanyOddMarketSetting, error) { + rows, err := q.db.Query(ctx, GetAllCompanyMarketSettings, arg.CompanyID, arg.Offset, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CompanyOddMarketSetting + for rows.Next() { + var i CompanyOddMarketSetting + if err := rows.Scan( + &i.MarketID, + &i.MarketName, + &i.CompanyID, + &i.IsActive, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetAllGlobalMarketSettings = `-- name: GetAllGlobalMarketSettings :many +SELECT market_id, market_name, is_active, updated_at +FROM global_odd_market_settings +LIMIT $2 OFFSET $1 +` + +type GetAllGlobalMarketSettingsParams struct { + Offset pgtype.Int4 `json:"offset"` + Limit pgtype.Int4 `json:"limit"` +} + +func (q *Queries) GetAllGlobalMarketSettings(ctx context.Context, arg GetAllGlobalMarketSettingsParams) ([]GlobalOddMarketSetting, error) { + rows, err := q.db.Query(ctx, GetAllGlobalMarketSettings, arg.Offset, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GlobalOddMarketSetting + for rows.Next() { + var i GlobalOddMarketSetting + if err := rows.Scan( + &i.MarketID, + &i.MarketName, + &i.IsActive, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetAllOverrideMarketSettings = `-- name: GetAllOverrideMarketSettings :many +SELECT gdm.market_id, + gdm.market_name, + COALESCE(cdm.is_active, gdm.is_active) AS is_active, + COALESCE(cdm.updated_at, gdm.updated_at) AS updated_at +FROM global_odd_market_settings gdm + LEFT JOIN company_odd_market_settings cdm ON cdm.market_id = gdm.market_id + AND company_id = $1 +LIMIT $3 OFFSET $2 +` + +type GetAllOverrideMarketSettingsParams struct { + CompanyID int64 `json:"company_id"` + Offset pgtype.Int4 `json:"offset"` + Limit pgtype.Int4 `json:"limit"` +} + +type GetAllOverrideMarketSettingsRow struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive bool `json:"is_active"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` +} + +func (q *Queries) GetAllOverrideMarketSettings(ctx context.Context, arg GetAllOverrideMarketSettingsParams) ([]GetAllOverrideMarketSettingsRow, error) { + rows, err := q.db.Query(ctx, GetAllOverrideMarketSettings, arg.CompanyID, arg.Offset, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAllOverrideMarketSettingsRow + for rows.Next() { + var i GetAllOverrideMarketSettingsRow + if err := rows.Scan( + &i.MarketID, + &i.MarketName, + &i.IsActive, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetCompanyMarketSettingsByID = `-- name: GetCompanyMarketSettingsByID :one +SELECT market_id, market_name, company_id, is_active, updated_at +FROM company_odd_market_settings +WHERE market_id = $1 +` + +func (q *Queries) GetCompanyMarketSettingsByID(ctx context.Context, marketID int64) (CompanyOddMarketSetting, error) { + row := q.db.QueryRow(ctx, GetCompanyMarketSettingsByID, marketID) + var i CompanyOddMarketSetting + err := row.Scan( + &i.MarketID, + &i.MarketName, + &i.CompanyID, + &i.IsActive, + &i.UpdatedAt, + ) + return i, err +} + +const GetGlobalMarketSettingsByID = `-- name: GetGlobalMarketSettingsByID :one +SELECT market_id, market_name, is_active, updated_at +FROM global_odd_market_settings +WHERE market_id = $1 +` + +func (q *Queries) GetGlobalMarketSettingsByID(ctx context.Context, marketID int64) (GlobalOddMarketSetting, error) { + row := q.db.QueryRow(ctx, GetGlobalMarketSettingsByID, marketID) + var i GlobalOddMarketSetting + err := row.Scan( + &i.MarketID, + &i.MarketName, + &i.IsActive, + &i.UpdatedAt, + ) + return i, err +} + +const GetOverrideMarketSettingByID = `-- name: GetOverrideMarketSettingByID :one +SELECT gdm.market_id, + gdm.market_name, + COALESCE(cdm.is_active, gdm.is_active) AS is_active, + COALESCE(cdm.updated_at, gdm.updated_at) AS updated_at +FROM global_odd_market_settings gdm + LEFT JOIN company_odd_market_settings cdm ON cdm.market_id = gdm.market_id + AND company_id = $1 +WHERE gdm.market_id = $2 +` + +type GetOverrideMarketSettingByIDParams struct { + CompanyID int64 `json:"company_id"` + MarketID int64 `json:"market_id"` +} + +type GetOverrideMarketSettingByIDRow struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive bool `json:"is_active"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` +} + +func (q *Queries) GetOverrideMarketSettingByID(ctx context.Context, arg GetOverrideMarketSettingByIDParams) (GetOverrideMarketSettingByIDRow, error) { + row := q.db.QueryRow(ctx, GetOverrideMarketSettingByID, arg.CompanyID, arg.MarketID) + var i GetOverrideMarketSettingByIDRow + err := row.Scan( + &i.MarketID, + &i.MarketName, + &i.IsActive, + &i.UpdatedAt, + ) + return i, err +} + +const InsertCompanyMarketSettings = `-- name: InsertCompanyMarketSettings :exec +INSERT INTO company_odd_market_settings (company_id, market_id, market_name, is_active) +VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, market_id) DO +UPDATE +SET is_active = EXCLUDED.is_active, + updated_at = CURRENT_TIMESTAMP +` + +type InsertCompanyMarketSettingsParams struct { + CompanyID int64 `json:"company_id"` + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive pgtype.Bool `json:"is_active"` +} + +func (q *Queries) InsertCompanyMarketSettings(ctx context.Context, arg InsertCompanyMarketSettingsParams) error { + _, err := q.db.Exec(ctx, InsertCompanyMarketSettings, + arg.CompanyID, + arg.MarketID, + arg.MarketName, + arg.IsActive, + ) + return err +} + +const InsertGlobalMarketSettings = `-- name: InsertGlobalMarketSettings :exec +INSERT INTO global_odd_market_settings (market_id, market_name, is_active) +VALUES ($1, $2, $3) ON CONFLICT (market_id) DO +UPDATE +SET is_active = EXCLUDED.is_active, + updated_at = CURRENT_TIMESTAMP +` + +type InsertGlobalMarketSettingsParams struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive bool `json:"is_active"` +} + +func (q *Queries) InsertGlobalMarketSettings(ctx context.Context, arg InsertGlobalMarketSettingsParams) error { + _, err := q.db.Exec(ctx, InsertGlobalMarketSettings, arg.MarketID, arg.MarketName, arg.IsActive) + return err +} diff --git a/gen/db/models.go b/gen/db/models.go index fc8102b..6e3c87e 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -230,6 +230,14 @@ type CompanyLeagueSetting struct { UpdatedAt pgtype.Timestamp `json:"updated_at"` } +type CompanyOddMarketSetting struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + CompanyID int64 `json:"company_id"` + IsActive pgtype.Bool `json:"is_active"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` +} + type CompanyOddSetting struct { ID int64 `json:"id"` CompanyID int64 `json:"company_id"` @@ -518,6 +526,13 @@ type Flag struct { Resolved pgtype.Bool `json:"resolved"` } +type GlobalOddMarketSetting struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive bool `json:"is_active"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` +} + type GlobalSetting struct { Key string `json:"key"` Value string `json:"value"` @@ -625,6 +640,7 @@ type OddsMarketWithSetting struct { ExpiresAt pgtype.Timestamp `json:"expires_at"` CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` + IsMarketActive bool `json:"is_market_active"` RawOdds []byte `json:"raw_odds"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } diff --git a/gen/db/odds.sql.go b/gen/db/odds.sql.go index 632f03c..d394b56 100644 --- a/gen/db/odds.sql.go +++ b/gen/db/odds.sql.go @@ -107,11 +107,14 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $1 + AND cos.company_id = $1 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $1 LIMIT $3 OFFSET $2 ` @@ -134,6 +137,7 @@ type GetAllOddsWithSettingsRow struct { ExpiresAt pgtype.Timestamp `json:"expires_at"` CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` + IsMarketActive bool `json:"is_market_active"` RawOdds []byte `json:"raw_odds"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } @@ -160,6 +164,7 @@ func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWith &i.ExpiresAt, &i.CompanyID, &i.IsActive, + &i.IsMarketActive, &i.RawOdds, &i.UpdatedAt, ); err != nil { @@ -321,11 +326,14 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $2 + AND cos.company_id = $2 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $2 WHERE event_id = $1 LIMIT $4 OFFSET $3 ` @@ -350,6 +358,7 @@ type GetOddsWithSettingsByEventIDRow struct { ExpiresAt pgtype.Timestamp `json:"expires_at"` CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` + IsMarketActive bool `json:"is_market_active"` RawOdds []byte `json:"raw_odds"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } @@ -381,6 +390,7 @@ func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsW &i.ExpiresAt, &i.CompanyID, &i.IsActive, + &i.IsMarketActive, &i.RawOdds, &i.UpdatedAt, ); err != nil { @@ -407,11 +417,14 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $2 + AND cos.company_id = $2 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $2 WHERE o.id = $1 ` @@ -433,6 +446,7 @@ type GetOddsWithSettingsByIDRow struct { ExpiresAt pgtype.Timestamp `json:"expires_at"` CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` + IsMarketActive bool `json:"is_market_active"` RawOdds []byte `json:"raw_odds"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } @@ -453,6 +467,7 @@ func (q *Queries) GetOddsWithSettingsByID(ctx context.Context, arg GetOddsWithSe &i.ExpiresAt, &i.CompanyID, &i.IsActive, + &i.IsMarketActive, &i.RawOdds, &i.UpdatedAt, ) @@ -472,12 +487,15 @@ SELECT o.id, o.expires_at, cos.company_id, COALESCE(cos.is_active, o.default_is_active) AS is_active, + COALESCE(cms.is_active, TRUE) AS is_market_active, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, cos.updated_at FROM odds_market o LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id - AND company_id = $3 -WHERE market_id = $1 + AND cos.company_id = $3 + LEFT JOIN company_odd_market_settings cms ON o.market_id = cms.market_id + AND cms.company_id = $3 +WHERE o.market_id = $1 AND event_id = $2 ` @@ -500,6 +518,7 @@ type GetOddsWithSettingsByMarketIDRow struct { ExpiresAt pgtype.Timestamp `json:"expires_at"` CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` + IsMarketActive bool `json:"is_market_active"` RawOdds []byte `json:"raw_odds"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } @@ -520,6 +539,7 @@ func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOdds &i.ExpiresAt, &i.CompanyID, &i.IsActive, + &i.IsMarketActive, &i.RawOdds, &i.UpdatedAt, ) @@ -546,7 +566,7 @@ VALUES ( $5, $6, $7, - $8, + $8, $9 ) ON CONFLICT (event_id, market_id) DO UPDATE diff --git a/gen/db/settings.sql.go b/gen/db/settings.sql.go index 96ea916..f4261fb 100644 --- a/gen/db/settings.sql.go +++ b/gen/db/settings.sql.go @@ -240,6 +240,23 @@ func (q *Queries) InsertCompanySetting(ctx context.Context, arg InsertCompanySet return err } +const InsertGlobalSetting = `-- name: InsertGlobalSetting :exec +INSERT INTO global_settings (key, value) +VALUES ($1, $2) ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value +` + +type InsertGlobalSettingParams struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func (q *Queries) InsertGlobalSetting(ctx context.Context, arg InsertGlobalSettingParams) error { + _, err := q.db.Exec(ctx, InsertGlobalSetting, arg.Key, arg.Value) + return err +} + const UpdateGlobalSetting = `-- name: UpdateGlobalSetting :exec UPDATE global_settings SET value = $2, diff --git a/internal/domain/market_settings.go b/internal/domain/market_settings.go new file mode 100644 index 0000000..62f8064 --- /dev/null +++ b/internal/domain/market_settings.go @@ -0,0 +1,169 @@ +package domain + +import ( + "time" + + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" +) + +type MarketSettings struct { + MarketID int64 + MarketName string + IsActive bool + UpdatedAt time.Time +} +type MarketSettingsRes struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive bool `json:"is_active"` + UpdatedAt time.Time `json:"updated_at"` +} + +type CreateGlobalMarketSettings struct { + MarketID int64 + MarketName string + IsActive bool +} + +type CreateCompanyMarketSettings struct { + CompanyID int64 + MarketID int64 + MarketName string + IsActive ValidBool +} +type CreateCompanyMarketSettingsReq struct { + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive *bool `json:"is_active,omitempty"` +} + +type CompanyMarketSettings struct { + CompanyID int64 + MarketID int64 + MarketName string + IsActive ValidBool + UpdatedAt time.Time +} + +type CompanyMarketSettingsRes struct { + CompanyID int64 `json:"company_id"` + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + IsActive bool `json:"is_active"` + UpdatedAt time.Time `json:"updated_at"` +} + +type MarketSettingFilter struct { + Limit ValidInt32 + Offset ValidInt32 +} +type CompanyMarketSettingFilter struct { + Limit ValidInt32 + Offset ValidInt32 + CompanyID ValidInt64 +} + +func ConvertMarketSettingsRes(setting MarketSettings) MarketSettingsRes { + return MarketSettingsRes{ + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: setting.IsActive, + UpdatedAt: setting.UpdatedAt, + } +} + +func ConvertMarketSettingsResList(settings []MarketSettings) []MarketSettingsRes { + result := make([]MarketSettingsRes, len(settings)) + for i, setting := range settings { + result[i] = ConvertMarketSettingsRes(setting) + } + return result +} + +func ConvertCreateCompanyMarketSettingsReq(setting CreateCompanyMarketSettingsReq, companyId int64) CreateCompanyMarketSettings { + return CreateCompanyMarketSettings{ + CompanyID: companyId, + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: ConvertBoolPtr(setting.IsActive), + } +} + +func ConvertCreateGlobalMarketSettings(setting CreateGlobalMarketSettings) dbgen.InsertGlobalMarketSettingsParams { + return dbgen.InsertGlobalMarketSettingsParams{ + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: setting.IsActive, + } +} + +func ConvertCreateCompanyMarketSettings(setting CreateCompanyMarketSettings) dbgen.InsertCompanyMarketSettingsParams { + return dbgen.InsertCompanyMarketSettingsParams{ + CompanyID: setting.CompanyID, + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: setting.IsActive.ToPG(), + } +} + +func ConvertDBGlobalMarketSettings(setting dbgen.GlobalOddMarketSetting) MarketSettings { + return MarketSettings{ + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: setting.IsActive, + UpdatedAt: setting.UpdatedAt.Time, + } +} + +func ConvertDBCompanyMarketSettingsList(settings []dbgen.CompanyOddMarketSetting) []CompanyMarketSettings { + result := make([]CompanyMarketSettings, len(settings)) + for i, setting := range settings { + result[i] = ConvertDBCompanyMarketSettings(setting) + } + return result +} +func ConvertDBCompanyMarketSettings(setting dbgen.CompanyOddMarketSetting) CompanyMarketSettings { + return CompanyMarketSettings{ + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: ValidBool{ + Value: setting.IsActive.Bool, + Valid: setting.IsActive.Valid, + }, + UpdatedAt: setting.UpdatedAt.Time, + } +} + +func ConvertDBGlobalMarketSettingsList(settings []dbgen.GlobalOddMarketSetting) []MarketSettings { + result := make([]MarketSettings, len(settings)) + for i, setting := range settings { + result[i] = ConvertDBGlobalMarketSettings(setting) + } + return result +} + +func ConvertDBGetAllOverrideMarketSettings(setting dbgen.GetAllOverrideMarketSettingsRow) MarketSettings { + return MarketSettings{ + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: setting.IsActive, + UpdatedAt: setting.UpdatedAt.Time, + } +} + +func ConvertDBGetOverrideMarketSettingsByID(setting dbgen.GetOverrideMarketSettingByIDRow) MarketSettings { + return MarketSettings{ + MarketID: setting.MarketID, + MarketName: setting.MarketName, + IsActive: setting.IsActive, + UpdatedAt: setting.UpdatedAt.Time, + } +} + +func ConvertDBGetAllOverrideMarketSettingsList(settings []dbgen.GetAllOverrideMarketSettingsRow) []MarketSettings { + result := make([]MarketSettings, len(settings)) + for i, setting := range settings { + result[i] = ConvertDBGetAllOverrideMarketSettings(setting) + } + return result +} diff --git a/internal/domain/market_string.go b/internal/domain/market_string.go new file mode 100644 index 0000000..2fa9d4d --- /dev/null +++ b/internal/domain/market_string.go @@ -0,0 +1,407 @@ +// Code generated by "stringer -type=Market"; DO NOT EDIT. + +package domain + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[FOOTBALL_FULL_TIME_RESULT-40] + _ = x[FOOTBALL_DOUBLE_CHANCE-10114] + _ = x[FOOTBALL_GOALS_OVER_UNDER-981] + _ = x[FOOTBALL_CORRECT_SCORE-43] + _ = x[FOOTBALL_ASIAN_HANDICAP-938] + _ = x[FOOTBALL_GOAL_LINE-10143] + _ = x[FOOTBALL_FULL_TIME_RESULT_ENHANCED-4001] + _ = x[FOOTBALL_BOTH_TEAMS_TO_SCORE-10150] + _ = x[FOOTBALL_RESULT_BOTH_TEAMS_TO_SCORE-50404] + _ = x[FOOTBALL_MATCH_GOAL_RANGE-177816] + _ = x[FOOTBALL_TEAM_GOAL_RANGE-177817] + _ = x[FOOTBALL_BOTH_TEAMS_TO_RECEIVE_CARDS-50942] + _ = x[FOOTBALL_FIRST_HALF_GOAL_RANGE-177819] + _ = x[FOOTBALL_SECOND_HALF_GOAL_RANGE-177820] + _ = x[FOOTBALL_RESULT_GOAL_RANGE-177821] + _ = x[FOOTBALL_DOUBLE_CHANCE_GOAL_RANGE-177822] + _ = x[FOOTBALL_HALF_TIME_RESULT-1579] + _ = x[FOOTBALL_FIRST_HALF_ASIAN_HANDICAP-50137] + _ = x[FOOTBALL_FIRST_HALF_GOAL_LINE-50136] + _ = x[FOOTBALL_FIRST_TEAM_TO_SCORE-1178] + _ = x[FOOTBALL_GOALS_ODD_EVEN-10111] + _ = x[FOOTBALL_DRAW_NO_BET-10544] + _ = x[FOOTBALL_HALF_TIME_DOUBLE_CHANCE-10257] + _ = x[FOOTBALL_HALF_TIME_RESULT_BOTH_TEAMS_TO_SCORE-50425] + _ = x[FOOTBALL_ALTERNATE_FIRST_HALF_ASIAN_HANDICAP-50265] + _ = x[FOOTBALL_ALTERNATE_FIRST_HALF_GOAL_LINE-50266] + _ = x[FOOTBALL_FIRST_HALF_HANDICAP-50264] + _ = x[FOOTBALL_ALTERNATE_FIRST_HALF_HANDICAP-10207] + _ = x[FOOTBALL_FIRST_HALF_GOAL-10538] + _ = x[FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN-10206] + _ = x[FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN-50433] + _ = x[FOOTBALL_HALF_TIME_CORRECT_SCORE-10540] + _ = x[FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF-50424] + _ = x[FOOTBALL_BOTH_TEAMS_TO_SCORE_SECOND_HALF-50432] + _ = x[FOOTBALL_TO_SCORE_IN_HALF-50419] + _ = x[FOOTBALL_HALF_WITH_MOST_GOALS-10537] + _ = x[FOOTBALL_HOME_TEAM_WITH_HIGHEST_SCORING_HALF-50417] + _ = x[FOOTBALL_AWAY_TEAM_WITH_HIGHEST_SCORING_HALF-50418] + _ = x[FOOTBALL_SECOND_HALF_RESULT-10208] + _ = x[FOOTBALL_SECOND_HALF_GOALS-10209] + _ = x[FOOTBALL_TEN_MINUTE_RESULT-10244] + _ = x[FOOTBALL_FIRST_TEN_MINUTE-10245] + _ = x[FOOTBALL_TEAM_PERFORMANCE-10110] + _ = x[FOOTBALL_TEAM_TOTAL_GOALS-10127] + _ = x[FOOTBALL_ASIAN_TOTAL_CARDS-10166] + _ = x[FOOTBALL_EXACT_TOTAL_GOALS-10203] + _ = x[FOOTBALL_ALTERNATIVE_HANDICAP_RESULT-10204] + _ = x[FOOTBALL_EXACT_FIRST_HALF_GOALS-10205] + _ = x[FOOTBALL_CLEAN_SHEET-10210] + _ = x[FOOTBALL_TEAMS_TO_SCORE-10211] + _ = x[FOOTBALL_TIME_OF_FIRST_TEAM_GOAL-10214] + _ = x[FOOTBALL_FIRST_GOAL_METHOD-10216] + _ = x[FOOTBALL_MULTI_SCORERS-10217] + _ = x[FOOTBALL_OWN_GOAL-10223] + _ = x[FOOTBALL_TO_SCORE_PENALTY-10229] + _ = x[FOOTBALL_TO_MISS_PENALTY-10230] + _ = x[FOOTBALL_ASIAN_HANDICAP_CARDS-10239] + _ = x[FOOTBALL_CARD_HANDICAP-10240] + _ = x[FOOTBALL_ALTERNATIVE_CARD_HANDICAP-10241] + _ = x[FOOTBALL_TEAM_CARDS-10242] + _ = x[FOOTBALL_EXACT_SECOND_HALF_GOALS-10252] + _ = x[FOOTBALL_EARLY_GOAL-10258] + _ = x[FOOTBALL_LATE_GOAL-10259] + _ = x[FOOTBALL_FIRST_MATCH_CORNER-10519] + _ = x[FOOTBALL_LAST_MATCH_CORNER-10520] + _ = x[FOOTBALL_LAST_TEAM_TO_SCORE-10534] + _ = x[FOOTBALL_CORNER_HANDICAP-10535] + _ = x[FOOTBALL_NUMBER_OF_GOALS_IN_MATCH-10536] + _ = x[FOOTBALL_TIME_OF_FIRST_GOAL_BRACKETS-10541] + _ = x[FOOTBALL_CORNER_MATCH_BET-1175] + _ = x[FOOTBALL_MULTI_CORNERS-1181] + _ = x[FOOTBALL_TIME_OF_FIRST_CARD-1183] + _ = x[FOOTBALL_HANDICAP_RESULT-171] + _ = x[FOOTBALL_TOTAL_GOAL_MINUTES-1776] + _ = x[FOOTBALL_PLAYER_TO_SCORE_ASSIST-177704] + _ = x[FOOTBALL_TEAM_TO_GET_MOST-177790] + _ = x[FOOTBALL_GOALSCORER-45] + _ = x[FOOTBALL_FIRST_CARD_RECEIVED-476] + _ = x[FOOTBALL_PLAYER_CARD-50135] + _ = x[FOOTBALL_ALTERNATIVE_ASIAN_HANDICAP-50138] + _ = x[FOOTBALL_ALTERNATIVE_GOAL_LINE-50139] + _ = x[FOOTBALL_HOME_TEAM_ODD_EVEN_GOALS-50406] + _ = x[FOOTBALL_AWAY_TEAM_ODD_EVEN_GOALS-50407] + _ = x[FOOTBALL_HOME_TEAM_EXACT_GOALS-50415] + _ = x[FOOTBALL_AWAY_TEAM_EXACT_GOALS-50416] + _ = x[FOOTBALL_HALF_TIME_RESULT_TOTAL_GOALS-50426] + _ = x[FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF_SECOND_HALF-50435] + _ = x[FOOTBALL_MATCH_SHOTS_ON_TARGET-50527] + _ = x[FOOTBALL_MATCH_SHOTS-50528] + _ = x[FOOTBALL_TEAM_SHOTS_ON_TARGET-50530] + _ = x[FOOTBALL_TEAM_SHOTS-50532] + _ = x[FOOTBALL_GOAL_METHOD-50962] + _ = x[FOOTBALL_WINNING_MARGIN-56] + _ = x[FOOTBALL_TIME_OF_FIRST_CORNER-761] + _ = x[FOOTBALL_TEAM_GOALSCORER-10151] + _ = x[FOOTBALL_PLAYER_SHOTS_ON_TARGET-50920] + _ = x[FOOTBALL_PLAYER_SHOTS-50921] + _ = x[FOOTBALL_SPECIALS-10224] + _ = x[FOOTBALL_CORNERS-760] + _ = x[FOOTBALL_CORNERS_TWO_WAY-10235] + _ = x[FOOTBALL_FIRST_HALF_CORNERS-10539] + _ = x[FOOTBALL_ASIAN_TOTAL_CORNERS-10164] + _ = x[FOOTBALL_FIRST_HALF_ASIAN_CORNERS-10233] + _ = x[FOOTBALL_ASIAN_HANDICAP_CORNERS-10165] + _ = x[FOOTBALL_ALTERNATIVE_CORNER-10234] + _ = x[FOOTBALL_CORNER_RACE-10238] + _ = x[FOOTBALL_NUMBER_OF_CARDS_IN_MATCH-10542] + _ = x[BASKETBALL_GAME_LINES-1453] + _ = x[BASKETBALL_FIRST_HALF-928] + _ = x[BASKETBALL_FIRST_QUARTER-941] + _ = x[BASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTS-181273] + _ = x[BASKETBALL_DOUBLE_RESULT-1517] + _ = x[BASKETBALL_MATCH_RESULT_AND_TOTAL-181125] + _ = x[BASKETBALL_MATCH_HANDICAP_AND_TOTAL-181126] + _ = x[BASKETBALL_RACE_TO_20_POINTS-1503] + _ = x[BASKETBALL_TIED_AT_END_OF_REGULATION-181127] + _ = x[BASKETBALL_QUARTER_CORRECT_SCORE-181276] + _ = x[BASKETBALL_FIRST_HALF_TEAM_TOTALS-181159] + _ = x[BASKETBALL_FIRST_HALF_WINNING_MARGIN-181185] + _ = x[BASKETBALL_FIRST_HALF_RESULT_AND_TOTAL-181181] + _ = x[BASKETBALL_FIRST_HALF_HANDICAP_AND_TOTAL-181182] + _ = x[BASKETBALL_FIRST_HALF_RACE_TO_POINTS-181186] + _ = x[BASKETBALL_FIRST_HALF_BOTH_TEAMS_TO_SCORE_X_POINTS-181195] + _ = x[BASKETBALL_FIRST_HALF_TEAM_TO_SCORE_X_POINTS-181198] + _ = x[BASKETBALL_FIRST_HALF_MONEY_LINE_3_WAY-181183] + _ = x[BASKETBALL_GAME_TOTAL_ODD_EVEN-180013] + _ = x[BASKETBALL_FIRST_QUARTER_TOTAL_ODD_EVEN-180170] + _ = x[BASKETBALL_FIRST_QUARTER_MARGIN_OF_VICTORY-180180] + _ = x[BASKETBALL_HIGHEST_SCORING_HALF-181131] + _ = x[BASKETBALL_HIGHEST_SCORING_QUARTER-181132] + _ = x[BASKETBALL_FIRST_HALF_DOUBLE_CHANCE-181184] + _ = x[BASKETBALL_FIRST_HALF_TOTAL_ODD_EVEN-181204] + _ = x[BASKETBALL_FIRST_QUARTER_3_WAY_LINES-181212] + _ = x[BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL-181242] + _ = x[BASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTAL-181243] + _ = x[BASKETBALL_FIRST_QUARTER_DOUBLE_CHANCE-181245] + _ = x[BASKETBALL_FIRST_QUARTER_RACE_TO_POINTS-181248] + _ = x[BASKETBALL_FIRST_QUARTER_BOTH_TEAMS_TO_SCORE_X_POINTS-181252] + _ = x[BASKETBALL_FIRST_QUARTER_TEAM_TO_SCORE_X_POINTS-181255] + _ = x[BASKETBALL_FIRST_QUARTER_TEAM_TOTALS-181220] + _ = x[BASKETBALL_FIRST_QUARTER_WINNING_MARGIN-181247] + _ = x[BASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTER-181377] + _ = x[BASKETBALL_TEAM_TOTALS-181335] + _ = x[BASKETBALL_TEAM_TOTAL_ODD_EVEN-1731] + _ = x[ICE_HOCKEY_GAME_LINES-972] + _ = x[ICE_HOCKEY_FIRST_PERIOD-1531] + _ = x[ICE_HOCKEY_THREE_WAY-170008] + _ = x[ICE_HOCKEY_DRAW_NO_BET-170447] + _ = x[ICE_HOCKEY_DOUBLE_CHANCE-170038] + _ = x[ICE_HOCKEY_WINNING_MARGIN-1556] + _ = x[ICE_HOCKEY_HIGHEST_SCORING_PERIOD-1557] + _ = x[ICE_HOCKEY_TIED_AFTER_REGULATION-170479] + _ = x[ICE_HOCKEY_WHEN_WILL_MATCH_END-170481] + _ = x[ICE_HOCKEY_GAME_TOTAL_ODD_EVEN-170013] + _ = x[ICE_HOCKEY_ALTERNATIVE_PUCK_LINE_TWO_WAY-170226] + _ = x[ICE_HOCKEY_ALTERNATIVE_TOTAL_TWO_WAY-170240] + _ = x[CRICKET_TO_WIN_THE_MATCH-1246] + _ = x[CRICKET_TEAM_TOP_BATTER-1241] + _ = x[CRICKET_TEAM_TOP_BOWLE-1242] + _ = x[CRICKET_PLAYER_OF_THE_MATCH-346] + _ = x[CRICKET_FIRST_WICKET_METHOD-30205] + _ = x[CRICKET_FIRST_OVER_TOTAL_RUNS-300336] + _ = x[CRICKET_FIRST_OVER_TOTAL_RUNS_Odd_Even-300118] + _ = x[CRICKET_FIRST_INNINIGS_SCORE-300338] + _ = x[CRICKET_INNINGS_OF_MATCH_BOWLED_OUT-300108] + _ = x[CRICKET_TOP_MATCH_BATTER-30245] + _ = x[CRICKET_TOP_MATCH_BOWLER-30246] + _ = x[VOLLEYBALL_GAME_LINES-910000] + _ = x[VOLLEYBALL_CORRECT_SET_SCORE-910201] + _ = x[VOLLEYBALL_MATCH_TOTAL_ODD_EVEN-910217] + _ = x[VOLLEYBALL_SET_ONE_LINES-910204] + _ = x[VOLLEYBALL_SET_ONE_TO_GO_TO_EXTRA_POINTS-910209] + _ = x[VOLLEYBALL_SET_ONE_TOTAL_ODD_EVEN-910218] + _ = x[DARTS_MATCH_WINNER-703] + _ = x[DARTS_MATCH_DOUBLE-150228] + _ = x[DARTS_MATCH_TREBLE-150230] + _ = x[DARTS_CORRECT_LEG_SCORE-150015] + _ = x[DARTS_TOTAL_LEGS-150117] + _ = x[DARTS_MOST_HUNDERED_EIGHTYS-150030] + _ = x[DARTS_TOTAL_HUNDERED_EIGHTYS-150012] + _ = x[DARTS_MOST_HUNDERED_EIGHTYS_HANDICAP-150227] + _ = x[DARTS_PLAYER_HUNDERED_EIGHTYS-150121] + _ = x[DARTS_FIRST_DART-150125] + _ = x[FUTSAL_GAME_LINES-830001] + _ = x[FUTSAL_MONEY_LINE-830130] + _ = x[FUTSAL_DOUBLE_RESULT_9_WAY-830124] + _ = x[FUTSAL_TEAM_TO_SCORE_FIRST-830141] + _ = x[FUTSAL_RACE_TO_GOALS-830142] + _ = x[AMERICAN_FOOTBALL_GAME_LINES-1441] + _ = x[RUGBY_L_GAME_BETTING_2_WAY-190006] + _ = x[RUGBY_U_GAME_BETTING_2_WAY-80007] + _ = x[BASEBALL_GAME_LINES-1096] +} + +const _Market_name = "FOOTBALL_FULL_TIME_RESULTFOOTBALL_CORRECT_SCOREFOOTBALL_GOALSCORERFOOTBALL_WINNING_MARGINFOOTBALL_HANDICAP_RESULTCRICKET_PLAYER_OF_THE_MATCHFOOTBALL_FIRST_CARD_RECEIVEDDARTS_MATCH_WINNERFOOTBALL_CORNERSFOOTBALL_TIME_OF_FIRST_CORNERBASKETBALL_FIRST_HALFFOOTBALL_ASIAN_HANDICAPBASKETBALL_FIRST_QUARTERICE_HOCKEY_GAME_LINESFOOTBALL_GOALS_OVER_UNDERBASEBALL_GAME_LINESFOOTBALL_CORNER_MATCH_BETFOOTBALL_FIRST_TEAM_TO_SCOREFOOTBALL_MULTI_CORNERSFOOTBALL_TIME_OF_FIRST_CARDCRICKET_TEAM_TOP_BATTERCRICKET_TEAM_TOP_BOWLECRICKET_TO_WIN_THE_MATCHAMERICAN_FOOTBALL_GAME_LINESBASKETBALL_GAME_LINESBASKETBALL_RACE_TO_20_POINTSBASKETBALL_DOUBLE_RESULTICE_HOCKEY_FIRST_PERIODICE_HOCKEY_WINNING_MARGINICE_HOCKEY_HIGHEST_SCORING_PERIODFOOTBALL_HALF_TIME_RESULTBASKETBALL_TEAM_TOTAL_ODD_EVENFOOTBALL_TOTAL_GOAL_MINUTESFOOTBALL_FULL_TIME_RESULT_ENHANCEDFOOTBALL_TEAM_PERFORMANCEFOOTBALL_GOALS_ODD_EVENFOOTBALL_DOUBLE_CHANCEFOOTBALL_TEAM_TOTAL_GOALSFOOTBALL_GOAL_LINEFOOTBALL_BOTH_TEAMS_TO_SCOREFOOTBALL_TEAM_GOALSCORERFOOTBALL_ASIAN_TOTAL_CORNERSFOOTBALL_ASIAN_HANDICAP_CORNERSFOOTBALL_ASIAN_TOTAL_CARDSFOOTBALL_EXACT_TOTAL_GOALSFOOTBALL_ALTERNATIVE_HANDICAP_RESULTFOOTBALL_EXACT_FIRST_HALF_GOALSFOOTBALL_FIRST_HALF_GOALS_ODD_EVENFOOTBALL_ALTERNATE_FIRST_HALF_HANDICAPFOOTBALL_SECOND_HALF_RESULTFOOTBALL_SECOND_HALF_GOALSFOOTBALL_CLEAN_SHEETFOOTBALL_TEAMS_TO_SCOREFOOTBALL_TIME_OF_FIRST_TEAM_GOALFOOTBALL_FIRST_GOAL_METHODFOOTBALL_MULTI_SCORERSFOOTBALL_OWN_GOALFOOTBALL_SPECIALSFOOTBALL_TO_SCORE_PENALTYFOOTBALL_TO_MISS_PENALTYFOOTBALL_FIRST_HALF_ASIAN_CORNERSFOOTBALL_ALTERNATIVE_CORNERFOOTBALL_CORNERS_TWO_WAYFOOTBALL_CORNER_RACEFOOTBALL_ASIAN_HANDICAP_CARDSFOOTBALL_CARD_HANDICAPFOOTBALL_ALTERNATIVE_CARD_HANDICAPFOOTBALL_TEAM_CARDSFOOTBALL_TEN_MINUTE_RESULTFOOTBALL_FIRST_TEN_MINUTEFOOTBALL_EXACT_SECOND_HALF_GOALSFOOTBALL_HALF_TIME_DOUBLE_CHANCEFOOTBALL_EARLY_GOALFOOTBALL_LATE_GOALFOOTBALL_FIRST_MATCH_CORNERFOOTBALL_LAST_MATCH_CORNERFOOTBALL_LAST_TEAM_TO_SCOREFOOTBALL_CORNER_HANDICAPFOOTBALL_NUMBER_OF_GOALS_IN_MATCHFOOTBALL_HALF_WITH_MOST_GOALSFOOTBALL_FIRST_HALF_GOALFOOTBALL_FIRST_HALF_CORNERSFOOTBALL_HALF_TIME_CORRECT_SCOREFOOTBALL_TIME_OF_FIRST_GOAL_BRACKETSFOOTBALL_NUMBER_OF_CARDS_IN_MATCHFOOTBALL_DRAW_NO_BETCRICKET_FIRST_WICKET_METHODCRICKET_TOP_MATCH_BATTERCRICKET_TOP_MATCH_BOWLERFOOTBALL_PLAYER_CARDFOOTBALL_FIRST_HALF_GOAL_LINEFOOTBALL_FIRST_HALF_ASIAN_HANDICAPFOOTBALL_ALTERNATIVE_ASIAN_HANDICAPFOOTBALL_ALTERNATIVE_GOAL_LINEFOOTBALL_FIRST_HALF_HANDICAPFOOTBALL_ALTERNATE_FIRST_HALF_ASIAN_HANDICAPFOOTBALL_ALTERNATE_FIRST_HALF_GOAL_LINEFOOTBALL_RESULT_BOTH_TEAMS_TO_SCOREFOOTBALL_HOME_TEAM_ODD_EVEN_GOALSFOOTBALL_AWAY_TEAM_ODD_EVEN_GOALSFOOTBALL_HOME_TEAM_EXACT_GOALSFOOTBALL_AWAY_TEAM_EXACT_GOALSFOOTBALL_HOME_TEAM_WITH_HIGHEST_SCORING_HALFFOOTBALL_AWAY_TEAM_WITH_HIGHEST_SCORING_HALFFOOTBALL_TO_SCORE_IN_HALFFOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALFFOOTBALL_HALF_TIME_RESULT_BOTH_TEAMS_TO_SCOREFOOTBALL_HALF_TIME_RESULT_TOTAL_GOALSFOOTBALL_BOTH_TEAMS_TO_SCORE_SECOND_HALFFOOTBALL_SECOND_HALF_GOALS_ODD_EVENFOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF_SECOND_HALFFOOTBALL_MATCH_SHOTS_ON_TARGETFOOTBALL_MATCH_SHOTSFOOTBALL_TEAM_SHOTS_ON_TARGETFOOTBALL_TEAM_SHOTSFOOTBALL_PLAYER_SHOTS_ON_TARGETFOOTBALL_PLAYER_SHOTSFOOTBALL_BOTH_TEAMS_TO_RECEIVE_CARDSFOOTBALL_GOAL_METHODRUGBY_U_GAME_BETTING_2_WAYDARTS_TOTAL_HUNDERED_EIGHTYSDARTS_CORRECT_LEG_SCOREDARTS_MOST_HUNDERED_EIGHTYSDARTS_TOTAL_LEGSDARTS_PLAYER_HUNDERED_EIGHTYSDARTS_FIRST_DARTDARTS_MOST_HUNDERED_EIGHTYS_HANDICAPDARTS_MATCH_DOUBLEDARTS_MATCH_TREBLEICE_HOCKEY_THREE_WAYICE_HOCKEY_GAME_TOTAL_ODD_EVENICE_HOCKEY_DOUBLE_CHANCEICE_HOCKEY_ALTERNATIVE_PUCK_LINE_TWO_WAYICE_HOCKEY_ALTERNATIVE_TOTAL_TWO_WAYICE_HOCKEY_DRAW_NO_BETICE_HOCKEY_TIED_AFTER_REGULATIONICE_HOCKEY_WHEN_WILL_MATCH_ENDFOOTBALL_PLAYER_TO_SCORE_ASSISTFOOTBALL_TEAM_TO_GET_MOSTFOOTBALL_MATCH_GOAL_RANGEFOOTBALL_TEAM_GOAL_RANGEFOOTBALL_FIRST_HALF_GOAL_RANGEFOOTBALL_SECOND_HALF_GOAL_RANGEFOOTBALL_RESULT_GOAL_RANGEFOOTBALL_DOUBLE_CHANCE_GOAL_RANGEBASKETBALL_GAME_TOTAL_ODD_EVENBASKETBALL_FIRST_QUARTER_TOTAL_ODD_EVENBASKETBALL_FIRST_QUARTER_MARGIN_OF_VICTORYBASKETBALL_MATCH_RESULT_AND_TOTALBASKETBALL_MATCH_HANDICAP_AND_TOTALBASKETBALL_TIED_AT_END_OF_REGULATIONBASKETBALL_HIGHEST_SCORING_HALFBASKETBALL_HIGHEST_SCORING_QUARTERBASKETBALL_FIRST_HALF_TEAM_TOTALSBASKETBALL_FIRST_HALF_RESULT_AND_TOTALBASKETBALL_FIRST_HALF_HANDICAP_AND_TOTALBASKETBALL_FIRST_HALF_MONEY_LINE_3_WAYBASKETBALL_FIRST_HALF_DOUBLE_CHANCEBASKETBALL_FIRST_HALF_WINNING_MARGINBASKETBALL_FIRST_HALF_RACE_TO_POINTSBASKETBALL_FIRST_HALF_BOTH_TEAMS_TO_SCORE_X_POINTSBASKETBALL_FIRST_HALF_TEAM_TO_SCORE_X_POINTSBASKETBALL_FIRST_HALF_TOTAL_ODD_EVENBASKETBALL_FIRST_QUARTER_3_WAY_LINESBASKETBALL_FIRST_QUARTER_TEAM_TOTALSBASKETBALL_FIRST_QUARTER_RESULT_AND_TOTALBASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTALBASKETBALL_FIRST_QUARTER_DOUBLE_CHANCEBASKETBALL_FIRST_QUARTER_WINNING_MARGINBASKETBALL_FIRST_QUARTER_RACE_TO_POINTSBASKETBALL_FIRST_QUARTER_BOTH_TEAMS_TO_SCORE_X_POINTSBASKETBALL_FIRST_QUARTER_TEAM_TO_SCORE_X_POINTSBASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTSBASKETBALL_QUARTER_CORRECT_SCOREBASKETBALL_TEAM_TOTALSBASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTERRUGBY_L_GAME_BETTING_2_WAYCRICKET_INNINGS_OF_MATCH_BOWLED_OUTCRICKET_FIRST_OVER_TOTAL_RUNS_Odd_EvenCRICKET_FIRST_OVER_TOTAL_RUNSCRICKET_FIRST_INNINIGS_SCOREFUTSAL_GAME_LINESFUTSAL_DOUBLE_RESULT_9_WAYFUTSAL_MONEY_LINEFUTSAL_TEAM_TO_SCORE_FIRSTFUTSAL_RACE_TO_GOALSVOLLEYBALL_GAME_LINESVOLLEYBALL_CORRECT_SET_SCOREVOLLEYBALL_SET_ONE_LINESVOLLEYBALL_SET_ONE_TO_GO_TO_EXTRA_POINTSVOLLEYBALL_MATCH_TOTAL_ODD_EVENVOLLEYBALL_SET_ONE_TOTAL_ODD_EVEN" + +var _Market_map = map[Market]string{ + 40: _Market_name[0:25], + 43: _Market_name[25:47], + 45: _Market_name[47:66], + 56: _Market_name[66:89], + 171: _Market_name[89:113], + 346: _Market_name[113:140], + 476: _Market_name[140:168], + 703: _Market_name[168:186], + 760: _Market_name[186:202], + 761: _Market_name[202:231], + 928: _Market_name[231:252], + 938: _Market_name[252:275], + 941: _Market_name[275:299], + 972: _Market_name[299:320], + 981: _Market_name[320:345], + 1096: _Market_name[345:364], + 1175: _Market_name[364:389], + 1178: _Market_name[389:417], + 1181: _Market_name[417:439], + 1183: _Market_name[439:466], + 1241: _Market_name[466:489], + 1242: _Market_name[489:511], + 1246: _Market_name[511:535], + 1441: _Market_name[535:563], + 1453: _Market_name[563:584], + 1503: _Market_name[584:612], + 1517: _Market_name[612:636], + 1531: _Market_name[636:659], + 1556: _Market_name[659:684], + 1557: _Market_name[684:717], + 1579: _Market_name[717:742], + 1731: _Market_name[742:772], + 1776: _Market_name[772:799], + 4001: _Market_name[799:833], + 10110: _Market_name[833:858], + 10111: _Market_name[858:881], + 10114: _Market_name[881:903], + 10127: _Market_name[903:928], + 10143: _Market_name[928:946], + 10150: _Market_name[946:974], + 10151: _Market_name[974:998], + 10164: _Market_name[998:1026], + 10165: _Market_name[1026:1057], + 10166: _Market_name[1057:1083], + 10203: _Market_name[1083:1109], + 10204: _Market_name[1109:1145], + 10205: _Market_name[1145:1176], + 10206: _Market_name[1176:1210], + 10207: _Market_name[1210:1248], + 10208: _Market_name[1248:1275], + 10209: _Market_name[1275:1301], + 10210: _Market_name[1301:1321], + 10211: _Market_name[1321:1344], + 10214: _Market_name[1344:1376], + 10216: _Market_name[1376:1402], + 10217: _Market_name[1402:1424], + 10223: _Market_name[1424:1441], + 10224: _Market_name[1441:1458], + 10229: _Market_name[1458:1483], + 10230: _Market_name[1483:1507], + 10233: _Market_name[1507:1540], + 10234: _Market_name[1540:1567], + 10235: _Market_name[1567:1591], + 10238: _Market_name[1591:1611], + 10239: _Market_name[1611:1640], + 10240: _Market_name[1640:1662], + 10241: _Market_name[1662:1696], + 10242: _Market_name[1696:1715], + 10244: _Market_name[1715:1741], + 10245: _Market_name[1741:1766], + 10252: _Market_name[1766:1798], + 10257: _Market_name[1798:1830], + 10258: _Market_name[1830:1849], + 10259: _Market_name[1849:1867], + 10519: _Market_name[1867:1894], + 10520: _Market_name[1894:1920], + 10534: _Market_name[1920:1947], + 10535: _Market_name[1947:1971], + 10536: _Market_name[1971:2004], + 10537: _Market_name[2004:2033], + 10538: _Market_name[2033:2057], + 10539: _Market_name[2057:2084], + 10540: _Market_name[2084:2116], + 10541: _Market_name[2116:2152], + 10542: _Market_name[2152:2185], + 10544: _Market_name[2185:2205], + 30205: _Market_name[2205:2232], + 30245: _Market_name[2232:2256], + 30246: _Market_name[2256:2280], + 50135: _Market_name[2280:2300], + 50136: _Market_name[2300:2329], + 50137: _Market_name[2329:2363], + 50138: _Market_name[2363:2398], + 50139: _Market_name[2398:2428], + 50264: _Market_name[2428:2456], + 50265: _Market_name[2456:2500], + 50266: _Market_name[2500:2539], + 50404: _Market_name[2539:2574], + 50406: _Market_name[2574:2607], + 50407: _Market_name[2607:2640], + 50415: _Market_name[2640:2670], + 50416: _Market_name[2670:2700], + 50417: _Market_name[2700:2744], + 50418: _Market_name[2744:2788], + 50419: _Market_name[2788:2813], + 50424: _Market_name[2813:2852], + 50425: _Market_name[2852:2897], + 50426: _Market_name[2897:2934], + 50432: _Market_name[2934:2974], + 50433: _Market_name[2974:3009], + 50435: _Market_name[3009:3060], + 50527: _Market_name[3060:3090], + 50528: _Market_name[3090:3110], + 50530: _Market_name[3110:3139], + 50532: _Market_name[3139:3158], + 50920: _Market_name[3158:3189], + 50921: _Market_name[3189:3210], + 50942: _Market_name[3210:3246], + 50962: _Market_name[3246:3266], + 80007: _Market_name[3266:3292], + 150012: _Market_name[3292:3320], + 150015: _Market_name[3320:3343], + 150030: _Market_name[3343:3370], + 150117: _Market_name[3370:3386], + 150121: _Market_name[3386:3415], + 150125: _Market_name[3415:3431], + 150227: _Market_name[3431:3467], + 150228: _Market_name[3467:3485], + 150230: _Market_name[3485:3503], + 170008: _Market_name[3503:3523], + 170013: _Market_name[3523:3553], + 170038: _Market_name[3553:3577], + 170226: _Market_name[3577:3617], + 170240: _Market_name[3617:3653], + 170447: _Market_name[3653:3675], + 170479: _Market_name[3675:3707], + 170481: _Market_name[3707:3737], + 177704: _Market_name[3737:3768], + 177790: _Market_name[3768:3793], + 177816: _Market_name[3793:3818], + 177817: _Market_name[3818:3842], + 177819: _Market_name[3842:3872], + 177820: _Market_name[3872:3903], + 177821: _Market_name[3903:3929], + 177822: _Market_name[3929:3962], + 180013: _Market_name[3962:3992], + 180170: _Market_name[3992:4031], + 180180: _Market_name[4031:4073], + 181125: _Market_name[4073:4106], + 181126: _Market_name[4106:4141], + 181127: _Market_name[4141:4177], + 181131: _Market_name[4177:4208], + 181132: _Market_name[4208:4242], + 181159: _Market_name[4242:4275], + 181181: _Market_name[4275:4313], + 181182: _Market_name[4313:4353], + 181183: _Market_name[4353:4391], + 181184: _Market_name[4391:4426], + 181185: _Market_name[4426:4462], + 181186: _Market_name[4462:4498], + 181195: _Market_name[4498:4548], + 181198: _Market_name[4548:4592], + 181204: _Market_name[4592:4628], + 181212: _Market_name[4628:4664], + 181220: _Market_name[4664:4700], + 181242: _Market_name[4700:4741], + 181243: _Market_name[4741:4784], + 181245: _Market_name[4784:4822], + 181247: _Market_name[4822:4861], + 181248: _Market_name[4861:4900], + 181252: _Market_name[4900:4953], + 181255: _Market_name[4953:5000], + 181273: _Market_name[5000:5050], + 181276: _Market_name[5050:5082], + 181335: _Market_name[5082:5104], + 181377: _Market_name[5104:5148], + 190006: _Market_name[5148:5174], + 300108: _Market_name[5174:5209], + 300118: _Market_name[5209:5247], + 300336: _Market_name[5247:5276], + 300338: _Market_name[5276:5304], + 830001: _Market_name[5304:5321], + 830124: _Market_name[5321:5347], + 830130: _Market_name[5347:5364], + 830141: _Market_name[5364:5390], + 830142: _Market_name[5390:5410], + 910000: _Market_name[5410:5431], + 910201: _Market_name[5431:5459], + 910204: _Market_name[5459:5483], + 910209: _Market_name[5483:5523], + 910217: _Market_name[5523:5554], + 910218: _Market_name[5554:5587], +} + +func (i Market) String() string { + if str, ok := _Market_map[i]; ok { + return str + } + return "Market(" + strconv.FormatInt(int64(i), 10) + ")" +} diff --git a/internal/domain/odds.go b/internal/domain/odds.go index 9d6ff2f..f082fd7 100644 --- a/internal/domain/odds.go +++ b/internal/domain/odds.go @@ -197,7 +197,7 @@ func ConvertDBOddMarketWithSetting(oms dbgen.OddsMarketWithSetting) (OddMarketWi RawOdds: rawOdds, FetchedAt: oms.FetchedAt.Time, ExpiresAt: oms.ExpiresAt.Time, - IsActive: oms.IsActive, + IsActive: oms.IsActive && oms.IsMarketActive, }, nil } diff --git a/internal/domain/setting_list.go b/internal/domain/setting_list.go index bd30ad9..b8b48f8 100644 --- a/internal/domain/setting_list.go +++ b/internal/domain/setting_list.go @@ -40,6 +40,63 @@ type SettingList struct { WelcomeBonusExpire int64 `json:"welcome_bonus_expiry"` } +// Default Global Settings added to the database if the setting isn't found +// This is already configured in the seed_data.sql, but just added it here too +// in case of database to code drift +func NewDefaultSettingList() SettingList { + return SettingList{ + SMSProvider: AfroMessage, //Provider that will be used for sending sms + MaxNumberOfOutcomes: 30, //Maximum number of outcomes for a single bet + MaxUnsettledBets: 100, //Maximum number of unsettled bets before system disabled bet service + BetAmountLimit: 10000000, //Maximum amount that can be bet (100,000.00 Birr Limit) + DailyTicketPerIP: 50, //Daily Number of Tickets That can be cut + TotalWinningLimit: 100000000, //Winning Limit (1,000,000.00 Birr) + TotalWinningNotify: 10000000, //Notify if user wins (100,000.00+ Birr) + AmountForBetReferral: 1000000, //Reward for bet referral (only for betting) (10,000.00 Birr) + CashbackAmountCap: 10.00, //Cashback amount limit (10 Birr) + DefaultWinningLimit: 5000000, //Birr Limit on single event (50,000.00) + ReferralRewardAmount: 10000, //Reward for user referral (100.00 Birr) + CashbackPercentage: 0.2, //Cashback Percent (20%) + DefaultMaxReferrals: 15, //Max number of user referrals (15) + MinimumBetAmount: 100, //Minimum Bet Amount (1 Birr) + BetDuplicateLimit: 5, //Maximum number of duplicate bets (5) + SendEmailOnBetFinish: true, //Whether to send email to user when he wins bet + SendSMSOnBetFinish: false, //Whether to send sms to user when he wins bet + WelcomeBonusActive: false, //Is Welcome Bonus in effect + WelcomeBonusMultiplier: 1.5, //Welcome Bonus Multiplier + WelcomeBonusCap: 100000, //Welcome Bonus Limit + WelcomeBonusCount: 3, //Maximum number of welcome bonuses given + WelcomeBonusExpire: 10, //Welcome Bonus Expiry + } +} + +func (s SettingList) ToSettingArray() []Setting { + return []Setting{ + {"sms_provider", string(s.SMSProvider), time.Now()}, + {"max_number_of_outcomes", strconv.FormatInt(s.MaxNumberOfOutcomes, 10), time.Now()}, + {"max_unsettled_bets", strconv.FormatInt(s.MaxUnsettledBets, 10), time.Now()}, + {"bet_amount_limit", strconv.FormatInt(int64(s.BetAmountLimit), 10), time.Now()}, + {"daily_ticket_limit", strconv.FormatInt(s.DailyTicketPerIP, 10), time.Now()}, + {"total_winnings_limit", strconv.FormatInt(int64(s.TotalWinningLimit), 10), time.Now()}, + {"total_winnings_notify", strconv.FormatInt(int64(s.TotalWinningNotify), 10), time.Now()}, + {"amount_for_bet_referral", strconv.FormatInt(int64(s.AmountForBetReferral), 10), time.Now()}, + {"cashback_amount_cap", strconv.FormatInt(int64(s.CashbackAmountCap), 10), time.Now()}, + {"default_winning_limit", strconv.FormatInt(s.DefaultWinningLimit, 10), time.Now()}, + {"referral_reward_amount", strconv.FormatInt(int64(s.ReferralRewardAmount), 10), time.Now()}, + {"cashback_percentage", strconv.FormatFloat(float64(s.CashbackPercentage), 'f', -1, 32), time.Now()}, + {"default_max_referrals", strconv.FormatInt(s.DefaultMaxReferrals, 10), time.Now()}, + {"minimum_bet_amount", strconv.FormatInt(int64(s.MinimumBetAmount), 10), time.Now()}, + {"bet_duplicate_limit", strconv.FormatInt(s.BetDuplicateLimit, 10), time.Now()}, + {"send_email_on_bet_finish", strconv.FormatBool(s.SendEmailOnBetFinish), time.Now()}, + {"send_sms_on_bet_finish", strconv.FormatBool(s.SendSMSOnBetFinish), time.Now()}, + {"welcome_bonus_active", strconv.FormatBool(s.WelcomeBonusActive), time.Now()}, + {"welcome_bonus_multiplier", strconv.FormatFloat(float64(s.WelcomeBonusMultiplier), 'f', -1, 32), time.Now()}, + {"welcome_bonus_cap", strconv.FormatInt(int64(s.WelcomeBonusCap), 10), time.Now()}, + {"welcome_bonus_count", strconv.FormatInt(s.WelcomeBonusCount, 10), time.Now()}, + {"welcome_bonus_expiry", strconv.FormatInt(s.WelcomeBonusExpire, 10), time.Now()}, + } +} + type SettingListRes struct { SMSProvider SMSProvider `json:"sms_provider"` MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"` @@ -596,6 +653,7 @@ func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, er if err := dbSettingList.SetSetting(setting.Key, setting.Value); err != nil { if err == ErrSettingNotFound { MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key)) + continue } MongoDBLogger.Error("unknown error while fetching settings", zap.Error(err)) } diff --git a/internal/domain/settings.go b/internal/domain/settings.go index dfed96a..f84a608 100644 --- a/internal/domain/settings.go +++ b/internal/domain/settings.go @@ -12,6 +12,11 @@ type Setting struct { UpdatedAt time.Time } +type CreateSetting struct { + Key string + Value string +} + type SettingRes struct { Key string `json:"key"` Value string `json:"value"` diff --git a/internal/domain/sportmarket.go b/internal/domain/sportmarket.go index 5e68a08..6e071ba 100644 --- a/internal/domain/sportmarket.go +++ b/internal/domain/sportmarket.go @@ -1,301 +1,301 @@ +//go:generate stringer -type=Market package domain -type FootballMarket int64 +import ( + "fmt" + "strings" +) + +func GetMarketName(id int64) (string, error) { + name := Market(id).String() + + if strings.HasPrefix(name, "Market(") { + return "", fmt.Errorf("prefix_incorrect_%d_name_%v", id, name) + } + + name = strings.ToLower(name) + name = strings.ReplaceAll(name, "_", " ") + + return name, nil +} + +type Market int64 const ( // Main - FOOTBALL_FULL_TIME_RESULT FootballMarket = 40 //"full_time_result" - FOOTBALL_DOUBLE_CHANCE FootballMarket = 10114 //"double_chance" - FOOTBALL_GOALS_OVER_UNDER FootballMarket = 981 //"goals_over_under" - FOOTBALL_CORRECT_SCORE FootballMarket = 43 //"correct_score" - FOOTBALL_ASIAN_HANDICAP FootballMarket = 938 //"asian_handicap" - FOOTBALL_GOAL_LINE FootballMarket = 10143 //"goal_line" + FOOTBALL_FULL_TIME_RESULT Market = 40 //"full_time_result" + FOOTBALL_DOUBLE_CHANCE Market = 10114 //"double_chance" + FOOTBALL_GOALS_OVER_UNDER Market = 981 //"goals_over_under" + FOOTBALL_CORRECT_SCORE Market = 43 //"correct_score" + FOOTBALL_ASIAN_HANDICAP Market = 938 //"asian_handicap" + FOOTBALL_GOAL_LINE Market = 10143 //"goal_line" // Main New - FOOTBALL_FULL_TIME_RESULT_ENHANCED FootballMarket = 4001 //"full_time_result_–_enhanced_prices" - FOOTBALL_BOTH_TEAMS_TO_SCORE FootballMarket = 10150 //"both_teams_to_score" - FOOTBALL_RESULT_BOTH_TEAMS_TO_SCORE FootballMarket = 50404 //"result_both_teams_to_score" - FOOTBALL_MATCH_GOAL_RANGE FootballMarket = 177816 //"match_goals_range" - FOOTBALL_TEAM_GOAL_RANGE FootballMarket = 177817 //"team_goals_range" - FOOTBALL_BOTH_TEAMS_TO_RECEIVE_CARDS FootballMarket = 50942 //"both_teams_to_receive_cards" - FOOTBALL_FIRST_HALF_GOAL_RANGE FootballMarket = 177819 //"1st_half_goals_range" - FOOTBALL_SECOND_HALF_GOAL_RANGE FootballMarket = 177820 //"2nd_half_goals_range" - FOOTBALL_RESULT_GOAL_RANGE FootballMarket = 177821 //"results_goals_range" - FOOTBALL_DOUBLE_CHANCE_GOAL_RANGE FootballMarket = 177822 //"double_chance_goals_range" + FOOTBALL_FULL_TIME_RESULT_ENHANCED Market = 4001 //"full_time_result_–_enhanced_prices" + FOOTBALL_BOTH_TEAMS_TO_SCORE Market = 10150 //"both_teams_to_score" + FOOTBALL_RESULT_BOTH_TEAMS_TO_SCORE Market = 50404 //"result_both_teams_to_score" + FOOTBALL_MATCH_GOAL_RANGE Market = 177816 //"match_goals_range" + FOOTBALL_TEAM_GOAL_RANGE Market = 177817 //"team_goals_range" + FOOTBALL_BOTH_TEAMS_TO_RECEIVE_CARDS Market = 50942 //"both_teams_to_receive_cards" + FOOTBALL_FIRST_HALF_GOAL_RANGE Market = 177819 //"1st_half_goals_range" + FOOTBALL_SECOND_HALF_GOAL_RANGE Market = 177820 //"2nd_half_goals_range" + FOOTBALL_RESULT_GOAL_RANGE Market = 177821 //"results_goals_range" + FOOTBALL_DOUBLE_CHANCE_GOAL_RANGE Market = 177822 //"double_chance_goals_range" // Half - FOOTBALL_HALF_TIME_RESULT FootballMarket = 1579 //"half_time_result" - FOOTBALL_FIRST_HALF_ASIAN_HANDICAP FootballMarket = 50137 //"1st_half_asian_handicap" - FOOTBALL_FIRST_HALF_GOAL_LINE FootballMarket = 50136 //"1st_half_goal_line" - FOOTBALL_FIRST_TEAM_TO_SCORE FootballMarket = 1178 //"first_team_to_score" - FOOTBALL_GOALS_ODD_EVEN FootballMarket = 10111 //"goals_odd_even" - FOOTBALL_DRAW_NO_BET FootballMarket = 10544 //"draw_no_bet" - FOOTBALL_HALF_TIME_DOUBLE_CHANCE FootballMarket = 10257 //"half_time_double_chance" - FOOTBALL_HALF_TIME_RESULT_BOTH_TEAMS_TO_SCORE FootballMarket = 50425 //"half_time_result_both_teams_to_score" - FOOTBALL_ALTERNATE_FIRST_HALF_ASIAN_HANDICAP FootballMarket = 50265 //"alternative_1st_half_asian_handicap" - FOOTBALL_ALTERNATE_FIRST_HALF_GOAL_LINE FootballMarket = 50266 //"alternative_1st_half_goal_line" - FOOTBALL_FIRST_HALF_HANDICAP FootballMarket = 50264 //"1st_half_handicap" - FOOTBALL_ALTERNATE_FIRST_HALF_HANDICAP FootballMarket = 10207 //"alternative_1st_half_handicap_result" - FOOTBALL_FIRST_HALF_GOAL FootballMarket = 10538 //"first_half_goals" - FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN FootballMarket = 10206 //"1st_half_goals_odd_even" - FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN FootballMarket = 50433 //"2nd_half_goals_odd_even" - FOOTBALL_HALF_TIME_CORRECT_SCORE FootballMarket = 10540 //"half_time_correct_score" - FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF FootballMarket = 50424 //"both_teams_to_score_in_1st_half" - FOOTBALL_BOTH_TEAMS_TO_SCORE_SECOND_HALF FootballMarket = 50432 //"both_teams_to_score_in_2nd_half" - FOOTBALL_TO_SCORE_IN_HALF FootballMarket = 50419 //"to_score_in_half" - FOOTBALL_HALF_WITH_MOST_GOALS FootballMarket = 10537 //"half_with_most_goals" - FOOTBALL_HOME_TEAM_WITH_HIGHEST_SCORING_HALF FootballMarket = 50417 //"home_team_highest_scoring_half" - FOOTBALL_AWAY_TEAM_WITH_HIGHEST_SCORING_HALF FootballMarket = 50418 //"away_team_highest_scoring_half" - FOOTBALL_SECOND_HALF_RESULT FootballMarket = 10208 //"2nd_half_result" - FOOTBALL_SECOND_HALF_GOALS FootballMarket = 10209 //"2nd_half_goals" + FOOTBALL_HALF_TIME_RESULT Market = 1579 //"half_time_result" + FOOTBALL_FIRST_HALF_ASIAN_HANDICAP Market = 50137 //"1st_half_asian_handicap" + FOOTBALL_FIRST_HALF_GOAL_LINE Market = 50136 //"1st_half_goal_line" + FOOTBALL_FIRST_TEAM_TO_SCORE Market = 1178 //"first_team_to_score" + FOOTBALL_GOALS_ODD_EVEN Market = 10111 //"goals_odd_even" + FOOTBALL_DRAW_NO_BET Market = 10544 //"draw_no_bet" + FOOTBALL_HALF_TIME_DOUBLE_CHANCE Market = 10257 //"half_time_double_chance" + FOOTBALL_HALF_TIME_RESULT_BOTH_TEAMS_TO_SCORE Market = 50425 //"half_time_result_both_teams_to_score" + FOOTBALL_ALTERNATE_FIRST_HALF_ASIAN_HANDICAP Market = 50265 //"alternative_1st_half_asian_handicap" + FOOTBALL_ALTERNATE_FIRST_HALF_GOAL_LINE Market = 50266 //"alternative_1st_half_goal_line" + FOOTBALL_FIRST_HALF_HANDICAP Market = 50264 //"1st_half_handicap" + FOOTBALL_ALTERNATE_FIRST_HALF_HANDICAP Market = 10207 //"alternative_1st_half_handicap_result" + FOOTBALL_FIRST_HALF_GOAL Market = 10538 //"first_half_goals" + FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN Market = 10206 //"1st_half_goals_odd_even" + FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN Market = 50433 //"2nd_half_goals_odd_even" + FOOTBALL_HALF_TIME_CORRECT_SCORE Market = 10540 //"half_time_correct_score" + FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF Market = 50424 //"both_teams_to_score_in_1st_half" + FOOTBALL_BOTH_TEAMS_TO_SCORE_SECOND_HALF Market = 50432 //"both_teams_to_score_in_2nd_half" + FOOTBALL_TO_SCORE_IN_HALF Market = 50419 //"to_score_in_half" + FOOTBALL_HALF_WITH_MOST_GOALS Market = 10537 //"half_with_most_goals" + FOOTBALL_HOME_TEAM_WITH_HIGHEST_SCORING_HALF Market = 50417 //"home_team_highest_scoring_half" + FOOTBALL_AWAY_TEAM_WITH_HIGHEST_SCORING_HALF Market = 50418 //"away_team_highest_scoring_half" + FOOTBALL_SECOND_HALF_RESULT Market = 10208 //"2nd_half_result" + FOOTBALL_SECOND_HALF_GOALS Market = 10209 //"2nd_half_goals" // Minutes - FOOTBALL_TEN_MINUTE_RESULT FootballMarket = 10244 //"10_minute_result" - FOOTBALL_FIRST_TEN_MINUTE FootballMarket = 10245 //"first_10_minutes_(00:00_09:59)" + FOOTBALL_TEN_MINUTE_RESULT Market = 10244 //"10_minute_result" + FOOTBALL_FIRST_TEN_MINUTE Market = 10245 //"first_10_minutes_(00:00_09:59)" // Others - FOOTBALL_TEAM_PERFORMANCE FootballMarket = 10110 //"team_performances" - FOOTBALL_TEAM_TOTAL_GOALS FootballMarket = 10127 //"team_total_goals" - FOOTBALL_ASIAN_TOTAL_CARDS FootballMarket = 10166 //"asian_total_cards" - FOOTBALL_EXACT_TOTAL_GOALS FootballMarket = 10203 //"asian_total_cards" - FOOTBALL_ALTERNATIVE_HANDICAP_RESULT FootballMarket = 10204 //"alternative_handicap_result" - FOOTBALL_EXACT_FIRST_HALF_GOALS FootballMarket = 10205 //"exact_1st_half_goals" - FOOTBALL_CLEAN_SHEET FootballMarket = 10210 //"clean_sheet" - FOOTBALL_TEAMS_TO_SCORE FootballMarket = 10211 //"teams_to_score" - FOOTBALL_TIME_OF_FIRST_TEAM_GOAL FootballMarket = 10214 //"time_of_1st_team_goal" - FOOTBALL_FIRST_GOAL_METHOD FootballMarket = 10216 //"first_goal_method" - FOOTBALL_MULTI_SCORERS FootballMarket = 10217 //"multi_scorers" - FOOTBALL_OWN_GOAL FootballMarket = 10223 //"own_goal" - FOOTBALL_TO_SCORE_PENALTY FootballMarket = 10229 //"to_score_a_penalty" - FOOTBALL_TO_MISS_PENALTY FootballMarket = 10230 //"to_miss_a_penalty" - FOOTBALL_ASIAN_HANDICAP_CARDS FootballMarket = 10239 //"asian_handicap_cards" - FOOTBALL_CARD_HANDICAP FootballMarket = 10240 //"card_handicap" - FOOTBALL_ALTERNATIVE_CARD_HANDICAP FootballMarket = 10241 //"alternative_card_handicap" - FOOTBALL_TEAM_CARDS FootballMarket = 10242 //"team_cards" - FOOTBALL_EXACT_SECOND_HALF_GOALS FootballMarket = 10252 //"exact_2nd_half_goals" - FOOTBALL_EARLY_GOAL FootballMarket = 10258 //"early_goal" - FOOTBALL_LATE_GOAL FootballMarket = 10259 //"late_goal" - FOOTBALL_FIRST_MATCH_CORNER FootballMarket = 10519 //"first_match_corner" - FOOTBALL_LAST_MATCH_CORNER FootballMarket = 10520 //"last_match_corner" - FOOTBALL_LAST_TEAM_TO_SCORE FootballMarket = 10534 //"last_team_to_score" - FOOTBALL_CORNER_HANDICAP FootballMarket = 10535 //"corner_handicap" - FOOTBALL_NUMBER_OF_GOALS_IN_MATCH FootballMarket = 10536 //"number_of_goals_in_match" - FOOTBALL_TIME_OF_FIRST_GOAL_BRACKETS FootballMarket = 10541 //"time_of_first_goal_brackets" - FOOTBALL_CORNER_MATCH_BET FootballMarket = 1175 //"corner_match_bet" - FOOTBALL_MULTI_CORNERS FootballMarket = 1181 //"Multicorners" - FOOTBALL_TIME_OF_FIRST_CARD FootballMarket = 1183 //"time_of_first_card" - FOOTBALL_HANDICAP_RESULT FootballMarket = 171 //"handicap_result" - FOOTBALL_TOTAL_GOAL_MINUTES FootballMarket = 1776 //"total_goal_minutes" - FOOTBALL_PLAYER_TO_SCORE_ASSIST FootballMarket = 177704 //"player_to_score_or_assist" - FOOTBALL_TEAM_TO_GET_MOST FootballMarket = 177790 //"team_to_get_most" - FOOTBALL_GOALSCORER FootballMarket = 45 //"goalscorers" - FOOTBALL_FIRST_CARD_RECEIVED FootballMarket = 476 //"first_card_received" - FOOTBALL_PLAYER_CARD FootballMarket = 50135 //"player_cards" - FOOTBALL_ALTERNATIVE_ASIAN_HANDICAP FootballMarket = 50138 //"alternative_asian_handicap" - FOOTBALL_ALTERNATIVE_GOAL_LINE FootballMarket = 50139 //"alternative_goal_line" - FOOTBALL_HOME_TEAM_ODD_EVEN_GOALS FootballMarket = 50406 //"home_team_odd_even_goals" - FOOTBALL_AWAY_TEAM_ODD_EVEN_GOALS FootballMarket = 50407 //"away_team_odd_even_goals" - FOOTBALL_HOME_TEAM_EXACT_GOALS FootballMarket = 50415 //"home_team_exact_goals" - FOOTBALL_AWAY_TEAM_EXACT_GOALS FootballMarket = 50416 //"away_team_exact_goals" - FOOTBALL_HALF_TIME_RESULT_TOTAL_GOALS FootballMarket = 50426 //"half_time_result_total_goals" - FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF_SECOND_HALF FootballMarket = 50435 //"both_teams_to_score_1st_half_2nd_half" - FOOTBALL_MATCH_SHOTS_ON_TARGET FootballMarket = 50527 //"match_shots_on_target" - FOOTBALL_MATCH_SHOTS FootballMarket = 50528 //"match_shots" - FOOTBALL_TEAM_SHOTS_ON_TARGET FootballMarket = 50530 //"team_shots_on_target" - FOOTBALL_TEAM_SHOTS FootballMarket = 50532 //"team_shots" - FOOTBALL_GOAL_METHOD FootballMarket = 50962 //"goal_method" - FOOTBALL_WINNING_MARGIN FootballMarket = 56 //"winning_margin" - FOOTBALL_TIME_OF_FIRST_CORNER FootballMarket = 761 //"time_of_first_corner" + FOOTBALL_TEAM_PERFORMANCE Market = 10110 //"team_performances" + FOOTBALL_TEAM_TOTAL_GOALS Market = 10127 //"team_total_goals" + FOOTBALL_ASIAN_TOTAL_CARDS Market = 10166 //"asian_total_cards" + FOOTBALL_EXACT_TOTAL_GOALS Market = 10203 //"asian_total_cards" + FOOTBALL_ALTERNATIVE_HANDICAP_RESULT Market = 10204 //"alternative_handicap_result" + FOOTBALL_EXACT_FIRST_HALF_GOALS Market = 10205 //"exact_1st_half_goals" + FOOTBALL_CLEAN_SHEET Market = 10210 //"clean_sheet" + FOOTBALL_TEAMS_TO_SCORE Market = 10211 //"teams_to_score" + FOOTBALL_TIME_OF_FIRST_TEAM_GOAL Market = 10214 //"time_of_1st_team_goal" + FOOTBALL_FIRST_GOAL_METHOD Market = 10216 //"first_goal_method" + FOOTBALL_MULTI_SCORERS Market = 10217 //"multi_scorers" + FOOTBALL_OWN_GOAL Market = 10223 //"own_goal" + FOOTBALL_TO_SCORE_PENALTY Market = 10229 //"to_score_a_penalty" + FOOTBALL_TO_MISS_PENALTY Market = 10230 //"to_miss_a_penalty" + FOOTBALL_ASIAN_HANDICAP_CARDS Market = 10239 //"asian_handicap_cards" + FOOTBALL_CARD_HANDICAP Market = 10240 //"card_handicap" + FOOTBALL_ALTERNATIVE_CARD_HANDICAP Market = 10241 //"alternative_card_handicap" + FOOTBALL_TEAM_CARDS Market = 10242 //"team_cards" + FOOTBALL_EXACT_SECOND_HALF_GOALS Market = 10252 //"exact_2nd_half_goals" + FOOTBALL_EARLY_GOAL Market = 10258 //"early_goal" + FOOTBALL_LATE_GOAL Market = 10259 //"late_goal" + FOOTBALL_FIRST_MATCH_CORNER Market = 10519 //"first_match_corner" + FOOTBALL_LAST_MATCH_CORNER Market = 10520 //"last_match_corner" + FOOTBALL_LAST_TEAM_TO_SCORE Market = 10534 //"last_team_to_score" + FOOTBALL_CORNER_HANDICAP Market = 10535 //"corner_handicap" + FOOTBALL_NUMBER_OF_GOALS_IN_MATCH Market = 10536 //"number_of_goals_in_match" + FOOTBALL_TIME_OF_FIRST_GOAL_BRACKETS Market = 10541 //"time_of_first_goal_brackets" + FOOTBALL_CORNER_MATCH_BET Market = 1175 //"corner_match_bet" + FOOTBALL_MULTI_CORNERS Market = 1181 //"Multicorners" + FOOTBALL_TIME_OF_FIRST_CARD Market = 1183 //"time_of_first_card" + FOOTBALL_HANDICAP_RESULT Market = 171 //"handicap_result" + FOOTBALL_TOTAL_GOAL_MINUTES Market = 1776 //"total_goal_minutes" + FOOTBALL_PLAYER_TO_SCORE_ASSIST Market = 177704 //"player_to_score_or_assist" + FOOTBALL_TEAM_TO_GET_MOST Market = 177790 //"team_to_get_most" + FOOTBALL_GOALSCORER Market = 45 //"goalscorers" + FOOTBALL_FIRST_CARD_RECEIVED Market = 476 //"first_card_received" + FOOTBALL_PLAYER_CARD Market = 50135 //"player_cards" + FOOTBALL_ALTERNATIVE_ASIAN_HANDICAP Market = 50138 //"alternative_asian_handicap" + FOOTBALL_ALTERNATIVE_GOAL_LINE Market = 50139 //"alternative_goal_line" + FOOTBALL_HOME_TEAM_ODD_EVEN_GOALS Market = 50406 //"home_team_odd_even_goals" + FOOTBALL_AWAY_TEAM_ODD_EVEN_GOALS Market = 50407 //"away_team_odd_even_goals" + FOOTBALL_HOME_TEAM_EXACT_GOALS Market = 50415 //"home_team_exact_goals" + FOOTBALL_AWAY_TEAM_EXACT_GOALS Market = 50416 //"away_team_exact_goals" + FOOTBALL_HALF_TIME_RESULT_TOTAL_GOALS Market = 50426 //"half_time_result_total_goals" + FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF_SECOND_HALF Market = 50435 //"both_teams_to_score_1st_half_2nd_half" + FOOTBALL_MATCH_SHOTS_ON_TARGET Market = 50527 //"match_shots_on_target" + FOOTBALL_MATCH_SHOTS Market = 50528 //"match_shots" + FOOTBALL_TEAM_SHOTS_ON_TARGET Market = 50530 //"team_shots_on_target" + FOOTBALL_TEAM_SHOTS Market = 50532 //"team_shots" + FOOTBALL_GOAL_METHOD Market = 50962 //"goal_method" + FOOTBALL_WINNING_MARGIN Market = 56 //"winning_margin" + FOOTBALL_TIME_OF_FIRST_CORNER Market = 761 //"time_of_first_corner" // Player - FOOTBALL_TEAM_GOALSCORER FootballMarket = 10151 //"team_goalscorer" - FOOTBALL_PLAYER_SHOTS_ON_TARGET FootballMarket = 50920 //"player_shots_on_target" - FOOTBALL_PLAYER_SHOTS FootballMarket = 50921 //"player_shots" + FOOTBALL_TEAM_GOALSCORER Market = 10151 //"team_goalscorer" + FOOTBALL_PLAYER_SHOTS_ON_TARGET Market = 50920 //"player_shots_on_target" + FOOTBALL_PLAYER_SHOTS Market = 50921 //"player_shots" // Specials - FOOTBALL_SPECIALS FootballMarket = 10224 //"specials + FOOTBALL_SPECIALS Market = 10224 //"specials // Corner - FOOTBALL_CORNERS FootballMarket = 760 //"corners" - FOOTBALL_CORNERS_TWO_WAY FootballMarket = 10235 //"corners_2_way" - FOOTBALL_FIRST_HALF_CORNERS FootballMarket = 10539 //"first_half_corners" - FOOTBALL_ASIAN_TOTAL_CORNERS FootballMarket = 10164 //"asian_total_corners" - FOOTBALL_FIRST_HALF_ASIAN_CORNERS FootballMarket = 10233 //"1st_half_asian_corners" - FOOTBALL_ASIAN_HANDICAP_CORNERS FootballMarket = 10165 //"asian_handicap_corners" - FOOTBALL_ALTERNATIVE_CORNER FootballMarket = 10234 //"alternative_corners" - FOOTBALL_CORNER_RACE FootballMarket = 10238 //"corners_race" + FOOTBALL_CORNERS Market = 760 //"corners" + FOOTBALL_CORNERS_TWO_WAY Market = 10235 //"corners_2_way" + FOOTBALL_FIRST_HALF_CORNERS Market = 10539 //"first_half_corners" + FOOTBALL_ASIAN_TOTAL_CORNERS Market = 10164 //"asian_total_corners" + FOOTBALL_FIRST_HALF_ASIAN_CORNERS Market = 10233 //"1st_half_asian_corners" + FOOTBALL_ASIAN_HANDICAP_CORNERS Market = 10165 //"asian_handicap_corners" + FOOTBALL_ALTERNATIVE_CORNER Market = 10234 //"alternative_corners" + FOOTBALL_CORNER_RACE Market = 10238 //"corners_race" // Cards - FOOTBALL_NUMBER_OF_CARDS_IN_MATCH FootballMarket = 10542 //"number_of_cards_in_match" + FOOTBALL_NUMBER_OF_CARDS_IN_MATCH Market = 10542 //"number_of_cards_in_match" ) -type BasketBallMarket int64 - +// Basketball Markets const ( // Main - BASKETBALL_GAME_LINES BasketBallMarket = 1453 //"game_lines" - BASKETBALL_FIRST_HALF BasketBallMarket = 928 //"1st_half" - BASKETBALL_FIRST_QUARTER BasketBallMarket = 941 //"1st_quarter" + BASKETBALL_GAME_LINES Market = 1453 //"game_lines" + BASKETBALL_FIRST_HALF Market = 928 //"1st_half" + BASKETBALL_FIRST_QUARTER Market = 941 //"1st_quarter" // Main Props - BASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTS BasketBallMarket = 181273 //"result_and_both_teams_to_score_'x'_points" - BASKETBALL_DOUBLE_RESULT BasketBallMarket = 1517 //"double_result" - BASKETBALL_MATCH_RESULT_AND_TOTAL BasketBallMarket = 181125 //"match_result_and_total" - BASKETBALL_MATCH_HANDICAP_AND_TOTAL BasketBallMarket = 181126 //"match_handicap_and_total" - BASKETBALL_RACE_TO_20_POINTS BasketBallMarket = 1503 //"race_to_20_points" - BASKETBALL_TIED_AT_END_OF_REGULATION BasketBallMarket = 181127 //"tied_at_end_of_regulation" - BASKETBALL_QUARTER_CORRECT_SCORE BasketBallMarket = 181276 //"quarter_correct_score" + BASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTS Market = 181273 //"result_and_both_teams_to_score_'x'_points" + BASKETBALL_DOUBLE_RESULT Market = 1517 //"double_result" + BASKETBALL_MATCH_RESULT_AND_TOTAL Market = 181125 //"match_result_and_total" + BASKETBALL_MATCH_HANDICAP_AND_TOTAL Market = 181126 //"match_handicap_and_total" + BASKETBALL_RACE_TO_20_POINTS Market = 1503 //"race_to_20_points" + BASKETBALL_TIED_AT_END_OF_REGULATION Market = 181127 //"tied_at_end_of_regulation" + BASKETBALL_QUARTER_CORRECT_SCORE Market = 181276 //"quarter_correct_score" // Half Props - BASKETBALL_FIRST_HALF_TEAM_TOTALS BasketBallMarket = 181159 //"1st_half_team_totals" - BASKETBALL_FIRST_HALF_WINNING_MARGIN BasketBallMarket = 181185 //"1st_half_winning_margin" - BASKETBALL_FIRST_HALF_RESULT_AND_TOTAL BasketBallMarket = 181181 //"1st_half_result_and_total" - BASKETBALL_FIRST_HALF_HANDICAP_AND_TOTAL BasketBallMarket = 181182 //"1st_half_handicap_and_total" - BASKETBALL_FIRST_HALF_RACE_TO_POINTS BasketBallMarket = 181186 //"1st_half_race_to_(points)" - BASKETBALL_FIRST_HALF_BOTH_TEAMS_TO_SCORE_X_POINTS BasketBallMarket = 181195 //"1st_half_both_teams_to_score_x_points" - BASKETBALL_FIRST_HALF_TEAM_TO_SCORE_X_POINTS BasketBallMarket = 181198 //"1st_half_team_to_score_x_points" - BASKETBALL_FIRST_HALF_MONEY_LINE_3_WAY BasketBallMarket = 181183 //"1st_half_money_line_3_way" + BASKETBALL_FIRST_HALF_TEAM_TOTALS Market = 181159 //"1st_half_team_totals" + BASKETBALL_FIRST_HALF_WINNING_MARGIN Market = 181185 //"1st_half_winning_margin" + BASKETBALL_FIRST_HALF_RESULT_AND_TOTAL Market = 181181 //"1st_half_result_and_total" + BASKETBALL_FIRST_HALF_HANDICAP_AND_TOTAL Market = 181182 //"1st_half_handicap_and_total" + BASKETBALL_FIRST_HALF_RACE_TO_POINTS Market = 181186 //"1st_half_race_to_(points)" + BASKETBALL_FIRST_HALF_BOTH_TEAMS_TO_SCORE_X_POINTS Market = 181195 //"1st_half_both_teams_to_score_x_points" + BASKETBALL_FIRST_HALF_TEAM_TO_SCORE_X_POINTS Market = 181198 //"1st_half_team_to_score_x_points" + BASKETBALL_FIRST_HALF_MONEY_LINE_3_WAY Market = 181183 //"1st_half_money_line_3_way" // Others - BASKETBALL_GAME_TOTAL_ODD_EVEN BasketBallMarket = 180013 //"game_total_odd_even" - BASKETBALL_FIRST_QUARTER_TOTAL_ODD_EVEN BasketBallMarket = 180170 //"1st_quarter_total_odd_even" - BASKETBALL_FIRST_QUARTER_MARGIN_OF_VICTORY BasketBallMarket = 180180 //"1st_quarter_margin_of_victory" - BASKETBALL_HIGHEST_SCORING_HALF BasketBallMarket = 181131 //"highest_scoring_half" - BASKETBALL_HIGHEST_SCORING_QUARTER BasketBallMarket = 181132 //"highest_scoring_quarter" - BASKETBALL_FIRST_HALF_DOUBLE_CHANCE BasketBallMarket = 181184 //"1st_half_double_chance" - BASKETBALL_FIRST_HALF_TOTAL_ODD_EVEN BasketBallMarket = 181204 //"1st_half_total_odd_even" - BASKETBALL_FIRST_QUARTER_3_WAY_LINES BasketBallMarket = 181212 //"1st_quarter_3_way_lines" - BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL BasketBallMarket = 181242 //"1st_quarter_result_and_total" - BASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTAL BasketBallMarket = 181243 //"1st_quarter_handicap_and_total" - BASKETBALL_FIRST_QUARTER_DOUBLE_CHANCE BasketBallMarket = 181245 //"1st_quarter_double_chance" - BASKETBALL_FIRST_QUARTER_RACE_TO_POINTS BasketBallMarket = 181248 //"1st_quarter_race_to_(points)" - BASKETBALL_FIRST_QUARTER_BOTH_TEAMS_TO_SCORE_X_POINTS BasketBallMarket = 181252 //"1st_quarter_both_teams_to_score_x_points" - BASKETBALL_FIRST_QUARTER_TEAM_TO_SCORE_X_POINTS BasketBallMarket = 181255 //"1st_quarter_team_to_score_x_points" + BASKETBALL_GAME_TOTAL_ODD_EVEN Market = 180013 //"game_total_odd_even" + BASKETBALL_FIRST_QUARTER_TOTAL_ODD_EVEN Market = 180170 //"1st_quarter_total_odd_even" + BASKETBALL_FIRST_QUARTER_MARGIN_OF_VICTORY Market = 180180 //"1st_quarter_margin_of_victory" + BASKETBALL_HIGHEST_SCORING_HALF Market = 181131 //"highest_scoring_half" + BASKETBALL_HIGHEST_SCORING_QUARTER Market = 181132 //"highest_scoring_quarter" + BASKETBALL_FIRST_HALF_DOUBLE_CHANCE Market = 181184 //"1st_half_double_chance" + BASKETBALL_FIRST_HALF_TOTAL_ODD_EVEN Market = 181204 //"1st_half_total_odd_even" + BASKETBALL_FIRST_QUARTER_3_WAY_LINES Market = 181212 //"1st_quarter_3_way_lines" + BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL Market = 181242 //"1st_quarter_result_and_total" + BASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTAL Market = 181243 //"1st_quarter_handicap_and_total" + BASKETBALL_FIRST_QUARTER_DOUBLE_CHANCE Market = 181245 //"1st_quarter_double_chance" + BASKETBALL_FIRST_QUARTER_RACE_TO_POINTS Market = 181248 //"1st_quarter_race_to_(points)" + BASKETBALL_FIRST_QUARTER_BOTH_TEAMS_TO_SCORE_X_POINTS Market = 181252 //"1st_quarter_both_teams_to_score_x_points" + BASKETBALL_FIRST_QUARTER_TEAM_TO_SCORE_X_POINTS Market = 181255 //"1st_quarter_team_to_score_x_points" // Quarter Props - BASKETBALL_FIRST_QUARTER_TEAM_TOTALS BasketBallMarket = 181220 //"1st_quarter_team_totals" - BASKETBALL_FIRST_QUARTER_WINNING_MARGIN BasketBallMarket = 181247 //"1st_quarter_winning_margin" + BASKETBALL_FIRST_QUARTER_TEAM_TOTALS Market = 181220 //"1st_quarter_team_totals" + BASKETBALL_FIRST_QUARTER_WINNING_MARGIN Market = 181247 //"1st_quarter_winning_margin" // Team Props - BASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTER BasketBallMarket = 181377 //"team_with_highest_scoring_quarter" - BASKETBALL_TEAM_TOTALS BasketBallMarket = 181335 //"team_totals" + BASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTER Market = 181377 //"team_with_highest_scoring_quarter" + BASKETBALL_TEAM_TOTALS Market = 181335 //"team_totals" - BASKETBALL_TEAM_TOTAL_ODD_EVEN BasketBallMarket = 1731 //"team_total_odd_even" + BASKETBALL_TEAM_TOTAL_ODD_EVEN Market = 1731 //"team_total_odd_even" ) -type IceHockeyMarket int64 - const ( // Main - ICE_HOCKEY_GAME_LINES IceHockeyMarket = 972 + ICE_HOCKEY_GAME_LINES Market = 972 - ICE_HOCKEY_FIRST_PERIOD IceHockeyMarket = 1531 - ICE_HOCKEY_THREE_WAY IceHockeyMarket = 170008 - ICE_HOCKEY_DRAW_NO_BET IceHockeyMarket = 170447 - ICE_HOCKEY_DOUBLE_CHANCE IceHockeyMarket = 170038 - ICE_HOCKEY_WINNING_MARGIN IceHockeyMarket = 1556 - ICE_HOCKEY_HIGHEST_SCORING_PERIOD IceHockeyMarket = 1557 - ICE_HOCKEY_TIED_AFTER_REGULATION IceHockeyMarket = 170479 - ICE_HOCKEY_WHEN_WILL_MATCH_END IceHockeyMarket = 170481 - ICE_HOCKEY_GAME_TOTAL_ODD_EVEN IceHockeyMarket = 170013 + ICE_HOCKEY_FIRST_PERIOD Market = 1531 + ICE_HOCKEY_THREE_WAY Market = 170008 + ICE_HOCKEY_DRAW_NO_BET Market = 170447 + ICE_HOCKEY_DOUBLE_CHANCE Market = 170038 + ICE_HOCKEY_WINNING_MARGIN Market = 1556 + ICE_HOCKEY_HIGHEST_SCORING_PERIOD Market = 1557 + ICE_HOCKEY_TIED_AFTER_REGULATION Market = 170479 + ICE_HOCKEY_WHEN_WILL_MATCH_END Market = 170481 + ICE_HOCKEY_GAME_TOTAL_ODD_EVEN Market = 170013 - ICE_HOCKEY_ALTERNATIVE_PUCK_LINE_TWO_WAY IceHockeyMarket = 170226 - ICE_HOCKEY_ALTERNATIVE_TOTAL_TWO_WAY IceHockeyMarket = 170240 + ICE_HOCKEY_ALTERNATIVE_PUCK_LINE_TWO_WAY Market = 170226 + ICE_HOCKEY_ALTERNATIVE_TOTAL_TWO_WAY Market = 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 + CRICKET_TO_WIN_THE_MATCH Market = 1246 + CRICKET_TEAM_TOP_BATTER Market = 1241 + CRICKET_TEAM_TOP_BOWLE Market = 1242 + CRICKET_PLAYER_OF_THE_MATCH Market = 346 + CRICKET_FIRST_WICKET_METHOD Market = 30205 // First Over - CRICKET_FIRST_OVER_TOTAL_RUNS CricketMarket = 300336 - CRICKET_FIRST_OVER_TOTAL_RUNS_Odd_Even CricketMarket = 300118 + CRICKET_FIRST_OVER_TOTAL_RUNS Market = 300336 + CRICKET_FIRST_OVER_TOTAL_RUNS_Odd_Even Market = 300118 // Inninigs 1 - CRICKET_FIRST_INNINIGS_SCORE CricketMarket = 300338 - CRICKET_INNINGS_OF_MATCH_BOWLED_OUT CricketMarket = 300108 + CRICKET_FIRST_INNINIGS_SCORE Market = 300338 + CRICKET_INNINGS_OF_MATCH_BOWLED_OUT Market = 300108 // Match - CRICKET_TOP_MATCH_BATTER CricketMarket = 30245 - CRICKET_TOP_MATCH_BOWLER CricketMarket = 30246 + CRICKET_TOP_MATCH_BATTER Market = 30245 + CRICKET_TOP_MATCH_BOWLER Market = 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 + VOLLEYBALL_GAME_LINES Market = 910000 + VOLLEYBALL_CORRECT_SET_SCORE Market = 910201 + VOLLEYBALL_MATCH_TOTAL_ODD_EVEN Market = 910217 + VOLLEYBALL_SET_ONE_LINES Market = 910204 + VOLLEYBALL_SET_ONE_TO_GO_TO_EXTRA_POINTS Market = 910209 + VOLLEYBALL_SET_ONE_TOTAL_ODD_EVEN Market = 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_MATCH_WINNER Market = 703 // match_winner + DARTS_MATCH_DOUBLE Market = 150228 // match_double + DARTS_MATCH_TREBLE Market = 150230 // match_treble + DARTS_CORRECT_LEG_SCORE Market = 150015 // correct_leg_score + DARTS_TOTAL_LEGS Market = 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 + DARTS_MOST_HUNDERED_EIGHTYS Market = 150030 // "most_180s" + DARTS_TOTAL_HUNDERED_EIGHTYS Market = 150012 // total_180s + DARTS_MOST_HUNDERED_EIGHTYS_HANDICAP Market = 150227 // most_180s_handicap + DARTS_PLAYER_HUNDERED_EIGHTYS Market = 150121 // player_180s + DARTS_FIRST_DART Market = 150125 // first_dart ) -type FutsalMarket int64 - const ( // Main - FUTSAL_GAME_LINES FutsalMarket = 830001 - FUTSAL_MONEY_LINE FutsalMarket = 830130 + FUTSAL_GAME_LINES Market = 830001 + FUTSAL_MONEY_LINE Market = 830130 // Others - FUTSAL_DOUBLE_RESULT_9_WAY FutsalMarket = 830124 + FUTSAL_DOUBLE_RESULT_9_WAY Market = 830124 // Score - FUTSAL_TEAM_TO_SCORE_FIRST FutsalMarket = 830141 - FUTSAL_RACE_TO_GOALS FutsalMarket = 830142 + FUTSAL_TEAM_TO_SCORE_FIRST Market = 830141 + FUTSAL_RACE_TO_GOALS Market = 830142 ) -type AmericanFootballMarket int64 - const ( // Main - AMERICAN_FOOTBALL_GAME_LINES AmericanFootballMarket = 1441 + AMERICAN_FOOTBALL_GAME_LINES Market = 1441 ) -type RugbyLeagueMarket int64 - const ( // Main - RUGBY_L_GAME_BETTING_2_WAY RugbyLeagueMarket = 190006 + RUGBY_L_GAME_BETTING_2_WAY Market = 190006 ) -type RugbyUnionMarket int64 - const ( // Main - RUGBY_U_GAME_BETTING_2_WAY RugbyLeagueMarket = 80007 + RUGBY_U_GAME_BETTING_2_WAY Market = 80007 ) -type BaseballMarket int64 - const ( // Main - BASEBALL_GAME_LINES BaseballMarket = 1096 + BASEBALL_GAME_LINES Market = 1096 ) // TODO: Move this into the database so that it can be modified dynamically @@ -323,6 +323,48 @@ var SupportedMarkets = map[int64]bool{ int64(FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN): true, int64(FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN): true, + int64(FOOTBALL_FULL_TIME_RESULT_ENHANCED): true, + int64(FOOTBALL_ALTERNATIVE_ASIAN_HANDICAP): true, + int64(FOOTBALL_ALTERNATIVE_GOAL_LINE): true, + int64(FOOTBALL_ALTERNATE_FIRST_HALF_ASIAN_HANDICAP): true, + int64(FOOTBALL_ALTERNATE_FIRST_HALF_GOAL_LINE): true, + int64(FOOTBALL_ALTERNATIVE_CORNER): true, + int64(FOOTBALL_BOTH_TEAMS_TO_SCORE): true, + int64(FOOTBALL_RESULT_BOTH_TEAMS_TO_SCORE): true, + int64(FOOTBALL_HALF_TIME_CORRECT_SCORE): true, + int64(FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF): true, + int64(FOOTBALL_BOTH_TEAMS_TO_SCORE_SECOND_HALF): true, + int64(FOOTBALL_SECOND_HALF_RESULT): true, + int64(FOOTBALL_CLEAN_SHEET): true, + int64(FOOTBALL_LAST_TEAM_TO_SCORE): true, + int64(FOOTBALL_WINNING_MARGIN): true, + int64(FOOTBALL_BOTH_TEAMS_TO_RECEIVE_CARDS): true, + int64(FOOTBALL_HALF_TIME_DOUBLE_CHANCE): true, + int64(FOOTBALL_HALF_TIME_RESULT_BOTH_TEAMS_TO_SCORE): true, + int64(FOOTBALL_HALF_WITH_MOST_GOALS): true, + int64(FOOTBALL_HOME_TEAM_WITH_HIGHEST_SCORING_HALF): true, + int64(FOOTBALL_AWAY_TEAM_WITH_HIGHEST_SCORING_HALF): true, + int64(FOOTBALL_SECOND_HALF_GOALS): true, + int64(FOOTBALL_TEAM_TOTAL_GOALS): true, + int64(FOOTBALL_EXACT_TOTAL_GOALS): true, + int64(FOOTBALL_EXACT_FIRST_HALF_GOALS): true, + int64(FOOTBALL_TEAMS_TO_SCORE): true, + int64(FOOTBALL_EXACT_SECOND_HALF_GOALS): true, + int64(FOOTBALL_FIRST_MATCH_CORNER): true, + int64(FOOTBALL_LAST_MATCH_CORNER): true, + int64(FOOTBALL_CORNER_MATCH_BET): true, + int64(FOOTBALL_MULTI_CORNERS): true, + int64(FOOTBALL_MATCH_SHOTS_ON_TARGET): true, + int64(FOOTBALL_TEAM_SHOTS_ON_TARGET): true, + int64(FOOTBALL_SPECIALS): true, + int64(FOOTBALL_ASIAN_HANDICAP_CORNERS): true, + int64(FOOTBALL_CORNER_HANDICAP): true, + int64(FOOTBALL_ASIAN_TOTAL_CARDS): true, + int64(FOOTBALL_NUMBER_OF_CARDS_IN_MATCH): true, + int64(FOOTBALL_TIME_OF_FIRST_GOAL_BRACKETS): true, + int64(FOOTBALL_EARLY_GOAL): true, + int64(FOOTBALL_LATE_GOAL): true, + // Basketball Markets int64(BASKETBALL_GAME_LINES): true, int64(BASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTS): true, @@ -435,3 +477,49 @@ var SupportedMarkets = map[int64]bool{ // Baseball Markets int64(BASEBALL_GAME_LINES): true, } + + +// These are temporarily disabled markets that will be disabled for all companies except for fortune +var DisabledMarkets = map[int64]bool{ + int64(FOOTBALL_FULL_TIME_RESULT_ENHANCED): true, + int64(FOOTBALL_ALTERNATIVE_ASIAN_HANDICAP): true, + int64(FOOTBALL_ALTERNATIVE_GOAL_LINE): true, + int64(FOOTBALL_ALTERNATE_FIRST_HALF_ASIAN_HANDICAP): true, + int64(FOOTBALL_ALTERNATE_FIRST_HALF_GOAL_LINE): true, + int64(FOOTBALL_ALTERNATIVE_CORNER): true, + int64(FOOTBALL_BOTH_TEAMS_TO_SCORE): true, + int64(FOOTBALL_RESULT_BOTH_TEAMS_TO_SCORE): true, + int64(FOOTBALL_HALF_TIME_CORRECT_SCORE): true, + int64(FOOTBALL_BOTH_TEAMS_TO_SCORE_FIRST_HALF): true, + int64(FOOTBALL_BOTH_TEAMS_TO_SCORE_SECOND_HALF): true, + int64(FOOTBALL_SECOND_HALF_RESULT): true, + int64(FOOTBALL_CLEAN_SHEET): true, + int64(FOOTBALL_LAST_TEAM_TO_SCORE): true, + int64(FOOTBALL_WINNING_MARGIN): true, + int64(FOOTBALL_BOTH_TEAMS_TO_RECEIVE_CARDS): true, + int64(FOOTBALL_HALF_TIME_DOUBLE_CHANCE): true, + int64(FOOTBALL_HALF_TIME_RESULT_BOTH_TEAMS_TO_SCORE): true, + int64(FOOTBALL_HALF_WITH_MOST_GOALS): true, + int64(FOOTBALL_HOME_TEAM_WITH_HIGHEST_SCORING_HALF): true, + int64(FOOTBALL_AWAY_TEAM_WITH_HIGHEST_SCORING_HALF): true, + int64(FOOTBALL_SECOND_HALF_GOALS): true, + int64(FOOTBALL_TEAM_TOTAL_GOALS): true, + int64(FOOTBALL_EXACT_TOTAL_GOALS): true, + int64(FOOTBALL_EXACT_FIRST_HALF_GOALS): true, + int64(FOOTBALL_TEAMS_TO_SCORE): true, + int64(FOOTBALL_EXACT_SECOND_HALF_GOALS): true, + int64(FOOTBALL_FIRST_MATCH_CORNER): true, + int64(FOOTBALL_LAST_MATCH_CORNER): true, + int64(FOOTBALL_CORNER_MATCH_BET): true, + int64(FOOTBALL_MULTI_CORNERS): true, + int64(FOOTBALL_MATCH_SHOTS_ON_TARGET): true, + int64(FOOTBALL_TEAM_SHOTS_ON_TARGET): true, + int64(FOOTBALL_SPECIALS): true, + int64(FOOTBALL_ASIAN_HANDICAP_CORNERS): true, + int64(FOOTBALL_CORNER_HANDICAP): true, + int64(FOOTBALL_ASIAN_TOTAL_CARDS): true, + int64(FOOTBALL_NUMBER_OF_CARDS_IN_MATCH): true, + int64(FOOTBALL_TIME_OF_FIRST_GOAL_BRACKETS): true, + int64(FOOTBALL_EARLY_GOAL): true, + int64(FOOTBALL_LATE_GOAL): true, +} diff --git a/internal/ports/market_settings.go b/internal/ports/market_settings.go new file mode 100644 index 0000000..5905ef3 --- /dev/null +++ b/internal/ports/market_settings.go @@ -0,0 +1,21 @@ +package ports + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +type MarketSettingStore interface { + InsertGlobalMarketSettings(ctx context.Context, setting domain.CreateGlobalMarketSettings) error + InsertCompanyMarketSettings(ctx context.Context, setting domain.CreateCompanyMarketSettings) error + GetAllGlobalMarketSettings(ctx context.Context, filter domain.MarketSettingFilter) ([]domain.MarketSettings, error) + GetGlobalMarketSettingsByID(ctx context.Context, Id int64) (domain.MarketSettings, error) + GetAllCompanyMarketSettings(ctx context.Context, filter domain.CompanyMarketSettingFilter) ([]domain.CompanyMarketSettings, error) + GetCompanyMarketSettings(ctx context.Context, ID int64) (domain.CompanyMarketSettings, error) + GetAllOverrideMarketSettings(ctx context.Context, companyID int64, filter domain.MarketSettingFilter) ([]domain.MarketSettings, error) + GetOverrideMarketSettingByID(ctx context.Context, companyID int64, marketID int64) (domain.MarketSettings, error) + DeleteAllCompanyMarketSettings(ctx context.Context, companyID int64) error + DeleteCompanyMarketSettings(ctx context.Context, companyID int64, marketID int64) error + EnsureAllMarketSettingsExist(ctx context.Context) error +} diff --git a/internal/ports/settings.go b/internal/ports/settings.go index c5e3056..bd16c0b 100644 --- a/internal/ports/settings.go +++ b/internal/ports/settings.go @@ -21,4 +21,5 @@ type SettingStore interface { GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error DeleteAllCompanySetting(ctx context.Context, companyID int64) error + EnsureAllSettingsExist(ctx context.Context) error } diff --git a/internal/repository/market_settings.go b/internal/repository/market_settings.go new file mode 100644 index 0000000..06ad9ed --- /dev/null +++ b/internal/repository/market_settings.go @@ -0,0 +1,187 @@ +package repository + +import ( + "context" + "fmt" + + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/SamuelTariku/FortuneBet-Backend/internal/ports" + "github.com/jackc/pgx/v5/pgtype" +) + + + +func NewMarketSettingStore(s *Store) ports.MarketSettingStore { return s } + +func (s *Store) InsertGlobalMarketSettings(ctx context.Context, setting domain.CreateGlobalMarketSettings) error { + err := s.queries.InsertGlobalMarketSettings(ctx, domain.ConvertCreateGlobalMarketSettings(setting)) + if err != nil { + return err + } + return nil +} + +func (s *Store) InsertCompanyMarketSettings(ctx context.Context, setting domain.CreateCompanyMarketSettings) error { + err := s.queries.InsertCompanyMarketSettings(ctx, domain.ConvertCreateCompanyMarketSettings(setting)) + if err != nil { + return err + } + return nil +} + +func (s *Store) GetAllGlobalMarketSettings(ctx context.Context, filter domain.MarketSettingFilter) ([]domain.MarketSettings, error) { + settings, err := s.queries.GetAllGlobalMarketSettings(ctx, dbgen.GetAllGlobalMarketSettingsParams{ + Offset: pgtype.Int4{ + Int32: int32(filter.Offset.Value * filter.Limit.Value), + Valid: filter.Offset.Valid, + }, + Limit: filter.Limit.ToPG(), + }) + if err != nil { + return nil, err + } + + return domain.ConvertDBGlobalMarketSettingsList(settings), nil +} + +func (s *Store) GetGlobalMarketSettingsByID(ctx context.Context, Id int64) (domain.MarketSettings, error) { + setting, err := s.queries.GetGlobalMarketSettingsByID(ctx, Id) + if err != nil { + return domain.MarketSettings{}, err + } + + return domain.ConvertDBGlobalMarketSettings(setting), nil +} + +func (s *Store) GetAllCompanyMarketSettings(ctx context.Context, filter domain.CompanyMarketSettingFilter) ([]domain.CompanyMarketSettings, error) { + settings, err := s.queries.GetAllCompanyMarketSettings(ctx, dbgen.GetAllCompanyMarketSettingsParams{ + Offset: pgtype.Int4{ + Int32: int32(filter.Offset.Value * filter.Limit.Value), + Valid: filter.Offset.Valid, + }, + Limit: filter.Limit.ToPG(), + CompanyID: filter.CompanyID.ToPG(), + }) + if err != nil { + return nil, err + } + + return domain.ConvertDBCompanyMarketSettingsList(settings), nil +} + +func (s *Store) GetCompanyMarketSettings(ctx context.Context, ID int64) (domain.CompanyMarketSettings, error) { + setting, err := s.queries.GetCompanyMarketSettingsByID(ctx, ID) + if err != nil { + return domain.CompanyMarketSettings{}, err + } + + return domain.ConvertDBCompanyMarketSettings(setting), nil +} + +func (s *Store) GetAllOverrideMarketSettings(ctx context.Context, companyID int64, filter domain.MarketSettingFilter) ([]domain.MarketSettings, error) { + settings, err := s.queries.GetAllOverrideMarketSettings(ctx, dbgen.GetAllOverrideMarketSettingsParams{ + CompanyID: companyID, + Offset: pgtype.Int4{ + Int32: int32(filter.Offset.Value * filter.Limit.Value), + Valid: filter.Offset.Valid, + }, + Limit: filter.Limit.ToPG(), + }) + if err != nil { + return nil, err + } + + return domain.ConvertDBGetAllOverrideMarketSettingsList(settings), nil +} + +func (s *Store) GetOverrideMarketSettingByID(ctx context.Context, companyID int64, marketID int64) (domain.MarketSettings, error) { + setting, err := s.queries.GetOverrideMarketSettingByID(ctx, dbgen.GetOverrideMarketSettingByIDParams{ + CompanyID: companyID, + MarketID: marketID, + }) + + if err != nil { + return domain.MarketSettings{}, nil + } + + return domain.ConvertDBGetOverrideMarketSettingsByID(setting), nil +} + +func (s *Store) DeleteAllCompanyMarketSettings(ctx context.Context, companyID int64) error { + err := s.queries.DeleteAllMarketSettingsForCompany(ctx, companyID) + if err != nil { + return err + } + return nil +} + +func (s *Store) DeleteCompanyMarketSettings(ctx context.Context, companyID int64, marketID int64) error { + err := s.queries.DeleteCompanyMarketSettings(ctx, dbgen.DeleteCompanyMarketSettingsParams{ + MarketID: marketID, + CompanyID: companyID, + }) + if err != nil { + return err + } + return nil +} + +func (s *Store) EnsureAllMarketSettingsExist(ctx context.Context) error { + dbMarketSettings, err := s.GetAllGlobalMarketSettings(ctx, domain.MarketSettingFilter{}) + if err != nil { + return fmt.Errorf("failed to fetch global market settings: %w", err) + } + + dbCompanies, err := s.GetAllCompanies(ctx, domain.CompanyFilter{}) + if err != nil { + return fmt.Errorf("failed to fetch companies: %w", err) + } + existing := map[int64]struct{}{} + for _, s := range dbMarketSettings { + existing[s.MarketID] = struct{}{} + } + + for id, defaultIsActive := range domain.SupportedMarkets { + if _, found := existing[id]; !found { + name, err := domain.GetMarketName(id) + if err != nil { + return err + } + err = s.InsertGlobalMarketSettings(ctx, domain.CreateGlobalMarketSettings{ + MarketID: id, + MarketName: name, + IsActive: defaultIsActive, + }) + if err != nil{ + return fmt.Errorf("failed to insert market %d (%s): %w", id, name, err) + } + } + + // This is to auto disabled markets that haven't been tested yet + for _, company := range dbCompanies { + if company.Slug == "fortunebets" { + continue + } + + if _, found := domain.DisabledMarkets[id]; !found { + continue + } + name, err := domain.GetMarketName(id) + err = s.InsertCompanyMarketSettings(ctx, domain.CreateCompanyMarketSettings{ + CompanyID: company.ID, + MarketID: id, + MarketName: name, + IsActive: domain.ValidBool{ + Value: false, + Valid: true, + }, + }) + if err != nil { + return fmt.Errorf("failed to insert company market %d (%s): %w", id, name, err) + } + } + } + return nil + +} \ No newline at end of file diff --git a/internal/repository/odds.go b/internal/repository/odds.go index e7740c5..ec5e13c 100644 --- a/internal/repository/odds.go +++ b/internal/repository/odds.go @@ -118,7 +118,7 @@ func (s *Store) GetAllOddsWithSettings(ctx context.Context, companyID int64, fil RawOdds: rawOdds, FetchedAt: o.FetchedAt.Time, ExpiresAt: o.ExpiresAt.Time, - IsActive: o.IsActive, + IsActive: o.IsActive && o.IsMarketActive, } } @@ -194,7 +194,7 @@ func (s *Store) GetOddsWithSettingsByMarketID(ctx context.Context, marketID int6 RawOdds: rawOdds, FetchedAt: odds.FetchedAt.Time, ExpiresAt: odds.ExpiresAt.Time, - IsActive: odds.IsActive, + IsActive: odds.IsActive && odds.IsMarketActive, } return converted, nil } @@ -236,7 +236,7 @@ func (s *Store) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID RawOdds: rawOdds, FetchedAt: odds.FetchedAt.Time, ExpiresAt: odds.ExpiresAt.Time, - IsActive: odds.IsActive, + IsActive: odds.IsActive && odds.IsMarketActive, } return converted, nil @@ -303,7 +303,7 @@ func (s *Store) GetOddsWithSettingsByEventID(ctx context.Context, eventID int64, RawOdds: rawOdds, FetchedAt: o.FetchedAt.Time, ExpiresAt: o.ExpiresAt.Time, - IsActive: o.IsActive, + IsActive: o.IsActive && o.IsMarketActive, } } diff --git a/internal/repository/settings.go b/internal/repository/settings.go index 30371da..cfda489 100644 --- a/internal/repository/settings.go +++ b/internal/repository/settings.go @@ -2,6 +2,7 @@ package repository import ( "context" + "fmt" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" @@ -12,6 +13,17 @@ import ( // Interface for creating new setting store func NewSettingStore(s *Store) ports.SettingStore { return s } +func (s *Store) InsertGlobalSetting(ctx context.Context, setting domain.CreateSetting) error { + err := s.queries.InsertGlobalSetting(ctx, dbgen.InsertGlobalSettingParams{ + Key: setting.Key, + Value: setting.Value, + }) + if err != nil { + return err + } + return nil +} + func (s *Store) GetGlobalSettingList(ctx context.Context) (domain.SettingList, error) { settings, err := s.queries.GetGlobalSettings(ctx) if err != nil { @@ -175,3 +187,30 @@ func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key s func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64) error { return s.queries.DeleteAllCompanySetting(ctx, companyID) } + +func (s *Store) EnsureAllSettingsExist(ctx context.Context) error { + defaultSettings := domain.NewDefaultSettingList().ToSettingArray() // returns []domain.Setting from your typed struct + + dbSettings, err := s.GetGlobalSettings(ctx) + if err != nil { + return fmt.Errorf("failed to fetch settings: %w", err) + } + + existing := map[string]struct{}{} + for _, s := range dbSettings { + existing[s.Key] = struct{}{} + } + + for _, setting := range defaultSettings { + if _, found := existing[setting.Key]; !found { + if err := s.InsertGlobalSetting(ctx, domain.CreateSetting{ + Key: setting.Key, + Value: setting.Value, + }); err != nil { + return fmt.Errorf("failed to create missing setting %q: %w", setting.Key, err) + } + } + } + + return nil +} diff --git a/internal/services/bet/service.go b/internal/services/bet/service.go index ac6c3ef..9be7254 100644 --- a/internal/services/bet/service.go +++ b/internal/services/bet/service.go @@ -141,6 +141,28 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI return domain.CreateBetOutcome{}, ErrEventHasNotEnded } + + setting, err := s.prematchSvc.GetOverrideMarketSettingByID(ctx, companyID, marketID) + if err != nil { + s.mongoLogger.Error("failed to get override market settings by id", + zap.Int64("company_id", companyID), + zap.Int64("event_id", eventID), + zap.Int64("market_id", marketID), + zap.Error(err), + ) + return domain.CreateBetOutcome{}, err + } + + if !setting.IsActive { + s.mongoLogger.Error("Attempted to create bet on disabled market", + zap.Int64("event_id", eventID), + zap.Int64("market_id", marketID), + zap.Int64("company_id", companyID), + zap.Error(err), + ) + return domain.CreateBetOutcome{}, ErrOddHasBeenDisabled + } + odds, err := s.prematchSvc.GetOddsWithSettingsByMarketID(ctx, marketID, eventID, companyID) if err != nil { s.mongoLogger.Error("failed to get raw odds by market ID", @@ -152,7 +174,7 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI } if !odds.IsActive { - s.mongoLogger.Error("failed to get raw odds by market ID", + s.mongoLogger.Info("Attempted to created bet on disabled odd", zap.Int64("event_id", eventID), zap.Int64("market_id", marketID), zap.Error(err), @@ -160,6 +182,7 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI return domain.CreateBetOutcome{}, ErrOddHasBeenDisabled } + type rawOddType struct { ID string Name string diff --git a/internal/services/odds/market_settings.go b/internal/services/odds/market_settings.go new file mode 100644 index 0000000..d9c5fcc --- /dev/null +++ b/internal/services/odds/market_settings.go @@ -0,0 +1,38 @@ +package odds + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +func (s *ServiceImpl) InsertGlobalMarketSettings(ctx context.Context, setting domain.CreateGlobalMarketSettings) error { + return s.marketSettingStore.InsertGlobalMarketSettings(ctx, setting) +} +func (s *ServiceImpl) InsertCompanyMarketSettings(ctx context.Context, setting domain.CreateCompanyMarketSettings) error { + return s.marketSettingStore.InsertCompanyMarketSettings(ctx, setting) +} +func (s *ServiceImpl) GetAllGlobalMarketSettings(ctx context.Context, filter domain.MarketSettingFilter) ([]domain.MarketSettings, error) { + return s.marketSettingStore.GetAllGlobalMarketSettings(ctx, filter) +} +func (s *ServiceImpl) GetGlobalMarketSettingsByID(ctx context.Context, Id int64) (domain.MarketSettings, error) { + return s.marketSettingStore.GetGlobalMarketSettingsByID(ctx, Id) +} +func (s *ServiceImpl) GetAllCompanyMarketSettings(ctx context.Context, filter domain.CompanyMarketSettingFilter) ([]domain.CompanyMarketSettings, error) { + return s.marketSettingStore.GetAllCompanyMarketSettings(ctx, filter) +} +func (s *ServiceImpl) GetCompanyMarketSettings(ctx context.Context, ID int64) (domain.CompanyMarketSettings, error) { + return s.marketSettingStore.GetCompanyMarketSettings(ctx, ID) +} +func (s *ServiceImpl) GetAllOverrideMarketSettings(ctx context.Context, companyID int64, filter domain.MarketSettingFilter) ([]domain.MarketSettings, error) { + return s.marketSettingStore.GetAllOverrideMarketSettings(ctx, companyID, filter) +} +func (s *ServiceImpl) GetOverrideMarketSettingByID(ctx context.Context, companyID int64, marketID int64) (domain.MarketSettings, error) { + return s.marketSettingStore.GetOverrideMarketSettingByID(ctx, companyID, marketID) +} +func (s *ServiceImpl) DeleteAllCompanyMarketSettings(ctx context.Context, companyID int64) error { + return s.marketSettingStore.DeleteAllCompanyMarketSettings(ctx, companyID) +} +func (s *ServiceImpl) DeleteCompanyMarketSettings(ctx context.Context, companyID int64, marketID int64) error { + return s.marketSettingStore.DeleteCompanyMarketSettings(ctx, companyID, marketID) +} diff --git a/internal/services/odds/service.go b/internal/services/odds/service.go index 667dff7..24b72da 100644 --- a/internal/services/odds/service.go +++ b/internal/services/odds/service.go @@ -22,22 +22,24 @@ import ( ) type ServiceImpl struct { - store ports.OddStore - config *config.Config - eventSvc *event.Service - logger *slog.Logger - mongoLogger *zap.Logger - client *http.Client + store ports.OddStore + marketSettingStore ports.MarketSettingStore + config *config.Config + eventSvc *event.Service + logger *slog.Logger + mongoLogger *zap.Logger + client *http.Client } -func New(store ports.OddStore, cfg *config.Config, eventSvc *event.Service, logger *slog.Logger, mongoLogger *zap.Logger) *ServiceImpl { +func New(store ports.OddStore, marketSettingStore ports.MarketSettingStore, cfg *config.Config, eventSvc *event.Service, logger *slog.Logger, mongoLogger *zap.Logger) *ServiceImpl { return &ServiceImpl{ - store: store, - config: cfg, - eventSvc: eventSvc, - logger: logger, - mongoLogger: mongoLogger, - client: &http.Client{Timeout: 10 * time.Second}, + store: store, + marketSettingStore: marketSettingStore, + config: cfg, + eventSvc: eventSvc, + logger: logger, + mongoLogger: mongoLogger, + client: &http.Client{Timeout: 10 * time.Second}, } } diff --git a/internal/web_server/cron.go b/internal/web_server/cron.go index 1200b2a..48a227b 100644 --- a/internal/web_server/cron.go +++ b/internal/web_server/cron.go @@ -37,86 +37,86 @@ func StartBetAPIDataFetchingCrons( spec string task func() }{ - { - spec: "0 0 * * * *", // Every 1 hour - task: func() { - start := time.Now() - mongoLogger.Info("[BetAPI Event Fetching Crons] Began fetching upcoming events cron task", zap.Time("timestamp", time.Now())) - if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { - mongoLogger.Error("[BetAPI Event Fetching Crons] Failed to fetch upcoming events", - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - zap.Error(err), - ) - } else { - mongoLogger.Info("[BetAPI Event Fetching Crons] Completed fetching upcoming events without errors", - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } - }, - }, - { - spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) - task: func() { - start := time.Now() - mongoLogger.Info("[BetAPI Pre-Match Odds Fetching Crons] Began fetching pre-match odds cron task", - zap.Time("timestamp", time.Now()), - ) - if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { - mongoLogger.Error("[BetAPI Pre-Match Odds Fetching Crons] Failed to fetch pre-match odds", - zap.Error(err), - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } else { - mongoLogger.Info("[BetAPI Pre-Match Odds Fetching Crons] Completed fetching pre-match odds without errors", - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } - }, - }, - { - spec: "0 */5 * * * *", // Every 5 Minutes - task: func() { - start := time.Now() - mongoLogger.Info("[BetAPI Check And Update Expired Events Crons] Began update all expired events status cron task", - zap.Time("timestamp", time.Now()), - ) - if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil { - mongoLogger.Error("[BetAPI Check And Update Expired Events Crons] Failed to update expired events status", - zap.Error(err), - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } else { - mongoLogger.Info("[BetAPI Check And Update Expired Events Crons] Completed expired events without errors", - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } - }, - }, - { - spec: "0 */15 * * * *", // Every 15 Minutes - task: func() { - start := time.Now() - mongoLogger.Info("[BetAPI Fetch Result and Update Bets Crons] Began updating bets based on event results cron task") - if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil { - mongoLogger.Error("[BetAPI Fetch Result and Update Bets Crons] Failed to process result", - zap.Error(err), - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } else { - mongoLogger.Info("[BetAPI Fetch Result and Update Bets Crons] Completed processing all event result outcomes without errors", - zap.Time("timestamp", time.Now()), - zap.Duration("duration", time.Since(start)), - ) - } - }, - }, + // { + // spec: "0 0 * * * *", // Every 1 hour + // task: func() { + // start := time.Now() + // mongoLogger.Info("[BetAPI Event Fetching Crons] Began fetching upcoming events cron task", zap.Time("timestamp", time.Now())) + // if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { + // mongoLogger.Error("[BetAPI Event Fetching Crons] Failed to fetch upcoming events", + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // zap.Error(err), + // ) + // } else { + // mongoLogger.Info("[BetAPI Event Fetching Crons] Completed fetching upcoming events without errors", + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } + // }, + // }, + // { + // spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) + // task: func() { + // start := time.Now() + // mongoLogger.Info("[BetAPI Pre-Match Odds Fetching Crons] Began fetching pre-match odds cron task", + // zap.Time("timestamp", time.Now()), + // ) + // if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { + // mongoLogger.Error("[BetAPI Pre-Match Odds Fetching Crons] Failed to fetch pre-match odds", + // zap.Error(err), + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } else { + // mongoLogger.Info("[BetAPI Pre-Match Odds Fetching Crons] Completed fetching pre-match odds without errors", + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } + // }, + // }, + // { + // spec: "0 */5 * * * *", // Every 5 Minutes + // task: func() { + // start := time.Now() + // mongoLogger.Info("[BetAPI Check And Update Expired Events Crons] Began update all expired events status cron task", + // zap.Time("timestamp", time.Now()), + // ) + // if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil { + // mongoLogger.Error("[BetAPI Check And Update Expired Events Crons] Failed to update expired events status", + // zap.Error(err), + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } else { + // mongoLogger.Info("[BetAPI Check And Update Expired Events Crons] Completed expired events without errors", + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } + // }, + // }, + // { + // spec: "0 */15 * * * *", // Every 15 Minutes + // task: func() { + // start := time.Now() + // mongoLogger.Info("[BetAPI Fetch Result and Update Bets Crons] Began updating bets based on event results cron task") + // if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil { + // mongoLogger.Error("[BetAPI Fetch Result and Update Bets Crons] Failed to process result", + // zap.Error(err), + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } else { + // mongoLogger.Info("[BetAPI Fetch Result and Update Bets Crons] Completed processing all event result outcomes without errors", + // zap.Time("timestamp", time.Now()), + // zap.Duration("duration", time.Since(start)), + // ) + // } + // }, + // }, // { // spec: "0 0 0 * * 1", // Every Monday // task: func() { diff --git a/internal/web_server/handlers/leagues.go b/internal/web_server/handlers/leagues.go index f801df8..9abc0f5 100644 --- a/internal/web_server/handlers/leagues.go +++ b/internal/web_server/handlers/leagues.go @@ -22,7 +22,7 @@ import ( // @Router /api/v1/leagues [get] func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { page := c.QueryInt("page", 1) - pageSize := c.QueryInt("page_size", 10) + pageSize := c.QueryInt("page_size", 0) limit := domain.ValidInt64{ Value: int64(pageSize), @@ -30,7 +30,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { } offset := domain.ValidInt64{ Value: int64(page - 1), - Valid: true, + Valid: page != 1, } searchQuery := c.Query("query") diff --git a/internal/web_server/handlers/market_settings_handler.go b/internal/web_server/handlers/market_settings_handler.go new file mode 100644 index 0000000..6304020 --- /dev/null +++ b/internal/web_server/handlers/market_settings_handler.go @@ -0,0 +1,195 @@ +package handlers + +import ( + "fmt" + "strconv" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +// InsertCompanyMarketSettings +// @Summary Insert company-specific market settings +// @Description Insert new market settings for a specific tenant/company +// @Tags market_settings +// @Accept json +// @Produce json +// @Param body body domain.CreateCompanyMarketSettings true "Market Settings" +// @Success 200 {object} response.APIResponse +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/{tenant_slug}/market-settings [post] +func (h *Handler) InsertCompanyMarketSettings(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + var req domain.CreateCompanyMarketSettingsReq + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("Failed to parse request", zap.Int64("company_id", companyID.Value), zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + valErrs, ok := h.validator.Validate(c, req) + if !ok { + errMsg := "" + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.BadRequestLogger().Error("Validation failed", zap.String("errors", errMsg)) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + } + + if err := h.prematchSvc.InsertCompanyMarketSettings(c.Context(), domain.ConvertCreateCompanyMarketSettingsReq( + req, companyID.Value, + )); err != nil { + h.InternalServerErrorLogger().Error("Failed to insert company market settings", zap.Int64("company_id", companyID.Value), zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to insert market settings: "+err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Company market settings inserted successfully", nil, nil) +} + +// GetAllGlobalMarketSettings +// @Summary Retrieve all global market settings +// @Description Get all market settings that apply globally +// @Tags market_settings +// @Accept json +// @Produce json +// @Param limit query int false "Number of results to return (default 10)" +// @Param offset query int false "Number of results to skip (default 0)" +// @Success 200 {array} domain.MarketSettings +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/market-settings [get] +func (h *Handler) GetAllGlobalMarketSettings(c *fiber.Ctx) error { + limit, err := strconv.Atoi(c.Query("limit", "10")) + if err != nil || limit <= 0 { + h.BadRequestLogger().Info("Invalid limit value", zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") + } + + offset, err := strconv.Atoi(c.Query("offset", "0")) + if err != nil || offset < 0 { + h.BadRequestLogger().Info("Invalid offset value", zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid offset value") + } + + settings, err := h.prematchSvc.GetAllGlobalMarketSettings(c.Context(), domain.MarketSettingFilter{ + Limit: domain.ValidInt32{Value: int32(limit), Valid: true}, + Offset: domain.ValidInt32{Value: int32(offset), Valid: true}, + }) + if err != nil { + h.InternalServerErrorLogger().Error("Failed to retrieve global market settings", zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve global market settings: "+err.Error()) + } + + res := domain.ConvertMarketSettingsResList(settings) + + return response.WriteJSON(c, fiber.StatusOK, "Global market settings retrieved successfully", res, nil) +} + +// GetAllTenantMarketSettings +// @Summary Retrieve all market settings for a tenant +// @Description Get all market settings overridden for a specific tenant +// @Tags market_settings +// @Accept json +// @Produce json +// @Param limit query int false "Number of results to return (default 10)" +// @Param offset query int false "Number of results to skip (default 0)" +// @Success 200 {array} domain.CompanyMarketSettings +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/{tenant_slug}/market-settings [get] +func (h *Handler) GetAllTenantMarketSettings(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + limit, err := strconv.Atoi(c.Query("limit", "10")) + if err != nil || limit <= 0 { + h.BadRequestLogger().Info("Invalid limit value", zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") + } + + offset, err := strconv.Atoi(c.Query("offset", "0")) + if err != nil || offset < 0 { + h.BadRequestLogger().Info("Invalid offset value", zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid offset value") + } + + settings, err := h.prematchSvc.GetAllOverrideMarketSettings(c.Context(), companyID.Value, domain.MarketSettingFilter{ + Limit: domain.ValidInt32{Value: int32(limit), Valid: true}, + Offset: domain.ValidInt32{Value: int32(offset), Valid: true}, + }) + if err != nil { + h.InternalServerErrorLogger().Error("Failed to retrieve tenant market settings", zap.Int64("company_id", companyID.Value), zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve tenant market settings: "+err.Error()) + } + res := domain.ConvertMarketSettingsResList(settings) + + return response.WriteJSON(c, fiber.StatusOK, "Tenant market settings retrieved successfully", res, nil) +} + +// DeleteAllCompanyMarketSettings +// @Summary Delete all market settings for a tenant +// @Description Remove all overridden market settings for a specific tenant +// @Tags market_settings +// @Accept json +// @Produce json +// @Success 200 {object} response.APIResponse +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/{tenant_slug}/market-settings [delete] +func (h *Handler) DeleteAllCompanyMarketSettings(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + if err := h.prematchSvc.DeleteAllCompanyMarketSettings(c.Context(), companyID.Value); err != nil { + h.InternalServerErrorLogger().Error("Failed to delete all company market settings", zap.Int64("company_id", companyID.Value), zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete all company market settings: "+err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "All tenant market settings removed successfully", nil, nil) +} + +// DeleteCompanyMarketSettings +// @Summary Delete a specific market setting for a tenant +// @Description Remove a specific overridden market setting for a tenant +// @Tags market_settings +// @Accept json +// @Produce json +// @Param id path int true "Market ID" +// @Success 200 {object} response.APIResponse +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/{tenant_slug}/market-settings/{id} [delete] +func (h *Handler) DeleteCompanyMarketSettings(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + marketIDStr := c.Params("id") + marketID, err := strconv.ParseInt(marketIDStr, 10, 64) + if err != nil { + h.BadRequestLogger().Info("Failed to parse market id", zap.String("id", marketIDStr)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid market id") + } + + if err := h.prematchSvc.DeleteCompanyMarketSettings(c.Context(), companyID.Value, marketID); err != nil { + h.InternalServerErrorLogger().Error("Failed to delete company market setting", zap.Int64("company_id", companyID.Value), zap.Int64("market_id", marketID), zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete market setting: "+err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Tenant market setting removed successfully", nil, nil) +} diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 355c983..00069a2 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -53,7 +53,7 @@ func (a *App) initAppRoutes() { a.prematchSvc, a.eventSvc, a.leagueSvc, - *a.resultSvc, + *a.resultSvc, a.statSvc, a.cfg, a.mongoLoggerSvc, @@ -260,15 +260,20 @@ func (a *App) initAppRoutes() { groupV1.Get("/odds/upcoming/:upcoming_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByUpcomingID) groupV1.Get("/odds/upcoming/:upcoming_id/market/:market_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByMarketID) groupV1.Post("/odds/settings", a.authMiddleware, a.SuperAdminOnly, h.SaveOddSettings) + groupV1.Get("/odds/market-settings", a.authMiddleware, a.SuperAdminOnly, h.GetAllGlobalMarketSettings) groupV1.Put("/odds/bet-outcome/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAllBetOutcomeStatusByOddID) groupV1.Put("/odds/bet-outcome", a.authMiddleware, a.SuperAdminOnly, h.BulkUpdateAllBetOutcomeStatusByOddID) tenant.Get("/odds", h.GetAllTenantOdds) tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID) tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID) - tenant.Post("/odds/settings", a.CompanyOnly, h.SaveTenantOddsSetting) - tenant.Delete("/odds/settings/:id", a.CompanyOnly, h.RemoveOddsSettings) - tenant.Delete("/odds/settings", a.CompanyOnly, h.RemoveAllOddsSettings) + tenant.Post("/odds/settings", a.authMiddleware, a.CompanyOnly, h.SaveTenantOddsSetting) + tenant.Delete("/odds/settings/:id", a.authMiddleware, a.CompanyOnly, h.RemoveOddsSettings) + tenant.Delete("/odds/settings", a.authMiddleware, a.CompanyOnly, h.RemoveAllOddsSettings) + tenant.Post("/odds/market-settings", a.authMiddleware, a.CompanyOnly, h.InsertCompanyMarketSettings) + tenant.Get("/odds/market-settings", a.authMiddleware, a.CompanyOnly, h.GetAllTenantMarketSettings) + tenant.Delete("/odds/market-settings", a.authMiddleware, a.CompanyOnly, h.DeleteAllCompanyMarketSettings) + tenant.Delete("/odds/market-settings/:id", a.authMiddleware, a.CompanyOnly, h.DeleteCompanyMarketSettings) groupV1.Get("/events", a.authMiddleware, h.GetAllEvents) groupV1.Get("/events/:id", a.authMiddleware, h.GetEventByID)