fix: result log and notification
This commit is contained in:
parent
7d8d824a94
commit
3fb3da6cc8
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -9,3 +9,4 @@ logs/
|
|||
app_logs/
|
||||
backup/
|
||||
reports/
|
||||
exports/
|
||||
|
|
@ -264,6 +264,7 @@ CREATE TABLE events (
|
|||
fetched_at TIMESTAMP DEFAULT now(),
|
||||
source TEXT DEFAULT 'b365api',
|
||||
is_featured BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_monitorred BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
CREATE TABLE odds (
|
||||
|
|
@ -287,6 +288,22 @@ CREATE TABLE odds (
|
|||
UNIQUE (event_id, market_id, name, handicap),
|
||||
UNIQUE (event_id, market_id)
|
||||
);
|
||||
CREATE TABLE result_log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
status_not_finished_count INT NOT NULL,
|
||||
status_not_finished_bets INT NOT NULL,
|
||||
status_to_be_fixed_count INT NOT NULL,
|
||||
status_to_be_fixed_bets INT NOT NULL,
|
||||
status_postponed_count INT NOT NULL,
|
||||
status_postponed_bets INT NOT NULL,
|
||||
status_ended_count INT NOT NULL,
|
||||
status_ended_bets INT NOT NULL,
|
||||
status_removed_count INT NOT NULL,
|
||||
status_removed_bets INT NOT NULL,
|
||||
removed_count INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE TABLE companies (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
|
|
|
|||
|
|
@ -17,3 +17,55 @@ WHERE (
|
|||
)
|
||||
GROUP BY month
|
||||
ORDER BY month;
|
||||
|
||||
-- name: GetLeagueEventStat :many
|
||||
SELECT leagues.id,
|
||||
leagues.name,
|
||||
COUNT(*) AS total_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'pending'
|
||||
) AS pending,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'in_play'
|
||||
) AS in_play,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'to_be_fixed'
|
||||
) AS to_be_fixed,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'ended'
|
||||
) AS ended,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'postponed'
|
||||
) AS postponed,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'cancelled'
|
||||
) AS cancelled,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'walkover'
|
||||
) AS walkover,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'interrupted'
|
||||
) AS interrupted,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'abandoned'
|
||||
) AS abandoned,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'retired'
|
||||
) AS retired,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'suspended'
|
||||
) AS suspended,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'decided_by_fa'
|
||||
) AS decided_by_fa,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'removed'
|
||||
) AS removed
|
||||
FROM leagues
|
||||
JOIN events ON leagues.id = events.league_id
|
||||
WHERE (
|
||||
leagues.is_featured = sqlc.narg('is_league_featured')
|
||||
OR sqlc.narg('is_league_featured') IS NULL
|
||||
)
|
||||
GROUP BY leagues.id,
|
||||
leagues.name;
|
||||
28
db/query/result_log.sql
Normal file
28
db/query/result_log.sql
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
-- name: CreateResultLog :one
|
||||
INSERT INTO result_log (
|
||||
status_not_finished_count,
|
||||
status_not_finished_bets,
|
||||
status_to_be_fixed_count,
|
||||
status_to_be_fixed_bets,
|
||||
status_postponed_count,
|
||||
status_postponed_bets,
|
||||
status_ended_count,
|
||||
status_ended_bets,
|
||||
status_removed_count,
|
||||
status_removed_bets,
|
||||
removed_count
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING *;
|
||||
-- name: GetAllResultLog :many
|
||||
SELECT *
|
||||
FROM result_log
|
||||
WHERE (
|
||||
created_at < sqlc.narg('created_before')
|
||||
OR sqlc.narg('created_before') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > sqlc.narg('created_after')
|
||||
OR sqlc.narg('created_after') IS NULL
|
||||
)
|
||||
ORDER BY created_at DESC;
|
||||
|
|
@ -18,6 +18,7 @@ services:
|
|||
retries: 5
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./exports:/exports
|
||||
|
||||
mongo:
|
||||
container_name: fortunebet-mongo
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ func (q *Queries) DeleteEvent(ctx context.Context, id string) error {
|
|||
}
|
||||
|
||||
const GetAllUpcomingEvents = `-- name: GetAllUpcomingEvents :many
|
||||
SELECT 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, league_cc, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, is_featured, is_active
|
||||
SELECT 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, league_cc, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, is_featured, is_monitorred, is_active
|
||||
FROM events
|
||||
WHERE start_time > now()
|
||||
AND is_live = false
|
||||
|
|
@ -63,6 +63,7 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]Event, error) {
|
|||
&i.FetchedAt,
|
||||
&i.Source,
|
||||
&i.IsFeatured,
|
||||
&i.IsMonitorred,
|
||||
&i.IsActive,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -76,7 +77,7 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]Event, error) {
|
|||
}
|
||||
|
||||
const GetExpiredUpcomingEvents = `-- name: GetExpiredUpcomingEvents :many
|
||||
SELECT events.id, events.sport_id, events.match_name, events.home_team, events.away_team, events.home_team_id, events.away_team_id, events.home_kit_image, events.away_kit_image, events.league_id, events.league_name, events.league_cc, events.start_time, events.score, events.match_minute, events.timer_status, events.added_time, events.match_period, events.is_live, events.status, events.fetched_at, events.source, events.is_featured, events.is_active,
|
||||
SELECT events.id, events.sport_id, events.match_name, events.home_team, events.away_team, events.home_team_id, events.away_team_id, events.home_kit_image, events.away_kit_image, events.league_id, events.league_name, events.league_cc, events.start_time, events.score, events.match_minute, events.timer_status, events.added_time, events.match_period, events.is_live, events.status, events.fetched_at, events.source, events.is_featured, events.is_monitorred, events.is_active,
|
||||
leagues.country_code as league_cc
|
||||
FROM events
|
||||
LEFT JOIN leagues ON leagues.id = league_id
|
||||
|
|
@ -112,6 +113,7 @@ type GetExpiredUpcomingEventsRow struct {
|
|||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
IsMonitorred bool `json:"is_monitorred"`
|
||||
IsActive bool `json:"is_active"`
|
||||
LeagueCc_2 pgtype.Text `json:"league_cc_2"`
|
||||
}
|
||||
|
|
@ -149,6 +151,7 @@ func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context, status pgtype.Te
|
|||
&i.FetchedAt,
|
||||
&i.Source,
|
||||
&i.IsFeatured,
|
||||
&i.IsMonitorred,
|
||||
&i.IsActive,
|
||||
&i.LeagueCc_2,
|
||||
); err != nil {
|
||||
|
|
@ -163,7 +166,7 @@ func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context, status pgtype.Te
|
|||
}
|
||||
|
||||
const GetPaginatedUpcomingEvents = `-- name: GetPaginatedUpcomingEvents :many
|
||||
SELECT events.id, events.sport_id, events.match_name, events.home_team, events.away_team, events.home_team_id, events.away_team_id, events.home_kit_image, events.away_kit_image, events.league_id, events.league_name, events.league_cc, events.start_time, events.score, events.match_minute, events.timer_status, events.added_time, events.match_period, events.is_live, events.status, events.fetched_at, events.source, events.is_featured, events.is_active,
|
||||
SELECT events.id, events.sport_id, events.match_name, events.home_team, events.away_team, events.home_team_id, events.away_team_id, events.home_kit_image, events.away_kit_image, events.league_id, events.league_name, events.league_cc, events.start_time, events.score, events.match_minute, events.timer_status, events.added_time, events.match_period, events.is_live, events.status, events.fetched_at, events.source, events.is_featured, events.is_monitorred, events.is_active,
|
||||
leagues.country_code as league_cc
|
||||
FROM events
|
||||
LEFT JOIN leagues ON leagues.id = league_id
|
||||
|
|
@ -239,6 +242,7 @@ type GetPaginatedUpcomingEventsRow struct {
|
|||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
IsMonitorred bool `json:"is_monitorred"`
|
||||
IsActive bool `json:"is_active"`
|
||||
LeagueCc_2 pgtype.Text `json:"league_cc_2"`
|
||||
}
|
||||
|
|
@ -286,6 +290,7 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat
|
|||
&i.FetchedAt,
|
||||
&i.Source,
|
||||
&i.IsFeatured,
|
||||
&i.IsMonitorred,
|
||||
&i.IsActive,
|
||||
&i.LeagueCc_2,
|
||||
); err != nil {
|
||||
|
|
@ -362,7 +367,7 @@ func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams)
|
|||
}
|
||||
|
||||
const GetUpcomingByID = `-- name: GetUpcomingByID :one
|
||||
SELECT 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, league_cc, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, is_featured, is_active
|
||||
SELECT 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, league_cc, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, is_featured, is_monitorred, is_active
|
||||
FROM events
|
||||
WHERE id = $1
|
||||
AND is_live = false
|
||||
|
|
@ -397,6 +402,7 @@ func (q *Queries) GetUpcomingByID(ctx context.Context, id string) (Event, error)
|
|||
&i.FetchedAt,
|
||||
&i.Source,
|
||||
&i.IsFeatured,
|
||||
&i.IsMonitorred,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
|
|
|
|||
|
|
@ -11,6 +11,115 @@ import (
|
|||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const GetLeagueEventStat = `-- name: GetLeagueEventStat :many
|
||||
SELECT leagues.id,
|
||||
leagues.name,
|
||||
COUNT(*) AS total_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'pending'
|
||||
) AS pending,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'in_play'
|
||||
) AS in_play,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'to_be_fixed'
|
||||
) AS to_be_fixed,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'ended'
|
||||
) AS ended,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'postponed'
|
||||
) AS postponed,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'cancelled'
|
||||
) AS cancelled,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'walkover'
|
||||
) AS walkover,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'interrupted'
|
||||
) AS interrupted,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'abandoned'
|
||||
) AS abandoned,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'retired'
|
||||
) AS retired,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'suspended'
|
||||
) AS suspended,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'decided_by_fa'
|
||||
) AS decided_by_fa,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'removed'
|
||||
) AS removed
|
||||
FROM leagues
|
||||
JOIN events ON leagues.id = events.league_id
|
||||
WHERE (
|
||||
leagues.is_featured = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
GROUP BY leagues.id,
|
||||
leagues.name
|
||||
`
|
||||
|
||||
type GetLeagueEventStatRow struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
TotalEvents int64 `json:"total_events"`
|
||||
Pending int64 `json:"pending"`
|
||||
InPlay int64 `json:"in_play"`
|
||||
ToBeFixed int64 `json:"to_be_fixed"`
|
||||
Ended int64 `json:"ended"`
|
||||
Postponed int64 `json:"postponed"`
|
||||
Cancelled int64 `json:"cancelled"`
|
||||
Walkover int64 `json:"walkover"`
|
||||
Interrupted int64 `json:"interrupted"`
|
||||
Abandoned int64 `json:"abandoned"`
|
||||
Retired int64 `json:"retired"`
|
||||
Suspended int64 `json:"suspended"`
|
||||
DecidedByFa int64 `json:"decided_by_fa"`
|
||||
Removed int64 `json:"removed"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetLeagueEventStat(ctx context.Context, isLeagueFeatured pgtype.Bool) ([]GetLeagueEventStatRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetLeagueEventStat, isLeagueFeatured)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetLeagueEventStatRow
|
||||
for rows.Next() {
|
||||
var i GetLeagueEventStatRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.TotalEvents,
|
||||
&i.Pending,
|
||||
&i.InPlay,
|
||||
&i.ToBeFixed,
|
||||
&i.Ended,
|
||||
&i.Postponed,
|
||||
&i.Cancelled,
|
||||
&i.Walkover,
|
||||
&i.Interrupted,
|
||||
&i.Abandoned,
|
||||
&i.Retired,
|
||||
&i.Suspended,
|
||||
&i.DecidedByFa,
|
||||
&i.Removed,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetTotalMontlyEventStat = `-- name: GetTotalMontlyEventStat :many
|
||||
SELECT DATE_TRUNC('month', start_time) AS month,
|
||||
COUNT(*) AS event_count
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ type Event struct {
|
|||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
IsMonitorred bool `json:"is_monitorred"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
|
|
@ -408,6 +409,23 @@ type Result struct {
|
|||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ResultLog struct {
|
||||
ID int64 `json:"id"`
|
||||
StatusNotFinishedCount int32 `json:"status_not_finished_count"`
|
||||
StatusNotFinishedBets int32 `json:"status_not_finished_bets"`
|
||||
StatusToBeFixedCount int32 `json:"status_to_be_fixed_count"`
|
||||
StatusToBeFixedBets int32 `json:"status_to_be_fixed_bets"`
|
||||
StatusPostponedCount int32 `json:"status_postponed_count"`
|
||||
StatusPostponedBets int32 `json:"status_postponed_bets"`
|
||||
StatusEndedCount int32 `json:"status_ended_count"`
|
||||
StatusEndedBets int32 `json:"status_ended_bets"`
|
||||
StatusRemovedCount int32 `json:"status_removed_count"`
|
||||
StatusRemovedBets int32 `json:"status_removed_bets"`
|
||||
RemovedCount int32 `json:"removed_count"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type Setting struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
|
|
|
|||
132
gen/db/result_log.sql.go
Normal file
132
gen/db/result_log.sql.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: result_log.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const CreateResultLog = `-- name: CreateResultLog :one
|
||||
INSERT INTO result_log (
|
||||
status_not_finished_count,
|
||||
status_not_finished_bets,
|
||||
status_to_be_fixed_count,
|
||||
status_to_be_fixed_bets,
|
||||
status_postponed_count,
|
||||
status_postponed_bets,
|
||||
status_ended_count,
|
||||
status_ended_bets,
|
||||
status_removed_count,
|
||||
status_removed_bets,
|
||||
removed_count
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING id, status_not_finished_count, status_not_finished_bets, status_to_be_fixed_count, status_to_be_fixed_bets, status_postponed_count, status_postponed_bets, status_ended_count, status_ended_bets, status_removed_count, status_removed_bets, removed_count, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateResultLogParams struct {
|
||||
StatusNotFinishedCount int32 `json:"status_not_finished_count"`
|
||||
StatusNotFinishedBets int32 `json:"status_not_finished_bets"`
|
||||
StatusToBeFixedCount int32 `json:"status_to_be_fixed_count"`
|
||||
StatusToBeFixedBets int32 `json:"status_to_be_fixed_bets"`
|
||||
StatusPostponedCount int32 `json:"status_postponed_count"`
|
||||
StatusPostponedBets int32 `json:"status_postponed_bets"`
|
||||
StatusEndedCount int32 `json:"status_ended_count"`
|
||||
StatusEndedBets int32 `json:"status_ended_bets"`
|
||||
StatusRemovedCount int32 `json:"status_removed_count"`
|
||||
StatusRemovedBets int32 `json:"status_removed_bets"`
|
||||
RemovedCount int32 `json:"removed_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateResultLog(ctx context.Context, arg CreateResultLogParams) (ResultLog, error) {
|
||||
row := q.db.QueryRow(ctx, CreateResultLog,
|
||||
arg.StatusNotFinishedCount,
|
||||
arg.StatusNotFinishedBets,
|
||||
arg.StatusToBeFixedCount,
|
||||
arg.StatusToBeFixedBets,
|
||||
arg.StatusPostponedCount,
|
||||
arg.StatusPostponedBets,
|
||||
arg.StatusEndedCount,
|
||||
arg.StatusEndedBets,
|
||||
arg.StatusRemovedCount,
|
||||
arg.StatusRemovedBets,
|
||||
arg.RemovedCount,
|
||||
)
|
||||
var i ResultLog
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.StatusNotFinishedCount,
|
||||
&i.StatusNotFinishedBets,
|
||||
&i.StatusToBeFixedCount,
|
||||
&i.StatusToBeFixedBets,
|
||||
&i.StatusPostponedCount,
|
||||
&i.StatusPostponedBets,
|
||||
&i.StatusEndedCount,
|
||||
&i.StatusEndedBets,
|
||||
&i.StatusRemovedCount,
|
||||
&i.StatusRemovedBets,
|
||||
&i.RemovedCount,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetAllResultLog = `-- name: GetAllResultLog :many
|
||||
SELECT id, status_not_finished_count, status_not_finished_bets, status_to_be_fixed_count, status_to_be_fixed_bets, status_postponed_count, status_postponed_bets, status_ended_count, status_ended_bets, status_removed_count, status_removed_bets, removed_count, created_at, updated_at
|
||||
FROM result_log
|
||||
WHERE (
|
||||
created_at < $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
type GetAllResultLogParams struct {
|
||||
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
||||
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllResultLog(ctx context.Context, arg GetAllResultLogParams) ([]ResultLog, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllResultLog, arg.CreatedBefore, arg.CreatedAfter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ResultLog
|
||||
for rows.Next() {
|
||||
var i ResultLog
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.StatusNotFinishedCount,
|
||||
&i.StatusNotFinishedBets,
|
||||
&i.StatusToBeFixedCount,
|
||||
&i.StatusToBeFixedBets,
|
||||
&i.StatusPostponedCount,
|
||||
&i.StatusPostponedBets,
|
||||
&i.StatusEndedCount,
|
||||
&i.StatusEndedBets,
|
||||
&i.StatusRemovedCount,
|
||||
&i.StatusRemovedBets,
|
||||
&i.RemovedCount,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ package domain
|
|||
|
||||
import (
|
||||
"time"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
)
|
||||
|
||||
type MarketConfig struct {
|
||||
|
|
@ -83,22 +85,78 @@ const (
|
|||
TIME_STATUS_REMOVED TimeStatus = 99
|
||||
)
|
||||
|
||||
type ResultStatusCounts struct {
|
||||
IsNotFinished int `json:"is_not_finished"`
|
||||
IsNotFinishedBets int `json:"is_not_finished_bets"`
|
||||
IsToBeFixed int `json:"is_to_be_fixed"`
|
||||
IsToBeFixedBets int `json:"is_to_be_fixed_bets"`
|
||||
IsPostponed int `json:"is_postponed"`
|
||||
IsPostponedBets int `json:"is_postponed_bets"`
|
||||
IsEnded int `json:"is_ended"`
|
||||
IsEndedBets int `json:"is_ended_bets"`
|
||||
IsRemoved int `json:"is_removed"`
|
||||
IsRemovedBets int `json:"is_removed_bets"`
|
||||
type ResultLog struct {
|
||||
ID int64 `json:"id"`
|
||||
StatusNotFinishedCount int `json:"status_not_finished_count"`
|
||||
StatusNotFinishedBets int `json:"status_not_finished_bets"`
|
||||
StatusToBeFixedCount int `json:"status_to_be_fixed_count"`
|
||||
StatusToBeFixedBets int `json:"status_to_be_fixed_bets"`
|
||||
StatusPostponedCount int `json:"status_postponed_count"`
|
||||
StatusPostponedBets int `json:"status_postponed_bets"`
|
||||
StatusEndedCount int `json:"status_ended_count"`
|
||||
StatusEndedBets int `json:"status_ended_bets"`
|
||||
StatusRemovedCount int `json:"status_removed_count"`
|
||||
StatusRemovedBets int `json:"status_removed_bets"`
|
||||
RemovedCount int `json:"removed"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type CreateResultLog struct {
|
||||
StatusNotFinishedCount int `json:"status_not_finished_count"`
|
||||
StatusNotFinishedBets int `json:"status_not_finished_bets"`
|
||||
StatusToBeFixedCount int `json:"status_to_be_fixed_count"`
|
||||
StatusToBeFixedBets int `json:"status_to_be_fixed_bets"`
|
||||
StatusPostponedCount int `json:"status_postponed_count"`
|
||||
StatusPostponedBets int `json:"status_postponed_bets"`
|
||||
StatusEndedCount int `json:"status_ended_count"`
|
||||
StatusEndedBets int `json:"status_ended_bets"`
|
||||
StatusRemovedCount int `json:"status_removed_count"`
|
||||
StatusRemovedBets int `json:"status_removed_bets"`
|
||||
RemovedCount int `json:"removed"`
|
||||
}
|
||||
|
||||
type ResultFilter struct {
|
||||
CreatedBefore ValidTime
|
||||
CreatedAfter ValidTime
|
||||
}
|
||||
type ResultStatusBets struct {
|
||||
IsNotFinished []int64 `json:"is_not_finished"`
|
||||
IsToBeFixed []int64 `json:"is_to_be_fixed"`
|
||||
IsPostponed []int64 `json:"is_postponed"`
|
||||
IsEnded []int64 `json:"is_ended"`
|
||||
IsRemoved []int64 `json:"is_removed"`
|
||||
StatusNotFinished []int64 `json:"status_not_finished"`
|
||||
StatusToBeFixed []int64 `json:"status_to_be_fixed"`
|
||||
StatusPostponed []int64 `json:"status_postponed"`
|
||||
StatusEnded []int64 `json:"status_ended"`
|
||||
StatusRemoved []int64 `json:"status_removed"`
|
||||
}
|
||||
|
||||
func ConvertDBResultLog(result dbgen.ResultLog) ResultLog {
|
||||
return ResultLog{
|
||||
ID: result.ID,
|
||||
StatusNotFinishedCount: int(result.StatusNotFinishedCount),
|
||||
StatusNotFinishedBets: int(result.StatusNotFinishedBets),
|
||||
StatusToBeFixedCount: int(result.StatusToBeFixedCount),
|
||||
StatusToBeFixedBets: int(result.StatusToBeFixedBets),
|
||||
StatusPostponedCount: int(result.StatusPostponedCount),
|
||||
StatusPostponedBets: int(result.StatusPostponedBets),
|
||||
StatusEndedCount: int(result.StatusEndedCount),
|
||||
StatusEndedBets: int(result.StatusEndedBets),
|
||||
StatusRemovedCount: int(result.StatusRemovedCount),
|
||||
StatusRemovedBets: int(result.StatusRemovedBets),
|
||||
RemovedCount: int(result.RemovedCount),
|
||||
CreatedAt: result.CreatedAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertCreateResultLog(result CreateResultLog) dbgen.CreateResultLogParams {
|
||||
return dbgen.CreateResultLogParams{
|
||||
StatusNotFinishedCount: int32(result.StatusNotFinishedCount),
|
||||
StatusNotFinishedBets: int32(result.StatusNotFinishedBets),
|
||||
StatusToBeFixedCount: int32(result.StatusToBeFixedCount),
|
||||
StatusToBeFixedBets: int32(result.StatusToBeFixedBets),
|
||||
StatusPostponedCount: int32(result.StatusPostponedCount),
|
||||
StatusPostponedBets: int32(result.StatusPostponedBets),
|
||||
StatusEndedCount: int32(result.StatusEndedCount),
|
||||
StatusEndedBets: int32(result.StatusEndedBets),
|
||||
StatusRemovedCount: int32(result.StatusRemovedCount),
|
||||
StatusRemovedBets: int32(result.StatusRemovedBets),
|
||||
RemovedCount: int32(result.RemovedCount),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,93 +8,34 @@ import (
|
|||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func convertDBResult(result dbgen.Result) domain.Result {
|
||||
scores := make(map[string]domain.Score)
|
||||
return domain.Result{
|
||||
ID: result.ID,
|
||||
BetOutcomeID: result.BetOutcomeID,
|
||||
EventID: result.EventID,
|
||||
OddID: result.OddID,
|
||||
MarketID: result.MarketID,
|
||||
Status: domain.OutcomeStatus(result.Status),
|
||||
Score: result.Score.String,
|
||||
FullTimeScore: result.FullTimeScore.String,
|
||||
HalfTimeScore: result.HalfTimeScore.String,
|
||||
SS: result.Ss.String,
|
||||
Scores: scores,
|
||||
CreatedAt: result.CreatedAt.Time,
|
||||
UpdatedAt: result.UpdatedAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
func convertCreateResult(result domain.CreateResult) dbgen.CreateResultParams {
|
||||
return dbgen.CreateResultParams{
|
||||
BetOutcomeID: result.BetOutcomeID,
|
||||
EventID: result.EventID,
|
||||
OddID: result.OddID,
|
||||
MarketID: result.MarketID,
|
||||
Status: int32(result.Status),
|
||||
Score: pgtype.Text{String: result.Score},
|
||||
}
|
||||
}
|
||||
|
||||
func convertResult(result domain.Result) dbgen.InsertResultParams {
|
||||
return dbgen.InsertResultParams{
|
||||
BetOutcomeID: result.BetOutcomeID,
|
||||
EventID: result.EventID,
|
||||
OddID: result.OddID,
|
||||
MarketID: result.MarketID,
|
||||
Status: int32(result.Status),
|
||||
Score: pgtype.Text{String: result.Score},
|
||||
FullTimeScore: pgtype.Text{String: result.FullTimeScore},
|
||||
HalfTimeScore: pgtype.Text{String: result.HalfTimeScore},
|
||||
Ss: pgtype.Text{String: result.SS},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) CreateResult(ctx context.Context, result domain.CreateResult) (domain.Result, error) {
|
||||
dbResult, err := s.queries.CreateResult(ctx, convertCreateResult(result))
|
||||
func (s *Store) CreateResultLog(ctx context.Context, result domain.CreateResultLog) (domain.ResultLog, error) {
|
||||
dbResult, err := s.queries.CreateResultLog(ctx, domain.ConvertCreateResultLog(result))
|
||||
if err != nil {
|
||||
return domain.Result{}, err
|
||||
return domain.ResultLog{}, err
|
||||
}
|
||||
return convertDBResult(dbResult), nil
|
||||
return domain.ConvertDBResultLog(dbResult), nil
|
||||
}
|
||||
|
||||
func (s *Store) InsertResult(ctx context.Context, result domain.Result) error {
|
||||
return s.queries.InsertResult(ctx, convertResult(result))
|
||||
}
|
||||
|
||||
func (s *Store) GetResultByBetOutcomeID(ctx context.Context, betOutcomeID int64) (domain.Result, error) {
|
||||
dbResult, err := s.queries.GetResultByBetOutcomeID(ctx, betOutcomeID)
|
||||
if err != nil {
|
||||
return domain.Result{}, err
|
||||
}
|
||||
return convertDBResult(dbResult), nil
|
||||
}
|
||||
|
||||
func (s *Store) GetPendingBetOutcomes(ctx context.Context) ([]domain.BetOutcome, error) {
|
||||
dbOutcomes, err := s.queries.GetPendingBetOutcomes(ctx)
|
||||
func (s *Store) GetAllResultLog(ctx context.Context, filter domain.ResultFilter) ([]domain.ResultLog, error) {
|
||||
dbResultLogs, err := s.queries.GetAllResultLog(ctx, dbgen.GetAllResultLogParams{
|
||||
CreatedBefore: pgtype.Timestamp{
|
||||
Time: filter.CreatedBefore.Value,
|
||||
Valid: filter.CreatedBefore.Valid,
|
||||
},
|
||||
CreatedAfter: pgtype.Timestamp{
|
||||
Time: filter.CreatedAfter.Value,
|
||||
Valid: filter.CreatedAfter.Valid,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outcomes := make([]domain.BetOutcome, 0, len(dbOutcomes))
|
||||
for _, dbOutcome := range dbOutcomes {
|
||||
outcomes = append(outcomes, domain.BetOutcome{
|
||||
ID: dbOutcome.ID,
|
||||
BetID: dbOutcome.BetID,
|
||||
EventID: dbOutcome.EventID,
|
||||
OddID: dbOutcome.OddID,
|
||||
HomeTeamName: dbOutcome.HomeTeamName,
|
||||
AwayTeamName: dbOutcome.AwayTeamName,
|
||||
MarketID: dbOutcome.MarketID,
|
||||
MarketName: dbOutcome.MarketName,
|
||||
Odd: dbOutcome.Odd,
|
||||
OddName: dbOutcome.OddName,
|
||||
OddHeader: dbOutcome.OddHeader,
|
||||
OddHandicap: dbOutcome.OddHandicap,
|
||||
Status: domain.OutcomeStatus(dbOutcome.Status),
|
||||
Expires: dbOutcome.Expires.Time,
|
||||
})
|
||||
result := make([]domain.ResultLog, 0, len(dbResultLogs))
|
||||
for _, dbResultLog := range dbResultLogs {
|
||||
result = append(result, domain.ConvertDBResultLog(dbResultLog))
|
||||
}
|
||||
return outcomes, nil
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -987,6 +987,8 @@ func (s *Service) SendWinningStatusNotification(ctx context.Context, status doma
|
|||
|
||||
betNotification := &domain.Notification{
|
||||
RecipientID: userID,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
IsRead: false,
|
||||
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
||||
Level: domain.NotificationLevelSuccess,
|
||||
Reciever: domain.NotificationRecieverSideCustomer,
|
||||
|
|
@ -1028,6 +1030,8 @@ func (s *Service) SendLosingStatusNotification(ctx context.Context, status domai
|
|||
|
||||
betNotification := &domain.Notification{
|
||||
RecipientID: userID,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
IsRead: false,
|
||||
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
||||
Level: domain.NotificationLevelSuccess,
|
||||
Reciever: domain.NotificationRecieverSideCustomer,
|
||||
|
|
@ -1070,6 +1074,8 @@ func (s *Service) SendErrorStatusNotification(ctx context.Context, status domain
|
|||
|
||||
betNotification := &domain.Notification{
|
||||
RecipientID: userID,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
IsRead: false,
|
||||
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
||||
Level: domain.NotificationLevelSuccess,
|
||||
Reciever: domain.NotificationRecieverSideCustomer,
|
||||
|
|
@ -1104,11 +1110,15 @@ func (s *Service) SendAdminErrorAlertNotification(ctx context.Context, status do
|
|||
|
||||
switch status {
|
||||
case domain.OUTCOME_STATUS_ERROR, domain.OUTCOME_STATUS_PENDING:
|
||||
headline = "There was an error with your bet"
|
||||
message = "We have encounter an error with your bet. We will fix it as soon as we can"
|
||||
headline = "There was an error processing bet"
|
||||
message = "We have encounter an error with bet. We will fix it as soon as we can"
|
||||
}
|
||||
|
||||
errorSeverity := domain.NotificationErrorSeverityHigh
|
||||
betNotification := &domain.Notification{
|
||||
ErrorSeverity: &errorSeverity,
|
||||
DeliveryStatus: domain.DeliveryStatusPending,
|
||||
IsRead: false,
|
||||
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
||||
Level: domain.NotificationLevelSuccess,
|
||||
Reciever: domain.NotificationRecieverSideCustomer,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,16 @@ package result
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
type ResultService interface {
|
||||
FetchAndProcessResults(ctx context.Context) error
|
||||
FetchAndStoreResult(ctx context.Context, eventID string) error
|
||||
}
|
||||
|
||||
type ResultLogStore interface {
|
||||
CreateResultLog(ctx context.Context, result domain.CreateResultLog) (domain.ResultLog, error)
|
||||
GetAllResultLog(ctx context.Context, filter domain.ResultFilter) ([]domain.ResultLog, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,9 +264,8 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
removed := 0
|
||||
empty_sport_id := make([]int64, 0)
|
||||
var resultStatusCounts domain.ResultStatusCounts
|
||||
var resultLog domain.CreateResultLog
|
||||
var resultStatusBets domain.ResultStatusBets
|
||||
for _, event := range events {
|
||||
|
||||
|
|
@ -283,7 +282,6 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
result, err := s.fetchResult(ctx, eventID)
|
||||
if err != nil {
|
||||
if err == ErrEventIsNotActive {
|
||||
s.logger.Warn("Event is not active", "event_id", eventID, "error", err)
|
||||
s.mongoLogger.Warn(
|
||||
"Event is not active",
|
||||
zap.Int64("eventID", eventID),
|
||||
|
|
@ -329,25 +327,42 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
// Admin users will be able to review the events
|
||||
switch timeStatusParsed {
|
||||
case int64(domain.TIME_STATUS_NOT_STARTED), int64(domain.TIME_STATUS_IN_PLAY):
|
||||
resultStatusCounts.IsNotFinished += 1
|
||||
resultLog.StatusNotFinishedCount += 1
|
||||
bets, err := s.GetTotalBetsForEvents(ctx, eventID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
resultStatusCounts.IsNotFinishedBets = len(bets)
|
||||
resultLog.StatusNotFinishedBets = len(bets)
|
||||
for k := range bets {
|
||||
resultStatusBets.IsNotFinished = append(resultStatusBets.IsNotFinished, k)
|
||||
resultStatusBets.StatusNotFinished = append(resultStatusBets.StatusNotFinished, k)
|
||||
}
|
||||
|
||||
case int64(domain.TIME_STATUS_TO_BE_FIXED):
|
||||
resultStatusCounts.IsToBeFixed += 1
|
||||
bets, err := s.GetTotalBetsForEvents(ctx, eventID)
|
||||
totalBetsRefunded, err := s.RefundAllOutcomes(ctx, eventID)
|
||||
|
||||
err = s.repo.DeleteEvent(ctx, event.ID)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error(
|
||||
"Failed to remove event",
|
||||
zap.Int64("eventID", eventID),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
resultStatusCounts.IsToBeFixedBets = len(bets)
|
||||
for k := range bets {
|
||||
resultStatusBets.IsNotFinished = append(resultStatusBets.IsNotFinished, k)
|
||||
err = s.repo.DeleteOddsForEvent(ctx, event.ID)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error(
|
||||
"Failed to remove odds for event",
|
||||
zap.Int64("eventID", eventID),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
resultLog.RemovedCount += 1
|
||||
resultLog.StatusToBeFixedCount += 1
|
||||
resultLog.StatusToBeFixedBets = len(totalBetsRefunded)
|
||||
for k := range totalBetsRefunded {
|
||||
resultStatusBets.StatusToBeFixed = append(resultStatusBets.StatusToBeFixed, k)
|
||||
}
|
||||
// s.mongoLogger.Warn(
|
||||
// "Event needs to be rescheduled or corrected",
|
||||
|
|
@ -355,14 +370,16 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
// zap.Error(err),
|
||||
// )
|
||||
case int64(domain.TIME_STATUS_POSTPONED), int64(domain.TIME_STATUS_SUSPENDED):
|
||||
resultStatusCounts.IsPostponed += 1
|
||||
|
||||
bets, err := s.GetTotalBetsForEvents(ctx, eventID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
resultStatusCounts.IsPostponed = len(bets)
|
||||
|
||||
resultLog.StatusPostponedCount += 1
|
||||
resultLog.StatusPostponedBets = len(bets)
|
||||
for k := range bets {
|
||||
resultStatusBets.IsNotFinished = append(resultStatusBets.IsNotFinished, k)
|
||||
resultStatusBets.StatusPostponed = append(resultStatusBets.StatusPostponed, k)
|
||||
}
|
||||
// s.mongoLogger.Warn(
|
||||
// "Event has been temporarily postponed",
|
||||
|
|
@ -409,15 +426,15 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
)
|
||||
continue
|
||||
}
|
||||
removed += 1
|
||||
resultStatusCounts.IsEnded += 1
|
||||
resultLog.RemovedCount += 1
|
||||
resultLog.StatusEndedCount += 1
|
||||
bets, err := s.GetTotalBetsForEvents(ctx, eventID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
resultStatusCounts.IsEndedBets = len(bets)
|
||||
resultLog.StatusEndedBets = len(bets)
|
||||
for k := range bets {
|
||||
resultStatusBets.IsNotFinished = append(resultStatusBets.IsNotFinished, k)
|
||||
resultStatusBets.StatusEnded = append(resultStatusBets.StatusEnded, k)
|
||||
}
|
||||
case int64(domain.TIME_STATUS_ABANDONED), int64(domain.TIME_STATUS_CANCELLED), int64(domain.TIME_STATUS_REMOVED):
|
||||
// s.SendAdminResultStatusErrorNotification(
|
||||
|
|
@ -451,59 +468,126 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
)
|
||||
continue
|
||||
}
|
||||
removed += 1
|
||||
resultStatusCounts.IsRemoved += 1
|
||||
resultStatusCounts.IsRemovedBets = len(totalBetsRefunded)
|
||||
resultLog.RemovedCount += 1
|
||||
resultLog.StatusRemovedCount += 1
|
||||
resultLog.StatusRemovedBets = len(totalBetsRefunded)
|
||||
for k := range totalBetsRefunded {
|
||||
resultStatusBets.IsNotFinished = append(resultStatusBets.IsNotFinished, k)
|
||||
resultStatusBets.StatusRemoved = append(resultStatusBets.StatusRemoved, k)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
s.SendAdminResultStatusErrorNotification(
|
||||
ctx,
|
||||
resultStatusCounts,
|
||||
// This will be used to send daily notifications, since events will be removed
|
||||
_, err = s.repo.CreateResultLog(ctx, resultLog)
|
||||
if err != nil {
|
||||
s.mongoLogger.Warn(
|
||||
"Failed to store result log",
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
|
||||
var logMessage string
|
||||
if resultStatusCounts.IsNotFinished != 0 || resultStatusCounts.IsPostponed != 0 ||
|
||||
resultStatusCounts.IsRemoved != 0 || resultStatusCounts.IsToBeFixed != 0 {
|
||||
logMessage = "Completed processed results with issues"
|
||||
if resultLog.StatusNotFinishedCount != 0 || resultLog.StatusPostponedCount != 0 ||
|
||||
resultLog.StatusRemovedCount != 0 || resultLog.StatusToBeFixedCount != 0 {
|
||||
logMessage = "Completed processing results with issues"
|
||||
} else {
|
||||
logMessage = "Successfully processed results with no issues"
|
||||
}
|
||||
|
||||
s.mongoLogger.Info(
|
||||
logMessage,
|
||||
zap.Int("number_of_removed_events", removed),
|
||||
zap.Int("number_of_removed_events", resultLog.RemovedCount),
|
||||
zap.Int("total_expired_events", len(events)),
|
||||
zap.Any("events_with_empty_sport_id", empty_sport_id),
|
||||
zap.Any("result status counts", resultStatusCounts),
|
||||
zap.Any("result status counts", resultLog),
|
||||
zap.Any("bets by event status", resultStatusBets),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildHeadlineAndMessage(counts domain.ResultStatusCounts) (string, string) {
|
||||
totalIssues := counts.IsNotFinished + counts.IsToBeFixed + counts.IsPostponed + counts.IsRemoved
|
||||
func (s *Service) CheckAndSendResultNotifications(ctx context.Context, createdAfter time.Time) error {
|
||||
|
||||
resultLog, err := s.repo.GetAllResultLog(ctx, domain.ResultFilter{
|
||||
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 "✅ Event Results Processed", "All event results were processed successfully. No issues detected."
|
||||
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.IsNotFinished > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d unfinished", counts.IsNotFinished))
|
||||
if counts.StatusNotFinishedCount > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d unfinished with %d bets", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
||||
}
|
||||
if counts.IsToBeFixed > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d to-fix", counts.IsToBeFixed))
|
||||
if counts.StatusToBeFixedCount > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d to-fix with %d bets", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
||||
}
|
||||
if counts.IsPostponed > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d postponed", counts.IsPostponed))
|
||||
if counts.StatusPostponedCount > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d postponed with %d bets", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
||||
}
|
||||
if counts.IsRemoved > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d removed", counts.IsRemoved))
|
||||
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"
|
||||
|
|
@ -513,7 +597,7 @@ func buildHeadlineAndMessage(counts domain.ResultStatusCounts) (string, string)
|
|||
|
||||
func (s *Service) SendAdminResultStatusErrorNotification(
|
||||
ctx context.Context,
|
||||
counts domain.ResultStatusCounts,
|
||||
counts domain.ResultLog,
|
||||
) error {
|
||||
|
||||
superAdmins, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
||||
|
|
@ -558,6 +642,14 @@ func (s *Service) SendAdminResultStatusErrorNotification(
|
|||
)
|
||||
sendErrors = append(sendErrors, err)
|
||||
}
|
||||
notification.DeliveryChannel = domain.DeliveryChannelEmail
|
||||
if err := s.notificationSvc.SendNotification(ctx, notification); err != nil {
|
||||
s.mongoLogger.Error("failed to send admin email notification",
|
||||
zap.Int64("admin_id", user.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
sendErrors = append(sendErrors, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(sendErrors) > 0 {
|
||||
|
|
|
|||
|
|
@ -51,19 +51,19 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 */5 * * * *", // Every 5 Minutes
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began updating all expired events status")
|
||||
// if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to update expired events status",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Successfully updated expired events")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
{
|
||||
spec: "0 */5 * * * *", // Every 5 Minutes
|
||||
task: func() {
|
||||
mongoLogger.Info("Began updating all expired events status")
|
||||
if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil {
|
||||
mongoLogger.Error("Failed to update expired events status",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
mongoLogger.Info("Successfully updated expired events")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 */15 * * * *", // Every 15 Minutes
|
||||
task: func() {
|
||||
|
|
@ -77,6 +77,19 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 0 * * * *", // Every Day
|
||||
task: func() {
|
||||
mongoLogger.Info("Send daily result notification")
|
||||
if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-24*time.Hour)); err != nil {
|
||||
mongoLogger.Error("Failed to process result",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
mongoLogger.Info("Successfully processed all event result outcomes")
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, job := range schedule {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user