Refactor result notification service and remove redundant code
- Removed the CheckAndSendResultNotifications method from the result service. - Consolidated notification logic into a new notification.go file. - Updated email and in-app notification formatting to include event processing periods. - Added error handling for wallet operations to check if wallets are active before processing transfers. - Introduced new error for disabled wallets. - Updated cron jobs to comment out unnecessary tasks. - Added bulk update functionality for bet outcomes by odd IDs in the odd handler. - Renamed ticket handler methods for clarity and consistency. - Updated API version in routes.
This commit is contained in:
parent
0bab186a8f
commit
3dfa1255b0
|
|
@ -320,6 +320,7 @@ CREATE TABLE events (
|
||||||
is_live BOOLEAN NOT NULL DEFAULT false,
|
is_live BOOLEAN NOT NULL DEFAULT false,
|
||||||
status TEXT NOT NULL,
|
status TEXT NOT NULL,
|
||||||
fetched_at TIMESTAMP DEFAULT now (),
|
fetched_at TIMESTAMP DEFAULT now (),
|
||||||
|
updated_at TIMESTAMP DEFAULT now (),
|
||||||
source TEXT NOT NULL DEFAULT 'b365api' CHECK (
|
source TEXT NOT NULL DEFAULT 'b365api' CHECK (
|
||||||
source IN ('b365api', 'bfair', '1xbet', 'bwin', 'enetpulse')
|
source IN ('b365api', 'bfair', '1xbet', 'bwin', 'enetpulse')
|
||||||
),
|
),
|
||||||
|
|
@ -411,7 +412,7 @@ CREATE TABLE companies (
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
CONSTRAINT deducted_percentage_check CHECK (
|
CONSTRAINT deducted_percentage_check CHECK (
|
||||||
deducted_percentage >= 0
|
deducted_percentage > 0
|
||||||
AND deducted_percentage < 1
|
AND deducted_percentage < 1
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -581,14 +582,17 @@ CREATE VIEW bet_with_outcomes AS
|
||||||
SELECT bets.*,
|
SELECT bets.*,
|
||||||
CONCAT (users.first_name, ' ', users.last_name) AS full_name,
|
CONCAT (users.first_name, ' ', users.last_name) AS full_name,
|
||||||
users.phone_number,
|
users.phone_number,
|
||||||
JSON_AGG (bet_outcomes.*) AS outcomes
|
JSON_AGG (bet_outcomes.*) AS outcomes,
|
||||||
|
companies.slug as company_slug
|
||||||
FROM bets
|
FROM bets
|
||||||
LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id
|
LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id
|
||||||
LEFT JOIN users ON bets.user_id = users.id
|
LEFT JOIN users ON bets.user_id = users.id
|
||||||
|
JOIN companies ON bets.company_id = companies.id
|
||||||
GROUP BY bets.id,
|
GROUP BY bets.id,
|
||||||
users.first_name,
|
users.first_name,
|
||||||
users.last_name,
|
users.last_name,
|
||||||
users.phone_number;
|
users.phone_number,
|
||||||
|
companies.slug;
|
||||||
CREATE VIEW ticket_with_outcomes AS
|
CREATE VIEW ticket_with_outcomes AS
|
||||||
SELECT tickets.*,
|
SELECT tickets.*,
|
||||||
JSON_AGG (ticket_outcomes.*) AS outcomes
|
JSON_AGG (ticket_outcomes.*) AS outcomes
|
||||||
|
|
@ -688,7 +692,7 @@ SELECT e.*,
|
||||||
ces.winning_upper_limit,
|
ces.winning_upper_limit,
|
||||||
e.default_winning_upper_limit
|
e.default_winning_upper_limit
|
||||||
) AS winning_upper_limit,
|
) AS winning_upper_limit,
|
||||||
ces.updated_at,
|
ces.updated_at as company_updated_at,
|
||||||
l.country_code as league_cc
|
l.country_code as league_cc
|
||||||
FROM events e
|
FROM events e
|
||||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||||
|
|
@ -767,4 +771,4 @@ ADD CONSTRAINT fk_event_settings_company FOREIGN KEY (company_id) REFERENCES com
|
||||||
ADD CONSTRAINT fk_event_settings_event FOREIGN KEY (event_id) REFERENCES events (id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_event_settings_event FOREIGN KEY (event_id) REFERENCES events (id) ON DELETE CASCADE;
|
||||||
ALTER TABLE company_odd_settings
|
ALTER TABLE company_odd_settings
|
||||||
ADD CONSTRAINT fk_odds_settings_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE,
|
ADD CONSTRAINT fk_odds_settings_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE,
|
||||||
ADD CONSTRAINT fk_odds_settings_odds_market FOREIGN KEY (odds_market_id) REFERENCES odds_market (id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_odds_settings_odds_market FOREIGN KEY (odds_market_id) REFERENCES odds_market (id) ON DELETE CASCADE;
|
||||||
|
|
@ -138,10 +138,12 @@ SELECT bet_outcomes.*,
|
||||||
users.first_name,
|
users.first_name,
|
||||||
users.last_name,
|
users.last_name,
|
||||||
bets.amount,
|
bets.amount,
|
||||||
bets.total_odds
|
bets.total_odds,
|
||||||
|
companies.name as company_name
|
||||||
FROM bet_outcomes
|
FROM bet_outcomes
|
||||||
JOIN bets ON bets.id = bet_outcomes.bet_id
|
JOIN bets ON bets.id = bet_outcomes.bet_id
|
||||||
JOIN users ON bets.user_id = users.id
|
JOIN users ON bets.user_id = users.id
|
||||||
|
JOIN companies ON bets.company_id = companies.id
|
||||||
WHERE bet_outcomes.event_id = $1
|
WHERE bet_outcomes.event_id = $1
|
||||||
AND (
|
AND (
|
||||||
bets.company_id = sqlc.narg('company_id')
|
bets.company_id = sqlc.narg('company_id')
|
||||||
|
|
@ -217,6 +219,10 @@ UPDATE bet_outcomes
|
||||||
SEt status = $1
|
SEt status = $1
|
||||||
WHERE odd_id = $2
|
WHERE odd_id = $2
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
-- name: BulkUpdateBetOutcomeStatusByOddIDs :exec
|
||||||
|
UPDATE bet_outcomes
|
||||||
|
SET status = $1
|
||||||
|
WHERE odd_id = ANY(sqlc.arg('odd_ids')::BIGINT []);
|
||||||
-- name: UpdateStatus :exec
|
-- name: UpdateStatus :exec
|
||||||
UPDATE bets
|
UPDATE bets
|
||||||
SET status = $1,
|
SET status = $1,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ wHERE (
|
||||||
user_id = sqlc.narg('user_id')
|
user_id = sqlc.narg('user_id')
|
||||||
OR sqlc.narg('user_id') IS NULL
|
OR sqlc.narg('user_id') IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
company_id = sqlc.narg('company_id')
|
||||||
|
OR sqlc.narg('company_id') IS NULL
|
||||||
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > sqlc.narg('created_before')
|
created_at > sqlc.narg('created_before')
|
||||||
OR sqlc.narg('created_before') IS NULL
|
OR sqlc.narg('created_before') IS NULL
|
||||||
|
|
@ -60,6 +64,10 @@ wHERE (
|
||||||
user_id = sqlc.narg('user_id')
|
user_id = sqlc.narg('user_id')
|
||||||
OR sqlc.narg('user_id') IS NULL
|
OR sqlc.narg('user_id') IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
company_id = sqlc.narg('company_id')
|
||||||
|
OR sqlc.narg('company_id') IS NULL
|
||||||
|
)
|
||||||
AND (
|
AND (
|
||||||
is_shop_bet = sqlc.narg('is_shop_bet')
|
is_shop_bet = sqlc.narg('is_shop_bet')
|
||||||
OR sqlc.narg('is_shop_bet') IS NULL
|
OR sqlc.narg('is_shop_bet') IS NULL
|
||||||
|
|
@ -117,6 +125,10 @@ WITH market_counts AS (
|
||||||
user_id = sqlc.narg('user_id')
|
user_id = sqlc.narg('user_id')
|
||||||
OR sqlc.narg('user_id') IS NULL
|
OR sqlc.narg('user_id') IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
company_id = sqlc.narg('company_id')
|
||||||
|
OR sqlc.narg('company_id') IS NULL
|
||||||
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > sqlc.narg('created_before')
|
created_at > sqlc.narg('created_before')
|
||||||
OR sqlc.narg('created_before') IS NULL
|
OR sqlc.narg('created_before') IS NULL
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,22 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const BulkUpdateBetOutcomeStatusByOddIDs = `-- name: BulkUpdateBetOutcomeStatusByOddIDs :exec
|
||||||
|
UPDATE bet_outcomes
|
||||||
|
SET status = $1
|
||||||
|
WHERE odd_id = ANY($2::BIGINT [])
|
||||||
|
`
|
||||||
|
|
||||||
|
type BulkUpdateBetOutcomeStatusByOddIDsParams struct {
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
OddIds []int64 `json:"odd_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) BulkUpdateBetOutcomeStatusByOddIDs(ctx context.Context, arg BulkUpdateBetOutcomeStatusByOddIDsParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, BulkUpdateBetOutcomeStatusByOddIDs, arg.Status, arg.OddIds)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const CreateBet = `-- name: CreateBet :one
|
const CreateBet = `-- name: CreateBet :one
|
||||||
INSERT INTO bets (
|
INSERT INTO bets (
|
||||||
amount,
|
amount,
|
||||||
|
|
@ -104,7 +120,7 @@ func (q *Queries) DeleteBetOutcome(ctx context.Context, betID int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllBets = `-- name: GetAllBets :many
|
const GetAllBets = `-- name: GetAllBets :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, company_slug
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
wHERE (
|
wHERE (
|
||||||
user_id = $1
|
user_id = $1
|
||||||
|
|
@ -192,6 +208,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
&i.CompanySlug,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +221,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBetByFastCode = `-- name: GetBetByFastCode :one
|
const GetBetByFastCode = `-- name: GetBetByFastCode :one
|
||||||
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, company_slug
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
WHERE fast_code = $1
|
WHERE fast_code = $1
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
|
|
@ -230,12 +247,13 @@ func (q *Queries) GetBetByFastCode(ctx context.Context, fastCode string) (BetWit
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
&i.CompanySlug,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBetByID = `-- name: GetBetByID :one
|
const GetBetByID = `-- name: GetBetByID :one
|
||||||
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, company_slug
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -260,12 +278,13 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
&i.CompanySlug,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBetByUserID = `-- name: GetBetByUserID :many
|
const GetBetByUserID = `-- name: GetBetByUserID :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, company_slug
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -296,6 +315,7 @@ func (q *Queries) GetBetByUserID(ctx context.Context, userID int64) ([]BetWithOu
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
&i.CompanySlug,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -453,10 +473,12 @@ SELECT bet_outcomes.id, bet_outcomes.bet_id, bet_outcomes.sport_id, bet_outcomes
|
||||||
users.first_name,
|
users.first_name,
|
||||||
users.last_name,
|
users.last_name,
|
||||||
bets.amount,
|
bets.amount,
|
||||||
bets.total_odds
|
bets.total_odds,
|
||||||
|
companies.name as company_name
|
||||||
FROM bet_outcomes
|
FROM bet_outcomes
|
||||||
JOIN bets ON bets.id = bet_outcomes.bet_id
|
JOIN bets ON bets.id = bet_outcomes.bet_id
|
||||||
JOIN users ON bets.user_id = users.id
|
JOIN users ON bets.user_id = users.id
|
||||||
|
JOIN companies ON bets.company_id = companies.id
|
||||||
WHERE bet_outcomes.event_id = $1
|
WHERE bet_outcomes.event_id = $1
|
||||||
AND (
|
AND (
|
||||||
bets.company_id = $2
|
bets.company_id = $2
|
||||||
|
|
@ -497,6 +519,7 @@ type GetBetOutcomeViewByEventIDRow struct {
|
||||||
LastName string `json:"last_name"`
|
LastName string `json:"last_name"`
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32 `json:"total_odds"`
|
TotalOdds float32 `json:"total_odds"`
|
||||||
|
CompanyName string `json:"company_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutcomeViewByEventIDParams) ([]GetBetOutcomeViewByEventIDRow, error) {
|
func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutcomeViewByEventIDParams) ([]GetBetOutcomeViewByEventIDRow, error) {
|
||||||
|
|
@ -534,6 +557,7 @@ func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutc
|
||||||
&i.LastName,
|
&i.LastName,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.TotalOdds,
|
&i.TotalOdds,
|
||||||
|
&i.CompanyName,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -546,7 +570,7 @@ func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutc
|
||||||
}
|
}
|
||||||
|
|
||||||
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, company_slug
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
WHERE status = 2
|
WHERE status = 2
|
||||||
AND processed = false
|
AND processed = false
|
||||||
|
|
@ -578,6 +602,7 @@ func (q *Queries) GetBetsForCashback(ctx context.Context) ([]BetWithOutcome, err
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
&i.CompanySlug,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,32 +34,37 @@ wHERE (
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
is_shop_bet = $2
|
company_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
cashed_out = $3
|
is_shop_bet = $3
|
||||||
OR $3 IS NULL
|
OR $3 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
full_name ILIKE '%' || $4 || '%'
|
cashed_out = $4
|
||||||
OR phone_number ILIKE '%' || $4 || '%'
|
|
||||||
OR $4 IS NULL
|
OR $4 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > $5
|
full_name ILIKE '%' || $5 || '%'
|
||||||
|
OR phone_number ILIKE '%' || $5 || '%'
|
||||||
OR $5 IS NULL
|
OR $5 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at < $6
|
created_at > $6
|
||||||
OR $6 IS NULL
|
OR $6 IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
created_at < $7
|
||||||
|
OR $7 IS NULL
|
||||||
|
)
|
||||||
GROUP BY DATE(created_at)
|
GROUP BY DATE(created_at)
|
||||||
ORDER BY DATE(created_at)
|
ORDER BY DATE(created_at)
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetBetStatsParams struct {
|
type GetBetStatsParams struct {
|
||||||
UserID pgtype.Int8 `json:"user_id"`
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
IsShopBet pgtype.Bool `json:"is_shop_bet"`
|
IsShopBet pgtype.Bool `json:"is_shop_bet"`
|
||||||
CashedOut pgtype.Bool `json:"cashed_out"`
|
CashedOut pgtype.Bool `json:"cashed_out"`
|
||||||
Query pgtype.Text `json:"query"`
|
Query pgtype.Text `json:"query"`
|
||||||
|
|
@ -79,6 +84,7 @@ type GetBetStatsRow struct {
|
||||||
func (q *Queries) GetBetStats(ctx context.Context, arg GetBetStatsParams) ([]GetBetStatsRow, error) {
|
func (q *Queries) GetBetStats(ctx context.Context, arg GetBetStatsParams) ([]GetBetStatsRow, error) {
|
||||||
rows, err := q.db.Query(ctx, GetBetStats,
|
rows, err := q.db.Query(ctx, GetBetStats,
|
||||||
arg.UserID,
|
arg.UserID,
|
||||||
|
arg.CompanyID,
|
||||||
arg.IsShopBet,
|
arg.IsShopBet,
|
||||||
arg.CashedOut,
|
arg.CashedOut,
|
||||||
arg.Query,
|
arg.Query,
|
||||||
|
|
@ -143,17 +149,22 @@ wHERE (
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > $2
|
company_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at < $3
|
created_at > $3
|
||||||
OR $3 IS NULL
|
OR $3 IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
created_at < $4
|
||||||
|
OR $4 IS NULL
|
||||||
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetBetSummaryParams struct {
|
type GetBetSummaryParams struct {
|
||||||
UserID pgtype.Int8 `json:"user_id"`
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
||||||
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +179,12 @@ type GetBetSummaryRow struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetBetSummary(ctx context.Context, arg GetBetSummaryParams) (GetBetSummaryRow, error) {
|
func (q *Queries) GetBetSummary(ctx context.Context, arg GetBetSummaryParams) (GetBetSummaryRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetBetSummary, arg.UserID, arg.CreatedBefore, arg.CreatedAfter)
|
row := q.db.QueryRow(ctx, GetBetSummary,
|
||||||
|
arg.UserID,
|
||||||
|
arg.CompanyID,
|
||||||
|
arg.CreatedBefore,
|
||||||
|
arg.CreatedAfter,
|
||||||
|
)
|
||||||
var i GetBetSummaryRow
|
var i GetBetSummaryRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.TotalStakes,
|
&i.TotalStakes,
|
||||||
|
|
@ -198,13 +214,17 @@ WITH market_counts AS (
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > $2
|
company_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at < $3
|
created_at > $3
|
||||||
OR $3 IS NULL
|
OR $3 IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
created_at < $4
|
||||||
|
OR $4 IS NULL
|
||||||
|
)
|
||||||
GROUP BY DATE(b.created_at),
|
GROUP BY DATE(b.created_at),
|
||||||
bo.market_name
|
bo.market_name
|
||||||
)
|
)
|
||||||
|
|
@ -216,6 +236,7 @@ WHERE rank = 1
|
||||||
|
|
||||||
type GetMarketPopularityParams struct {
|
type GetMarketPopularityParams struct {
|
||||||
UserID pgtype.Int8 `json:"user_id"`
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
||||||
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
||||||
}
|
}
|
||||||
|
|
@ -226,7 +247,12 @@ type GetMarketPopularityRow struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetMarketPopularity(ctx context.Context, arg GetMarketPopularityParams) (GetMarketPopularityRow, error) {
|
func (q *Queries) GetMarketPopularity(ctx context.Context, arg GetMarketPopularityParams) (GetMarketPopularityRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetMarketPopularity, arg.UserID, arg.CreatedBefore, arg.CreatedAfter)
|
row := q.db.QueryRow(ctx, GetMarketPopularity,
|
||||||
|
arg.UserID,
|
||||||
|
arg.CompanyID,
|
||||||
|
arg.CreatedBefore,
|
||||||
|
arg.CreatedAfter,
|
||||||
|
)
|
||||||
var i GetMarketPopularityRow
|
var i GetMarketPopularityRow
|
||||||
err := row.Scan(&i.Date, &i.MarketName)
|
err := row.Scan(&i.Date, &i.MarketName)
|
||||||
return i, err
|
return i, err
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ func (q *Queries) DeleteEvent(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllEvents = `-- name: GetAllEvents :many
|
const GetAllEvents = `-- name: GetAllEvents :many
|
||||||
SELECT id, source_event_id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc
|
SELECT id, source_event_id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, updated_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc
|
||||||
FROM event_with_country
|
FROM event_with_country
|
||||||
WHERE (
|
WHERE (
|
||||||
is_live = $1
|
is_live = $1
|
||||||
|
|
@ -122,6 +122,7 @@ func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]E
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.DefaultIsActive,
|
&i.DefaultIsActive,
|
||||||
&i.DefaultIsFeatured,
|
&i.DefaultIsFeatured,
|
||||||
|
|
@ -140,7 +141,7 @@ func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]E
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetEventByID = `-- name: GetEventByID :one
|
const GetEventByID = `-- name: GetEventByID :one
|
||||||
SELECT id, source_event_id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc
|
SELECT id, source_event_id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, updated_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc
|
||||||
FROM event_with_country
|
FROM event_with_country
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
|
|
@ -171,6 +172,7 @@ func (q *Queries) GetEventByID(ctx context.Context, id int64) (EventWithCountry,
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.DefaultIsActive,
|
&i.DefaultIsActive,
|
||||||
&i.DefaultIsFeatured,
|
&i.DefaultIsFeatured,
|
||||||
|
|
@ -182,7 +184,7 @@ func (q *Queries) GetEventByID(ctx context.Context, id int64) (EventWithCountry,
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetEventBySourceID = `-- name: GetEventBySourceID :one
|
const GetEventBySourceID = `-- name: GetEventBySourceID :one
|
||||||
SELECT id, source_event_id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc
|
SELECT id, source_event_id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, updated_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc
|
||||||
FROM event_with_country
|
FROM event_with_country
|
||||||
WHERE source_event_id = $1
|
WHERE source_event_id = $1
|
||||||
AND source = $2
|
AND source = $2
|
||||||
|
|
@ -218,6 +220,7 @@ func (q *Queries) GetEventBySourceID(ctx context.Context, arg GetEventBySourceID
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.DefaultIsActive,
|
&i.DefaultIsActive,
|
||||||
&i.DefaultIsFeatured,
|
&i.DefaultIsFeatured,
|
||||||
|
|
@ -229,7 +232,7 @@ func (q *Queries) GetEventBySourceID(ctx context.Context, arg GetEventBySourceID
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetEventWithSettingByID = `-- name: GetEventWithSettingByID :one
|
const GetEventWithSettingByID = `-- name: GetEventWithSettingByID :one
|
||||||
SELECT e.id, e.source_event_id, e.sport_id, e.match_name, e.home_team, e.away_team, e.home_team_id, e.away_team_id, e.home_kit_image, e.away_kit_image, e.league_id, e.league_name, e.start_time, e.score, e.match_minute, e.timer_status, e.added_time, e.match_period, e.is_live, e.status, e.fetched_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
SELECT e.id, e.source_event_id, e.sport_id, e.match_name, e.home_team, e.away_team, e.home_team_id, e.away_team_id, e.home_kit_image, e.away_kit_image, e.league_id, e.league_name, e.start_time, e.score, e.match_minute, e.timer_status, e.added_time, e.match_period, e.is_live, e.status, e.fetched_at, e.updated_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
||||||
ces.company_id,
|
ces.company_id,
|
||||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||||
|
|
@ -274,6 +277,7 @@ type GetEventWithSettingByIDRow struct {
|
||||||
IsLive bool `json:"is_live"`
|
IsLive bool `json:"is_live"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
DefaultIsActive bool `json:"default_is_active"`
|
DefaultIsActive bool `json:"default_is_active"`
|
||||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||||
|
|
@ -283,7 +287,7 @@ type GetEventWithSettingByIDRow struct {
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
IsFeatured bool `json:"is_featured"`
|
IsFeatured bool `json:"is_featured"`
|
||||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt_2 pgtype.Timestamp `json:"updated_at_2"`
|
||||||
LeagueCc pgtype.Text `json:"league_cc"`
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,6 +316,7 @@ func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithS
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.DefaultIsActive,
|
&i.DefaultIsActive,
|
||||||
&i.DefaultIsFeatured,
|
&i.DefaultIsFeatured,
|
||||||
|
|
@ -321,14 +326,14 @@ func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithS
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.IsFeatured,
|
&i.IsFeatured,
|
||||||
&i.WinningUpperLimit,
|
&i.WinningUpperLimit,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt_2,
|
||||||
&i.LeagueCc,
|
&i.LeagueCc,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetEventsWithSettings = `-- name: GetEventsWithSettings :many
|
const GetEventsWithSettings = `-- name: GetEventsWithSettings :many
|
||||||
SELECT e.id, e.source_event_id, e.sport_id, e.match_name, e.home_team, e.away_team, e.home_team_id, e.away_team_id, e.home_kit_image, e.away_kit_image, e.league_id, e.league_name, e.start_time, e.score, e.match_minute, e.timer_status, e.added_time, e.match_period, e.is_live, e.status, e.fetched_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
SELECT e.id, e.source_event_id, e.sport_id, e.match_name, e.home_team, e.away_team, e.home_team_id, e.away_team_id, e.home_kit_image, e.away_kit_image, e.league_id, e.league_name, e.start_time, e.score, e.match_minute, e.timer_status, e.added_time, e.match_period, e.is_live, e.status, e.fetched_at, e.updated_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
||||||
ces.company_id,
|
ces.company_id,
|
||||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||||
|
|
@ -432,6 +437,7 @@ type GetEventsWithSettingsRow struct {
|
||||||
IsLive bool `json:"is_live"`
|
IsLive bool `json:"is_live"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
DefaultIsActive bool `json:"default_is_active"`
|
DefaultIsActive bool `json:"default_is_active"`
|
||||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||||
|
|
@ -441,7 +447,7 @@ type GetEventsWithSettingsRow struct {
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
IsFeatured bool `json:"is_featured"`
|
IsFeatured bool `json:"is_featured"`
|
||||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt_2 pgtype.Timestamp `json:"updated_at_2"`
|
||||||
LeagueCc pgtype.Text `json:"league_cc"`
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -491,6 +497,7 @@ func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSe
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.DefaultIsActive,
|
&i.DefaultIsActive,
|
||||||
&i.DefaultIsFeatured,
|
&i.DefaultIsFeatured,
|
||||||
|
|
@ -500,7 +507,7 @@ func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSe
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.IsFeatured,
|
&i.IsFeatured,
|
||||||
&i.WinningUpperLimit,
|
&i.WinningUpperLimit,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt_2,
|
||||||
&i.LeagueCc,
|
&i.LeagueCc,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ type BetWithOutcome struct {
|
||||||
FullName interface{} `json:"full_name"`
|
FullName interface{} `json:"full_name"`
|
||||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Outcomes []BetOutcome `json:"outcomes"`
|
Outcomes []BetOutcome `json:"outcomes"`
|
||||||
|
CompanySlug string `json:"company_slug"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Branch struct {
|
type Branch struct {
|
||||||
|
|
@ -331,6 +332,7 @@ type Event struct {
|
||||||
IsLive bool `json:"is_live"`
|
IsLive bool `json:"is_live"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
DefaultIsActive bool `json:"default_is_active"`
|
DefaultIsActive bool `json:"default_is_active"`
|
||||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||||
|
|
@ -367,6 +369,7 @@ type EventWithCountry struct {
|
||||||
IsLive bool `json:"is_live"`
|
IsLive bool `json:"is_live"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
DefaultIsActive bool `json:"default_is_active"`
|
DefaultIsActive bool `json:"default_is_active"`
|
||||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||||
|
|
@ -397,6 +400,7 @@ type EventWithSetting struct {
|
||||||
IsLive bool `json:"is_live"`
|
IsLive bool `json:"is_live"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
DefaultIsActive bool `json:"default_is_active"`
|
DefaultIsActive bool `json:"default_is_active"`
|
||||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||||
|
|
@ -406,7 +410,7 @@ type EventWithSetting struct {
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
IsFeatured bool `json:"is_featured"`
|
IsFeatured bool `json:"is_featured"`
|
||||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
CompanyUpdatedAt pgtype.Timestamp `json:"company_updated_at"`
|
||||||
LeagueCc pgtype.Text `json:"league_cc"`
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ type GetBet struct {
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
UserID int64
|
UserID int64
|
||||||
CompanyID int64
|
CompanyID int64
|
||||||
|
CompanySlug string
|
||||||
IsShopBet bool
|
IsShopBet bool
|
||||||
CashedOut bool
|
CashedOut bool
|
||||||
Outcomes []BetOutcome
|
Outcomes []BetOutcome
|
||||||
|
|
@ -149,23 +150,25 @@ type CreateBetRes struct {
|
||||||
FastCode string `json:"fast_code"`
|
FastCode string `json:"fast_code"`
|
||||||
}
|
}
|
||||||
type BetRes struct {
|
type BetRes struct {
|
||||||
ID int64 `json:"id" example:"1"`
|
ID int64 `json:"id" example:"1"`
|
||||||
Outcomes []BetOutcome `json:"outcomes"`
|
Outcomes []BetOutcome `json:"outcomes"`
|
||||||
Amount float32 `json:"amount" example:"100.0"`
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||||
Status OutcomeStatus `json:"status" example:"1"`
|
Status OutcomeStatus `json:"status" example:"1"`
|
||||||
Fullname string `json:"full_name" example:"John Smith"`
|
Fullname string `json:"full_name" example:"John Smith"`
|
||||||
UserID int64 `json:"user_id" example:"2"`
|
UserID int64 `json:"user_id" example:"2"`
|
||||||
CompanyID int64 `json:"company_id" example:"1"`
|
CompanyID int64 `json:"company_id" example:"1"`
|
||||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
CompanySlug string `json:"company_slug" example:"fortune"`
|
||||||
CashedOut bool `json:"cashed_out" example:"false"`
|
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||||
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
CashedOut bool `json:"cashed_out" example:"false"`
|
||||||
FastCode string `json:"fast_code"`
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
||||||
|
FastCode string `json:"fast_code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BetOutcomeViewRes struct {
|
type BetOutcomeViewRes struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
BetID int64 `json:"bet_id"`
|
BetID int64 `json:"bet_id"`
|
||||||
|
CompanyName string `json:"company_name"`
|
||||||
SportID int64 `json:"sport_id"`
|
SportID int64 `json:"sport_id"`
|
||||||
EventID int64 `json:"event_id"`
|
EventID int64 `json:"event_id"`
|
||||||
OddID int64 `json:"odd_id"`
|
OddID int64 `json:"odd_id"`
|
||||||
|
|
@ -208,18 +211,19 @@ func ConvertCreateBetRes(bet Bet, createdNumber int64) CreateBetRes {
|
||||||
|
|
||||||
func ConvertBet(bet GetBet) BetRes {
|
func ConvertBet(bet GetBet) BetRes {
|
||||||
return BetRes{
|
return BetRes{
|
||||||
ID: bet.ID,
|
ID: bet.ID,
|
||||||
Amount: bet.Amount.Float32(),
|
Amount: bet.Amount.Float32(),
|
||||||
TotalOdds: bet.TotalOdds,
|
TotalOdds: bet.TotalOdds,
|
||||||
Status: bet.Status,
|
Status: bet.Status,
|
||||||
Fullname: bet.FullName,
|
Fullname: bet.FullName,
|
||||||
UserID: bet.UserID,
|
UserID: bet.UserID,
|
||||||
CompanyID: bet.CompanyID,
|
CompanyID: bet.CompanyID,
|
||||||
Outcomes: bet.Outcomes,
|
CompanySlug: bet.CompanySlug,
|
||||||
IsShopBet: bet.IsShopBet,
|
Outcomes: bet.Outcomes,
|
||||||
CashedOut: bet.CashedOut,
|
IsShopBet: bet.IsShopBet,
|
||||||
CreatedAt: bet.CreatedAt,
|
CashedOut: bet.CashedOut,
|
||||||
FastCode: bet.FastCode,
|
CreatedAt: bet.CreatedAt,
|
||||||
|
FastCode: bet.FastCode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,6 +265,7 @@ func ConvertDBBetOutcomesView(outcome dbgen.GetBetOutcomeViewByEventIDRow) BetOu
|
||||||
return BetOutcomeViewRes{
|
return BetOutcomeViewRes{
|
||||||
ID: outcome.ID,
|
ID: outcome.ID,
|
||||||
BetID: outcome.BetID,
|
BetID: outcome.BetID,
|
||||||
|
CompanyName: outcome.CompanyName,
|
||||||
SportID: outcome.SportID,
|
SportID: outcome.SportID,
|
||||||
EventID: outcome.EventID,
|
EventID: outcome.EventID,
|
||||||
OddID: outcome.OddID,
|
OddID: outcome.OddID,
|
||||||
|
|
@ -291,6 +296,7 @@ func ConvertDBBetWithOutcomes(bet dbgen.BetWithOutcome) GetBet {
|
||||||
return GetBet{
|
return GetBet{
|
||||||
ID: bet.ID,
|
ID: bet.ID,
|
||||||
CompanyID: bet.CompanyID,
|
CompanyID: bet.CompanyID,
|
||||||
|
CompanySlug: bet.CompanySlug,
|
||||||
Amount: Currency(bet.Amount),
|
Amount: Currency(bet.Amount),
|
||||||
TotalOdds: bet.TotalOdds,
|
TotalOdds: bet.TotalOdds,
|
||||||
Status: OutcomeStatus(bet.Status),
|
Status: OutcomeStatus(bet.Status),
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,24 @@ func (s *Store) UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64,
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) BulkUpdateBetOutcomeStatusForOddIds(ctx context.Context, oddID []int64, status domain.OutcomeStatus) (error) {
|
||||||
|
err := s.queries.BulkUpdateBetOutcomeStatusByOddIDs(ctx, dbgen.BulkUpdateBetOutcomeStatusByOddIDsParams{
|
||||||
|
Status: int32(status),
|
||||||
|
OddIds: oddID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Error("failed to update bet outcome status for oddIDs",
|
||||||
|
zap.Int64s("oddIds", oddID),
|
||||||
|
zap.Int32("status", int32(status)),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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{
|
||||||
ID: betID,
|
ID: betID,
|
||||||
|
|
|
||||||
|
|
@ -63,12 +63,15 @@ func (s *Store) GetAllEvents(ctx context.Context, filter domain.EventFilter) ([]
|
||||||
|
|
||||||
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) {
|
||||||
events, err := s.queries.GetEventsWithSettings(ctx, dbgen.GetEventsWithSettingsParams{
|
events, err := s.queries.GetEventsWithSettings(ctx, dbgen.GetEventsWithSettingsParams{
|
||||||
CompanyID: companyID,
|
CompanyID: companyID,
|
||||||
LeagueID: filter.LeagueID.ToPG(),
|
LeagueID: filter.LeagueID.ToPG(),
|
||||||
SportID: filter.SportID.ToPG(),
|
SportID: filter.SportID.ToPG(),
|
||||||
Query: filter.Query.ToPG(),
|
Query: filter.Query.ToPG(),
|
||||||
Limit: filter.Limit.ToPG(),
|
Limit: filter.Limit.ToPG(),
|
||||||
Offset: filter.Offset.ToPG(),
|
Offset: pgtype.Int4{
|
||||||
|
Int32: int32(filter.Offset.Value * filter.Limit.Value),
|
||||||
|
Valid: filter.Offset.Valid,
|
||||||
|
},
|
||||||
FirstStartTime: filter.FirstStartTime.ToPG(),
|
FirstStartTime: filter.FirstStartTime.ToPG(),
|
||||||
LastStartTime: filter.LastStartTime.ToPG(),
|
LastStartTime: filter.LastStartTime.ToPG(),
|
||||||
CountryCode: filter.CountryCode.ToPG(),
|
CountryCode: filter.CountryCode.ToPG(),
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ func (s *Service) SendAdminErrorNotification(ctx context.Context, betID int64, s
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
for _, channel := range []domain.DeliveryChannel{
|
for _, channel := range []domain.DeliveryChannel{
|
||||||
domain.DeliveryChannelInApp,
|
domain.DeliveryChannelInApp,
|
||||||
domain.DeliveryChannelEmail,
|
// domain.DeliveryChannelEmail,
|
||||||
} {
|
} {
|
||||||
n := newBetResultNotification(user.ID, domain.NotificationLevelError, channel, headline, message, map[string]any{
|
n := newBetResultNotification(user.ID, domain.NotificationLevelError, channel, headline, message, map[string]any{
|
||||||
"status": status,
|
"status": status,
|
||||||
|
|
@ -283,7 +283,7 @@ func (s *Service) SendAdminLargeBetNotification(ctx context.Context, betID int64
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
for _, channel := range []domain.DeliveryChannel{
|
for _, channel := range []domain.DeliveryChannel{
|
||||||
domain.DeliveryChannelInApp,
|
domain.DeliveryChannelInApp,
|
||||||
domain.DeliveryChannelEmail,
|
// domain.DeliveryChannelEmail,
|
||||||
} {
|
} {
|
||||||
raw, _ := json.Marshal(map[string]any{
|
raw, _ := json.Marshal(map[string]any{
|
||||||
"winnings": totalWinnings,
|
"winnings": totalWinnings,
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ type BetStore interface {
|
||||||
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)
|
UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error)
|
||||||
|
BulkUpdateBetOutcomeStatusForOddIds(ctx context.Context, oddID []int64, status domain.OutcomeStatus) 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,
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,10 @@ var (
|
||||||
ErrGenerateRandomOutcome = errors.New("failed to generate any random outcome for events")
|
ErrGenerateRandomOutcome = errors.New("failed to generate any random outcome for events")
|
||||||
ErrOutcomesNotCompleted = errors.New("some bet outcomes are still pending")
|
ErrOutcomesNotCompleted = errors.New("some bet outcomes are still pending")
|
||||||
ErrEventHasBeenRemoved = errors.New("event has been removed")
|
ErrEventHasBeenRemoved = errors.New("event has been removed")
|
||||||
|
ErrEventHasBeenDisabled = errors.New("event has been disabled")
|
||||||
|
|
||||||
ErrEventHasNotEnded = errors.New("event has not ended yet")
|
ErrEventHasNotEnded = errors.New("event has not ended yet")
|
||||||
|
ErrOddHasBeenDisabled = errors.New("odd has been disabled")
|
||||||
ErrRawOddInvalid = errors.New("prematch Raw Odd is Invalid")
|
ErrRawOddInvalid = errors.New("prematch Raw Odd is Invalid")
|
||||||
ErrBranchIDRequired = errors.New("branch ID required for this role")
|
ErrBranchIDRequired = errors.New("branch ID required for this role")
|
||||||
ErrOutcomeLimit = errors.New("too many outcomes on a single bet")
|
ErrOutcomeLimit = errors.New("too many outcomes on a single bet")
|
||||||
|
|
@ -108,10 +110,10 @@ func (s *Service) GenerateCashoutID() (string, error) {
|
||||||
return string(result), nil
|
return string(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketID int64, oddID int64) (domain.CreateBetOutcome, error) {
|
func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketID int64, oddID int64, companyID int64) (domain.CreateBetOutcome, error) {
|
||||||
oddIDStr := strconv.FormatInt(oddID, 10)
|
oddIDStr := strconv.FormatInt(oddID, 10)
|
||||||
|
|
||||||
event, err := s.eventSvc.GetEventByID(ctx, eventID)
|
event, err := s.eventSvc.GetEventWithSettingByID(ctx, eventID, companyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to fetch upcoming event by ID",
|
s.mongoLogger.Error("failed to fetch upcoming event by ID",
|
||||||
zap.Int64("event_id", eventID),
|
zap.Int64("event_id", eventID),
|
||||||
|
|
@ -120,6 +122,14 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
|
||||||
return domain.CreateBetOutcome{}, ErrEventHasBeenRemoved
|
return domain.CreateBetOutcome{}, ErrEventHasBeenRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !event.IsActive {
|
||||||
|
s.mongoLogger.Warn("attempting to create bet with disabled event",
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return domain.CreateBetOutcome{}, ErrEventHasBeenDisabled
|
||||||
|
}
|
||||||
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
if event.StartTime.Before(currentTime) {
|
if event.StartTime.Before(currentTime) {
|
||||||
s.mongoLogger.Error("event has already started",
|
s.mongoLogger.Error("event has already started",
|
||||||
|
|
@ -130,7 +140,7 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
|
||||||
return domain.CreateBetOutcome{}, ErrEventHasNotEnded
|
return domain.CreateBetOutcome{}, ErrEventHasNotEnded
|
||||||
}
|
}
|
||||||
|
|
||||||
odds, err := s.prematchSvc.GetOddsByMarketID(ctx, marketID, eventID)
|
odds, err := s.prematchSvc.GetOddsWithSettingsByMarketID(ctx, marketID, eventID, companyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to get raw odds by market ID",
|
s.mongoLogger.Error("failed to get raw odds by market ID",
|
||||||
zap.Int64("event_id", eventID),
|
zap.Int64("event_id", eventID),
|
||||||
|
|
@ -140,6 +150,15 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI
|
||||||
return domain.CreateBetOutcome{}, err
|
return domain.CreateBetOutcome{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !odds.IsActive {
|
||||||
|
s.mongoLogger.Error("failed to get raw odds by market ID",
|
||||||
|
zap.Int64("event_id", eventID),
|
||||||
|
zap.Int64("market_id", marketID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return domain.CreateBetOutcome{}, ErrOddHasBeenDisabled
|
||||||
|
}
|
||||||
|
|
||||||
type rawOddType struct {
|
type rawOddType struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
|
|
@ -257,7 +276,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
||||||
var totalOdds float32 = 1
|
var totalOdds float32 = 1
|
||||||
|
|
||||||
for _, outcomeReq := range req.Outcomes {
|
for _, outcomeReq := range req.Outcomes {
|
||||||
newOutcome, err := s.GenerateBetOutcome(ctx, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID)
|
newOutcome, err := s.GenerateBetOutcome(ctx, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID, companyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to generate outcome",
|
s.mongoLogger.Error("failed to generate outcome",
|
||||||
zap.Int64("event_id", outcomeReq.EventID),
|
zap.Int64("event_id", outcomeReq.EventID),
|
||||||
|
|
@ -536,7 +555,9 @@ func (s *Service) DeductBetFromBranchWallet(ctx context.Context, amount float32,
|
||||||
return ErrCompanyDeductedPercentInvalid
|
return ErrCompanyDeductedPercentInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
deductedAmount := amount - (amount * company.DeductedPercentage)
|
// This is the amount that we take from a company/tenant when they
|
||||||
|
// create a bet. I.e. if its 5% (0.05), then thats the percentage we take every
|
||||||
|
deductedAmount := amount * company.DeductedPercentage
|
||||||
|
|
||||||
if deductedAmount == 0 {
|
if deductedAmount == 0 {
|
||||||
s.mongoLogger.Fatal("Amount",
|
s.mongoLogger.Fatal("Amount",
|
||||||
|
|
@ -1113,6 +1134,19 @@ func (s *Service) UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int6
|
||||||
return outcomes, nil
|
return outcomes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) BulkUpdateBetOutcomeStatusForOddIds(ctx context.Context, oddID []int64, status domain.OutcomeStatus) error {
|
||||||
|
err := s.betStore.BulkUpdateBetOutcomeStatusForOddIds(ctx, oddID, status)
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to update bet outcome status by oddIds",
|
||||||
|
zap.Int64s("oddID", oddID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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 {
|
||||||
|
|
|
||||||
292
internal/services/result/notification.go
Normal file
292
internal/services/result/notification.go
Normal file
|
|
@ -0,0 +1,292 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CheckAndSendResultNotifications(ctx context.Context, createdAfter time.Time) error {
|
||||||
|
|
||||||
|
resultLog, err := s.repo.GetAllResultLog(ctx, domain.ResultLogFilter{
|
||||||
|
CreatedAfter: domain.ValidTime{
|
||||||
|
Value: createdAfter,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error(
|
||||||
|
"Failed to get result log",
|
||||||
|
zap.Time("CreatedAfter", createdAfter),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resultLog) == 0 {
|
||||||
|
s.mongoLogger.Info(
|
||||||
|
"No results found for check and send result notification",
|
||||||
|
zap.Time("CreatedAfter", createdAfter),
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
totalResultLog := domain.ResultLog{
|
||||||
|
StatusNotFinishedCount: resultLog[0].StatusNotFinishedCount,
|
||||||
|
StatusPostponedCount: resultLog[0].StatusPostponedCount,
|
||||||
|
}
|
||||||
|
for _, log := range resultLog {
|
||||||
|
// Add all the bets
|
||||||
|
totalResultLog.StatusNotFinishedBets += log.StatusNotFinishedBets
|
||||||
|
totalResultLog.StatusPostponedBets += log.StatusPostponedBets
|
||||||
|
totalResultLog.StatusToBeFixedBets += log.StatusToBeFixedBets
|
||||||
|
totalResultLog.StatusRemovedBets += log.StatusRemovedBets
|
||||||
|
totalResultLog.StatusEndedBets += log.StatusEndedBets
|
||||||
|
|
||||||
|
totalResultLog.StatusToBeFixedCount += log.StatusToBeFixedCount
|
||||||
|
totalResultLog.StatusRemovedCount += log.StatusRemovedCount
|
||||||
|
totalResultLog.StatusEndedCount += log.StatusEndedCount
|
||||||
|
totalResultLog.RemovedCount += log.RemovedCount
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.SendAdminResultStatusErrorNotification(ctx, totalResultLog, createdAfter, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error(
|
||||||
|
"Failed to send admin result status notification",
|
||||||
|
zap.Time("CreatedAfter", createdAfter),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildHeadlineAndMessage(counts domain.ResultLog, createdAfter time.Time, endTime time.Time) (string, string) {
|
||||||
|
period := fmt.Sprintf("%s - %s", createdAfter.Format("02 Jan 2006"), endTime.Format("02 Jan 2006"))
|
||||||
|
|
||||||
|
totalIssues := counts.StatusNotFinishedCount + counts.StatusToBeFixedCount + counts.StatusPostponedCount + counts.StatusRemovedCount
|
||||||
|
totalBets := counts.StatusEndedBets + counts.StatusNotFinishedBets + counts.StatusPostponedBets + counts.StatusRemovedBets + counts.StatusToBeFixedBets
|
||||||
|
if totalIssues == 0 {
|
||||||
|
return "✅ Successfully Processed Event Results", fmt.Sprintf(
|
||||||
|
"%d total ended events with %d total bets. No issues detected", counts.StatusEndedCount, totalBets,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := []string{}
|
||||||
|
if counts.StatusNotFinishedCount > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%d unfinished with %d bets", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusToBeFixedCount > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%d to-fix with %d bets", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusPostponedCount > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%d postponed with %d bets", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusRemovedCount > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%d removed with %d bets", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusEndedCount > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%d ended with %d bets", counts.StatusEndedCount, counts.StatusEndedBets))
|
||||||
|
}
|
||||||
|
|
||||||
|
headline := "⚠️ Issues Found Processing Event Results"
|
||||||
|
message := fmt.Sprintf("Processed expired event results (%s): %s. Please review pending entries.",
|
||||||
|
period, strings.Join(parts, ", "))
|
||||||
|
return headline, message
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildHeadlineAndMessageEmail(counts domain.ResultLog, user domain.User, createdAfter time.Time, endTime time.Time) (string, string, string) {
|
||||||
|
period := fmt.Sprintf("%s - %s", createdAfter.Format("02 Jan 2006"), endTime.Format("02 Jan 2006"))
|
||||||
|
|
||||||
|
totalIssues := counts.StatusNotFinishedCount + counts.StatusToBeFixedCount +
|
||||||
|
counts.StatusPostponedCount + counts.StatusRemovedCount
|
||||||
|
totalEvents := counts.StatusEndedCount + counts.StatusNotFinishedCount +
|
||||||
|
counts.StatusToBeFixedCount + counts.StatusPostponedCount + counts.StatusRemovedCount
|
||||||
|
totalBets := counts.StatusEndedBets + counts.StatusNotFinishedBets +
|
||||||
|
counts.StatusPostponedBets + counts.StatusRemovedBets + counts.StatusToBeFixedBets
|
||||||
|
|
||||||
|
greeting := fmt.Sprintf("Hi %s %s,", user.FirstName, user.LastName)
|
||||||
|
|
||||||
|
if totalIssues == 0 {
|
||||||
|
headline := "✅ Weekly Results Report — All Events Processed Successfully"
|
||||||
|
plain := fmt.Sprintf(`%s
|
||||||
|
|
||||||
|
Weekly Results Summary (%s):
|
||||||
|
- %d Ended Events
|
||||||
|
- %d Total Bets
|
||||||
|
|
||||||
|
All events were processed successfully, and no issues were detected.
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
The System`, greeting, period, counts.StatusEndedCount, totalBets)
|
||||||
|
|
||||||
|
html := fmt.Sprintf(`<p>%s</p>
|
||||||
|
<h2>Weekly Results Summary</h2>
|
||||||
|
<p><em>Period: %s</em></p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>%d Ended Events</strong></li>
|
||||||
|
<li><strong>%d Total Bets</strong></li>
|
||||||
|
</ul>
|
||||||
|
<p>All events were processed successfully, and no issues were detected.</p>
|
||||||
|
<p>Best regards,<br>The System</p>`,
|
||||||
|
greeting, period, counts.StatusEndedCount, totalBets)
|
||||||
|
|
||||||
|
return headline, plain, html
|
||||||
|
}
|
||||||
|
|
||||||
|
partsPlain := []string{}
|
||||||
|
partsHTML := []string{}
|
||||||
|
|
||||||
|
if counts.StatusNotFinishedCount > 0 {
|
||||||
|
partsPlain = append(partsPlain,
|
||||||
|
fmt.Sprintf("- %d Incomplete Events (%d Bets)", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
||||||
|
partsHTML = append(partsHTML,
|
||||||
|
fmt.Sprintf("<li><strong>%d Incomplete Events</strong> (%d Bets)</li>", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusToBeFixedCount > 0 {
|
||||||
|
partsPlain = append(partsPlain,
|
||||||
|
fmt.Sprintf("- %d Requires Review (%d Bets)", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
||||||
|
partsHTML = append(partsHTML,
|
||||||
|
fmt.Sprintf("<li><strong>%d Requires Review</strong> (%d Bets)</li>", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusPostponedCount > 0 {
|
||||||
|
partsPlain = append(partsPlain,
|
||||||
|
fmt.Sprintf("- %d Postponed Events (%d Bets)", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
||||||
|
partsHTML = append(partsHTML,
|
||||||
|
fmt.Sprintf("<li><strong>%d Postponed Events</strong> (%d Bets)</li>", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusRemovedCount > 0 {
|
||||||
|
partsPlain = append(partsPlain,
|
||||||
|
fmt.Sprintf("- %d Discarded Events (%d Bets)", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
||||||
|
partsHTML = append(partsHTML,
|
||||||
|
fmt.Sprintf("<li><strong>%d Discarded Events</strong> (%d Bets)</li>", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
||||||
|
}
|
||||||
|
if counts.StatusEndedCount > 0 {
|
||||||
|
partsPlain = append(partsPlain,
|
||||||
|
fmt.Sprintf("- %d Successfully Ended Events (%d Bets)", counts.StatusEndedCount, counts.StatusEndedBets))
|
||||||
|
partsHTML = append(partsHTML,
|
||||||
|
fmt.Sprintf("<li><strong>%d Successfully Ended Events</strong> (%d Bets)</li>", counts.StatusEndedCount, counts.StatusEndedBets))
|
||||||
|
}
|
||||||
|
|
||||||
|
headline := "⚠️ Weekly Results Report — Review Required"
|
||||||
|
|
||||||
|
plain := fmt.Sprintf(`%s
|
||||||
|
|
||||||
|
Weekly Results Summary (%s):
|
||||||
|
%s
|
||||||
|
|
||||||
|
Totals:
|
||||||
|
- %d Events Processed
|
||||||
|
- %d Total Bets
|
||||||
|
|
||||||
|
Next Steps:
|
||||||
|
Some events require your attention. Please log into the admin dashboard to review pending issues.
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
The System`,
|
||||||
|
greeting,
|
||||||
|
period,
|
||||||
|
strings.Join(partsPlain, "\n"),
|
||||||
|
totalEvents,
|
||||||
|
totalBets,
|
||||||
|
)
|
||||||
|
|
||||||
|
html := fmt.Sprintf(`<p>%s</p>
|
||||||
|
<h2>Weekly Results Summary</h2>
|
||||||
|
<p><em>Period: %s</em></p>
|
||||||
|
<ul>
|
||||||
|
%s
|
||||||
|
</ul>
|
||||||
|
<h3>Totals</h3>
|
||||||
|
<ul>
|
||||||
|
<li><strong>%d Events Processed</strong></li>
|
||||||
|
<li><strong>%d Total Bets</strong></li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Next Steps:</strong><br>Some events require your attention. Please <a href="https://admin.fortunebets.net">log into the admin dashboard</a> to review pending issues.</p>
|
||||||
|
<p>Best regards,<br>The System</p>`,
|
||||||
|
greeting,
|
||||||
|
period,
|
||||||
|
strings.Join(partsHTML, "\n"),
|
||||||
|
totalEvents,
|
||||||
|
totalBets,
|
||||||
|
)
|
||||||
|
|
||||||
|
return headline, plain, html
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendAdminResultStatusErrorNotification(
|
||||||
|
ctx context.Context,
|
||||||
|
counts domain.ResultLog,
|
||||||
|
createdAfter time.Time,
|
||||||
|
endTime time.Time,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
superAdmins, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
||||||
|
Role: string(domain.RoleSuperAdmin),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to get super_admin recipients", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
metaBytes, err := json.Marshal(counts)
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to marshal metadata", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
headline, message := buildHeadlineAndMessage(counts, createdAfter, endTime)
|
||||||
|
|
||||||
|
notification := &domain.Notification{
|
||||||
|
ErrorSeverity: domain.NotificationErrorSeverityHigh,
|
||||||
|
DeliveryStatus: domain.DeliveryStatusPending,
|
||||||
|
IsRead: false,
|
||||||
|
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
||||||
|
Level: domain.NotificationLevelWarning,
|
||||||
|
Reciever: domain.NotificationRecieverSideAdmin,
|
||||||
|
DeliveryChannel: domain.DeliveryChannelInApp,
|
||||||
|
Payload: domain.NotificationPayload{
|
||||||
|
Headline: headline,
|
||||||
|
Message: message,
|
||||||
|
},
|
||||||
|
Priority: 2,
|
||||||
|
Metadata: metaBytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendErrors []error
|
||||||
|
for _, user := range superAdmins {
|
||||||
|
notification.RecipientID = user.ID
|
||||||
|
if err := s.notificationSvc.SendNotification(ctx, notification); err != nil {
|
||||||
|
s.mongoLogger.Error("failed to send admin notification",
|
||||||
|
zap.Int64("admin_id", user.ID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
sendErrors = append(sendErrors, err)
|
||||||
|
}
|
||||||
|
// notification.DeliveryChannel = domain.DeliveryChannelEmail
|
||||||
|
if user.Email == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
subject, plain, html := buildHeadlineAndMessageEmail(counts, user, createdAfter, endTime)
|
||||||
|
if err := s.messengerSvc.SendEmail(ctx, user.Email, plain, html, subject); err != nil {
|
||||||
|
s.mongoLogger.Error("failed to send admin result report email",
|
||||||
|
zap.Int64("admin_id", user.ID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
sendErrors = append(sendErrors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sendErrors) > 0 {
|
||||||
|
return fmt.Errorf("sent with partial failure: %d errors", len(sendErrors))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -457,275 +457,6 @@ func (s *Service) FetchB365ResultAndUpdateBets(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) CheckAndSendResultNotifications(ctx context.Context, createdAfter time.Time) error {
|
|
||||||
|
|
||||||
resultLog, err := s.repo.GetAllResultLog(ctx, domain.ResultLogFilter{
|
|
||||||
CreatedAfter: domain.ValidTime{
|
|
||||||
Value: createdAfter,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error(
|
|
||||||
"Failed to get result log",
|
|
||||||
zap.Time("CreatedAfter", createdAfter),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resultLog) == 0 {
|
|
||||||
s.mongoLogger.Info(
|
|
||||||
"No results found for check and send result notification",
|
|
||||||
zap.Time("CreatedAfter", createdAfter),
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
totalResultLog := domain.ResultLog{
|
|
||||||
StatusNotFinishedCount: resultLog[0].StatusNotFinishedCount,
|
|
||||||
StatusPostponedCount: resultLog[0].StatusPostponedCount,
|
|
||||||
}
|
|
||||||
for _, log := range resultLog {
|
|
||||||
// Add all the bets
|
|
||||||
totalResultLog.StatusNotFinishedBets += log.StatusNotFinishedBets
|
|
||||||
totalResultLog.StatusPostponedBets += log.StatusPostponedBets
|
|
||||||
totalResultLog.StatusToBeFixedBets += log.StatusToBeFixedBets
|
|
||||||
totalResultLog.StatusRemovedBets += log.StatusRemovedBets
|
|
||||||
totalResultLog.StatusEndedBets += log.StatusEndedBets
|
|
||||||
|
|
||||||
totalResultLog.StatusToBeFixedCount += log.StatusToBeFixedCount
|
|
||||||
totalResultLog.StatusRemovedCount += log.StatusRemovedCount
|
|
||||||
totalResultLog.StatusEndedCount += log.StatusEndedCount
|
|
||||||
totalResultLog.RemovedCount += log.RemovedCount
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.SendAdminResultStatusErrorNotification(ctx, totalResultLog)
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error(
|
|
||||||
"Failed to send admin result status notification",
|
|
||||||
zap.Time("CreatedAfter", createdAfter),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildHeadlineAndMessage(counts domain.ResultLog) (string, string) {
|
|
||||||
|
|
||||||
totalIssues := counts.StatusNotFinishedCount + counts.StatusToBeFixedCount + counts.StatusPostponedCount + counts.StatusRemovedCount
|
|
||||||
totalBets := counts.StatusEndedBets + counts.StatusNotFinishedBets + counts.StatusPostponedBets + counts.StatusRemovedBets + counts.StatusToBeFixedBets
|
|
||||||
if totalIssues == 0 {
|
|
||||||
return "✅ Successfully Processed Event Results", fmt.Sprintf(
|
|
||||||
"%d total ended events with %d total bets. No issues detected", counts.StatusEndedCount, totalBets,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := []string{}
|
|
||||||
if counts.StatusNotFinishedCount > 0 {
|
|
||||||
parts = append(parts, fmt.Sprintf("%d unfinished with %d bets", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusToBeFixedCount > 0 {
|
|
||||||
parts = append(parts, fmt.Sprintf("%d to-fix with %d bets", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusPostponedCount > 0 {
|
|
||||||
parts = append(parts, fmt.Sprintf("%d postponed with %d bets", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusRemovedCount > 0 {
|
|
||||||
parts = append(parts, fmt.Sprintf("%d removed with %d bets", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusEndedCount > 0 {
|
|
||||||
parts = append(parts, fmt.Sprintf("%d ended with %d bets", counts.StatusEndedCount, counts.StatusEndedBets))
|
|
||||||
}
|
|
||||||
|
|
||||||
headline := "⚠️ Issues Found Processing Event Results"
|
|
||||||
message := fmt.Sprintf("Processed expired event results: %s. Please review pending entries.", strings.Join(parts, ", "))
|
|
||||||
return headline, message
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildHeadlineAndMessageEmail(counts domain.ResultLog, user domain.User) (string, string, string) {
|
|
||||||
totalIssues := counts.StatusNotFinishedCount + counts.StatusToBeFixedCount +
|
|
||||||
counts.StatusPostponedCount + counts.StatusRemovedCount
|
|
||||||
totalEvents := counts.StatusEndedCount + counts.StatusNotFinishedCount +
|
|
||||||
counts.StatusToBeFixedCount + counts.StatusPostponedCount + counts.StatusRemovedCount
|
|
||||||
totalBets := counts.StatusEndedBets + counts.StatusNotFinishedBets +
|
|
||||||
counts.StatusPostponedBets + counts.StatusRemovedBets + counts.StatusToBeFixedBets
|
|
||||||
|
|
||||||
greeting := fmt.Sprintf("Hi %s %s,", user.FirstName, user.LastName)
|
|
||||||
|
|
||||||
if totalIssues == 0 {
|
|
||||||
headline := "✅ Weekly Results Report — All Events Processed Successfully"
|
|
||||||
plain := fmt.Sprintf(`%s
|
|
||||||
|
|
||||||
Weekly Results Summary:
|
|
||||||
- %d Ended Events
|
|
||||||
- %d Total Bets
|
|
||||||
|
|
||||||
All events were processed successfully, and no issues were detected.
|
|
||||||
|
|
||||||
Best regards,
|
|
||||||
The System`, greeting, counts.StatusEndedCount, totalBets)
|
|
||||||
|
|
||||||
html := fmt.Sprintf(`<p>%s</p>
|
|
||||||
<h2>Weekly Results Summary</h2>
|
|
||||||
<ul>
|
|
||||||
<li><strong>%d Ended Events</strong></li>
|
|
||||||
<li><strong>%d Total Bets</strong></li>
|
|
||||||
</ul>
|
|
||||||
<p>All events were processed successfully, and no issues were detected.</p>
|
|
||||||
<p>Best regards,<br>The System</p>`,
|
|
||||||
greeting, counts.StatusEndedCount, totalBets)
|
|
||||||
|
|
||||||
return headline, plain, html
|
|
||||||
}
|
|
||||||
|
|
||||||
partsPlain := []string{}
|
|
||||||
partsHTML := []string{}
|
|
||||||
|
|
||||||
if counts.StatusNotFinishedCount > 0 {
|
|
||||||
partsPlain = append(partsPlain,
|
|
||||||
fmt.Sprintf("- %d Incomplete Events (%d Bets)", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
|
||||||
partsHTML = append(partsHTML,
|
|
||||||
fmt.Sprintf("<li><strong>%d Incomplete Events</strong> (%d Bets)</li>", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusToBeFixedCount > 0 {
|
|
||||||
partsPlain = append(partsPlain,
|
|
||||||
fmt.Sprintf("- %d Requires Review (%d Bets)", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
|
||||||
partsHTML = append(partsHTML,
|
|
||||||
fmt.Sprintf("<li><strong>%d Requires Review</strong> (%d Bets)</li>", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusPostponedCount > 0 {
|
|
||||||
partsPlain = append(partsPlain,
|
|
||||||
fmt.Sprintf("- %d Postponed Events (%d Bets)", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
|
||||||
partsHTML = append(partsHTML,
|
|
||||||
fmt.Sprintf("<li><strong>%d Postponed Events</strong> (%d Bets)</li>", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusRemovedCount > 0 {
|
|
||||||
partsPlain = append(partsPlain,
|
|
||||||
fmt.Sprintf("- %d Discarded Events (%d Bets)", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
|
||||||
partsHTML = append(partsHTML,
|
|
||||||
fmt.Sprintf("<li><strong>%d Discarded Events</strong> (%d Bets)</li>", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
|
||||||
}
|
|
||||||
if counts.StatusEndedCount > 0 {
|
|
||||||
partsPlain = append(partsPlain,
|
|
||||||
fmt.Sprintf("- %d Successfully Ended Events (%d Bets)", counts.StatusEndedCount, counts.StatusEndedBets))
|
|
||||||
partsHTML = append(partsHTML,
|
|
||||||
fmt.Sprintf("<li><strong>%d Successfully Ended Events</strong> (%d Bets)</li>", counts.StatusEndedCount, counts.StatusEndedBets))
|
|
||||||
}
|
|
||||||
|
|
||||||
headline := "⚠️ Weekly Results Report — Review Required"
|
|
||||||
|
|
||||||
plain := fmt.Sprintf(`%s
|
|
||||||
|
|
||||||
Weekly Results Summary:
|
|
||||||
%s
|
|
||||||
|
|
||||||
Totals:
|
|
||||||
- %d Events Processed
|
|
||||||
- %d Total Bets
|
|
||||||
|
|
||||||
Next Steps:
|
|
||||||
Some events require your attention. Please log into the admin dashboard to review pending issues.
|
|
||||||
|
|
||||||
Best regards,
|
|
||||||
The System`,
|
|
||||||
greeting,
|
|
||||||
strings.Join(partsPlain, "\n"),
|
|
||||||
totalEvents,
|
|
||||||
totalBets,
|
|
||||||
)
|
|
||||||
|
|
||||||
html := fmt.Sprintf(`<p>%s</p>
|
|
||||||
<h2>Weekly Results Summary</h2>
|
|
||||||
<ul>
|
|
||||||
%s
|
|
||||||
</ul>
|
|
||||||
<h3>Totals</h3>
|
|
||||||
<ul>
|
|
||||||
<li><strong>%d Events Processed</strong></li>
|
|
||||||
<li><strong>%d Total Bets</strong></li>
|
|
||||||
</ul>
|
|
||||||
<p><strong>Next Steps:</strong><br>Some events require your attention. Please <a href="https://admin.fortunebets.net">log into the admin dashboard</a> to review pending issues.</p>
|
|
||||||
<p>Best regards,<br>The System</p>`,
|
|
||||||
greeting,
|
|
||||||
strings.Join(partsHTML, "\n"),
|
|
||||||
totalEvents,
|
|
||||||
totalBets,
|
|
||||||
)
|
|
||||||
|
|
||||||
return headline, plain, html
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) SendAdminResultStatusErrorNotification(
|
|
||||||
ctx context.Context,
|
|
||||||
counts domain.ResultLog,
|
|
||||||
) error {
|
|
||||||
|
|
||||||
superAdmins, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
|
||||||
Role: string(domain.RoleSuperAdmin),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error("failed to get super_admin recipients", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
metaBytes, err := json.Marshal(counts)
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error("failed to marshal metadata", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
headline, message := buildHeadlineAndMessage(counts)
|
|
||||||
|
|
||||||
notification := &domain.Notification{
|
|
||||||
ErrorSeverity: domain.NotificationErrorSeverityHigh,
|
|
||||||
DeliveryStatus: domain.DeliveryStatusPending,
|
|
||||||
IsRead: false,
|
|
||||||
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
|
||||||
Level: domain.NotificationLevelWarning,
|
|
||||||
Reciever: domain.NotificationRecieverSideAdmin,
|
|
||||||
DeliveryChannel: domain.DeliveryChannelInApp,
|
|
||||||
Payload: domain.NotificationPayload{
|
|
||||||
Headline: headline,
|
|
||||||
Message: message,
|
|
||||||
},
|
|
||||||
Priority: 2,
|
|
||||||
Metadata: metaBytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
var sendErrors []error
|
|
||||||
for _, user := range superAdmins {
|
|
||||||
notification.RecipientID = user.ID
|
|
||||||
if err := s.notificationSvc.SendNotification(ctx, notification); err != nil {
|
|
||||||
s.mongoLogger.Error("failed to send admin notification",
|
|
||||||
zap.Int64("admin_id", user.ID),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
sendErrors = append(sendErrors, err)
|
|
||||||
}
|
|
||||||
// notification.DeliveryChannel = domain.DeliveryChannelEmail
|
|
||||||
if user.Email == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
subject, plain, html := buildHeadlineAndMessageEmail(counts, user)
|
|
||||||
if err := s.messengerSvc.SendEmail(ctx, user.Email, plain, html, subject); err != nil {
|
|
||||||
s.mongoLogger.Error("failed to send admin result report email",
|
|
||||||
zap.Int64("admin_id", user.ID),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
sendErrors = append(sendErrors, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sendErrors) > 0 {
|
|
||||||
return fmt.Errorf("sent with partial failure: %d errors", len(sendErrors))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) CheckAndUpdateExpiredB365Events(ctx context.Context) (int64, error) {
|
func (s *Service) CheckAndUpdateExpiredB365Events(ctx context.Context) (int64, error) {
|
||||||
events, _, err := s.repo.GetAllEvents(ctx, domain.EventFilter{
|
events, _, err := s.repo.GetAllEvents(ctx, domain.EventFilter{
|
||||||
|
|
|
||||||
|
|
@ -170,16 +170,16 @@ func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWalle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
adminNotification.DeliveryChannel = domain.DeliveryChannelEmail
|
// adminNotification.DeliveryChannel = domain.DeliveryChannelEmail
|
||||||
|
|
||||||
if err := s.notificationSvc.SendNotification(ctx, adminNotification); err != nil {
|
// if err := s.notificationSvc.SendNotification(ctx, adminNotification); err != nil {
|
||||||
s.mongoLogger.Error("failed to send email admin notification",
|
// s.mongoLogger.Error("failed to send email admin notification",
|
||||||
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 err
|
// return err
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,11 @@ func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiver
|
||||||
|
|
||||||
senderWallet, err := s.GetWalletByID(ctx, senderID)
|
senderWallet, err := s.GetWalletByID(ctx, senderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
return domain.Transfer{}, err
|
return domain.Transfer{}, err
|
||||||
}
|
}
|
||||||
|
if !senderWallet.IsActive {
|
||||||
|
return domain.Transfer{}, ErrWalletIsDisabled
|
||||||
|
}
|
||||||
|
|
||||||
if !senderWallet.IsTransferable {
|
if !senderWallet.IsTransferable {
|
||||||
fmt.Printf("Error: %d Sender Wallet is not transferable \n", senderWallet.ID)
|
fmt.Printf("Error: %d Sender Wallet is not transferable \n", senderWallet.ID)
|
||||||
|
|
@ -65,7 +67,9 @@ func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiver
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Transfer{}, err
|
return domain.Transfer{}, err
|
||||||
}
|
}
|
||||||
|
if !receiverWallet.IsActive {
|
||||||
|
return domain.Transfer{}, ErrWalletIsDisabled
|
||||||
|
}
|
||||||
if !receiverWallet.IsTransferable {
|
if !receiverWallet.IsTransferable {
|
||||||
fmt.Printf("Error: %d Receiver Wallet is not transferable \n", senderWallet.ID)
|
fmt.Printf("Error: %d Receiver Wallet is not transferable \n", senderWallet.ID)
|
||||||
return domain.Transfer{}, ErrReceiverWalletNotTransferable
|
return domain.Transfer{}, ErrReceiverWalletNotTransferable
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrBalanceInsufficient = errors.New("wallet balance is insufficient")
|
ErrBalanceInsufficient = errors.New("wallet balance is insufficient")
|
||||||
|
ErrWalletIsDisabled = errors.New("wallet is disabled")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
|
func (s *Service) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
|
||||||
|
|
@ -84,12 +85,17 @@ func (s *Service) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWalle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
||||||
err := s.walletStore.UpdateBalance(ctx, id, balance)
|
|
||||||
|
wallet, err := s.GetWalletByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
wallet, err := s.GetWalletByID(ctx, id)
|
if !wallet.IsActive {
|
||||||
|
return ErrWalletIsDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.walletStore.UpdateBalance(ctx, id, balance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +126,9 @@ func (s *Service) AddToWallet(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Transfer{}, err
|
return domain.Transfer{}, err
|
||||||
}
|
}
|
||||||
|
if !wallet.IsActive {
|
||||||
|
return domain.Transfer{}, ErrWalletIsDisabled
|
||||||
|
}
|
||||||
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Transfer{}, err
|
return domain.Transfer{}, err
|
||||||
|
|
@ -166,6 +174,9 @@ func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.
|
||||||
return domain.Transfer{}, err
|
return domain.Transfer{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !wallet.IsActive {
|
||||||
|
return domain.Transfer{}, ErrWalletIsDisabled
|
||||||
|
}
|
||||||
if wallet.Balance < amount {
|
if wallet.Balance < amount {
|
||||||
// Send Wallet low to admin
|
// Send Wallet low to admin
|
||||||
if wallet.Type == domain.CompanyWalletType || wallet.Type == domain.BranchWalletType {
|
if wallet.Type == domain.CompanyWalletType || wallet.Type == domain.BranchWalletType {
|
||||||
|
|
@ -186,8 +197,11 @@ func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.
|
||||||
}
|
}
|
||||||
|
|
||||||
balance := wallet.Balance.Float32()
|
balance := wallet.Balance.Float32()
|
||||||
if balance < thresholds[0] {
|
for _, thresholds := range thresholds {
|
||||||
s.SendAdminWalletLowNotification(ctx, wallet)
|
if thresholds < balance && thresholds > (balance-amount.Float32()) {
|
||||||
|
s.SendAdminWalletLowNotification(ctx, wallet)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,7 +227,7 @@ func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.
|
||||||
zap.Int64("wallet_id", wallet.ID),
|
zap.Int64("wallet_id", wallet.ID),
|
||||||
zap.Error(err))
|
zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the transfer here for reference
|
// Log the transfer here for reference
|
||||||
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
||||||
Message: message,
|
Message: message,
|
||||||
|
|
|
||||||
|
|
@ -28,71 +28,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 {
|
||||||
|
|
|
||||||
|
|
@ -483,3 +483,45 @@ func (h *Handler) UpdateAllBetOutcomeStatusByOddID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Updated All Bet Outcome Status Successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Updated All Bet Outcome Status Successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
type BulkUpdateAllBetStatusByOddIDsReq struct {
|
||||||
|
OddIDs []int64 `json:"odd_ids"`
|
||||||
|
Status domain.OutcomeStatus `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) BulkUpdateAllBetOutcomeStatusByOddID(c *fiber.Ctx) error {
|
||||||
|
var req BulkUpdateAllBetStatusByOddIDsReq
|
||||||
|
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.Int64s("odd_ids", req.OddIDs),
|
||||||
|
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.BulkUpdateBetOutcomeStatusForOddIds(c.Context(), req.OddIDs, req.Status)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.InternalServerErrorLogger().Error("Failed to bulk update bet status by odd ids",
|
||||||
|
append(logFields, zap.Error(err))...,
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Bulk Updated All Bet Outcome Status Successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/ticket [post]
|
// @Router /api/v1/{tenant_slug}/ticket [post]
|
||||||
func (h *Handler) CreateTicket(c *fiber.Ctx) error {
|
func (h *Handler) CreateTenantTicket(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")
|
||||||
|
|
@ -91,7 +91,7 @@ func (h *Handler) CreateTicket(c *fiber.Ctx) error {
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/ticket/{id} [get]
|
// @Router /api/v1/{tenant_slug}/ticket/{id} [get]
|
||||||
func (h *Handler) GetTicketByID(c *fiber.Ctx) error {
|
func (h *Handler) GetTenantTicketByID(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")
|
||||||
|
|
@ -154,7 +154,7 @@ func (h *Handler) GetTicketByID(c *fiber.Ctx) error {
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/ticket [get]
|
// @Router /api/v1/{tenant_slug}/ticket [get]
|
||||||
func (h *Handler) GetAllTickets(c *fiber.Ctx) error {
|
func (h *Handler) GetAllTenantTickets(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")
|
||||||
|
|
@ -186,3 +186,84 @@ func (h *Handler) GetAllTickets(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "All tickets retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "All tickets retrieved successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTicketByID godoc
|
||||||
|
// @Summary Get ticket by ID
|
||||||
|
// @Description Retrieve ticket details by ticket ID
|
||||||
|
// @Tags ticket
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Ticket ID"
|
||||||
|
// @Success 200 {object} domain.TicketRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/ticket/{id} [get]
|
||||||
|
func (h *Handler) GetTicketByID(c *fiber.Ctx) error {
|
||||||
|
ticketID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(ticketID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Invalid ticket ID",
|
||||||
|
zap.String("ticketID", ticketID),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid ticket ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket, err := h.ticketSvc.GetTicketByID(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to get ticket by ID",
|
||||||
|
zap.Int64("ticketID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusNotFound),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, "Failed to retrieve ticket")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := domain.TicketRes{
|
||||||
|
ID: ticket.ID,
|
||||||
|
Outcomes: ticket.Outcomes,
|
||||||
|
Amount: ticket.Amount.Float32(),
|
||||||
|
TotalOdds: ticket.TotalOdds,
|
||||||
|
CompanyID: ticket.CompanyID,
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Ticket retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllTickets godoc
|
||||||
|
// @Summary Get all tickets
|
||||||
|
// @Description Retrieve all tickets
|
||||||
|
// @Tags ticket
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.TicketRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/ticket [get]
|
||||||
|
func (h *Handler) GetAllTickets(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
tickets, err := h.ticketSvc.GetAllTickets(c.Context(), domain.TicketFilter{})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get tickets",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve tickets")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]domain.TicketRes, len(tickets))
|
||||||
|
for i, ticket := range tickets {
|
||||||
|
res[i] = domain.TicketRes{
|
||||||
|
ID: ticket.ID,
|
||||||
|
Outcomes: ticket.Outcomes,
|
||||||
|
Amount: ticket.Amount.Float32(),
|
||||||
|
TotalOdds: ticket.TotalOdds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All tickets retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Get("/", func(c *fiber.Ctx) error {
|
a.fiber.Get("/", func(c *fiber.Ctx) error {
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"message": "Welcome to the FortuneBet API",
|
"message": "Welcome to the FortuneBet API",
|
||||||
"version": "1.0.dev17",
|
"version": "1.0.1",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -110,8 +110,8 @@ func (a *App) initAppRoutes() {
|
||||||
|
|
||||||
groupV1.Get("/", func(c *fiber.Ctx) error {
|
groupV1.Get("/", func(c *fiber.Ctx) error {
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"message": "FortuneBet API V1 pre-alpha",
|
"message": "FortuneBet API V1",
|
||||||
"version": "1.0dev11",
|
"version": "1.0.1",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -183,8 +183,9 @@ func (a *App) initAppRoutes() {
|
||||||
tenant.Post("/user/sendRegisterCode", h.SendRegisterCode)
|
tenant.Post("/user/sendRegisterCode", h.SendRegisterCode)
|
||||||
tenant.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
tenant.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
||||||
|
|
||||||
|
groupV1.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
||||||
|
|
||||||
tenant.Get("/user/customer-profile", a.authMiddleware, h.CustomerProfile)
|
tenant.Get("/user/customer-profile", a.authMiddleware, h.CustomerProfile)
|
||||||
tenant.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
|
||||||
tenant.Get("/user/bets", a.authMiddleware, h.GetBetByUserID)
|
tenant.Get("/user/bets", a.authMiddleware, h.GetBetByUserID)
|
||||||
|
|
||||||
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
||||||
|
|
@ -257,8 +258,9 @@ func (a *App) initAppRoutes() {
|
||||||
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.Post("/odds/settings", a.authMiddleware, a.SuperAdminOnly, h.SaveOddSettings)
|
||||||
groupV1.Put("/odds/bet-outcome/:id", a.SuperAdminOnly, h.UpdateAllBetOutcomeStatusByOddID)
|
groupV1.Put("/odds/bet-outcome/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAllBetOutcomeStatusByOddID)
|
||||||
|
groupV1.Put("/odds/bet-outcome", a.authMiddleware, a.SuperAdminOnly, h.BulkUpdateAllBetOutcomeStatusByOddID)
|
||||||
|
|
||||||
tenant.Get("/odds", h.GetAllTenantOdds)
|
tenant.Get("/odds", h.GetAllTenantOdds)
|
||||||
tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
|
tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
|
||||||
|
|
@ -334,10 +336,13 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Get("/search/company", a.authMiddleware, a.CompanyOnly, h.SearchCompany)
|
groupV1.Get("/search/company", a.authMiddleware, a.CompanyOnly, h.SearchCompany)
|
||||||
groupV1.Get("/admin-company", a.authMiddleware, a.CompanyOnly, h.GetCompanyForAdmin)
|
groupV1.Get("/admin-company", a.authMiddleware, a.CompanyOnly, h.GetCompanyForAdmin)
|
||||||
|
|
||||||
|
groupV1.Get("/ticket", h.GetAllTickets)
|
||||||
|
groupV1.Get("/ticket/:id", h.GetTicketByID)
|
||||||
|
|
||||||
// Ticket Routes
|
// Ticket Routes
|
||||||
tenant.Post("/ticket", h.CreateTicket)
|
tenant.Post("/ticket", h.CreateTenantTicket)
|
||||||
tenant.Get("/ticket", h.GetAllTickets)
|
tenant.Get("/ticket", h.GetAllTenantTickets)
|
||||||
tenant.Get("/ticket/:id", h.GetTicketByID)
|
tenant.Get("/ticket/:id", h.GetTenantBetByID)
|
||||||
|
|
||||||
// Bet Routes
|
// Bet Routes
|
||||||
tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet)
|
tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user