feat: Enhance league, odds, events and bets functionality

- Updated league handling to ensure valid page size checks and improved error handling for sport ID parsing.
- Introduced new endpoint to update global league settings with comprehensive validation and error logging.
- Refactored odds settings management, including saving, removing, and updating odds settings with enhanced validation.
- Added tenant slug retrieval by token, ensuring proper user and company validation.
- Improved middleware to check for active company status and adjusted route permissions for various endpoints.
- Added SQL script to fix auto-increment desynchronization across multiple tables.
This commit is contained in:
Samuel Tariku 2025-10-05 23:45:31 +03:00
parent e401d1d82f
commit c00110a503
44 changed files with 1672 additions and 316 deletions

View File

@ -75,8 +75,6 @@ CREATE TABLE IF NOT EXISTS wallets (
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, type) UNIQUE(user_id, type)
); );
CREATE TABLE refresh_tokens ( CREATE TABLE refresh_tokens (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL, user_id BIGINT NOT NULL,
@ -342,7 +340,7 @@ CREATE TABLE company_event_settings (
event_id BIGINT NOT NULL, event_id BIGINT NOT NULL,
is_active BOOLEAN, is_active BOOLEAN,
is_featured BOOLEAN, is_featured BOOLEAN,
winning_upper_limit INT, winning_upper_limit BIGINT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (company_id, event_id) UNIQUE (company_id, event_id)
); );

View File

@ -133,6 +133,38 @@ SELECT *
FROM bet_with_outcomes FROM bet_with_outcomes
WHERE status = 2 WHERE status = 2
AND processed = false; AND processed = false;
-- name: GetBetOutcomeViewByEventID :many
SELECT bet_outcomes.*,
users.first_name,
users.last_name,
bets.amount,
bets.total_odds
FROM bet_outcomes
JOIN bets ON bets.id = bet_outcomes.bet_id
JOIN users ON bets.user_id = users.id
WHERE bet_outcomes.event_id = $1
AND (
bets.company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
)
AND (
bet_outcomes.status = sqlc.narg('filter_status')
OR sqlc.narg('filter_status') IS NULL
)
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: TotalBetOutcomeViewByEventID :one
SELECT count(*)
FROM bet_outcomes
JOIN bets ON bets.id = bet_outcomes.bet_id
WHERE bet_outcomes.event_id = $1
AND (
bets.company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
)
AND (
bet_outcomes.status = sqlc.narg('filter_status')
OR sqlc.narg('filter_status') IS NULL
);
-- name: GetBetOutcomeByEventID :many -- name: GetBetOutcomeByEventID :many
SELECT * SELECT *
FROM bet_outcomes FROM bet_outcomes
@ -180,6 +212,11 @@ UPDATE bet_outcomes
SEt status = $1 SEt status = $1
WHERE event_id = $2 WHERE event_id = $2
RETURNING *; RETURNING *;
-- name: UpdateBetOutcomeStatusForOddID :many
UPDATE bet_outcomes
SEt status = $1
WHERE odd_id = $2
RETURNING *;
-- name: UpdateStatus :exec -- name: UpdateStatus :exec
UPDATE bets UPDATE bets
SET status = $1, SET status = $1,

View File

@ -30,8 +30,8 @@ WHERE (
SELECT * SELECT *
FROM companies_details FROM companies_details
WHERE id = $1; WHERE id = $1;
-- name: GetCompanyIDUsingSlug :one -- name: GetCompanyUsingSlug :one
SELECT id SELECT *
FROM companies FROM companies
WHERE slug = $1; WHERE slug = $1;
-- name: SearchCompanyByName :many -- name: SearchCompanyByName :many

View File

@ -56,7 +56,7 @@ SET sport_id = EXCLUDED.sport_id,
source = EXCLUDED.source, source = EXCLUDED.source,
default_winning_upper_limit = EXCLUDED.default_winning_upper_limit, default_winning_upper_limit = EXCLUDED.default_winning_upper_limit,
fetched_at = now(); fetched_at = now();
-- name: SaveEventSettings :exec -- name: SaveTenantEventSettings :exec
INSERT INTO company_event_settings ( INSERT INTO company_event_settings (
company_id, company_id,
event_id, event_id,
@ -300,7 +300,9 @@ FROM events e
WHERE e.id = $1 WHERE e.id = $1
LIMIT 1; LIMIT 1;
-- name: GetSportAndLeagueIDs :one -- name: GetSportAndLeagueIDs :one
SELECT sport_id, league_id FROM events SELECT sport_id,
league_id
FROM events
WHERE id = $1; WHERE id = $1;
-- name: UpdateMatchResult :exec -- name: UpdateMatchResult :exec
UPDATE events UPDATE events
@ -313,8 +315,22 @@ FROM events
WHERE id = $1; WHERE id = $1;
-- name: UpdateEventMonitored :exec -- name: UpdateEventMonitored :exec
UPDATE events UPDATE events
SET is_monitored = $1 SET is_monitored = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2; WHERE id = $2;
-- name: UpdateGlobalEventSettings :exec
UPDATE events
SET default_is_active = COALESCE(sqlc.narg(default_is_active), default_is_active),
default_is_featured = COALESCE(
sqlc.narg(default_is_featured),
default_is_featured
),
default_winning_upper_limit = COALESCE(
sqlc.narg(default_winning_upper_limit),
default_winning_upper_limit
),
updated_at = CURRENT_TIMESTAMP
WHERE id = $1;
-- name: DeleteEvent :exec -- name: DeleteEvent :exec
DELETE FROM events DELETE FROM events
WHERE id = $1; WHERE id = $1;

View File

@ -14,7 +14,7 @@ SET name = EXCLUDED.name,
country_code = EXCLUDED.country_code, country_code = EXCLUDED.country_code,
bet365_id = EXCLUDED.bet365_id, bet365_id = EXCLUDED.bet365_id,
sport_id = EXCLUDED.sport_id; sport_id = EXCLUDED.sport_id;
-- name: InsertLeagueSettings :exec -- name: SaveLeagueSettings :exec
INSERT INTO company_league_settings ( INSERT INTO company_league_settings (
company_id, company_id,
league_id, league_id,
@ -118,7 +118,7 @@ SET name = COALESCE(sqlc.narg('name'), name),
bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id), bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id),
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id) sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
WHERE id = $1; WHERE id = $1;
-- name: UpdateLeagueSettings :exec -- name: UpdateCompanyLeagueSettings :exec
UPDATE company_league_settings UPDATE company_league_settings
SET is_active = COALESCE(sqlc.narg('is_active'), is_active), SET is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured = COALESCE( is_featured = COALESCE(
@ -126,4 +126,9 @@ SET is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured is_featured
) )
WHERE league_id = $1 WHERE league_id = $1
AND company_id = $2; AND company_id = $2;
-- name: UpdateGlobalLeagueSettings :exec
UPDATE leagues
SET default_is_active = COALESCE(sqlc.narg('is_active'), default_is_active),
default_is_featured = COALESCE(sqlc.narg('is_featured'), default_is_featured)
WHERE id = $1;

View File

@ -143,4 +143,15 @@ WHERE event_id = $1
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: DeleteOddsForEvent :exec -- name: DeleteOddsForEvent :exec
DELETE FROM odds_market DELETE FROM odds_market
Where event_id = $1; Where event_id = $1;
-- name: DeleteAllCompanyOddsSetting :exec
DELETE FROM company_odd_settings
WHERE company_id = $1;
-- name: DeleteCompanyOddsSettingByOddMarketID :exec
DELETE FROM company_odd_settings
WHERE company_id = $1
AND odds_market_id = $2;
-- name: UpdateGlobalOddsSetting :exec
UPDATE odds_market
SET default_is_active = COALESCE(sqlc.narg(default_is_active), default_is_active)
WHERE id = $1;

View File

@ -0,0 +1,31 @@
-- For each table with an id sequence
SELECT setval(
pg_get_serial_sequence('users', 'id'),
COALESCE(MAX(id), 1)
)
FROM users;
SELECT setval(
pg_get_serial_sequence('wallets', 'id'),
COALESCE(MAX(id), 1)
)
FROM wallets;
SELECT setval(
pg_get_serial_sequence('customer_wallets', 'id'),
COALESCE(MAX(id), 1)
)
FROM customer_wallets;
SELECT setval(
pg_get_serial_sequence('companies', 'id'),
COALESCE(MAX(id), 1)
)
FROM companies;
SELECT setval(
pg_get_serial_sequence('branches', 'id'),
COALESCE(MAX(id), 1)
)
FROM branches;
SELECT setval(
pg_get_serial_sequence('supported_operations', 'id'),
COALESCE(MAX(id), 1)
)
FROM supported_operations;

View File

@ -448,6 +448,103 @@ func (q *Queries) GetBetOutcomeCountByOddID(ctx context.Context, oddID int64) (i
return count, err return count, err
} }
const GetBetOutcomeViewByEventID = `-- name: GetBetOutcomeViewByEventID :many
SELECT bet_outcomes.id, bet_outcomes.bet_id, bet_outcomes.sport_id, bet_outcomes.event_id, bet_outcomes.odd_id, bet_outcomes.home_team_name, bet_outcomes.away_team_name, bet_outcomes.market_id, bet_outcomes.market_name, bet_outcomes.odd, bet_outcomes.odd_name, bet_outcomes.odd_header, bet_outcomes.odd_handicap, bet_outcomes.status, bet_outcomes.expires,
users.first_name,
users.last_name,
bets.amount,
bets.total_odds
FROM bet_outcomes
JOIN bets ON bets.id = bet_outcomes.bet_id
JOIN users ON bets.user_id = users.id
WHERE bet_outcomes.event_id = $1
AND (
bets.company_id = $2
OR $2 IS NULL
)
AND (
bet_outcomes.status = $3
OR $3 IS NULL
)
LIMIT $5 OFFSET $4
`
type GetBetOutcomeViewByEventIDParams struct {
EventID int64 `json:"event_id"`
CompanyID pgtype.Int8 `json:"company_id"`
FilterStatus pgtype.Int4 `json:"filter_status"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
type GetBetOutcomeViewByEventIDRow struct {
ID int64 `json:"id"`
BetID int64 `json:"bet_id"`
SportID int64 `json:"sport_id"`
EventID int64 `json:"event_id"`
OddID int64 `json:"odd_id"`
HomeTeamName string `json:"home_team_name"`
AwayTeamName string `json:"away_team_name"`
MarketID int64 `json:"market_id"`
MarketName string `json:"market_name"`
Odd float32 `json:"odd"`
OddName string `json:"odd_name"`
OddHeader string `json:"odd_header"`
OddHandicap string `json:"odd_handicap"`
Status int32 `json:"status"`
Expires pgtype.Timestamp `json:"expires"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
}
func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutcomeViewByEventIDParams) ([]GetBetOutcomeViewByEventIDRow, error) {
rows, err := q.db.Query(ctx, GetBetOutcomeViewByEventID,
arg.EventID,
arg.CompanyID,
arg.FilterStatus,
arg.Offset,
arg.Limit,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetBetOutcomeViewByEventIDRow
for rows.Next() {
var i GetBetOutcomeViewByEventIDRow
if err := rows.Scan(
&i.ID,
&i.BetID,
&i.SportID,
&i.EventID,
&i.OddID,
&i.HomeTeamName,
&i.AwayTeamName,
&i.MarketID,
&i.MarketName,
&i.Odd,
&i.OddName,
&i.OddHeader,
&i.OddHandicap,
&i.Status,
&i.Expires,
&i.FirstName,
&i.LastName,
&i.Amount,
&i.TotalOdds,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetBetsForCashback = `-- name: GetBetsForCashback :many const GetBetsForCashback = `-- name: GetBetsForCashback :many
SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes
FROM bet_with_outcomes FROM bet_with_outcomes
@ -557,6 +654,34 @@ func (q *Queries) GetTotalBets(ctx context.Context, arg GetTotalBetsParams) (int
return count, err return count, err
} }
const TotalBetOutcomeViewByEventID = `-- name: TotalBetOutcomeViewByEventID :one
SELECT count(*)
FROM bet_outcomes
JOIN bets ON bets.id = bet_outcomes.bet_id
WHERE bet_outcomes.event_id = $1
AND (
bets.company_id = $2
OR $2 IS NULL
)
AND (
bet_outcomes.status = $3
OR $3 IS NULL
)
`
type TotalBetOutcomeViewByEventIDParams struct {
EventID int64 `json:"event_id"`
CompanyID pgtype.Int8 `json:"company_id"`
FilterStatus pgtype.Int4 `json:"filter_status"`
}
func (q *Queries) TotalBetOutcomeViewByEventID(ctx context.Context, arg TotalBetOutcomeViewByEventIDParams) (int64, error) {
row := q.db.QueryRow(ctx, TotalBetOutcomeViewByEventID, arg.EventID, arg.CompanyID, arg.FilterStatus)
var count int64
err := row.Scan(&count)
return count, err
}
const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :one const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :one
UPDATE bet_outcomes UPDATE bet_outcomes
SET status = $1 SET status = $1
@ -675,6 +800,54 @@ func (q *Queries) UpdateBetOutcomeStatusForEvent(ctx context.Context, arg Update
return items, nil return items, nil
} }
const UpdateBetOutcomeStatusForOddID = `-- name: UpdateBetOutcomeStatusForOddID :many
UPDATE bet_outcomes
SEt status = $1
WHERE odd_id = $2
RETURNING id, bet_id, sport_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires
`
type UpdateBetOutcomeStatusForOddIDParams struct {
Status int32 `json:"status"`
OddID int64 `json:"odd_id"`
}
func (q *Queries) UpdateBetOutcomeStatusForOddID(ctx context.Context, arg UpdateBetOutcomeStatusForOddIDParams) ([]BetOutcome, error) {
rows, err := q.db.Query(ctx, UpdateBetOutcomeStatusForOddID, arg.Status, arg.OddID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []BetOutcome
for rows.Next() {
var i BetOutcome
if err := rows.Scan(
&i.ID,
&i.BetID,
&i.SportID,
&i.EventID,
&i.OddID,
&i.HomeTeamName,
&i.AwayTeamName,
&i.MarketID,
&i.MarketName,
&i.Odd,
&i.OddName,
&i.OddHeader,
&i.OddHandicap,
&i.Status,
&i.Expires,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const UpdateBetWithCashback = `-- name: UpdateBetWithCashback :exec const UpdateBetWithCashback = `-- name: UpdateBetWithCashback :exec
UPDATE bets UPDATE bets
SET processed = $1 SET processed = $1

View File

@ -153,17 +153,27 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail
return i, err return i, err
} }
const GetCompanyIDUsingSlug = `-- name: GetCompanyIDUsingSlug :one const GetCompanyUsingSlug = `-- name: GetCompanyUsingSlug :one
SELECT id SELECT id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
FROM companies FROM companies
WHERE slug = $1 WHERE slug = $1
` `
func (q *Queries) GetCompanyIDUsingSlug(ctx context.Context, slug string) (int64, error) { func (q *Queries) GetCompanyUsingSlug(ctx context.Context, slug string) (Company, error) {
row := q.db.QueryRow(ctx, GetCompanyIDUsingSlug, slug) row := q.db.QueryRow(ctx, GetCompanyUsingSlug, slug)
var id int64 var i Company
err := row.Scan(&id) err := row.Scan(
return id, err &i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
} }
const SearchCompanyByName = `-- name: SearchCompanyByName :many const SearchCompanyByName = `-- name: SearchCompanyByName :many

View File

@ -282,7 +282,7 @@ type GetEventWithSettingByIDRow struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"` IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"` WinningUpperLimit int64 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
LeagueCc pgtype.Text `json:"league_cc"` LeagueCc pgtype.Text `json:"league_cc"`
} }
@ -440,7 +440,7 @@ type GetEventsWithSettingsRow struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"` IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"` WinningUpperLimit int64 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
LeagueCc pgtype.Text `json:"league_cc"` LeagueCc pgtype.Text `json:"league_cc"`
} }
@ -514,7 +514,9 @@ func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSe
} }
const GetSportAndLeagueIDs = `-- name: GetSportAndLeagueIDs :one const GetSportAndLeagueIDs = `-- name: GetSportAndLeagueIDs :one
SELECT sport_id, league_id FROM events SELECT sport_id,
league_id
FROM events
WHERE id = $1 WHERE id = $1
` `
@ -831,7 +833,7 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]int64, error) {
return items, nil return items, nil
} }
const SaveEventSettings = `-- name: SaveEventSettings :exec const SaveTenantEventSettings = `-- name: SaveTenantEventSettings :exec
INSERT INTO company_event_settings ( INSERT INTO company_event_settings (
company_id, company_id,
event_id, event_id,
@ -846,16 +848,16 @@ SET is_active = EXCLUDED.is_active,
winning_upper_limit = EXCLUDED.winning_upper_limit winning_upper_limit = EXCLUDED.winning_upper_limit
` `
type SaveEventSettingsParams struct { type SaveTenantEventSettingsParams struct {
CompanyID int64 `json:"company_id"` CompanyID int64 `json:"company_id"`
EventID int64 `json:"event_id"` EventID int64 `json:"event_id"`
IsActive pgtype.Bool `json:"is_active"` IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"` IsFeatured pgtype.Bool `json:"is_featured"`
WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` WinningUpperLimit pgtype.Int8 `json:"winning_upper_limit"`
} }
func (q *Queries) SaveEventSettings(ctx context.Context, arg SaveEventSettingsParams) error { func (q *Queries) SaveTenantEventSettings(ctx context.Context, arg SaveTenantEventSettingsParams) error {
_, err := q.db.Exec(ctx, SaveEventSettings, _, err := q.db.Exec(ctx, SaveTenantEventSettings,
arg.CompanyID, arg.CompanyID,
arg.EventID, arg.EventID,
arg.IsActive, arg.IsActive,
@ -867,7 +869,8 @@ func (q *Queries) SaveEventSettings(ctx context.Context, arg SaveEventSettingsPa
const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec
UPDATE events UPDATE events
SET is_monitored = $1 SET is_monitored = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2 WHERE id = $2
` `
@ -881,6 +884,38 @@ func (q *Queries) UpdateEventMonitored(ctx context.Context, arg UpdateEventMonit
return err return err
} }
const UpdateGlobalEventSettings = `-- name: UpdateGlobalEventSettings :exec
UPDATE events
SET default_is_active = COALESCE($2, default_is_active),
default_is_featured = COALESCE(
$3,
default_is_featured
),
default_winning_upper_limit = COALESCE(
$4,
default_winning_upper_limit
),
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
`
type UpdateGlobalEventSettingsParams struct {
ID int64 `json:"id"`
DefaultIsActive pgtype.Bool `json:"default_is_active"`
DefaultIsFeatured pgtype.Bool `json:"default_is_featured"`
DefaultWinningUpperLimit pgtype.Int8 `json:"default_winning_upper_limit"`
}
func (q *Queries) UpdateGlobalEventSettings(ctx context.Context, arg UpdateGlobalEventSettingsParams) error {
_, err := q.db.Exec(ctx, UpdateGlobalEventSettings,
arg.ID,
arg.DefaultIsActive,
arg.DefaultIsFeatured,
arg.DefaultWinningUpperLimit,
)
return err
}
const UpdateMatchResult = `-- name: UpdateMatchResult :exec const UpdateMatchResult = `-- name: UpdateMatchResult :exec
UPDATE events UPDATE events
SET score = $1, SET score = $1,

View File

@ -292,7 +292,7 @@ func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) erro
return err return err
} }
const InsertLeagueSettings = `-- name: InsertLeagueSettings :exec const SaveLeagueSettings = `-- name: SaveLeagueSettings :exec
INSERT INTO company_league_settings ( INSERT INTO company_league_settings (
company_id, company_id,
league_id, league_id,
@ -305,15 +305,15 @@ SET is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured is_featured = EXCLUDED.is_featured
` `
type InsertLeagueSettingsParams struct { type SaveLeagueSettingsParams struct {
CompanyID int64 `json:"company_id"` CompanyID int64 `json:"company_id"`
LeagueID int64 `json:"league_id"` LeagueID int64 `json:"league_id"`
IsActive pgtype.Bool `json:"is_active"` IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"` IsFeatured pgtype.Bool `json:"is_featured"`
} }
func (q *Queries) InsertLeagueSettings(ctx context.Context, arg InsertLeagueSettingsParams) error { func (q *Queries) SaveLeagueSettings(ctx context.Context, arg SaveLeagueSettingsParams) error {
_, err := q.db.Exec(ctx, InsertLeagueSettings, _, err := q.db.Exec(ctx, SaveLeagueSettings,
arg.CompanyID, arg.CompanyID,
arg.LeagueID, arg.LeagueID,
arg.IsActive, arg.IsActive,
@ -322,6 +322,52 @@ func (q *Queries) InsertLeagueSettings(ctx context.Context, arg InsertLeagueSett
return err return err
} }
const UpdateCompanyLeagueSettings = `-- name: UpdateCompanyLeagueSettings :exec
UPDATE company_league_settings
SET is_active = COALESCE($3, is_active),
is_featured = COALESCE(
$4,
is_featured
)
WHERE league_id = $1
AND company_id = $2
`
type UpdateCompanyLeagueSettingsParams struct {
LeagueID int64 `json:"league_id"`
CompanyID int64 `json:"company_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
}
func (q *Queries) UpdateCompanyLeagueSettings(ctx context.Context, arg UpdateCompanyLeagueSettingsParams) error {
_, err := q.db.Exec(ctx, UpdateCompanyLeagueSettings,
arg.LeagueID,
arg.CompanyID,
arg.IsActive,
arg.IsFeatured,
)
return err
}
const UpdateGlobalLeagueSettings = `-- name: UpdateGlobalLeagueSettings :exec
UPDATE leagues
SET default_is_active = COALESCE($2, default_is_active),
default_is_featured = COALESCE($3, default_is_featured)
WHERE id = $1
`
type UpdateGlobalLeagueSettingsParams struct {
ID int64 `json:"id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
}
func (q *Queries) UpdateGlobalLeagueSettings(ctx context.Context, arg UpdateGlobalLeagueSettingsParams) error {
_, err := q.db.Exec(ctx, UpdateGlobalLeagueSettings, arg.ID, arg.IsActive, arg.IsFeatured)
return err
}
const UpdateLeague = `-- name: UpdateLeague :exec const UpdateLeague = `-- name: UpdateLeague :exec
UPDATE leagues UPDATE leagues
SET name = COALESCE($2, name), SET name = COALESCE($2, name),
@ -349,31 +395,3 @@ func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) erro
) )
return err return err
} }
const UpdateLeagueSettings = `-- name: UpdateLeagueSettings :exec
UPDATE company_league_settings
SET is_active = COALESCE($3, is_active),
is_featured = COALESCE(
$4,
is_featured
)
WHERE league_id = $1
AND company_id = $2
`
type UpdateLeagueSettingsParams struct {
LeagueID int64 `json:"league_id"`
CompanyID int64 `json:"company_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
}
func (q *Queries) UpdateLeagueSettings(ctx context.Context, arg UpdateLeagueSettingsParams) error {
_, err := q.db.Exec(ctx, UpdateLeagueSettings,
arg.LeagueID,
arg.CompanyID,
arg.IsActive,
arg.IsFeatured,
)
return err
}

View File

@ -177,7 +177,7 @@ type CompanyEventSetting struct {
EventID int64 `json:"event_id"` EventID int64 `json:"event_id"`
IsActive pgtype.Bool `json:"is_active"` IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"` IsFeatured pgtype.Bool `json:"is_featured"`
WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` WinningUpperLimit pgtype.Int8 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
} }
@ -405,7 +405,7 @@ type EventWithSetting struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"` IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"` WinningUpperLimit int64 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
LeagueCc pgtype.Text `json:"league_cc"` LeagueCc pgtype.Text `json:"league_cc"`
} }

View File

@ -11,6 +11,32 @@ import (
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
const DeleteAllCompanyOddsSetting = `-- name: DeleteAllCompanyOddsSetting :exec
DELETE FROM company_odd_settings
WHERE company_id = $1
`
func (q *Queries) DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error {
_, err := q.db.Exec(ctx, DeleteAllCompanyOddsSetting, companyID)
return err
}
const DeleteCompanyOddsSettingByOddMarketID = `-- name: DeleteCompanyOddsSettingByOddMarketID :exec
DELETE FROM company_odd_settings
WHERE company_id = $1
AND odds_market_id = $2
`
type DeleteCompanyOddsSettingByOddMarketIDParams struct {
CompanyID int64 `json:"company_id"`
OddsMarketID int64 `json:"odds_market_id"`
}
func (q *Queries) DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, arg DeleteCompanyOddsSettingByOddMarketIDParams) error {
_, err := q.db.Exec(ctx, DeleteCompanyOddsSettingByOddMarketID, arg.CompanyID, arg.OddsMarketID)
return err
}
const DeleteOddsForEvent = `-- name: DeleteOddsForEvent :exec const DeleteOddsForEvent = `-- name: DeleteOddsForEvent :exec
DELETE FROM odds_market DELETE FROM odds_market
Where event_id = $1 Where event_id = $1
@ -568,3 +594,19 @@ func (q *Queries) SaveOddSettings(ctx context.Context, arg SaveOddSettingsParams
) )
return err return err
} }
const UpdateGlobalOddsSetting = `-- name: UpdateGlobalOddsSetting :exec
UPDATE odds_market
SET default_is_active = COALESCE($2, default_is_active)
WHERE id = $1
`
type UpdateGlobalOddsSettingParams struct {
ID int64 `json:"id"`
DefaultIsActive pgtype.Bool `json:"default_is_active"`
}
func (q *Queries) UpdateGlobalOddsSetting(ctx context.Context, arg UpdateGlobalOddsSettingParams) error {
_, err := q.db.Exec(ctx, UpdateGlobalOddsSetting, arg.ID, arg.DefaultIsActive)
return err
}

View File

@ -163,6 +163,35 @@ type BetRes struct {
FastCode string `json:"fast_code"` FastCode string `json:"fast_code"`
} }
type BetOutcomeViewRes struct {
ID int64 `json:"id"`
BetID int64 `json:"bet_id"`
SportID int64 `json:"sport_id"`
EventID int64 `json:"event_id"`
OddID int64 `json:"odd_id"`
HomeTeamName string `json:"home_team_name"`
AwayTeamName string `json:"away_team_name"`
MarketID int64 `json:"market_id"`
MarketName string `json:"market_name"`
Odd float32 `json:"odd"`
OddName string `json:"odd_name"`
OddHeader string `json:"odd_header"`
OddHandicap string `json:"odd_handicap"`
Status OutcomeStatus `json:"status"`
Expires time.Time `json:"expires"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Amount int64 `json:"amount"`
TotalOdds float32 `json:"total_odds"`
}
type BetOutcomeViewFilter struct {
OutcomeStatus ValidOutcomeStatus
CompanyID ValidInt64
Limit ValidInt32
Offset ValidInt32
}
func ConvertCreateBetRes(bet Bet, createdNumber int64) CreateBetRes { func ConvertCreateBetRes(bet Bet, createdNumber int64) CreateBetRes {
return CreateBetRes{ return CreateBetRes{
ID: bet.ID, ID: bet.ID,
@ -228,6 +257,29 @@ func ConvertDBBetOutcomes(outcome dbgen.BetOutcome) BetOutcome {
Expires: outcome.Expires.Time, Expires: outcome.Expires.Time,
} }
} }
func ConvertDBBetOutcomesView(outcome dbgen.GetBetOutcomeViewByEventIDRow) BetOutcomeViewRes {
return BetOutcomeViewRes{
ID: outcome.ID,
BetID: outcome.BetID,
SportID: outcome.SportID,
EventID: outcome.EventID,
OddID: outcome.OddID,
HomeTeamName: outcome.HomeTeamName,
AwayTeamName: outcome.AwayTeamName,
MarketID: outcome.MarketID,
MarketName: outcome.MarketName,
Odd: outcome.Odd,
OddName: outcome.OddName,
OddHeader: outcome.OddHeader,
OddHandicap: outcome.OddHandicap,
Status: OutcomeStatus(outcome.Status),
Expires: outcome.Expires.Time,
FirstName: outcome.FirstName,
LastName: outcome.LastName,
Amount: outcome.Amount,
TotalOdds: outcome.TotalOdds,
}
}
func ConvertDBBetWithOutcomes(bet dbgen.BetWithOutcome) GetBet { func ConvertDBBetWithOutcomes(bet dbgen.BetWithOutcome) GetBet {
var outcomes []BetOutcome = make([]BetOutcome, 0, len(bet.Outcomes)) var outcomes []BetOutcome = make([]BetOutcome, 0, len(bet.Outcomes))

View File

@ -1,6 +1,7 @@
package domain package domain
import ( import (
"fmt"
"time" "time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
@ -50,6 +51,58 @@ const (
EVENT_SOURCE_ENET EventSource = "enetpulse" EVENT_SOURCE_ENET EventSource = "enetpulse"
) )
// --- EventStatus Validation ---
func (s EventStatus) IsValid() bool {
switch s {
case STATUS_PENDING,
STATUS_IN_PLAY,
STATUS_TO_BE_FIXED,
STATUS_ENDED,
STATUS_POSTPONED,
STATUS_CANCELLED,
STATUS_WALKOVER,
STATUS_INTERRUPTED,
STATUS_ABANDONED,
STATUS_RETIRED,
STATUS_SUSPENDED,
STATUS_DECIDED_BY_FA,
STATUS_REMOVED:
return true
default:
return false
}
}
func ParseEventStatus(val string) (EventStatus, error) {
s := EventStatus(val)
if !s.IsValid() {
return "", fmt.Errorf("invalid EventStatus: %q", val)
}
return s, nil
}
// --- EventSource Validation ---
func (s EventSource) IsValid() bool {
switch s {
case EVENT_SOURCE_BET365,
EVENT_SOURCE_BWIN,
EVENT_SOURCE_BETFAIR,
EVENT_SOURCE_1XBET,
EVENT_SOURCE_ENET:
return true
default:
return false
}
}
func ParseEventSource(val string) (EventSource, error) {
s := EventSource(val)
if !s.IsValid() {
return "", fmt.Errorf("invalid EventSource: %q", val)
}
return s, nil
}
type BaseEvent struct { type BaseEvent struct {
ID int64 ID int64
SourceEventID string SourceEventID string
@ -128,7 +181,7 @@ type EventWithSettings struct {
IsMonitored bool IsMonitored bool
IsFeatured bool IsFeatured bool
IsActive bool IsActive bool
WinningUpperLimit int32 WinningUpperLimit int64
DefaultIsFeatured bool DefaultIsFeatured bool
DefaultIsActive bool DefaultIsActive bool
DefaultWinningUpperLimit int64 DefaultWinningUpperLimit int64
@ -181,7 +234,7 @@ type EventWithSettingsRes struct {
IsMonitored bool `json:"is_monitored"` IsMonitored bool `json:"is_monitored"`
IsFeatured bool `json:"is_featured"` IsFeatured bool `json:"is_featured"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
WinningUpperLimit int32 `json:"winning_upper_limit"` WinningUpperLimit int64 `json:"winning_upper_limit"`
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"` DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
@ -204,12 +257,18 @@ type EventSettings struct {
UpdatedAt time.Time UpdatedAt time.Time
} }
type CreateEventSettings struct { type UpdateTenantEventSettings struct {
CompanyID int64 CompanyID int64
EventID int64 EventID int64
IsActive ValidBool IsActive ValidBool
IsFeatured ValidBool IsFeatured ValidBool
WinningUpperLimit ValidInt WinningUpperLimit ValidInt64
}
type UpdateGlobalEventSettings struct {
EventID int64
IsActive ValidBool
IsFeatured ValidBool
WinningUpperLimit ValidInt64
} }
type ValidEventStatus struct { type ValidEventStatus struct {
@ -331,8 +390,8 @@ func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams {
} }
} }
func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEventSettingsParams { func ConvertCreateEventSettings(eventSettings UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams {
return dbgen.SaveEventSettingsParams{ return dbgen.SaveTenantEventSettingsParams{
CompanyID: eventSettings.CompanyID, CompanyID: eventSettings.CompanyID,
EventID: eventSettings.EventID, EventID: eventSettings.EventID,
IsActive: eventSettings.IsActive.ToPG(), IsActive: eventSettings.IsActive.ToPG(),
@ -343,17 +402,19 @@ func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEve
func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings { func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings {
return EventWithSettings{ return EventWithSettings{
ID: event.ID, ID: event.ID,
SportID: event.SportID, SourceEventID: event.SourceEventID,
MatchName: event.MatchName, WinningUpperLimit: event.WinningUpperLimit,
HomeTeam: event.HomeTeam, SportID: event.SportID,
AwayTeam: event.AwayTeam, MatchName: event.MatchName,
HomeTeamID: event.HomeTeamID, HomeTeam: event.HomeTeam,
AwayTeamID: event.AwayTeamID, AwayTeam: event.AwayTeam,
HomeTeamImage: event.HomeKitImage, HomeTeamID: event.HomeTeamID,
AwayTeamImage: event.AwayKitImage, AwayTeamID: event.AwayTeamID,
LeagueID: event.LeagueID, HomeTeamImage: event.HomeKitImage,
LeagueName: event.LeagueName, AwayTeamImage: event.AwayKitImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: ValidString{ LeagueCC: ValidString{
Value: event.LeagueCc.String, Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid, Valid: event.LeagueCc.Valid,
@ -401,8 +462,8 @@ func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSett
return result return result
} }
func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettingsParams { func ConvertUpdateTenantEventSettings(event UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams {
return dbgen.SaveEventSettingsParams{ return dbgen.SaveTenantEventSettingsParams{
EventID: event.EventID, EventID: event.EventID,
CompanyID: event.CompanyID, CompanyID: event.CompanyID,
IsActive: event.IsActive.ToPG(), IsActive: event.IsActive.ToPG(),
@ -410,10 +471,19 @@ func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettin
WinningUpperLimit: event.WinningUpperLimit.ToPG(), WinningUpperLimit: event.WinningUpperLimit.ToPG(),
} }
} }
func ConvertUpdateGlobalEventSettings(event UpdateGlobalEventSettings) dbgen.UpdateGlobalEventSettingsParams {
return dbgen.UpdateGlobalEventSettingsParams{
ID: event.EventID,
DefaultIsActive: event.IsActive.ToPG(),
DefaultIsFeatured: event.IsFeatured.ToPG(),
DefaultWinningUpperLimit: event.WinningUpperLimit.ToPG(),
}
}
func ConvertEventRes(event BaseEvent) BaseEventRes { func ConvertEventRes(event BaseEvent) BaseEventRes {
return BaseEventRes{ return BaseEventRes{
ID: event.ID, ID: event.ID,
SourceEventID: event.SourceEventID,
SportID: event.SportID, SportID: event.SportID,
MatchName: event.MatchName, MatchName: event.MatchName,
HomeTeam: event.HomeTeam, HomeTeam: event.HomeTeam,
@ -452,6 +522,7 @@ func ConvertEventResList(events []BaseEvent) []BaseEventRes {
func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes { func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
return EventWithSettingsRes{ return EventWithSettingsRes{
ID: event.ID, ID: event.ID,
SourceEventID: event.SourceEventID,
SportID: event.SportID, SportID: event.SportID,
MatchName: event.MatchName, MatchName: event.MatchName,
HomeTeam: event.HomeTeam, HomeTeam: event.HomeTeam,
@ -480,6 +551,7 @@ func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
MatchPeriod: event.MatchPeriod.Value, MatchPeriod: event.MatchPeriod.Value,
IsLive: event.IsLive, IsLive: event.IsLive,
FetchedAt: event.FetchedAt.UTC(), FetchedAt: event.FetchedAt.UTC(),
UpdatedAt: event.UpdatedAt,
} }
} }

View File

@ -87,6 +87,17 @@ type UpdateLeague struct {
SportID ValidInt32 `json:"sport_id" example:"1"` SportID ValidInt32 `json:"sport_id" example:"1"`
} }
type UpdateLeagueSettingsReq struct {
IsFeatured *bool `json:"is_featured" example:"true"`
IsActive *bool `json:"is_active" example:"true"`
}
type UpdateGlobalLeagueSettings struct {
ID int64
DefaultIsActive ValidBool
DefaultIsFeatured ValidBool
}
type LeagueFilter struct { type LeagueFilter struct {
Query ValidString Query ValidString
CountryCode ValidString CountryCode ValidString
@ -109,8 +120,8 @@ func ConvertCreateLeague(league CreateLeague) dbgen.InsertLeagueParams {
} }
} }
func ConvertCreateLeagueSettings(leagueSetting CreateLeagueSettings) dbgen.InsertLeagueSettingsParams { func ConvertCreateLeagueSettings(leagueSetting CreateLeagueSettings) dbgen.SaveLeagueSettingsParams {
return dbgen.InsertLeagueSettingsParams{ return dbgen.SaveLeagueSettingsParams{
CompanyID: leagueSetting.CompanyID, CompanyID: leagueSetting.CompanyID,
LeagueID: leagueSetting.LeagueID, LeagueID: leagueSetting.LeagueID,
IsActive: leagueSetting.IsActive.ToPG(), IsActive: leagueSetting.IsActive.ToPG(),
@ -149,7 +160,7 @@ func ConvertDBLeagueWithSetting(lws dbgen.GetAllLeaguesWithSettingsRow) LeagueWi
ID: lws.ID, ID: lws.ID,
Name: lws.Name, Name: lws.Name,
CompanyID: lws.CompanyID.Int64, CompanyID: lws.CompanyID.Int64,
CountryCode: ValidString{ CountryCode: ValidString{
Value: lws.CountryCode.String, Value: lws.CountryCode.String,
Valid: lws.CountryCode.Valid, Valid: lws.CountryCode.Valid,
}, },
@ -187,15 +198,15 @@ func ConvertUpdateLeague(updateLeague UpdateLeague) dbgen.UpdateLeagueParams {
func ConvertLeagueWithSettingRes(lws LeagueWithSettings) LeagueWithSettingsRes { func ConvertLeagueWithSettingRes(lws LeagueWithSettings) LeagueWithSettingsRes {
return LeagueWithSettingsRes{ return LeagueWithSettingsRes{
ID: lws.ID, ID: lws.ID,
Name: lws.Name, Name: lws.Name,
CompanyID: lws.CompanyID, CompanyID: lws.CompanyID,
CountryCode: lws.CountryCode.Value, CountryCode: lws.CountryCode.Value,
Bet365ID: lws.Bet365ID.Value, Bet365ID: lws.Bet365ID.Value,
IsActive: lws.IsActive, IsActive: lws.IsActive,
SportID: lws.SportID, SportID: lws.SportID,
IsFeatured: lws.IsFeatured, IsFeatured: lws.IsFeatured,
UpdatedAt: lws.UpdatedAt, UpdatedAt: lws.UpdatedAt,
DefaultIsActive: lws.DefaultIsActive, DefaultIsActive: lws.DefaultIsActive,
DefaultIsFeatured: lws.DefaultIsFeatured, DefaultIsFeatured: lws.DefaultIsFeatured,
} }
@ -213,12 +224,12 @@ func ConvertLeagueWithSettingResList(leagues []LeagueWithSettings) []LeagueWithS
func ConvertBaseLeagueRes(league BaseLeague) BaseLeagueRes { func ConvertBaseLeagueRes(league BaseLeague) BaseLeagueRes {
return BaseLeagueRes{ return BaseLeagueRes{
ID: league.ID, ID: league.ID,
Name: league.Name, Name: league.Name,
CountryCode: league.CountryCode.Value, CountryCode: league.CountryCode.Value,
Bet365ID: league.Bet365ID.Value, Bet365ID: league.Bet365ID.Value,
SportID: league.SportID, SportID: league.SportID,
DefaultIsActive: league.DefaultIsActive, DefaultIsActive: league.DefaultIsActive,
DefaultIsFeatured: league.DefaultIsFeatured, DefaultIsFeatured: league.DefaultIsFeatured,
} }
} }
@ -231,3 +242,11 @@ func ConvertBaseLeagueResList(leagues []BaseLeague) []BaseLeagueRes {
return result return result
} }
func ConvertUpdateGlobalLeagueSetting(league UpdateGlobalLeagueSettings) dbgen.UpdateGlobalLeagueSettingsParams {
return dbgen.UpdateGlobalLeagueSettingsParams{
ID: league.ID,
IsActive: league.DefaultIsActive.ToPG(),
IsFeatured: league.DefaultIsFeatured.ToPG(),
}
}

View File

@ -61,6 +61,11 @@ type CreateOddMarketSettings struct {
CustomRawOdds []map[string]interface{} CustomRawOdds []map[string]interface{}
} }
type UpdateGlobalOddMarketSettings struct {
OddMarketID int64
IsActive ValidBool
}
type CustomOdd struct { type CustomOdd struct {
OddID int64 `json:"odd_id"` OddID int64 `json:"odd_id"`
OddValue float32 `json:"odd_value"` OddValue float32 `json:"odd_value"`
@ -72,6 +77,11 @@ type CreateOddMarketSettingsReq struct {
CustomOdd []CustomOdd `json:"custom_odd,omitempty"` CustomOdd []CustomOdd `json:"custom_odd,omitempty"`
} }
type UpdateGlobalOddMarketSettingsReq struct {
OddMarketID int64 `json:"odd_market_id"`
IsActive *bool `json:"is_active,omitempty"`
}
type RawOddsByMarketID struct { type RawOddsByMarketID struct {
ID int64 `json:"id"` ID int64 `json:"id"`
MarketName string `json:"market_name"` MarketName string `json:"market_name"`
@ -86,6 +96,8 @@ type OddMarketFilter struct {
Offset ValidInt32 Offset ValidInt32
} }
type OddMarketWithEventFilter struct { type OddMarketWithEventFilter struct {
Status ValidString
IsLive ValidBool
Limit ValidInt32 Limit ValidInt32
Offset ValidInt32 Offset ValidInt32
} }

View File

@ -1,6 +1,7 @@
package domain package domain
import ( import (
"fmt"
"time" "time"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
@ -48,6 +49,28 @@ const (
OUTCOME_STATUS_ERROR OutcomeStatus = 5 //Half Win and Half Given Back OUTCOME_STATUS_ERROR OutcomeStatus = 5 //Half Win and Half Given Back
) )
func (o OutcomeStatus) IsValid() bool {
switch o {
case OUTCOME_STATUS_PENDING,
OUTCOME_STATUS_WIN,
OUTCOME_STATUS_LOSS,
OUTCOME_STATUS_VOID,
OUTCOME_STATUS_HALF,
OUTCOME_STATUS_ERROR:
return true
default:
return false
}
}
func ParseOutcomeStatus(val int) (OutcomeStatus, error) {
o := OutcomeStatus(val)
if !o.IsValid() {
return 0, fmt.Errorf("invalid OutcomeStatus: %d", val)
}
return o, nil
}
func (o *OutcomeStatus) String() string { func (o *OutcomeStatus) String() string {
switch *o { switch *o {
case OUTCOME_STATUS_PENDING: case OUTCOME_STATUS_PENDING:
@ -72,7 +95,6 @@ type ValidOutcomeStatus struct {
Valid bool Valid bool
} }
func (v ValidOutcomeStatus) ToPG() pgtype.Int4 { func (v ValidOutcomeStatus) ToPG() pgtype.Int4 {
return pgtype.Int4{ return pgtype.Int4{
Int32: int32(v.Value), Int32: int32(v.Value),
@ -80,7 +102,6 @@ func (v ValidOutcomeStatus) ToPG() pgtype.Int4 {
} }
} }
type TimeStatus int32 type TimeStatus int32
const ( const (

View File

@ -123,7 +123,7 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma
Query: filter.Query.ToPG(), Query: filter.Query.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(), CreatedBefore: filter.CreatedBefore.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(), CreatedAfter: filter.CreatedAfter.ToPG(),
}); })
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets)) var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets { for _, bet := range bets {
@ -275,6 +275,36 @@ func (s *Store) SettleWinningBet(ctx context.Context, betID int64, userID int64,
return nil return nil
} }
func (s *Store) GetBetOutcomeViewByEventID(ctx context.Context, eventID int64, filter domain.BetOutcomeViewFilter) ([]domain.BetOutcomeViewRes, int64, error) {
outcomes, err := s.queries.GetBetOutcomeViewByEventID(ctx, dbgen.GetBetOutcomeViewByEventIDParams{
EventID: eventID,
FilterStatus: filter.OutcomeStatus.ToPG(),
CompanyID: filter.CompanyID.ToPG(),
Offset: filter.Offset.ToPG(),
Limit: filter.Limit.ToPG(),
})
if err != nil {
domain.MongoDBLogger.Error("failed to get bet outcomes by event ID",
zap.Int64("event_id", eventID),
zap.Error(err),
)
return nil, 0, err
}
total, err := s.queries.TotalBetOutcomeViewByEventID(ctx, dbgen.TotalBetOutcomeViewByEventIDParams{
EventID: eventID,
FilterStatus: filter.OutcomeStatus.ToPG(),
CompanyID: filter.CompanyID.ToPG(),
})
var result []domain.BetOutcomeViewRes = make([]domain.BetOutcomeViewRes, 0, len(outcomes))
for _, outcome := range outcomes {
result = append(result, domain.ConvertDBBetOutcomesView(outcome))
}
return result, total, nil
}
func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) { func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) {
outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, dbgen.GetBetOutcomeByEventIDParams{ outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, dbgen.GetBetOutcomeByEventIDParams{
@ -377,6 +407,27 @@ func (s *Store) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int6
} }
return result, nil return result, nil
} }
func (s *Store) UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) {
outcomes, err := s.queries.UpdateBetOutcomeStatusForOddID(ctx, dbgen.UpdateBetOutcomeStatusForOddIDParams{
OddID: oddID,
Status: int32(status),
})
if err != nil {
domain.MongoDBLogger.Error("failed to update bet outcome status for oddID",
zap.Int64("oddId", oddID),
zap.Int32("status", int32(status)),
zap.Error(err),
)
return nil, err
}
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
for _, outcome := range outcomes {
result = append(result, domain.ConvertDBBetOutcomes(outcome))
}
return result, nil
}
func (s *Store) UpdateBetWithCashback(ctx context.Context, betID int64, cashbackStatus bool) error { func (s *Store) UpdateBetWithCashback(ctx context.Context, betID int64, cashbackStatus bool) error {
err := s.queries.UpdateBetWithCashback(ctx, dbgen.UpdateBetWithCashbackParams{ err := s.queries.UpdateBetWithCashback(ctx, dbgen.UpdateBetWithCashbackParams{

View File

@ -17,7 +17,7 @@ func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany)
i := 1 i := 1
for { for {
_, err := s.queries.GetCompanyIDUsingSlug(ctx, uniqueSlug) _, err := s.queries.GetCompanyUsingSlug(ctx, uniqueSlug)
if err != nil { if err != nil {
if errors.Is(err, pgx.ErrNoRows) { if errors.Is(err, pgx.ErrNoRows) {
// slug is unique // slug is unique
@ -78,13 +78,13 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany
return domain.ConvertDBCompanyDetails(dbCompany), nil return domain.ConvertDBCompanyDetails(dbCompany), nil
} }
func (s *Store) GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error) { func (s *Store) GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error) {
dbCompanyID, err := s.queries.GetCompanyIDUsingSlug(ctx, slug) dbCompany, err := s.queries.GetCompanyUsingSlug(ctx, slug)
if err != nil { if err != nil {
return 0, err return domain.Company{}, err
} }
return dbCompanyID, nil return domain.ConvertDBCompany(dbCompany), nil
} }
func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) { func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {

View File

@ -3,7 +3,6 @@ package repository
import ( import (
"context" "context"
"fmt" "fmt"
"math"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -55,8 +54,7 @@ func (s *Store) GetAllEvents(ctx context.Context, filter domain.EventFilter) ([]
return nil, 0, err return nil, 0, err
} }
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value)) return domain.ConvertDBEvents(events), totalCount, nil
return domain.ConvertDBEvents(events), int64(numberOfPages), nil
} }
func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) { func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
@ -99,8 +97,6 @@ func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filt
return nil, 0, err return nil, 0, err
} }
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
result := make([]domain.EventWithSettings, len(events)) result := make([]domain.EventWithSettings, len(events))
for i, event := range events { for i, event := range events {
@ -155,7 +151,7 @@ func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filt
} }
} }
return result, int64(numberOfPages), nil return result, totalCount, nil
} }
func (s *Store) GetEventByID(ctx context.Context, ID int64) (domain.BaseEvent, error) { func (s *Store) GetEventByID(ctx context.Context, ID int64) (domain.BaseEvent, error) {
event, err := s.queries.GetEventByID(ctx, ID) event, err := s.queries.GetEventByID(ctx, ID)
@ -281,10 +277,13 @@ func (s *Store) UpdateEventMonitored(ctx context.Context, eventID int64, IsMonit
}) })
} }
func (s *Store) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { func (s *Store) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error {
return s.queries.SaveEventSettings(ctx, domain.ConvertUpdateEventSettings(event)) return s.queries.SaveTenantEventSettings(ctx, domain.ConvertUpdateTenantEventSettings(event))
} }
func (s *Store) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error {
return s.queries.UpdateGlobalEventSettings(ctx, domain.ConvertUpdateGlobalEventSettings(event))
}
func (s *Store) DeleteEvent(ctx context.Context, eventID int64) error { func (s *Store) DeleteEvent(ctx context.Context, eventID int64) error {
err := s.queries.DeleteEvent(ctx, eventID) err := s.queries.DeleteEvent(ctx, eventID)
if err != nil { if err != nil {

View File

@ -13,7 +13,7 @@ func (s *Store) SaveLeague(ctx context.Context, league domain.CreateLeague) erro
} }
func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error { func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error {
return s.queries.InsertLeagueSettings(ctx, domain.ConvertCreateLeagueSettings(leagueSettings)) return s.queries.SaveLeagueSettings(ctx, domain.ConvertCreateLeagueSettings(leagueSettings))
} }
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) { func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
@ -85,3 +85,7 @@ func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64, companyI
func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error { func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {
return s.queries.UpdateLeague(ctx, domain.ConvertUpdateLeague(league)) return s.queries.UpdateLeague(ctx, domain.ConvertUpdateLeague(league))
} }
func (s *Store) UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error {
return s.queries.UpdateGlobalLeagueSettings(ctx, domain.ConvertUpdateGlobalLeagueSetting(league))
}

View File

@ -239,17 +239,11 @@ func (s *Store) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID
func (s *Store) GetOddsByEventID(ctx context.Context, eventID int64, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) { func (s *Store) GetOddsByEventID(ctx context.Context, eventID int64, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{ odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{
EventID: eventID, EventID: eventID,
Status: filter.Status.ToPG(),
IsLive: filter.IsLive.ToPG(),
Limit: filter.Limit.ToPG(), Limit: filter.Limit.ToPG(),
Offset: filter.Offset.ToPG(), Offset: filter.Offset.ToPG(),
IsLive: pgtype.Bool{ Source: pgtype.Text{},
Bool: false,
Valid: true,
},
Status: pgtype.Text{
String: string(domain.STATUS_PENDING),
Valid: true,
},
Source: pgtype.Text{},
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -322,3 +316,21 @@ func (s *Store) SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketS
} }
return s.queries.SaveOddSettings(ctx, res) return s.queries.SaveOddSettings(ctx, res)
} }
func (s *Store) UpdateGlobalOddsSetting(ctx context.Context, odd domain.UpdateGlobalOddMarketSettings) error {
return s.queries.UpdateGlobalOddsSetting(ctx, dbgen.UpdateGlobalOddsSettingParams{
ID: odd.OddMarketID,
DefaultIsActive: odd.IsActive.ToPG(),
})
}
func (s *Store) DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error {
return s.queries.DeleteAllCompanyOddsSetting(ctx, companyID)
}
func (s *Store) DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, companyID int64, oddMarketID int64) error {
return s.queries.DeleteCompanyOddsSettingByOddMarketID(ctx, dbgen.DeleteCompanyOddsSettingByOddMarketIDParams{
CompanyID: companyID,
OddsMarketID: oddMarketID,
})
}

View File

@ -247,7 +247,7 @@ func (s *Service) SendAdminErrorNotification(ctx context.Context, betID int64, s
} }
func (s *Service) SendAdminLargeBetNotification(ctx context.Context, betID int64, totalWinnings float32, extra string, companyID int64) error { func (s *Service) SendAdminLargeBetNotification(ctx context.Context, betID int64, totalWinnings float32, extra string, companyID int64) error {
headline := fmt.Sprintf("SYSTEM WARNING: High Risk Bet", betID, totalWinnings) headline := "SYSTEM WARNING: High Risk Bet"
message := fmt.Sprintf("Bet #%d has been created with %v payout", betID, totalWinnings) message := fmt.Sprintf("Bet #%d has been created with %v payout", betID, totalWinnings)
super_admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{ super_admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{

View File

@ -15,6 +15,7 @@ type BetStore interface {
GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, int64, error) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, int64, error)
GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error)
GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error) GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error)
GetBetOutcomeViewByEventID(ctx context.Context, eventID int64, filter domain.BetOutcomeViewFilter) ([]domain.BetOutcomeViewRes, int64, error)
GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error)
GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error) GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error)
GetBetOutcomeCountByOddID(ctx context.Context, oddID int64) (int64, error) GetBetOutcomeCountByOddID(ctx context.Context, oddID int64) (int64, error)
@ -25,7 +26,7 @@ type BetStore interface {
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error)
UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error)
GetBetSummary(ctx context.Context, filter domain.ReportFilter) ( GetBetSummary(ctx context.Context, filter domain.ReportFilter) (
totalStakes domain.Currency, totalStakes domain.Currency,
totalBets int64, totalBets int64,

View File

@ -848,6 +848,9 @@ func (s *Service) GetBetOutcomeByBetID(ctx context.Context, UserID int64) ([]dom
return s.betStore.GetBetOutcomeByBetID(ctx, UserID) return s.betStore.GetBetOutcomeByBetID(ctx, UserID)
} }
func (s *Service) GetBetOutcomeViewByEventID(ctx context.Context, eventID int64, filter domain.BetOutcomeViewFilter) ([]domain.BetOutcomeViewRes, int64, error) {
return s.betStore.GetBetOutcomeViewByEventID(ctx, eventID, filter)
}
func (s *Service) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) { func (s *Service) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) {
return s.betStore.GetBetOutcomeByEventID(ctx, eventID, is_filtered) return s.betStore.GetBetOutcomeByEventID(ctx, eventID, is_filtered)
} }
@ -1076,6 +1079,19 @@ func (s *Service) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID in
return outcomes, nil return outcomes, nil
} }
func (s *Service) UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) {
outcomes, err := s.betStore.UpdateBetOutcomeStatusForOddId(ctx, oddID, status)
if err != nil {
s.mongoLogger.Error("failed to update bet outcome status",
zap.Int64("oddID", oddID),
zap.Error(err),
)
return nil, err
}
return outcomes, nil
}
func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error { func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error {
_, err := s.betStore.UpdateBetOutcomeStatusByBetID(ctx, id, domain.OUTCOME_STATUS_VOID) _, err := s.betStore.UpdateBetOutcomeStatusByBetID(ctx, id, domain.OUTCOME_STATUS_VOID)
if err != nil { if err != nil {

View File

@ -11,7 +11,7 @@ type CompanyStore interface {
GetAllCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.GetCompany, error) GetAllCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.GetCompany, error)
SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error)
GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error)
GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error) GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error)
UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error)
DeleteCompany(ctx context.Context, id int64) error DeleteCompany(ctx context.Context, id int64) error

View File

@ -26,8 +26,8 @@ func (s *Service) GetAllCompanies(ctx context.Context, filter domain.CompanyFilt
func (s *Service) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) { func (s *Service) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) {
return s.companyStore.GetCompanyByID(ctx, id) return s.companyStore.GetCompanyByID(ctx, id)
} }
func (s *Service) GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error){ func (s *Service) GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error) {
return s.companyStore.GetCompanyIDBySlug(ctx, slug) return s.companyStore.GetCompanyBySlug(ctx, slug)
} }
func (s *Service) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) { func (s *Service) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) {

View File

@ -18,6 +18,7 @@ type Service interface {
UpdateEventMonitored(ctx context.Context, eventID int64, IsMonitored bool) error UpdateEventMonitored(ctx context.Context, eventID int64, IsMonitored bool) error
GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error)
GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error) GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error)
UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error
UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error
GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error) GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error)
} }

View File

@ -491,8 +491,11 @@ func (s *service) GetEventWithSettingByID(ctx context.Context, ID int64, company
return s.store.GetEventWithSettingByID(ctx, ID, companyID) return s.store.GetEventWithSettingByID(ctx, ID, companyID)
} }
func (s *service) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { func (s *service) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error {
return s.store.UpdateEventSettings(ctx, event) return s.store.UpdateTenantEventSettings(ctx, event)
}
func (s *service) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error {
return s.store.UpdateGlobalEventSettings(ctx, event)
} }
func (s *service) GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error) { func (s *service) GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error) {

View File

@ -10,7 +10,8 @@ type Service interface {
SaveLeague(ctx context.Context, league domain.CreateLeague) error SaveLeague(ctx context.Context, league domain.CreateLeague) error
SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error)
GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error)
CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error)
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error UpdateLeague(ctx context.Context, league domain.UpdateLeague) error
UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error
} }

View File

@ -40,3 +40,7 @@ func (s *service) CheckLeagueSupport(ctx context.Context, leagueID int64, compan
func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error { func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {
return s.store.UpdateLeague(ctx, league) return s.store.UpdateLeague(ctx, league)
} }
func (s *service) UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error {
return s.store.UpdateGlobalLeagueSettings(ctx, league)
}

View File

@ -17,31 +17,17 @@ type Service interface {
GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error) GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error)
// GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error) // GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error)
DeleteOddsForEvent(ctx context.Context, eventID string) error DeleteOddsForEvent(ctx context.Context, eventID string) error
GetOddByID(ctx context.Context, id int64) (domain.OddMarket, error) GetOddByID(ctx context.Context, id int64) (domain.OddMarket, error)
GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error)
// Settings // Settings
SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error
UpdateGlobalOddsSetting(ctx context.Context, odd domain.UpdateGlobalOddMarketSettings) error
DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error
DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, companyID int64, oddMarketID int64) error
// Odd History // Odd History
InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error) InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error)
GetAllOddHistory(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) GetAllOddHistory(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error)
GetInitialOddPerDay(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) GetInitialOddPerDay(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error)
// Disabling Odds
InsertDisabledOdd(ctx context.Context, odd domain.CreateDisabledOdd) (domain.DisabledOdd, error)
GetAllDisabledOdds(ctx context.Context) ([]domain.DisabledOdd, error)
GetDisabledOddByRawOddID(ctx context.Context, rawOddID int64) (domain.DisabledOdd, error)
GetDisabledOddByID(ctx context.Context, id int64) (domain.DisabledOdd, error)
DeleteDisabledOddsByID(ctx context.Context, id int64) error
DeleteDisabledOddsByRawOddID(ctx context.Context, id int64) error
// Custom Odds
// InsertCustomOdds(ctx context.Context, odd domain.CreateCustomOdd) (domain.CustomOdd, error)
// GetAllCustomOdds(ctx context.Context, filter domain.CustomOddFilter) ([]domain.CustomOdd, error)
// GetCustomOddByID(ctx context.Context, id int64) (domain.CustomOdd, error)
// GetCustomOddByOddID(ctx context.Context, oddId int64, companyID int64) (domain.CustomOdd, error)
// DeleteCustomOddByID(ctx context.Context, id int64) error
// DeleteCustomOddsByOddID(ctx context.Context, oddId int64, companyID int64) error
// DeleteCustomOddByEventID(ctx context.Context, eventID string) error
} }

View File

@ -676,6 +676,10 @@ func (s *ServiceImpl) SaveOddsSetting(ctx context.Context, odd domain.CreateOddM
return s.store.SaveOddsSetting(ctx, odd) return s.store.SaveOddsSetting(ctx, odd)
} }
func (s *ServiceImpl) UpdateGlobalOddsSetting(ctx context.Context, odd domain.UpdateGlobalOddMarketSettings) error {
return s.store.UpdateGlobalOddsSetting(ctx, odd);
}
func (s *ServiceImpl) SaveOddsSettingReq(ctx context.Context, companyID int64, req domain.CreateOddMarketSettingsReq) error { func (s *ServiceImpl) SaveOddsSettingReq(ctx context.Context, companyID int64, req domain.CreateOddMarketSettingsReq) error {
odd, err := s.GetOddsWithSettingsByID(ctx, req.OddMarketID, companyID) odd, err := s.GetOddsWithSettingsByID(ctx, req.OddMarketID, companyID)
@ -741,6 +745,14 @@ func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID int64) err
return s.store.DeleteOddsForEvent(ctx, eventID) return s.store.DeleteOddsForEvent(ctx, eventID)
} }
func (s *ServiceImpl) DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error {
return s.store.DeleteAllCompanyOddsSetting(ctx, companyID)
}
func (s *ServiceImpl) DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, companyID int64, oddMarketID int64) error{
return s.store.DeleteCompanyOddsSettingByOddMarketID(ctx, companyID, oddMarketID)
}
// func getString(v interface{}) string { // func getString(v interface{}) string {
// if str, ok := v.(string); ok { // if str, ok := v.(string); ok {
// return str // return str

View File

@ -27,71 +27,71 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
spec string spec string
task func() task func()
}{ }{
{ // {
spec: "0 0 * * * *", // Every 1 hour // spec: "0 0 * * * *", // Every 1 hour
task: func() { // task: func() {
mongoLogger.Info("Began fetching upcoming events cron task") // mongoLogger.Info("Began fetching upcoming events cron task")
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { // if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch upcoming events", // mongoLogger.Error("Failed to fetch upcoming events",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed fetching upcoming events without errors") // mongoLogger.Info("Completed fetching upcoming events without errors")
} // }
}, // },
}, // },
{ // {
spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) // spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
task: func() { // task: func() {
mongoLogger.Info("Began fetching non live odds cron task") // mongoLogger.Info("Began fetching non live odds cron task")
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { // if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch non live odds", // mongoLogger.Error("Failed to fetch non live odds",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed fetching non live odds without errors") // mongoLogger.Info("Completed fetching non live odds without errors")
} // }
}, // },
}, // },
{ // {
spec: "0 */5 * * * *", // Every 5 Minutes // spec: "0 */5 * * * *", // Every 5 Minutes
task: func() { // task: func() {
mongoLogger.Info("Began update all expired events status cron task") // mongoLogger.Info("Began update all expired events status cron task")
if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil { // if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil {
mongoLogger.Error("Failed to update expired events status", // mongoLogger.Error("Failed to update expired events status",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed expired events without errors") // mongoLogger.Info("Completed expired events without errors")
} // }
}, // },
}, // },
{ // {
spec: "0 */15 * * * *", // Every 15 Minutes // spec: "0 */15 * * * *", // Every 15 Minutes
task: func() { // task: func() {
mongoLogger.Info("Began updating bets based on event results cron task") // mongoLogger.Info("Began updating bets based on event results cron task")
if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil { // if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil {
mongoLogger.Error("Failed to process result", // mongoLogger.Error("Failed to process result",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed processing all event result outcomes without errors") // mongoLogger.Info("Completed processing all event result outcomes without errors")
} // }
}, // },
}, // },
{ // {
spec: "0 0 0 * * 1", // Every Monday // spec: "0 0 0 * * 1", // Every Monday
task: func() { // task: func() {
mongoLogger.Info("Began Send weekly result notification cron task") // mongoLogger.Info("Began Send weekly result notification cron task")
if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-7*24*time.Hour)); err != nil { // if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-7*24*time.Hour)); err != nil {
mongoLogger.Error("Failed to process result", // mongoLogger.Error("Failed to process result",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed sending weekly result notification without errors") // mongoLogger.Info("Completed sending weekly result notification without errors")
} // }
}, // },
}, // },
} }
for _, job := range schedule { for _, job := range schedule {

View File

@ -451,24 +451,24 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error())
} }
if req.CompanyID != nil { // if req.CompanyID != nil {
_, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ // _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
ID: *req.CompanyID, // ID: *req.CompanyID,
AdminID: domain.ValidInt64{ // AdminID: domain.ValidInt64{
Value: AdminID, // Value: AdminID,
Valid: true, // Valid: true,
}, // },
}) // })
if err != nil { // if err != nil {
h.mongoLoggerSvc.Error("UpdateAdmin failed to update company", // h.mongoLoggerSvc.Error("UpdateAdmin failed to update company",
zap.Int("status_code", fiber.StatusInternalServerError), // zap.Int("status_code", fiber.StatusInternalServerError),
zap.Int64("admin_id", AdminID), // zap.Int64("admin_id", AdminID),
zap.Error(err), // zap.Error(err),
zap.Time("timestamp", time.Now()), // zap.Time("timestamp", time.Now()),
) // )
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company:"+err.Error()) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company:"+err.Error())
} // }
} // }
h.mongoLoggerSvc.Info("UpdateAdmin succeeded", h.mongoLoggerSvc.Info("UpdateAdmin succeeded",
zap.Int("status_code", fiber.StatusOK), zap.Int("status_code", fiber.StatusOK),

View File

@ -169,7 +169,7 @@ type loginAdminRes struct {
func (h *Handler) LoginAdmin(c *fiber.Ctx) error { func (h *Handler) LoginAdmin(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64) companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid { if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id") h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
} }
var req loginAdminReq var req loginAdminReq

View File

@ -552,6 +552,25 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
Valid: true, Valid: true,
} }
} }
var companyID domain.ValidInt64
companyIDQuery := c.Query("company_id")
if companyIDQuery != "" {
companyIDParsed, err := strconv.ParseInt(companyIDQuery, 10, 64)
if err != nil {
h.mongoLoggerSvc.Info("invalid company_id format",
zap.String("company_id", companyIDQuery),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid company_id format")
}
companyID = domain.ValidInt64{
Value: companyIDParsed,
Valid: true,
}
}
bets, total, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{ bets, total, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{
IsShopBet: isShopBet, IsShopBet: isShopBet,
Query: searchString, Query: searchString,
@ -560,6 +579,7 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
Status: statusFilter, Status: statusFilter,
Limit: limit, Limit: limit,
Offset: offset, Offset: offset,
CompanyID: companyID,
}) })
if err != nil { if err != nil {
h.mongoLoggerSvc.Error("Failed to get all bets", h.mongoLoggerSvc.Error("Failed to get all bets",

View File

@ -135,6 +135,40 @@ func (h *Handler) GetAllEvents(c *fiber.Ctx) error {
} }
} }
isActiveQuery := c.Query("is_active")
var isActive domain.ValidBool
if isActiveQuery != "" {
isActiveParsed, err := strconv.ParseBool(isActiveQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse isActive",
zap.String("is_active", isActiveQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_active")
}
isActive = domain.ValidBool{
Value: isActiveParsed,
Valid: true,
}
}
statusQuery := c.Query("status")
var eventStatus domain.ValidEventStatus
if statusQuery != "" {
eventStatusParsed, err := domain.ParseEventStatus(statusQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse statusQuery",
zap.String("is_featured", isFeaturedQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid event status string")
}
eventStatus = domain.ValidEventStatus{
Value: eventStatusParsed,
Valid: true,
}
}
events, total, err := h.eventSvc.GetAllEvents( events, total, err := h.eventSvc.GetAllEvents(
c.Context(), domain.EventFilter{ c.Context(), domain.EventFilter{
SportID: sportID, SportID: sportID,
@ -146,6 +180,8 @@ func (h *Handler) GetAllEvents(c *fiber.Ctx) error {
Offset: offset, Offset: offset,
CountryCode: countryCode, CountryCode: countryCode,
Featured: isFeatured, Featured: isFeatured,
Active: isActive,
Status: eventStatus,
}) })
// fmt.Printf("League ID: %v", leagueID) // fmt.Printf("League ID: %v", leagueID)
@ -294,18 +330,18 @@ func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error {
events, total, err := h.eventSvc.GetEventsWithSettings( events, total, err := h.eventSvc.GetEventsWithSettings(
c.Context(), companyID.Value, domain.EventFilter{ c.Context(), companyID.Value, domain.EventFilter{
SportID: sportID, SportID: sportID,
LeagueID: leagueID, LeagueID: leagueID,
Query: searchString, Query: searchString,
FirstStartTime: domain.ValidTime{ FirstStartTime: domain.ValidTime{
Value: time.Now(), Value: time.Now(),
Valid: true, Valid: true,
}, },
LastStartTime: lastStartTime, LastStartTime: lastStartTime,
Limit: limit, Limit: limit,
Offset: offset, Offset: offset,
CountryCode: countryCode, CountryCode: countryCode,
Featured: isFeatured, Featured: isFeatured,
Status: domain.ValidEventStatus{ Status: domain.ValidEventStatus{
Value: domain.STATUS_PENDING, Value: domain.STATUS_PENDING,
Valid: true, Valid: true,
@ -334,6 +370,200 @@ func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error {
} }
// @Summary Retrieve all upcoming events with settings
// @Description Retrieve all upcoming events settings from the database
// @Tags prematch
// @Accept json
// @Produce json
// @Param page query int false "Page number"
// @Param page_size query int false "Page size"
// @Param league_id query string false "League ID Filter"
// @Param sport_id query string false "Sport ID Filter"
// @Param cc query string false "Country Code Filter"
// @Param first_start_time query string false "Start Time"
// @Param last_start_time query string false "End Time"
// @Success 200 {array} domain.BaseEvent
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/{tenant_slug}/events [get]
func (h *Handler) GetTenantEvents(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")
}
page := c.QueryInt("page", 1)
pageSize := c.QueryInt("page_size", 10)
limit := domain.ValidInt32{
Value: int32(pageSize),
Valid: true,
}
offset := domain.ValidInt32{
Value: int32(page - 1),
Valid: true,
}
leagueIDQuery := c.Query("league_id")
var leagueID domain.ValidInt64
if leagueIDQuery != "" {
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
if err != nil {
h.BadRequestLogger().Error("invalid league id",
zap.String("league_id", leagueIDQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
}
leagueID = domain.ValidInt64{
Value: leagueIDInt,
Valid: true,
}
}
sportIDQuery := c.Query("sport_id")
var sportID domain.ValidInt32
if sportIDQuery != "" {
sportIDint, err := strconv.Atoi(sportIDQuery)
if err != nil {
h.BadRequestLogger().Info("invalid sport id",
zap.String("sportID", sportIDQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid sport id")
}
sportID = domain.ValidInt32{
Value: int32(sportIDint),
Valid: true,
}
}
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
firstStartTimeQuery := c.Query("first_start_time")
var firstStartTime domain.ValidTime
if firstStartTimeQuery != "" {
firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
if err != nil {
h.BadRequestLogger().Info("invalid start_time format",
zap.String("first_start_time", firstStartTimeQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
}
firstStartTime = domain.ValidTime{
Value: firstStartTimeParsed,
Valid: true,
}
}
lastStartTimeQuery := c.Query("last_start_time")
var lastStartTime domain.ValidTime
if lastStartTimeQuery != "" {
lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
if err != nil {
h.BadRequestLogger().Info("invalid last_start_time format",
zap.String("last_start_time", lastStartTimeQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
}
lastStartTime = domain.ValidTime{
Value: lastStartTimeParsed,
Valid: true,
}
}
countryCodeQuery := c.Query("cc")
countryCode := domain.ValidString{
Value: countryCodeQuery,
Valid: countryCodeQuery != "",
}
isFeaturedQuery := c.Query("is_featured")
var isFeatured domain.ValidBool
if isFeaturedQuery != "" {
isFeaturedParsed, err := strconv.ParseBool(isFeaturedQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse isFeatured",
zap.String("is_featured", isFeaturedQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_featured")
}
isFeatured = domain.ValidBool{
Value: isFeaturedParsed,
Valid: true,
}
}
isActiveQuery := c.Query("is_active")
var isActive domain.ValidBool
if isActiveQuery != "" {
isActiveParsed, err := strconv.ParseBool(isActiveQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse isActive",
zap.String("is_active", isActiveQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_active")
}
isActive = domain.ValidBool{
Value: isActiveParsed,
Valid: true,
}
}
statusQuery := c.Query("status")
var eventStatus domain.ValidEventStatus
if statusQuery != "" {
eventStatusParsed, err := domain.ParseEventStatus(statusQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse statusQuery",
zap.String("is_featured", isFeaturedQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid event status string")
}
eventStatus = domain.ValidEventStatus{
Value: eventStatusParsed,
Valid: true,
}
}
events, total, err := h.eventSvc.GetEventsWithSettings(
c.Context(), companyID.Value, domain.EventFilter{
SportID: sportID,
LeagueID: leagueID,
Query: searchString,
FirstStartTime: firstStartTime,
LastStartTime: lastStartTime,
Limit: limit,
Offset: offset,
CountryCode: countryCode,
Featured: isFeatured,
Status: eventStatus,
Active: isActive,
})
// fmt.Printf("League ID: %v", leagueID)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to retrieve all upcoming events",
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
res := domain.ConvertEventWithSettingResList(events)
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", res, nil, page, int(total))
}
type TopLeaguesRes struct { type TopLeaguesRes struct {
Leagues []TopLeague `json:"leagues"` Leagues []TopLeague `json:"leagues"`
} }
@ -483,6 +713,145 @@ func (h *Handler) GetTenantEventByID(c *fiber.Ctx) error {
} }
// @Summary Retrieve bet outcomes by event id
// @Description Retrieve bet outcomes by event id
// @Tags prematch
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} domain.BaseEvent
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/tenant/{tenant_slug}/events/{id}/bets [get]
func (h *Handler) GetTenantBetsByEventID(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")
}
idStr := c.Params("id")
eventID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
page := c.QueryInt("page", 1)
pageSize := c.QueryInt("page_size", 10)
limit := domain.ValidInt32{
Value: int32(pageSize),
Valid: true,
}
offset := domain.ValidInt32{
Value: int32(page - 1),
Valid: true,
}
statusQuery := c.Params("status")
var status domain.ValidOutcomeStatus
if statusQuery != "" {
statusIntParse, err := strconv.ParseInt(statusQuery, 10, 32)
if err != nil {
h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery))
return fiber.NewError(fiber.StatusBadRequest, "Invalid status query")
}
statusParsed, err := domain.ParseOutcomeStatus(int(statusIntParse))
if err != nil {
h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery))
return fiber.NewError(fiber.StatusBadRequest, "Invalid status query")
}
status = domain.ValidOutcomeStatus{
Value: statusParsed,
Valid: true,
}
}
res, total, err := h.betSvc.GetBetOutcomeViewByEventID(c.Context(), eventID, domain.BetOutcomeViewFilter{
OutcomeStatus: status,
CompanyID: companyID,
Limit: limit,
Offset: offset,
})
if err != nil {
h.InternalServerErrorLogger().Error("Failed to get upcoming event by id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return response.WritePaginatedJSON(c, fiber.StatusOK, "Bet Outcomes retrieved successfully", res, nil, page, int(total))
}
// @Summary Retrieve bet outcomes by event id
// @Description Retrieve bet outcomes by event id
// @Tags prematch
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} domain.BaseEvent
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/events/{id}/bets [get]
func (h *Handler) GetBetsByEventID(c *fiber.Ctx) error {
idStr := c.Params("id")
eventID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
page := c.QueryInt("page", 1)
pageSize := c.QueryInt("page_size", 10)
limit := domain.ValidInt32{
Value: int32(pageSize),
Valid: true,
}
offset := domain.ValidInt32{
Value: int32(page - 1),
Valid: true,
}
statusQuery := c.Params("status")
var status domain.ValidOutcomeStatus
if statusQuery != "" {
statusIntParse, err := strconv.ParseInt(statusQuery, 10, 32)
if err != nil {
h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery))
return fiber.NewError(fiber.StatusBadRequest, "Invalid status query")
}
statusParsed, err := domain.ParseOutcomeStatus(int(statusIntParse))
if err != nil {
h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery))
return fiber.NewError(fiber.StatusBadRequest, "Invalid status query")
}
status = domain.ValidOutcomeStatus{
Value: statusParsed,
Valid: true,
}
}
res, total, err := h.betSvc.GetBetOutcomeViewByEventID(c.Context(), eventID, domain.BetOutcomeViewFilter{
OutcomeStatus: status,
Limit: limit,
Offset: offset,
})
if err != nil {
h.InternalServerErrorLogger().Error("Failed to get upcoming event by id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return response.WritePaginatedJSON(c, fiber.StatusOK, "Bet Outcomes retrieved successfully", res, nil, page, int(total))
}
type UpdateEventStatusReq struct { type UpdateEventStatusReq struct {
} }
@ -519,9 +888,9 @@ func (h *Handler) SetEventStatusToRemoved(c *fiber.Ctx) error {
} }
type UpdateEventSettingsReq struct { type UpdateEventSettingsReq struct {
Featured *bool `json:"is_featured" example:"true"` Featured *bool `json:"is_featured" example:"true"`
IsActive *bool `json:"is_active" example:"true"` IsActive *bool `json:"is_active" example:"true"`
WinningUpperLimit *int `json:"winning_upper_limit" example:"10000"` WinningUpperLimit *int64 `json:"winning_upper_limit" example:"10000"`
} }
// UpdateEventSettings godoc // UpdateEventSettings godoc
@ -534,8 +903,72 @@ type UpdateEventSettingsReq struct {
// @Success 200 {object} response.APIResponse // @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse // @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse // @Failure 500 {object} response.APIResponse
// @Router /api/v1/tenant/{tenant_slug}/events/{id}/settings [put] // @Router /api/v1/events/{id}/settings [put]
func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
eventIDStr := c.Params("id")
eventID, err := strconv.ParseInt(eventIDStr, 10, 64)
if err != nil {
h.BadRequestLogger().Error("invalid event id")
return fiber.NewError(fiber.StatusBadRequest, "invalid event id")
}
var req UpdateEventSettingsReq
if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("Failed to parse event id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
logFields := []zap.Field{
zap.Int64("eventID", eventID),
zap.Any("is_featured", req.Featured),
zap.Any("is_active", req.IsActive),
zap.Any("winning_upper_limit", req.WinningUpperLimit),
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.BadRequestLogger().Error("Failed to update event settings",
append(logFields, zap.String("errMsg", errMsg))...,
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
err = h.eventSvc.UpdateGlobalEventSettings(c.Context(), domain.UpdateGlobalEventSettings{
EventID: eventID,
IsFeatured: domain.ConvertBoolPtr(req.Featured),
IsActive: domain.ConvertBoolPtr(req.IsActive),
WinningUpperLimit: domain.ConvertInt64Ptr(req.WinningUpperLimit),
})
if err != nil {
h.InternalServerErrorLogger().Error("Failed to update event settings", append(logFields, zap.Error(err))...)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil)
}
// UpdateTenantEventSettings godoc
// @Summary update the event settings
// @Description Update the event settings
// @Tags event
// @Accept json
// @Produce json
// @Param id path int true "Event ID"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/tenant/{tenant_slug}/events/{id}/settings [put]
func (h *Handler) UpdateTenantEventSettings(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64) companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid { if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id") h.BadRequestLogger().Error("invalid company id")
@ -579,12 +1012,12 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, errMsg) return fiber.NewError(fiber.StatusBadRequest, errMsg)
} }
err = h.eventSvc.UpdateEventSettings(c.Context(), domain.CreateEventSettings{ err = h.eventSvc.UpdateTenantEventSettings(c.Context(), domain.UpdateTenantEventSettings{
CompanyID: companyID.Value, CompanyID: companyID.Value,
EventID: eventID, EventID: eventID,
IsFeatured: domain.ConvertBoolPtr(req.Featured), IsFeatured: domain.ConvertBoolPtr(req.Featured),
IsActive: domain.ConvertBoolPtr(req.IsActive), IsActive: domain.ConvertBoolPtr(req.IsActive),
WinningUpperLimit: domain.ConvertIntPtr(req.WinningUpperLimit), WinningUpperLimit: domain.ConvertInt64Ptr(req.WinningUpperLimit),
}) })
if err != nil { if err != nil {

View File

@ -26,7 +26,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
limit := domain.ValidInt64{ limit := domain.ValidInt64{
Value: int64(pageSize), Value: int64(pageSize),
Valid: pageSize == 0, Valid: pageSize != 0,
} }
offset := domain.ValidInt64{ offset := domain.ValidInt64{
Value: int64(page - 1), Value: int64(page - 1),
@ -54,7 +54,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
sportIDQuery := c.Query("sport_id") sportIDQuery := c.Query("sport_id")
var sportID domain.ValidInt32 var sportID domain.ValidInt32
if sportIDQuery != "" { if sportIDQuery != "" {
sportIDint, err := strconv.Atoi(sportIDQuery) sportIDint, err := strconv.ParseInt(sportIDQuery, 10, 64)
if err != nil { if err != nil {
h.BadRequestLogger().Info("invalid sport id", h.BadRequestLogger().Info("invalid sport id",
zap.String("sport_id", sportIDQuery), zap.String("sport_id", sportIDQuery),
@ -156,7 +156,7 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error {
sportIDQuery := c.Query("sport_id") sportIDQuery := c.Query("sport_id")
var sportID domain.ValidInt32 var sportID domain.ValidInt32
if sportIDQuery != "" { if sportIDQuery != "" {
sportIDint, err := strconv.Atoi(sportIDQuery) sportIDint, err := strconv.ParseInt(sportIDQuery, 10, 64)
if err != nil { if err != nil {
h.BadRequestLogger().Info("invalid sport id", h.BadRequestLogger().Info("invalid sport id",
zap.String("sport_id", sportIDQuery), zap.String("sport_id", sportIDQuery),
@ -235,7 +235,7 @@ func (h *Handler) SetLeagueActive(c *fiber.Ctx) error {
if leagueIdStr == "" { if leagueIdStr == "" {
return fiber.NewError(fiber.StatusBadRequest, "Missing league id") return fiber.NewError(fiber.StatusBadRequest, "Missing league id")
} }
leagueId, err := strconv.Atoi(leagueIdStr) leagueId, err := strconv.ParseInt(leagueIdStr, 10, 64)
if err != nil { if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid league id") return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
} }
@ -266,7 +266,7 @@ func (h *Handler) SetLeagueActive(c *fiber.Ctx) error {
} }
if err := h.leagueSvc.SaveLeagueSettings(c.Context(), domain.CreateLeagueSettings{ if err := h.leagueSvc.SaveLeagueSettings(c.Context(), domain.CreateLeagueSettings{
LeagueID: int64(leagueId), LeagueID: leagueId,
CompanyID: companyID.Value, CompanyID: companyID.Value,
IsActive: domain.ValidBool{ IsActive: domain.ValidBool{
Value: req.IsActive, Value: req.IsActive,
@ -308,7 +308,7 @@ func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error {
if leagueIdStr == "" { if leagueIdStr == "" {
return fiber.NewError(fiber.StatusBadRequest, "Missing league id") return fiber.NewError(fiber.StatusBadRequest, "Missing league id")
} }
leagueId, err := strconv.Atoi(leagueIdStr) leagueId, err := strconv.ParseInt(leagueIdStr, 10, 64)
if err != nil { if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid league id") return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
} }
@ -336,7 +336,7 @@ func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error {
} }
err = h.leagueSvc.SaveLeagueSettings(c.Context(), domain.CreateLeagueSettings{ err = h.leagueSvc.SaveLeagueSettings(c.Context(), domain.CreateLeagueSettings{
LeagueID: int64(leagueId), LeagueID: leagueId,
CompanyID: companyID.Value, CompanyID: companyID.Value,
IsFeatured: domain.ValidBool{ IsFeatured: domain.ValidBool{
Value: req.IsFeatured, Value: req.IsFeatured,
@ -351,3 +351,45 @@ func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error {
h.SuccessResLogger().Info("League Featured has been successfully updated", queryLogFields...) h.SuccessResLogger().Info("League Featured has been successfully updated", queryLogFields...)
return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil) return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil)
} }
func (h *Handler) UpdateGlobalLeagueSetting(c *fiber.Ctx) error {
leagueIdStr := c.Params("id")
if leagueIdStr == "" {
return fiber.NewError(fiber.StatusBadRequest, "Missing league id")
}
leagueId, err := strconv.ParseInt(leagueIdStr, 10, 64)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
}
var req domain.UpdateLeagueSettingsReq
if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("UpdateLeagueSettingsReq failed to parse request body", zap.String("league_id", leagueIdStr), zap.Error(err))
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse request body:"+err.Error())
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.BadRequestLogger().Info("Failed to validate UpdateLeagueSettingsReq", zap.Error(err))
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
err = h.leagueSvc.UpdateGlobalLeagueSettings(c.Context(), domain.UpdateGlobalLeagueSettings{
ID: leagueId,
DefaultIsActive: domain.ConvertBoolPtr(req.IsActive),
DefaultIsFeatured: domain.ConvertBoolPtr(req.IsFeatured),
})
if err != nil {
h.InternalServerErrorLogger().Error("Failed to update league", zap.Error(err), zap.String("leagueId", leagueIdStr))
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update league:"+err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil)
}

View File

@ -276,7 +276,6 @@ func (h *Handler) GetTenantOddsByUpcomingID(c *fiber.Ctx) error {
zap.Int64("company_id", companyID.Value), zap.Int64("company_id", companyID.Value),
} }
eventIDStr := c.Params("upcoming_id") eventIDStr := c.Params("upcoming_id")
eventID, err := strconv.ParseInt(eventIDStr, 10, 64) eventID, err := strconv.ParseInt(eventIDStr, 10, 64)
if err != nil { if err != nil {
@ -309,16 +308,16 @@ func (h *Handler) GetTenantOddsByUpcomingID(c *fiber.Ctx) error {
} }
func (h *Handler) SaveOddsSetting(c *fiber.Ctx) error { func (h *Handler) SaveTenantOddsSetting(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64) companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid { if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id") h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
} }
var req domain.CreateOddMarketSettingsReq var req domain.CreateOddMarketSettingsReq
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("Failed to parse event id", h.BadRequestLogger().Info("Failed to parse CreateOddMarketSettingsReq",
zap.Int64("CompanyID", companyID.Value), zap.Int64("CompanyID", companyID.Value),
zap.Error(err), zap.Error(err),
) )
@ -337,7 +336,7 @@ func (h *Handler) SaveOddsSetting(c *fiber.Ctx) error {
for field, msg := range valErrs { for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg) errMsg += fmt.Sprintf("%s: %s; ", field, msg)
} }
h.BadRequestLogger().Error("Failed to insert odd settings", h.BadRequestLogger().Error("Failed to validate insert odd settings",
append(logFields, zap.String("errMsg", errMsg))..., append(logFields, zap.String("errMsg", errMsg))...,
) )
return fiber.NewError(fiber.StatusBadRequest, errMsg) return fiber.NewError(fiber.StatusBadRequest, errMsg)
@ -354,3 +353,133 @@ func (h *Handler) SaveOddsSetting(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil) return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil)
} }
func (h *Handler) SaveOddSettings(c *fiber.Ctx) error {
var req domain.UpdateGlobalOddMarketSettingsReq
if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("Failed to parse CreateOddMarketSettingsReq",
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
logFields := []zap.Field{
zap.Any("is_active", req.IsActive),
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.BadRequestLogger().Error("Failed to validate insert odd settings",
append(logFields, zap.String("errMsg", errMsg))...,
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
err := h.prematchSvc.UpdateGlobalOddsSetting(c.Context(), domain.UpdateGlobalOddMarketSettings{
OddMarketID: req.OddMarketID,
IsActive: domain.ConvertBoolPtr(req.IsActive),
})
if err != nil {
logFields = append(logFields, zap.Error(err))
h.InternalServerErrorLogger().Error("Failed to save odds settings", append(logFields, zap.Error(err))...)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to save odds settings"+err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil)
}
func (h *Handler) RemoveOddsSettings(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")
}
idStr := c.Params("id")
oddID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse odd id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
err = h.prematchSvc.DeleteCompanyOddsSettingByOddMarketID(c.Context(), companyID.Value, oddID)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to retrieve odds", zap.Error(err))
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove odds settings"+err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Odds settings successfully removed ", nil, nil)
}
func (h *Handler) RemoveAllOddsSettings(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")
}
err := h.prematchSvc.DeleteAllCompanyOddsSetting(c.Context(), companyID.Value)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to remove all odd settings", zap.Int64("company_id", companyID.Value), zap.Error(err))
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove all odds settings"+err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Odds settings successfully removed ", nil, nil)
}
type UpdateAllBetStatusByOddIDReq struct {
Status domain.OutcomeStatus `json:"status"`
}
func (h *Handler) UpdateAllBetOutcomeStatusByOddID(c *fiber.Ctx) error {
idStr := c.Params("id")
oddID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse odd_id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
var req UpdateAllBetStatusByOddIDReq
if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("Failed to parse event id",
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
logFields := []zap.Field{
zap.Any("status", req.Status),
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.BadRequestLogger().Error("Failed to insert odd settings",
append(logFields, zap.String("errMsg", errMsg))...,
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
_, err = h.betSvc.UpdateBetOutcomeStatusForOddId(c.Context(), oddID, req.Status)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to update bet status by odd id",
zap.Int64("oddID", oddID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Updated All Bet Outcome Status Successfully", nil, nil)
}

View File

@ -14,6 +14,74 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
type GetTenantSlugByToken struct {
Slug string `json:"slug"`
}
// GetTenantSlugByToken godoc
// @Summary Check if phone number or email exist
// @Description Check if phone number or email exist
// @Tags user
// @Accept json
// @Produce json
// @Param checkPhoneEmailExist body CheckPhoneEmailExistReq true "Check phone number or email exist"
// @Success 200 {object} CheckPhoneEmailExistRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/tenant [get]
func (h *Handler) GetTenantSlugByToken(c *fiber.Ctx) error {
userID, ok := c.Locals("user_id").(int64)
if !ok || userID == 0 {
h.mongoLoggerSvc.Error("Invalid user ID in context",
zap.Int64("userID", userID),
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
}
user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil {
h.mongoLoggerSvc.Error("Failed to get user profile",
zap.Int64("userID", userID),
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile:"+err.Error())
}
if !user.CompanyID.Valid {
if user.Role == domain.RoleSuperAdmin {
return fiber.NewError(fiber.StatusBadRequest, "Role Super-Admin Doesn't have a company-id")
}
h.mongoLoggerSvc.Error("Unknown Error: User doesn't have a company-id",
zap.Int64("userID", userID),
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Unknown Error: User doesn't have a company-id")
}
company, err := h.companySvc.GetCompanyByID(c.Context(), user.CompanyID.Value)
if err != nil {
h.mongoLoggerSvc.Error("Failed to get company by id",
zap.Int64("company", user.CompanyID.Value),
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve company:"+err.Error())
}
res := GetTenantSlugByToken{
Slug: company.Slug,
}
return response.WriteJSON(c, fiber.StatusOK, "Tenant Slug retrieved successfully", res, nil)
}
type CheckPhoneEmailExistReq struct { type CheckPhoneEmailExistReq struct {
Email string `json:"email" example:"john.doe@example.com"` Email string `json:"email" example:"john.doe@example.com"`
PhoneNumber string `json:"phone_number" example:"1234567890"` PhoneNumber string `json:"phone_number" example:"1234567890"`

View File

@ -236,7 +236,7 @@ func (a *App) TenantMiddleware(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "tenant is required for this route") return fiber.NewError(fiber.StatusBadRequest, "tenant is required for this route")
} }
companyID, err := a.companySvc.GetCompanyIDBySlug(c.Context(), tenantSlug) company, err := a.companySvc.GetCompanyBySlug(c.Context(), tenantSlug)
if err != nil { if err != nil {
a.mongoLoggerSvc.Info("failed to resolve tenant", a.mongoLoggerSvc.Info("failed to resolve tenant",
zap.String("tenant_slug", tenantSlug), zap.String("tenant_slug", tenantSlug),
@ -245,8 +245,16 @@ func (a *App) TenantMiddleware(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "failed to resolve tenant") return fiber.NewError(fiber.StatusBadRequest, "failed to resolve tenant")
} }
if !company.IsActive {
a.mongoLoggerSvc.Info("request using deactivated tenant",
zap.String("tenant_slug", tenantSlug),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusForbidden, "this tenant has been deactivated")
}
c.Locals("company_id", domain.ValidInt64{ c.Locals("company_id", domain.ValidInt64{
Value: companyID, Value: company.ID,
Valid: true, Valid: true,
}) })
return c.Next() return c.Next()

View File

@ -96,6 +96,10 @@ func (a *App) initAppRoutes() {
"message": "Company Tenant Active", "message": "Company Tenant Active",
}) })
}) })
// Get S
groupV1.Get("/tenant", a.authMiddleware, h.GetTenantSlugByToken)
//Direct_deposit //Direct_deposit
groupV1.Post("/direct_deposit", a.authMiddleware, h.InitiateDirectDeposit) groupV1.Post("/direct_deposit", a.authMiddleware, h.InitiateDirectDeposit)
groupV1.Post("/direct_deposit/verify", a.authMiddleware, h.VerifyDirectDeposit) groupV1.Post("/direct_deposit/verify", a.authMiddleware, h.VerifyDirectDeposit)
@ -219,55 +223,63 @@ func (a *App) initAppRoutes() {
// groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier) // groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier)
// groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier) // groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier)
groupV1.Get("/cashiers", a.authMiddleware, h.GetAllCashiers) groupV1.Get("/cashiers", a.authMiddleware, a.CompanyOnly, h.GetAllCashiers)
groupV1.Get("/cashiers/:id", a.authMiddleware, h.GetCashierByID) groupV1.Get("/cashiers/:id", a.authMiddleware, a.CompanyOnly, h.GetCashierByID)
groupV1.Post("/cashiers", a.authMiddleware, h.CreateCashier) groupV1.Post("/cashiers", a.authMiddleware, a.CompanyOnly, h.CreateCashier)
groupV1.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier) groupV1.Put("/cashiers/:id", a.authMiddleware, a.CompanyOnly, h.UpdateCashier)
tenant.Get("/customer", a.authMiddleware, h.GetAllTenantCustomers) tenant.Get("/customer", a.authMiddleware, a.CompanyOnly, h.GetAllTenantCustomers)
tenant.Get("/customer/:id", a.authMiddleware, h.GetTenantCustomerByID) tenant.Get("/customer/:id", a.authMiddleware, a.CompanyOnly, h.GetTenantCustomerByID)
tenant.Put("/customer/:id", a.authMiddleware, h.UpdateTenantCustomer) tenant.Put("/customer/:id", a.authMiddleware, a.CompanyOnly, h.UpdateTenantCustomer)
tenant.Get("/customer/:id/bets", a.authMiddleware, h.GetTenantCustomerBets) tenant.Get("/customer/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetTenantCustomerBets)
groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers) groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers)
groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID) groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID)
groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer) groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer)
groupV1.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets) groupV1.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets)
groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins) groupV1.Get("/admin", a.authMiddleware, a.SuperAdminOnly, h.GetAllAdmins)
groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID) groupV1.Get("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.GetAdminByID)
groupV1.Post("/admin", a.authMiddleware, h.CreateAdmin) groupV1.Post("/admin", a.authMiddleware, a.SuperAdminOnly, h.CreateAdmin)
groupV1.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin) groupV1.Put("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAdmin)
groupV1.Get("/t-approver", a.authMiddleware, h.GetAllTransactionApprovers) groupV1.Get("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllTransactionApprovers)
groupV1.Get("/t-approver/:id", a.authMiddleware, h.GetTransactionApproverByID) groupV1.Get("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetTransactionApproverByID)
groupV1.Post("/t-approver", a.authMiddleware, h.CreateTransactionApprover) groupV1.Post("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateTransactionApprover)
groupV1.Put("/t-approver/:id", a.authMiddleware, h.UpdateTransactionApprover) groupV1.Put("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateTransactionApprover)
groupV1.Get("/managers", a.authMiddleware, h.GetAllManagers) groupV1.Get("/managers", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllManagers)
groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID) groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID)
groupV1.Post("/managers", a.authMiddleware, h.CreateManager) groupV1.Post("/managers", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateManager)
groupV1.Put("/managers/:id", a.authMiddleware, h.UpdateManagers) groupV1.Put("/managers/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateManagers)
groupV1.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID) groupV1.Get("/manager/:id/branch", a.authMiddleware, a.OnlyAdminAndAbove, h.GetBranchByManagerID)
groupV1.Get("/odds", a.authMiddleware, a.SuperAdminOnly, h.GetAllOdds) groupV1.Get("/odds", a.authMiddleware, a.SuperAdminOnly, h.GetAllOdds)
groupV1.Get("/odds/upcoming/:upcoming_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByUpcomingID) 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.Get("/odds/upcoming/:upcoming_id/market/:market_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByMarketID)
groupV1.Post("/odds/settings", a.SuperAdminOnly, h.SaveOddSettings)
groupV1.Put("/odds/bet-outcome/:id", a.SuperAdminOnly, h.UpdateAllBetOutcomeStatusByOddID)
tenant.Get("/odds", h.GetAllTenantOdds) tenant.Get("/odds", h.GetAllTenantOdds)
tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID) tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID) tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID)
tenant.Post("/odds/settings", a.CompanyOnly, h.SaveOddsSetting) 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)
groupV1.Get("/events", a.authMiddleware, h.GetAllEvents) groupV1.Get("/events", a.authMiddleware, h.GetAllEvents)
groupV1.Get("/events/:id", a.authMiddleware, h.GetEventByID) groupV1.Get("/events/:id", a.authMiddleware, h.GetEventByID)
groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved) groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
groupV1.Patch("/events/:id/is_monitored", a.authMiddleware, a.SuperAdminOnly, h.SetEventIsMonitored) groupV1.Patch("/events/:id/is_monitored", a.authMiddleware, a.SuperAdminOnly, h.SetEventIsMonitored)
groupV1.Put("/events/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
groupV1.Get("/events/:id/bets", a.authMiddleware, a.SuperAdminOnly, h.GetBetsByEventID)
tenant.Get("/upcoming-events", h.GetTenantUpcomingEvents) tenant.Get("/upcoming-events", h.GetTenantUpcomingEvents)
tenant.Get("/events/:id", h.GetTenantEventByID)
tenant.Get("/top-leagues", h.GetTopLeagues) tenant.Get("/top-leagues", h.GetTopLeagues)
tenant.Put("/events/:id/settings", h.UpdateEventSettings) tenant.Get("/events", h.GetTenantEvents)
tenant.Get("/events/:id", h.GetTenantEventByID)
tenant.Put("/events/:id/settings", a.authMiddleware, a.CompanyOnly, h.UpdateTenantEventSettings)
tenant.Get("/events/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetTenantBetsByEventID)
//EnetPulse //EnetPulse
groupV1.Get("/odds/pre-match", h.GetPreMatchOdds) groupV1.Get("/odds/pre-match", h.GetPreMatchOdds)
@ -277,38 +289,40 @@ func (a *App) initAppRoutes() {
groupV1.Get("/tournament_stages", h.GetAllTournamentStages) groupV1.Get("/tournament_stages", h.GetAllTournamentStages)
// Leagues // Leagues
tenant.Get("/leagues", h.GetAllLeagues)
tenant.Put("/leagues/:id/set-active", h.SetLeagueActive)
tenant.Put("/leagues/:id/featured", h.SetLeagueFeatured)
groupV1.Get("/leagues", a.authMiddleware, a.SuperAdminOnly, h.GetAllLeagues) groupV1.Get("/leagues", a.authMiddleware, a.SuperAdminOnly, h.GetAllLeagues)
groupV1.Put("/leagues/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalLeagueSetting)
tenant.Get("/leagues", h.GetAllLeagues)
tenant.Put("/leagues/:id/featured", a.authMiddleware, a.CompanyOnly, h.SetLeagueFeatured)
tenant.Put("/leagues/:id/set-active", a.authMiddleware, a.CompanyOnly, h.SetLeagueActive)
groupV1.Get("/result/b365/:id", h.GetBet365ResultsByEventID) groupV1.Get("/result/b365/:id", h.GetBet365ResultsByEventID)
// Branch // Branch
groupV1.Post("/branch", a.authMiddleware, h.CreateBranch) groupV1.Post("/branch", a.authMiddleware, a.CompanyOnly, h.CreateBranch)
groupV1.Get("/branch", a.authMiddleware, h.GetAllBranches) groupV1.Get("/branch", a.authMiddleware, a.CompanyOnly, h.GetAllBranches)
groupV1.Get("/branch/:id", a.authMiddleware, h.GetBranchByID) groupV1.Get("/branch/:id", a.authMiddleware, a.CompanyOnly, h.GetBranchByID)
groupV1.Post("/branch/:id/return", a.authMiddleware, h.ReturnBranchWallet) groupV1.Post("/branch/:id/return", a.authMiddleware, a.CompanyOnly, h.ReturnBranchWallet)
groupV1.Get("/branch/:id/bets", a.authMiddleware, h.GetBetByBranchID) groupV1.Get("/branch/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetBetByBranchID)
groupV1.Put("/branch/:id", a.authMiddleware, h.UpdateBranch) groupV1.Put("/branch/:id", a.authMiddleware, a.CompanyOnly, h.UpdateBranch)
groupV1.Put("/branch/:id/set-active", a.authMiddleware, h.UpdateBranchStatus) groupV1.Put("/branch/:id/set-active", a.authMiddleware, a.CompanyOnly, h.UpdateBranchStatus)
groupV1.Put("/branch/:id/set-inactive", a.authMiddleware, h.UpdateBranchStatus) groupV1.Put("/branch/:id/set-inactive", a.authMiddleware, a.CompanyOnly, h.UpdateBranchStatus)
groupV1.Delete("/branch/:id", a.authMiddleware, h.DeleteBranch) groupV1.Delete("/branch/:id", a.authMiddleware, a.CompanyOnly, h.DeleteBranch)
groupV1.Get("/search/branch", a.authMiddleware, h.SearchBranch) groupV1.Get("/search/branch", a.authMiddleware, a.CompanyOnly, h.SearchBranch)
groupV1.Get("/branchLocation", a.authMiddleware, h.GetAllBranchLocations) groupV1.Get("/branchLocation", a.authMiddleware, a.CompanyOnly, h.GetAllBranchLocations)
groupV1.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers) groupV1.Get("/branch/:id/cashiers", a.authMiddleware, a.CompanyOnly, h.GetBranchCashiers)
groupV1.Get("/branchCashier", a.authMiddleware, h.GetBranchForCashier) groupV1.Get("/branchCashier", a.authMiddleware, a.CompanyOnly, h.GetBranchForCashier)
// Branch Operation // Branch Operation
groupV1.Get("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.GetAllSupportedOperations) groupV1.Get("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.GetAllSupportedOperations)
groupV1.Post("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.CreateSupportedOperation) groupV1.Post("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.CreateSupportedOperation)
groupV1.Post("/operation", a.authMiddleware, h.CreateBranchOperation) groupV1.Post("/operation", a.authMiddleware, a.CompanyOnly, h.CreateBranchOperation)
groupV1.Get("/branch/:id/operation", a.authMiddleware, h.GetBranchOperations) groupV1.Get("/branch/:id/operation", a.authMiddleware, a.CompanyOnly, h.GetBranchOperations)
groupV1.Delete("/branch/:id/operation/:opID", a.authMiddleware, h.DeleteBranchOperation) groupV1.Delete("/branch/:id/operation/:opID", a.authMiddleware, a.CompanyOnly, h.DeleteBranchOperation)
// Company // Company
groupV1.Post("/company", a.authMiddleware, a.SuperAdminOnly, h.CreateCompany) groupV1.Post("/company", a.authMiddleware, a.SuperAdminOnly, h.CreateCompany)
@ -316,9 +330,9 @@ func (a *App) initAppRoutes() {
groupV1.Get("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCompanyByID) groupV1.Get("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCompanyByID)
groupV1.Put("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCompany) groupV1.Put("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCompany)
groupV1.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany) groupV1.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany)
groupV1.Get("/company/:id/branch", a.authMiddleware, h.GetBranchByCompanyID) groupV1.Get("/company/:id/branch", a.authMiddleware, a.CompanyOnly, h.GetBranchByCompanyID)
groupV1.Get("/search/company", a.authMiddleware, h.SearchCompany) groupV1.Get("/search/company", a.authMiddleware, a.CompanyOnly, h.SearchCompany)
groupV1.Get("/admin-company", a.authMiddleware, h.GetCompanyForAdmin) groupV1.Get("/admin-company", a.authMiddleware, a.CompanyOnly, h.GetCompanyForAdmin)
// Ticket Routes // Ticket Routes
tenant.Post("/ticket", h.CreateTicket) tenant.Post("/ticket", h.CreateTicket)
@ -329,7 +343,7 @@ func (a *App) initAppRoutes() {
tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet) tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet)
tenant.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode) tenant.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode)
tenant.Get("/sport/bet/fastcode/:fast_code", h.GetBetByFastCode) tenant.Get("/sport/bet/fastcode/:fast_code", h.GetBetByFastCode)
tenant.Get("/sport/bet", a.authMiddleware, h.GetAllTenantBets) tenant.Get("/sport/bet", a.authMiddleware, a.CompanyOnly, h.GetAllTenantBets)
tenant.Get("/sport/bet/:id", a.authMiddleware, h.GetTenantBetByID) tenant.Get("/sport/bet/:id", a.authMiddleware, h.GetTenantBetByID)
tenant.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut) tenant.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut)
tenant.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteTenantBet) tenant.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteTenantBet)
@ -458,9 +472,9 @@ func (a *App) initAppRoutes() {
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey) groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList) groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
tenant.Get("/settings", a.authMiddleware, h.GetCompanySettingList) tenant.Get("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.GetCompanySettingList)
tenant.Put("/settings", a.authMiddleware, h.SaveCompanySettingList) tenant.Put("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.SaveCompanySettingList)
tenant.Delete("/settings/:key", a.authMiddleware, h.DeleteCompanySetting) tenant.Delete("/settings/:key", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteCompanySetting)
tenant.Delete("/settings", a.authMiddleware, h.DeleteAllCompanySetting) tenant.Delete("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteAllCompanySetting)
} }