feat: Add EventWithSettings domain model and related conversion functions
- Introduced EventWithSettings and EventWithSettingsRes structs for enhanced event data handling. - Implemented conversion functions for creating and updating event settings. - Added support for fetching events with settings from the database. - Created new report data structures for comprehensive reporting capabilities. - Implemented event statistics retrieval and filtering by league and sport. - Added handlers for event statistics endpoints in the web server. - Introduced DateInterval type for managing time intervals in reports.
This commit is contained in:
parent
528a948f20
commit
18689ea124
|
|
@ -101,6 +101,7 @@ CREATE TABLE IF NOT EXISTS bets (
|
|||
company_id BIGINT NOT NULL,
|
||||
amount BIGINT NOT NULL,
|
||||
total_odds REAL NOT NULL,
|
||||
potential_win BIGINT GENERATED ALWAYS AS (amount * total_odds) STORED,
|
||||
status INT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
is_shop_bet BOOLEAN NOT NULL,
|
||||
|
|
@ -329,6 +330,29 @@ CREATE TABLE events (
|
|||
is_monitored BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
UNIQUE(source_event_id, source)
|
||||
);
|
||||
CREATE INDEX idx_events_league_start_time ON events(league_id, start_time);
|
||||
CREATE INDEX IF NOT EXISTS idx_events_league_id ON events (league_id);
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
CREATE INDEX idx_events_search_trgm ON events USING GIN (
|
||||
match_name gin_trgm_ops,
|
||||
league_name gin_trgm_ops
|
||||
);
|
||||
CREATE INDEX idx_events_core_filter ON events (
|
||||
source,
|
||||
sport_id,
|
||||
league_id,
|
||||
status,
|
||||
is_live,
|
||||
start_time DESC
|
||||
);
|
||||
CREATE TABLE event_bet_stats (
|
||||
event_id BIGINT PRIMARY KEY,
|
||||
number_of_bets BIGINT,
|
||||
total_amount BIGINT,
|
||||
avg_bet_amount DOUBLE PRECISION,
|
||||
total_potential_winnings BIGINT,
|
||||
updated_at TIMESTAMP DEFAULT now()
|
||||
);
|
||||
CREATE TABLE event_history (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
event_id BIGINT NOT NULL,
|
||||
|
|
@ -359,6 +383,7 @@ CREATE TABLE odds_market (
|
|||
expires_at TIMESTAMP NOT NULL,
|
||||
UNIQUE (event_id, market_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_odds_market_event_id ON odds_market (event_id);
|
||||
CREATE TABLE odd_history (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
odds_market_id BIGINT NOT NULL REFERENCES odds_market (id),
|
||||
|
|
@ -416,6 +441,14 @@ CREATE TABLE companies (
|
|||
AND deducted_percentage < 1
|
||||
)
|
||||
);
|
||||
CREATE TABLE company_stats (
|
||||
company_id BIGINT PRIMARY KEY,
|
||||
total_bets BIGINT,
|
||||
total_cash_made BIGINT,
|
||||
total_cash_out BIGINT,
|
||||
total_cash_backs BIGINT,
|
||||
updated_at TIMESTAMP DEFAULT now()
|
||||
);
|
||||
CREATE TABLE leagues (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
|
|
@ -552,6 +585,16 @@ CREATE TABLE IF NOT EXISTS company_accumulator (
|
|||
outcome_count BIGINT NOT NULL,
|
||||
multiplier REAL NOT NULL
|
||||
);
|
||||
CREATE TABLE reports (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
company_id BIGINT,
|
||||
requested_by BIGINT,
|
||||
--For System Generated Reports
|
||||
file_path TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
created_at TIMESTAMP DEFAULT now(),
|
||||
completed_at TIMESTAMP
|
||||
);
|
||||
------ Views
|
||||
CREATE VIEW companies_details AS
|
||||
SELECT companies.*,
|
||||
|
|
@ -675,6 +718,35 @@ SELECT sd.*,
|
|||
st.verified AS transaction_verified
|
||||
FROM shop_deposits AS sd
|
||||
JOIN shop_transactions st ON st.id = sd.shop_transaction_id;
|
||||
CREATE OR REPLACE VIEW event_detailed AS
|
||||
SELECT ewc.*,
|
||||
leagues.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes,
|
||||
COALESCE(ebs.number_of_bets, 0) AS number_of_bets,
|
||||
COALESCE(ebs.total_amount, 0) AS total_amount,
|
||||
COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount,
|
||||
COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings
|
||||
FROM events ewc
|
||||
LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id
|
||||
LEFT JOIN leagues ON leagues.id = events.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = events.id;
|
||||
CREATE MATERIALIZED VIEW event_detailed_mat AS
|
||||
SELECT *
|
||||
FROM event_detailed;
|
||||
CREATE VIEW odds_market_with_event AS
|
||||
SELECT o.*,
|
||||
e.is_monitored,
|
||||
e.is_live,
|
||||
e.status,
|
||||
e.source
|
||||
FROM odds_market o
|
||||
JOIN events e ON o.event_id = e.id;
|
||||
-- Views only for SQLC to generate structs for them (so that we can reuse those structs)
|
||||
CREATE VIEW league_with_settings AS
|
||||
SELECT l.*,
|
||||
cls.company_id,
|
||||
|
|
@ -694,28 +766,21 @@ SELECT e.*,
|
|||
) AS winning_upper_limit,
|
||||
ces.updated_at as company_updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes,
|
||||
COALESCE(ebs.number_of_bets, 0) AS number_of_bets,
|
||||
COALESCE(ebs.total_amount, 0) AS total_amount,
|
||||
COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount,
|
||||
COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id;
|
||||
CREATE VIEW event_with_country AS
|
||||
SELECT events.*,
|
||||
leagues.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes
|
||||
FROM events
|
||||
LEFT JOIN leagues ON leagues.id = events.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = events.id;
|
||||
CREATE VIEW odds_market_with_settings AS
|
||||
SELECT o.id,
|
||||
o.event_id,
|
||||
|
|
@ -733,14 +798,6 @@ SELECT o.id,
|
|||
cos.updated_at
|
||||
FROM odds_market o
|
||||
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id;
|
||||
CREATE VIEW odds_market_with_event AS
|
||||
SELECT o.*,
|
||||
e.is_monitored,
|
||||
e.is_live,
|
||||
e.status,
|
||||
e.source
|
||||
FROM odds_market o
|
||||
JOIN events e ON o.event_id = e.id;
|
||||
-- Foreign Keys
|
||||
ALTER TABLE refresh_tokens
|
||||
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users (id);
|
||||
|
|
|
|||
31
db/query/branch_stats.sql
Normal file
31
db/query/branch_stats.sql
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
-- name: GetBranchStats :many
|
||||
SELECT b.branch_id,
|
||||
br.name AS branch_name,
|
||||
br.company_id,
|
||||
COUNT(*) AS total_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_cash_made,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN sb.cashed_out THEN b.amount -- use cashed_out from shop_bets
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_out,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.status = 5 THEN b.amount
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_backs
|
||||
FROM shop_bet_detail b
|
||||
JOIN branches br ON b.branch_id = br.id
|
||||
JOIN shop_bets sb ON sb.id = b.id -- join to get cashed_out
|
||||
WHERE b.created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to')
|
||||
GROUP BY b.branch_id,
|
||||
br.name,
|
||||
br.company_id;
|
||||
42
db/query/company_stats.sql
Normal file
42
db/query/company_stats.sql
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
-- Aggregate company stats
|
||||
-- name: UpdateCompanyStats :exec
|
||||
INSERT INTO company_stats (
|
||||
company_id,
|
||||
total_bets,
|
||||
total_cash_made,
|
||||
total_cash_backs,
|
||||
updated_at
|
||||
)
|
||||
SELECT b.company_id,
|
||||
COUNT(*) AS total_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_cash_made,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN sb.cashed_out THEN b.amount -- use actual cashed_out flag from shop_bets
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_out,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.status = 5 THEN b.amount
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_backs,
|
||||
NOW() AS updated_at
|
||||
FROM shop_bet_detail b
|
||||
JOIN companies c ON b.company_id = c.id
|
||||
JOIN shop_bets sb ON sb.id = b.id -- join to get cashed_out
|
||||
GROUP BY b.company_id,
|
||||
c.name ON CONFLICT (company_id) DO
|
||||
UPDATE
|
||||
SET total_bets = EXCLUDED.total_bets,
|
||||
total_cash_made = EXCLUDED.total_cash_made,
|
||||
total_cash_out = EXCLUDED.total_cash_out,
|
||||
total_cash_back = EXCLUDED.total_cash_back,
|
||||
updated_at = EXCLUDED.updated_at;
|
||||
|
|
@ -56,26 +56,14 @@ SET sport_id = EXCLUDED.sport_id,
|
|||
source = EXCLUDED.source,
|
||||
default_winning_upper_limit = EXCLUDED.default_winning_upper_limit,
|
||||
fetched_at = now();
|
||||
-- name: SaveTenantEventSettings :exec
|
||||
INSERT INTO company_event_settings (
|
||||
company_id,
|
||||
event_id,
|
||||
is_active,
|
||||
is_featured,
|
||||
winning_upper_limit
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
|
||||
UPDATE
|
||||
SET is_active = EXCLUDED.is_active,
|
||||
is_featured = EXCLUDED.is_featured,
|
||||
winning_upper_limit = EXCLUDED.winning_upper_limit;
|
||||
-- name: ListLiveEvents :many
|
||||
SELECT id
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE is_live = true;
|
||||
-- TODO: Figure out how to make this code reusable. SQLC prohibits CTEs within multiple queries
|
||||
-- name: GetAllEvents :many
|
||||
SELECT *
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE (
|
||||
is_live = sqlc.narg('is_live')
|
||||
OR sqlc.narg('is_live') IS NULL
|
||||
|
|
@ -117,7 +105,7 @@ ORDER BY start_time ASC
|
|||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||
-- name: GetTotalEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE (
|
||||
is_live = sqlc.narg('is_live')
|
||||
OR sqlc.narg('is_live') IS NULL
|
||||
|
|
@ -155,164 +143,17 @@ WHERE (
|
|||
source = sqlc.narg('source')
|
||||
OR sqlc.narg('source') IS NULL
|
||||
);
|
||||
-- name: GetTotalCompanyEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
WHERE (
|
||||
is_live = sqlc.narg('is_live')
|
||||
OR sqlc.narg('is_live') IS NULL
|
||||
)
|
||||
AND (
|
||||
status = sqlc.narg('status')
|
||||
OR sqlc.narg('status') IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = sqlc.narg('sport_id')
|
||||
OR sqlc.narg('sport_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR league_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < sqlc.narg('last_start_time')
|
||||
OR sqlc.narg('last_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > sqlc.narg('first_start_time')
|
||||
OR sqlc.narg('first_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = sqlc.narg('country_code')
|
||||
OR sqlc.narg('country_code') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = sqlc.narg('is_featured')
|
||||
OR e.default_is_featured = sqlc.narg('is_featured')
|
||||
OR sqlc.narg('is_featured') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = sqlc.narg('is_active')
|
||||
OR e.default_is_active = sqlc.narg('is_active')
|
||||
OR sqlc.narg('is_active') IS NULL
|
||||
)
|
||||
AND (
|
||||
source = sqlc.narg('source')
|
||||
OR sqlc.narg('source') IS NULL
|
||||
);
|
||||
-- name: GetEventsWithSettings :many
|
||||
SELECT e.*,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE (
|
||||
is_live = sqlc.narg('is_live')
|
||||
OR sqlc.narg('is_live') IS NULL
|
||||
)
|
||||
AND (
|
||||
status = sqlc.narg('status')
|
||||
OR sqlc.narg('status') IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = sqlc.narg('sport_id')
|
||||
OR sqlc.narg('sport_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR league_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < sqlc.narg('last_start_time')
|
||||
OR sqlc.narg('last_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > sqlc.narg('first_start_time')
|
||||
OR sqlc.narg('first_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = sqlc.narg('country_code')
|
||||
OR sqlc.narg('country_code') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = sqlc.narg('is_featured')
|
||||
OR e.default_is_featured = sqlc.narg('is_featured')
|
||||
OR sqlc.narg('is_featured') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = sqlc.narg('is_active')
|
||||
OR e.default_is_active = sqlc.narg('is_active')
|
||||
OR sqlc.narg('is_active') IS NULL
|
||||
)
|
||||
AND (
|
||||
source = sqlc.narg('source')
|
||||
OR sqlc.narg('source') IS NULL
|
||||
)
|
||||
ORDER BY start_time ASC
|
||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||
|
||||
-- name: GetEventByID :one
|
||||
SELECT *
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE id = $1
|
||||
LIMIT 1;
|
||||
-- name: GetEventBySourceID :one
|
||||
SELECT *
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE source_event_id = $1
|
||||
AND source = $2;
|
||||
-- name: GetEventWithSettingByID :one
|
||||
SELECT e.*,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $2
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE e.id = $1
|
||||
LIMIT 1;
|
||||
-- name: GetSportAndLeagueIDs :one
|
||||
SELECT sport_id,
|
||||
league_id
|
||||
|
|
|
|||
28
db/query/events_bet_stats.sql
Normal file
28
db/query/events_bet_stats.sql
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
-- Aggregate bet stats per event
|
||||
-- name: UpdateEventBetStats :exec
|
||||
INSERT INTO event_bet_stats (
|
||||
event_id,
|
||||
number_of_bets,
|
||||
total_amount,
|
||||
avg_bet_amount,
|
||||
total_potential_winnings,
|
||||
updated_at
|
||||
)
|
||||
SELECT bo.event_id,
|
||||
COUNT(DISTINCT b.id) AS number_of_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_amount,
|
||||
COALESCE(AVG(b.amount), 0) AS avg_bet_amount,
|
||||
COALESCE(SUM(b.potential_win), 0) AS total_potential_winnings,
|
||||
NOW() AS updated_at
|
||||
FROM bet_outcomes bo
|
||||
JOIN bets b ON bo.bet_id = b.id
|
||||
GROUP BY bo.event_id ON CONFLICT (event_id) DO
|
||||
UPDATE
|
||||
SET number_of_bets = EXCLUDED.number_of_bets,
|
||||
total_amount = EXCLUDED.total_amount,
|
||||
avg_bet_amount = EXCLUDED.avg_bet_amount,
|
||||
total_potential_winnings = EXCLUDED.total_potential_winnings,
|
||||
updated_at = EXCLUDED.updated_at;
|
||||
|
||||
-- name: UpdateEventDetailedViewMat :exec
|
||||
REFRESH MATERIALIZED VIEW event_detailed_mat;
|
||||
|
|
@ -1,20 +1,17 @@
|
|||
-- name: GetTotalMontlyEventStat :many
|
||||
SELECT DATE_TRUNC('month', start_time) AS month,
|
||||
COUNT(*) AS event_count
|
||||
FROM events
|
||||
JOIN leagues ON leagues.id = events.league_id
|
||||
WHERE (
|
||||
events.league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
GROUP BY month
|
||||
ORDER BY month;
|
||||
-- name: GetLeagueEventStat :many
|
||||
SELECT leagues.id,
|
||||
leagues.name,
|
||||
COUNT(*) AS total_events,
|
||||
-- name: GetTotalEventStats :one
|
||||
SELECT COUNT(*) AS event_count,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'pending'
|
||||
WHERE events.default_is_active = TRUE
|
||||
) AS total_active_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_active = FALSE
|
||||
) AS total_inactive_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_featured = TRUE
|
||||
) AS total_featured_events,
|
||||
COUNT(DISTINCT league_id) as total_leagues,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'upcoming'
|
||||
) AS pending,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'in_play'
|
||||
|
|
@ -52,7 +49,75 @@ SELECT leagues.id,
|
|||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'removed'
|
||||
) AS removed
|
||||
FROM leagues
|
||||
JOIN events ON leagues.id = events.league_id
|
||||
GROUP BY leagues.id,
|
||||
leagues.name;
|
||||
FROM events
|
||||
WHERE (
|
||||
events.league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
events.sport_id = sqlc.narg('sport_id')
|
||||
OR sqlc.narg('sport_id') IS NULL
|
||||
);
|
||||
-- name: GetTotalEventStatsByInterval :many
|
||||
SELECT DATE_TRUNC(sqlc.narg('interval'), start_time)::timestamp AS date,
|
||||
COUNT(*) AS event_count,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_active = TRUE
|
||||
) AS total_active_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_active = FALSE
|
||||
) AS total_inactive_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_featured = TRUE
|
||||
) AS total_featured_events,
|
||||
COUNT(DISTINCT league_id) as total_leagues,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'upcoming'
|
||||
) 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 events
|
||||
WHERE (
|
||||
events.league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
events.sport_id = sqlc.narg('sport_id')
|
||||
OR sqlc.narg('sport_id') IS NULL
|
||||
)
|
||||
GROUP BY date
|
||||
ORDER BY date;
|
||||
171
db/query/events_with_settings.sql
Normal file
171
db/query/events_with_settings.sql
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
-- name: SaveTenantEventSettings :exec
|
||||
INSERT INTO company_event_settings (
|
||||
company_id,
|
||||
event_id,
|
||||
is_active,
|
||||
is_featured,
|
||||
winning_upper_limit
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
|
||||
UPDATE
|
||||
SET is_active = EXCLUDED.is_active,
|
||||
is_featured = EXCLUDED.is_featured,
|
||||
winning_upper_limit = EXCLUDED.winning_upper_limit;
|
||||
-- name: GetTotalCompanyEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
WHERE (
|
||||
is_live = sqlc.narg('is_live')
|
||||
OR sqlc.narg('is_live') IS NULL
|
||||
)
|
||||
AND (
|
||||
status = sqlc.narg('status')
|
||||
OR sqlc.narg('status') IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = sqlc.narg('sport_id')
|
||||
OR sqlc.narg('sport_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR league_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < sqlc.narg('last_start_time')
|
||||
OR sqlc.narg('last_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > sqlc.narg('first_start_time')
|
||||
OR sqlc.narg('first_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = sqlc.narg('country_code')
|
||||
OR sqlc.narg('country_code') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = sqlc.narg('is_featured')
|
||||
OR e.default_is_featured = sqlc.narg('is_featured')
|
||||
OR sqlc.narg('is_featured') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = sqlc.narg('is_active')
|
||||
OR e.default_is_active = sqlc.narg('is_active')
|
||||
OR sqlc.narg('is_active') IS NULL
|
||||
)
|
||||
AND (
|
||||
source = sqlc.narg('source')
|
||||
OR sqlc.narg('source') IS NULL
|
||||
);
|
||||
-- name: GetEventsWithSettings :many
|
||||
SELECT e.*,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes,
|
||||
COALESCE(ebs.number_of_bets, 0) AS number_of_bets,
|
||||
COALESCE(ebs.total_amount, 0) AS total_amount,
|
||||
COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount,
|
||||
COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE (
|
||||
is_live = sqlc.narg('is_live')
|
||||
OR sqlc.narg('is_live') IS NULL
|
||||
)
|
||||
AND (
|
||||
status = sqlc.narg('status')
|
||||
OR sqlc.narg('status') IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = sqlc.narg('league_id')
|
||||
OR sqlc.narg('league_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = sqlc.narg('sport_id')
|
||||
OR sqlc.narg('sport_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR league_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < sqlc.narg('last_start_time')
|
||||
OR sqlc.narg('last_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > sqlc.narg('first_start_time')
|
||||
OR sqlc.narg('first_start_time') IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = sqlc.narg('country_code')
|
||||
OR sqlc.narg('country_code') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = sqlc.narg('is_featured')
|
||||
OR e.default_is_featured = sqlc.narg('is_featured')
|
||||
OR sqlc.narg('is_featured') IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = sqlc.narg('is_active')
|
||||
OR e.default_is_active = sqlc.narg('is_active')
|
||||
OR sqlc.narg('is_active') IS NULL
|
||||
)
|
||||
AND (
|
||||
source = sqlc.narg('source')
|
||||
OR sqlc.narg('source') IS NULL
|
||||
)
|
||||
ORDER BY start_time ASC
|
||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||
-- name: GetEventWithSettingByID :one
|
||||
SELECT e.*,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes,
|
||||
COALESCE(ebs.number_of_bets, 0) AS number_of_bets,
|
||||
COALESCE(ebs.total_amount, 0) AS total_amount,
|
||||
COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount,
|
||||
COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings
|
||||
FROM events e
|
||||
LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id
|
||||
AND ces.company_id = $2
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE e.id = $1
|
||||
LIMIT 1;
|
||||
47
db/query/league_stats.sql
Normal file
47
db/query/league_stats.sql
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
-- name: GetLeagueEventStat :many
|
||||
SELECT leagues.id,
|
||||
leagues.name,
|
||||
COUNT(*) AS total_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'upcoming'
|
||||
) 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
|
||||
GROUP BY leagues.id,
|
||||
leagues.name;
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
-- name: GetCompanyWiseReport :many
|
||||
SELECT
|
||||
b.company_id,
|
||||
c.name AS company_name,
|
||||
COUNT(*) AS total_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_cash_made,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN sb.cashed_out THEN b.amount -- use actual cashed_out flag from shop_bets
|
||||
ELSE 0
|
||||
END
|
||||
), 0
|
||||
) AS total_cash_out,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.status = 5 THEN b.amount
|
||||
ELSE 0
|
||||
END
|
||||
), 0
|
||||
) AS total_cash_backs
|
||||
FROM shop_bet_detail b
|
||||
JOIN companies c ON b.company_id = c.id
|
||||
JOIN shop_bets sb ON sb.id = b.id -- join to get cashed_out
|
||||
WHERE b.created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to')
|
||||
GROUP BY b.company_id, c.name;
|
||||
|
||||
-- name: GetBranchWiseReport :many
|
||||
SELECT
|
||||
b.branch_id,
|
||||
br.name AS branch_name,
|
||||
br.company_id,
|
||||
COUNT(*) AS total_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_cash_made,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN sb.cashed_out THEN b.amount -- use cashed_out from shop_bets
|
||||
ELSE 0
|
||||
END
|
||||
), 0
|
||||
) AS total_cash_out,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.status = 5 THEN b.amount
|
||||
ELSE 0
|
||||
END
|
||||
), 0
|
||||
) AS total_cash_backs
|
||||
FROM shop_bet_detail b
|
||||
JOIN branches br ON b.branch_id = br.id
|
||||
JOIN shop_bets sb ON sb.id = b.id -- join to get cashed_out
|
||||
WHERE b.created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to')
|
||||
GROUP BY b.branch_id, br.name, br.company_id;
|
||||
|
|
@ -2,6 +2,7 @@ version: "3.8"
|
|||
|
||||
services:
|
||||
postgres:
|
||||
container_name: fortunebet-backend-postgres-1
|
||||
image: postgres:16-alpine
|
||||
ports:
|
||||
- 5422:5432
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ INSERT INTO bets (
|
|||
company_id
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at
|
||||
RETURNING id, company_id, amount, total_odds, potential_win, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateBetParams struct {
|
||||
|
|
@ -70,6 +70,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro
|
|||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TotalOdds,
|
||||
&i.PotentialWin,
|
||||
&i.Status,
|
||||
&i.UserID,
|
||||
&i.IsShopBet,
|
||||
|
|
@ -120,7 +121,7 @@ func (q *Queries) DeleteBetOutcome(ctx context.Context, betID int64) error {
|
|||
}
|
||||
|
||||
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, company_slug
|
||||
SELECT id, company_id, amount, total_odds, potential_win, 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
|
||||
wHERE (
|
||||
user_id = $1
|
||||
|
|
@ -196,6 +197,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
|
|||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TotalOdds,
|
||||
&i.PotentialWin,
|
||||
&i.Status,
|
||||
&i.UserID,
|
||||
&i.IsShopBet,
|
||||
|
|
@ -221,7 +223,7 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
|
|||
}
|
||||
|
||||
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, company_slug
|
||||
SELECT id, company_id, amount, total_odds, potential_win, 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
|
||||
WHERE fast_code = $1
|
||||
LIMIT 1
|
||||
|
|
@ -235,6 +237,7 @@ func (q *Queries) GetBetByFastCode(ctx context.Context, fastCode string) (BetWit
|
|||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TotalOdds,
|
||||
&i.PotentialWin,
|
||||
&i.Status,
|
||||
&i.UserID,
|
||||
&i.IsShopBet,
|
||||
|
|
@ -253,7 +256,7 @@ func (q *Queries) GetBetByFastCode(ctx context.Context, fastCode string) (BetWit
|
|||
}
|
||||
|
||||
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, company_slug
|
||||
SELECT id, company_id, amount, total_odds, potential_win, 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
|
||||
WHERE id = $1
|
||||
`
|
||||
|
|
@ -266,6 +269,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err
|
|||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TotalOdds,
|
||||
&i.PotentialWin,
|
||||
&i.Status,
|
||||
&i.UserID,
|
||||
&i.IsShopBet,
|
||||
|
|
@ -284,7 +288,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err
|
|||
}
|
||||
|
||||
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, company_slug
|
||||
SELECT id, company_id, amount, total_odds, potential_win, 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
|
||||
WHERE user_id = $1
|
||||
`
|
||||
|
|
@ -303,6 +307,7 @@ func (q *Queries) GetBetByUserID(ctx context.Context, userID int64) ([]BetWithOu
|
|||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TotalOdds,
|
||||
&i.PotentialWin,
|
||||
&i.Status,
|
||||
&i.UserID,
|
||||
&i.IsShopBet,
|
||||
|
|
@ -570,7 +575,7 @@ func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutc
|
|||
}
|
||||
|
||||
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, company_slug
|
||||
SELECT id, company_id, amount, total_odds, potential_win, 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
|
||||
WHERE status = 2
|
||||
AND processed = false
|
||||
|
|
@ -590,6 +595,7 @@ func (q *Queries) GetBetsForCashback(ctx context.Context) ([]BetWithOutcome, err
|
|||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TotalOdds,
|
||||
&i.PotentialWin,
|
||||
&i.Status,
|
||||
&i.UserID,
|
||||
&i.IsShopBet,
|
||||
|
|
|
|||
88
gen/db/branch_stats.sql.go
Normal file
88
gen/db/branch_stats.sql.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: branch_stats.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const GetBranchStats = `-- name: GetBranchStats :many
|
||||
SELECT b.branch_id,
|
||||
br.name AS branch_name,
|
||||
br.company_id,
|
||||
COUNT(*) AS total_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_cash_made,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN sb.cashed_out THEN b.amount -- use cashed_out from shop_bets
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_out,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.status = 5 THEN b.amount
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_backs
|
||||
FROM shop_bet_detail b
|
||||
JOIN branches br ON b.branch_id = br.id
|
||||
JOIN shop_bets sb ON sb.id = b.id -- join to get cashed_out
|
||||
WHERE b.created_at BETWEEN $1 AND $2
|
||||
GROUP BY b.branch_id,
|
||||
br.name,
|
||||
br.company_id
|
||||
`
|
||||
|
||||
type GetBranchStatsParams struct {
|
||||
From pgtype.Timestamp `json:"from"`
|
||||
To pgtype.Timestamp `json:"to"`
|
||||
}
|
||||
|
||||
type GetBranchStatsRow struct {
|
||||
BranchID int64 `json:"branch_id"`
|
||||
BranchName string `json:"branch_name"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
TotalBets int64 `json:"total_bets"`
|
||||
TotalCashMade interface{} `json:"total_cash_made"`
|
||||
TotalCashOut interface{} `json:"total_cash_out"`
|
||||
TotalCashBacks interface{} `json:"total_cash_backs"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetBranchStats(ctx context.Context, arg GetBranchStatsParams) ([]GetBranchStatsRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetBranchStats, arg.From, arg.To)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetBranchStatsRow
|
||||
for rows.Next() {
|
||||
var i GetBranchStatsRow
|
||||
if err := rows.Scan(
|
||||
&i.BranchID,
|
||||
&i.BranchName,
|
||||
&i.CompanyID,
|
||||
&i.TotalBets,
|
||||
&i.TotalCashMade,
|
||||
&i.TotalCashOut,
|
||||
&i.TotalCashBacks,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
59
gen/db/company_stats.sql.go
Normal file
59
gen/db/company_stats.sql.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: company_stats.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const UpdateCompanyStats = `-- name: UpdateCompanyStats :exec
|
||||
INSERT INTO company_stats (
|
||||
company_id,
|
||||
total_bets,
|
||||
total_cash_made,
|
||||
total_cash_backs,
|
||||
updated_at
|
||||
)
|
||||
SELECT b.company_id,
|
||||
COUNT(*) AS total_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_cash_made,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN sb.cashed_out THEN b.amount -- use actual cashed_out flag from shop_bets
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_out,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.status = 5 THEN b.amount
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS total_cash_backs,
|
||||
NOW() AS updated_at
|
||||
FROM shop_bet_detail b
|
||||
JOIN companies c ON b.company_id = c.id
|
||||
JOIN shop_bets sb ON sb.id = b.id -- join to get cashed_out
|
||||
GROUP BY b.company_id,
|
||||
c.name ON CONFLICT (company_id) DO
|
||||
UPDATE
|
||||
SET total_bets = EXCLUDED.total_bets,
|
||||
total_cash_made = EXCLUDED.total_cash_made,
|
||||
total_cash_out = EXCLUDED.total_cash_out,
|
||||
total_cash_back = EXCLUDED.total_cash_back,
|
||||
updated_at = EXCLUDED.updated_at
|
||||
`
|
||||
|
||||
// Aggregate company stats
|
||||
func (q *Queries) UpdateCompanyStats(ctx context.Context) error {
|
||||
_, err := q.db.Exec(ctx, UpdateCompanyStats)
|
||||
return err
|
||||
}
|
||||
|
|
@ -22,8 +22,8 @@ func (q *Queries) DeleteEvent(ctx context.Context, id int64) error {
|
|||
}
|
||||
|
||||
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, updated_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc, total_outcomes
|
||||
FROM event_with_country
|
||||
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, total_outcomes, number_of_bets, total_amount, avg_bet_amount, total_potential_winnings
|
||||
FROM event_detailed
|
||||
WHERE (
|
||||
is_live = $1
|
||||
OR $1 IS NULL
|
||||
|
|
@ -79,7 +79,8 @@ type GetAllEventsParams struct {
|
|||
Limit pgtype.Int4 `json:"limit"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]EventWithCountry, error) {
|
||||
// TODO: Figure out how to make this code reusable. SQLC prohibits CTEs within multiple queries
|
||||
func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]EventDetailed, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllEvents,
|
||||
arg.IsLive,
|
||||
arg.Status,
|
||||
|
|
@ -97,9 +98,9 @@ func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]E
|
|||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []EventWithCountry
|
||||
var items []EventDetailed
|
||||
for rows.Next() {
|
||||
var i EventWithCountry
|
||||
var i EventDetailed
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
|
|
@ -130,6 +131,10 @@ func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]E
|
|||
&i.IsMonitored,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
&i.NumberOfBets,
|
||||
&i.TotalAmount,
|
||||
&i.AvgBetAmount,
|
||||
&i.TotalPotentialWinnings,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -142,15 +147,15 @@ func (q *Queries) GetAllEvents(ctx context.Context, arg GetAllEventsParams) ([]E
|
|||
}
|
||||
|
||||
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, updated_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc, total_outcomes
|
||||
FROM event_with_country
|
||||
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, total_outcomes, number_of_bets, total_amount, avg_bet_amount, total_potential_winnings
|
||||
FROM event_detailed
|
||||
WHERE id = $1
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) GetEventByID(ctx context.Context, id int64) (EventWithCountry, error) {
|
||||
func (q *Queries) GetEventByID(ctx context.Context, id int64) (EventDetailed, error) {
|
||||
row := q.db.QueryRow(ctx, GetEventByID, id)
|
||||
var i EventWithCountry
|
||||
var i EventDetailed
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
|
|
@ -181,13 +186,17 @@ func (q *Queries) GetEventByID(ctx context.Context, id int64) (EventWithCountry,
|
|||
&i.IsMonitored,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
&i.NumberOfBets,
|
||||
&i.TotalAmount,
|
||||
&i.AvgBetAmount,
|
||||
&i.TotalPotentialWinnings,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
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, updated_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, league_cc, total_outcomes
|
||||
FROM event_with_country
|
||||
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, total_outcomes, number_of_bets, total_amount, avg_bet_amount, total_potential_winnings
|
||||
FROM event_detailed
|
||||
WHERE source_event_id = $1
|
||||
AND source = $2
|
||||
`
|
||||
|
|
@ -197,9 +206,9 @@ type GetEventBySourceIDParams struct {
|
|||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetEventBySourceID(ctx context.Context, arg GetEventBySourceIDParams) (EventWithCountry, error) {
|
||||
func (q *Queries) GetEventBySourceID(ctx context.Context, arg GetEventBySourceIDParams) (EventDetailed, error) {
|
||||
row := q.db.QueryRow(ctx, GetEventBySourceID, arg.SourceEventID, arg.Source)
|
||||
var i EventWithCountry
|
||||
var i EventDetailed
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
|
|
@ -230,317 +239,14 @@ func (q *Queries) GetEventBySourceID(ctx context.Context, arg GetEventBySourceID
|
|||
&i.IsMonitored,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
&i.NumberOfBets,
|
||||
&i.TotalAmount,
|
||||
&i.AvgBetAmount,
|
||||
&i.TotalPotentialWinnings,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
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.updated_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $2
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE e.id = $1
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
type GetEventWithSettingByIDParams struct {
|
||||
ID int64 `json:"id"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
}
|
||||
|
||||
type GetEventWithSettingByIDRow struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeKitImage string `json:"home_kit_image"`
|
||||
AwayKitImage string `json:"away_kit_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
Score pgtype.Text `json:"score"`
|
||||
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||
TimerStatus pgtype.Text `json:"timer_status"`
|
||||
AddedTime pgtype.Int4 `json:"added_time"`
|
||||
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||
IsLive bool `json:"is_live"`
|
||||
Status string `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
Source string `json:"source"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||
UpdatedAt_2 pgtype.Timestamp `json:"updated_at_2"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithSettingByIDParams) (GetEventWithSettingByIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetEventWithSettingByID, arg.ID, arg.CompanyID)
|
||||
var i GetEventWithSettingByIDRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
&i.SportID,
|
||||
&i.MatchName,
|
||||
&i.HomeTeam,
|
||||
&i.AwayTeam,
|
||||
&i.HomeTeamID,
|
||||
&i.AwayTeamID,
|
||||
&i.HomeKitImage,
|
||||
&i.AwayKitImage,
|
||||
&i.LeagueID,
|
||||
&i.LeagueName,
|
||||
&i.StartTime,
|
||||
&i.Score,
|
||||
&i.MatchMinute,
|
||||
&i.TimerStatus,
|
||||
&i.AddedTime,
|
||||
&i.MatchPeriod,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.FetchedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Source,
|
||||
&i.DefaultIsActive,
|
||||
&i.DefaultIsFeatured,
|
||||
&i.DefaultWinningUpperLimit,
|
||||
&i.IsMonitored,
|
||||
&i.CompanyID,
|
||||
&i.IsActive,
|
||||
&i.IsFeatured,
|
||||
&i.WinningUpperLimit,
|
||||
&i.UpdatedAt_2,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
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.updated_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE (
|
||||
is_live = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
status = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || $6 || '%'
|
||||
OR league_name ILIKE '%' || $6 || '%'
|
||||
OR $6 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < $7
|
||||
OR $7 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > $8
|
||||
OR $8 IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = $9
|
||||
OR $9 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = $10
|
||||
OR e.default_is_featured = $10
|
||||
OR $10 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = $11
|
||||
OR e.default_is_active = $11
|
||||
OR $11 IS NULL
|
||||
)
|
||||
AND (
|
||||
source = $12
|
||||
OR $12 IS NULL
|
||||
)
|
||||
ORDER BY start_time ASC
|
||||
LIMIT $14 OFFSET $13
|
||||
`
|
||||
|
||||
type GetEventsWithSettingsParams struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
LeagueID pgtype.Int8 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
Query pgtype.Text `json:"query"`
|
||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
Offset pgtype.Int4 `json:"offset"`
|
||||
Limit pgtype.Int4 `json:"limit"`
|
||||
}
|
||||
|
||||
type GetEventsWithSettingsRow struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeKitImage string `json:"home_kit_image"`
|
||||
AwayKitImage string `json:"away_kit_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
Score pgtype.Text `json:"score"`
|
||||
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||
TimerStatus pgtype.Text `json:"timer_status"`
|
||||
AddedTime pgtype.Int4 `json:"added_time"`
|
||||
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||
IsLive bool `json:"is_live"`
|
||||
Status string `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
Source string `json:"source"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||
UpdatedAt_2 pgtype.Timestamp `json:"updated_at_2"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSettingsParams) ([]GetEventsWithSettingsRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetEventsWithSettings,
|
||||
arg.CompanyID,
|
||||
arg.IsLive,
|
||||
arg.Status,
|
||||
arg.LeagueID,
|
||||
arg.SportID,
|
||||
arg.Query,
|
||||
arg.LastStartTime,
|
||||
arg.FirstStartTime,
|
||||
arg.CountryCode,
|
||||
arg.IsFeatured,
|
||||
arg.IsActive,
|
||||
arg.Source,
|
||||
arg.Offset,
|
||||
arg.Limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetEventsWithSettingsRow
|
||||
for rows.Next() {
|
||||
var i GetEventsWithSettingsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
&i.SportID,
|
||||
&i.MatchName,
|
||||
&i.HomeTeam,
|
||||
&i.AwayTeam,
|
||||
&i.HomeTeamID,
|
||||
&i.AwayTeamID,
|
||||
&i.HomeKitImage,
|
||||
&i.AwayKitImage,
|
||||
&i.LeagueID,
|
||||
&i.LeagueName,
|
||||
&i.StartTime,
|
||||
&i.Score,
|
||||
&i.MatchMinute,
|
||||
&i.TimerStatus,
|
||||
&i.AddedTime,
|
||||
&i.MatchPeriod,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.FetchedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Source,
|
||||
&i.DefaultIsActive,
|
||||
&i.DefaultIsFeatured,
|
||||
&i.DefaultWinningUpperLimit,
|
||||
&i.IsMonitored,
|
||||
&i.CompanyID,
|
||||
&i.IsActive,
|
||||
&i.IsFeatured,
|
||||
&i.WinningUpperLimit,
|
||||
&i.UpdatedAt_2,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetSportAndLeagueIDs = `-- name: GetSportAndLeagueIDs :one
|
||||
SELECT sport_id,
|
||||
league_id
|
||||
|
|
@ -560,99 +266,9 @@ func (q *Queries) GetSportAndLeagueIDs(ctx context.Context, id int64) (GetSportA
|
|||
return i, err
|
||||
}
|
||||
|
||||
const GetTotalCompanyEvents = `-- name: GetTotalCompanyEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
WHERE (
|
||||
is_live = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
status = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || $6 || '%'
|
||||
OR league_name ILIKE '%' || $6 || '%'
|
||||
OR $6 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < $7
|
||||
OR $7 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > $8
|
||||
OR $8 IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = $9
|
||||
OR $9 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = $10
|
||||
OR e.default_is_featured = $10
|
||||
OR $10 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = $11
|
||||
OR e.default_is_active = $11
|
||||
OR $11 IS NULL
|
||||
)
|
||||
AND (
|
||||
source = $12
|
||||
OR $12 IS NULL
|
||||
)
|
||||
`
|
||||
|
||||
type GetTotalCompanyEventsParams struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
LeagueID pgtype.Int8 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
Query pgtype.Text `json:"query"`
|
||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTotalCompanyEvents(ctx context.Context, arg GetTotalCompanyEventsParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, GetTotalCompanyEvents,
|
||||
arg.CompanyID,
|
||||
arg.IsLive,
|
||||
arg.Status,
|
||||
arg.LeagueID,
|
||||
arg.SportID,
|
||||
arg.Query,
|
||||
arg.LastStartTime,
|
||||
arg.FirstStartTime,
|
||||
arg.CountryCode,
|
||||
arg.IsFeatured,
|
||||
arg.IsActive,
|
||||
arg.Source,
|
||||
)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const GetTotalEvents = `-- name: GetTotalEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE (
|
||||
is_live = $1
|
||||
OR $1 IS NULL
|
||||
|
|
@ -837,7 +453,7 @@ func (q *Queries) IsEventMonitored(ctx context.Context, id int64) (bool, error)
|
|||
|
||||
const ListLiveEvents = `-- name: ListLiveEvents :many
|
||||
SELECT id
|
||||
FROM event_with_country
|
||||
FROM event_detailed
|
||||
WHERE is_live = true
|
||||
`
|
||||
|
||||
|
|
@ -861,40 +477,6 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]int64, error) {
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const SaveTenantEventSettings = `-- name: SaveTenantEventSettings :exec
|
||||
INSERT INTO company_event_settings (
|
||||
company_id,
|
||||
event_id,
|
||||
is_active,
|
||||
is_featured,
|
||||
winning_upper_limit
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
|
||||
UPDATE
|
||||
SET is_active = EXCLUDED.is_active,
|
||||
is_featured = EXCLUDED.is_featured,
|
||||
winning_upper_limit = EXCLUDED.winning_upper_limit
|
||||
`
|
||||
|
||||
type SaveTenantEventSettingsParams struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
EventID int64 `json:"event_id"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||
WinningUpperLimit pgtype.Int8 `json:"winning_upper_limit"`
|
||||
}
|
||||
|
||||
func (q *Queries) SaveTenantEventSettings(ctx context.Context, arg SaveTenantEventSettingsParams) error {
|
||||
_, err := q.db.Exec(ctx, SaveTenantEventSettings,
|
||||
arg.CompanyID,
|
||||
arg.EventID,
|
||||
arg.IsActive,
|
||||
arg.IsFeatured,
|
||||
arg.WinningUpperLimit,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec
|
||||
UPDATE events
|
||||
SET is_monitored = $1,
|
||||
|
|
|
|||
51
gen/db/events_bet_stats.sql.go
Normal file
51
gen/db/events_bet_stats.sql.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: events_bet_stats.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const UpdateEventBetStats = `-- name: UpdateEventBetStats :exec
|
||||
INSERT INTO event_bet_stats (
|
||||
event_id,
|
||||
number_of_bets,
|
||||
total_amount,
|
||||
avg_bet_amount,
|
||||
total_potential_winnings,
|
||||
updated_at
|
||||
)
|
||||
SELECT bo.event_id,
|
||||
COUNT(DISTINCT b.id) AS number_of_bets,
|
||||
COALESCE(SUM(b.amount), 0) AS total_amount,
|
||||
COALESCE(AVG(b.amount), 0) AS avg_bet_amount,
|
||||
COALESCE(SUM(b.potential_win), 0) AS total_potential_winnings,
|
||||
NOW() AS updated_at
|
||||
FROM bet_outcomes bo
|
||||
JOIN bets b ON bo.bet_id = b.id
|
||||
GROUP BY bo.event_id ON CONFLICT (event_id) DO
|
||||
UPDATE
|
||||
SET number_of_bets = EXCLUDED.number_of_bets,
|
||||
total_amount = EXCLUDED.total_amount,
|
||||
avg_bet_amount = EXCLUDED.avg_bet_amount,
|
||||
total_potential_winnings = EXCLUDED.total_potential_winnings,
|
||||
updated_at = EXCLUDED.updated_at
|
||||
`
|
||||
|
||||
// Aggregate bet stats per event
|
||||
func (q *Queries) UpdateEventBetStats(ctx context.Context) error {
|
||||
_, err := q.db.Exec(ctx, UpdateEventBetStats)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateEventDetailedViewMat = `-- name: UpdateEventDetailedViewMat :exec
|
||||
REFRESH MATERIALIZED VIEW event_detailed_mat
|
||||
`
|
||||
|
||||
func (q *Queries) UpdateEventDetailedViewMat(ctx context.Context) error {
|
||||
_, err := q.db.Exec(ctx, UpdateEventDetailedViewMat)
|
||||
return err
|
||||
}
|
||||
|
|
@ -11,12 +11,20 @@ import (
|
|||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const GetLeagueEventStat = `-- name: GetLeagueEventStat :many
|
||||
SELECT leagues.id,
|
||||
leagues.name,
|
||||
COUNT(*) AS total_events,
|
||||
const GetTotalEventStats = `-- name: GetTotalEventStats :one
|
||||
SELECT COUNT(*) AS event_count,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'pending'
|
||||
WHERE events.default_is_active = TRUE
|
||||
) AS total_active_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_active = FALSE
|
||||
) AS total_inactive_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_featured = TRUE
|
||||
) AS total_featured_events,
|
||||
COUNT(DISTINCT league_id) as total_leagues,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'upcoming'
|
||||
) AS pending,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'in_play'
|
||||
|
|
@ -54,44 +62,178 @@ SELECT leagues.id,
|
|||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'removed'
|
||||
) AS removed
|
||||
FROM leagues
|
||||
JOIN events ON leagues.id = events.league_id
|
||||
GROUP BY leagues.id,
|
||||
leagues.name
|
||||
FROM events
|
||||
WHERE (
|
||||
events.league_id = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
events.sport_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
`
|
||||
|
||||
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"`
|
||||
type GetTotalEventStatsParams struct {
|
||||
LeagueID pgtype.Int8 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetLeagueEventStat(ctx context.Context) ([]GetLeagueEventStatRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetLeagueEventStat)
|
||||
type GetTotalEventStatsRow struct {
|
||||
EventCount int64 `json:"event_count"`
|
||||
TotalActiveEvents int64 `json:"total_active_events"`
|
||||
TotalInactiveEvents int64 `json:"total_inactive_events"`
|
||||
TotalFeaturedEvents int64 `json:"total_featured_events"`
|
||||
TotalLeagues int64 `json:"total_leagues"`
|
||||
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) GetTotalEventStats(ctx context.Context, arg GetTotalEventStatsParams) (GetTotalEventStatsRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetTotalEventStats, arg.LeagueID, arg.SportID)
|
||||
var i GetTotalEventStatsRow
|
||||
err := row.Scan(
|
||||
&i.EventCount,
|
||||
&i.TotalActiveEvents,
|
||||
&i.TotalInactiveEvents,
|
||||
&i.TotalFeaturedEvents,
|
||||
&i.TotalLeagues,
|
||||
&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,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetTotalEventStatsByInterval = `-- name: GetTotalEventStatsByInterval :many
|
||||
SELECT DATE_TRUNC($1, start_time)::timestamp AS date,
|
||||
COUNT(*) AS event_count,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_active = TRUE
|
||||
) AS total_active_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_active = FALSE
|
||||
) AS total_inactive_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.default_is_featured = TRUE
|
||||
) AS total_featured_events,
|
||||
COUNT(DISTINCT league_id) as total_leagues,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'upcoming'
|
||||
) 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 events
|
||||
WHERE (
|
||||
events.league_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
events.sport_id = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
GROUP BY date
|
||||
ORDER BY date
|
||||
`
|
||||
|
||||
type GetTotalEventStatsByIntervalParams struct {
|
||||
Interval pgtype.Text `json:"interval"`
|
||||
LeagueID pgtype.Int8 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
}
|
||||
|
||||
type GetTotalEventStatsByIntervalRow struct {
|
||||
Date pgtype.Timestamp `json:"date"`
|
||||
EventCount int64 `json:"event_count"`
|
||||
TotalActiveEvents int64 `json:"total_active_events"`
|
||||
TotalInactiveEvents int64 `json:"total_inactive_events"`
|
||||
TotalFeaturedEvents int64 `json:"total_featured_events"`
|
||||
TotalLeagues int64 `json:"total_leagues"`
|
||||
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) GetTotalEventStatsByInterval(ctx context.Context, arg GetTotalEventStatsByIntervalParams) ([]GetTotalEventStatsByIntervalRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetTotalEventStatsByInterval, arg.Interval, arg.LeagueID, arg.SportID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetLeagueEventStatRow
|
||||
var items []GetTotalEventStatsByIntervalRow
|
||||
for rows.Next() {
|
||||
var i GetLeagueEventStatRow
|
||||
var i GetTotalEventStatsByIntervalRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.TotalEvents,
|
||||
&i.Date,
|
||||
&i.EventCount,
|
||||
&i.TotalActiveEvents,
|
||||
&i.TotalInactiveEvents,
|
||||
&i.TotalFeaturedEvents,
|
||||
&i.TotalLeagues,
|
||||
&i.Pending,
|
||||
&i.InPlay,
|
||||
&i.ToBeFixed,
|
||||
|
|
@ -115,41 +257,3 @@ func (q *Queries) GetLeagueEventStat(ctx context.Context) ([]GetLeagueEventStatR
|
|||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetTotalMontlyEventStat = `-- name: GetTotalMontlyEventStat :many
|
||||
SELECT DATE_TRUNC('month', start_time) AS month,
|
||||
COUNT(*) AS event_count
|
||||
FROM events
|
||||
JOIN leagues ON leagues.id = events.league_id
|
||||
WHERE (
|
||||
events.league_id = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
GROUP BY month
|
||||
ORDER BY month
|
||||
`
|
||||
|
||||
type GetTotalMontlyEventStatRow struct {
|
||||
Month pgtype.Interval `json:"month"`
|
||||
EventCount int64 `json:"event_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTotalMontlyEventStat(ctx context.Context, leagueID pgtype.Int8) ([]GetTotalMontlyEventStatRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetTotalMontlyEventStat, leagueID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetTotalMontlyEventStatRow
|
||||
for rows.Next() {
|
||||
var i GetTotalMontlyEventStatRow
|
||||
if err := rows.Scan(&i.Month, &i.EventCount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
|
|
|||
469
gen/db/events_with_settings.sql.go
Normal file
469
gen/db/events_with_settings.sql.go
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: events_with_settings.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
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.updated_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes,
|
||||
COALESCE(ebs.number_of_bets, 0) AS number_of_bets,
|
||||
COALESCE(ebs.total_amount, 0) AS total_amount,
|
||||
COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount,
|
||||
COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings
|
||||
FROM events e
|
||||
LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id
|
||||
AND ces.company_id = $2
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE e.id = $1
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
type GetEventWithSettingByIDParams struct {
|
||||
ID int64 `json:"id"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
}
|
||||
|
||||
type GetEventWithSettingByIDRow struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeKitImage string `json:"home_kit_image"`
|
||||
AwayKitImage string `json:"away_kit_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
Score pgtype.Text `json:"score"`
|
||||
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||
TimerStatus pgtype.Text `json:"timer_status"`
|
||||
AddedTime pgtype.Int4 `json:"added_time"`
|
||||
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||
IsLive bool `json:"is_live"`
|
||||
Status string `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
Source string `json:"source"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||
UpdatedAt_2 pgtype.Timestamp `json:"updated_at_2"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount int64 `json:"total_amount"`
|
||||
AvgBetAmount float64 `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings int64 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithSettingByIDParams) (GetEventWithSettingByIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetEventWithSettingByID, arg.ID, arg.CompanyID)
|
||||
var i GetEventWithSettingByIDRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
&i.SportID,
|
||||
&i.MatchName,
|
||||
&i.HomeTeam,
|
||||
&i.AwayTeam,
|
||||
&i.HomeTeamID,
|
||||
&i.AwayTeamID,
|
||||
&i.HomeKitImage,
|
||||
&i.AwayKitImage,
|
||||
&i.LeagueID,
|
||||
&i.LeagueName,
|
||||
&i.StartTime,
|
||||
&i.Score,
|
||||
&i.MatchMinute,
|
||||
&i.TimerStatus,
|
||||
&i.AddedTime,
|
||||
&i.MatchPeriod,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.FetchedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Source,
|
||||
&i.DefaultIsActive,
|
||||
&i.DefaultIsFeatured,
|
||||
&i.DefaultWinningUpperLimit,
|
||||
&i.IsMonitored,
|
||||
&i.CompanyID,
|
||||
&i.IsActive,
|
||||
&i.IsFeatured,
|
||||
&i.WinningUpperLimit,
|
||||
&i.UpdatedAt_2,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
&i.NumberOfBets,
|
||||
&i.TotalAmount,
|
||||
&i.AvgBetAmount,
|
||||
&i.TotalPotentialWinnings,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
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.updated_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
|
||||
ces.company_id,
|
||||
COALESCE(ces.is_active, e.default_is_active) AS is_active,
|
||||
COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
|
||||
COALESCE(
|
||||
ces.winning_upper_limit,
|
||||
e.default_winning_upper_limit
|
||||
) AS winning_upper_limit,
|
||||
ces.updated_at,
|
||||
l.country_code as league_cc,
|
||||
COALESCE(om.total_outcomes, 0) AS total_outcomes,
|
||||
COALESCE(ebs.number_of_bets, 0) AS number_of_bets,
|
||||
COALESCE(ebs.total_amount, 0) AS total_amount,
|
||||
COALESCE(ebs.avg_bet_amount, 0) AS avg_bet_amount,
|
||||
COALESCE(ebs.total_potential_winnings, 0) AS total_potential_winnings
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
LEFT JOIN event_bet_stats ebs ON ebs.event_id = ewc.id
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
LEFT JOIN (
|
||||
SELECT event_id,
|
||||
SUM(number_of_outcomes) AS total_outcomes
|
||||
FROM odds_market
|
||||
GROUP BY event_id
|
||||
) om ON om.event_id = e.id
|
||||
WHERE (
|
||||
is_live = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
status = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || $6 || '%'
|
||||
OR league_name ILIKE '%' || $6 || '%'
|
||||
OR $6 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < $7
|
||||
OR $7 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > $8
|
||||
OR $8 IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = $9
|
||||
OR $9 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = $10
|
||||
OR e.default_is_featured = $10
|
||||
OR $10 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = $11
|
||||
OR e.default_is_active = $11
|
||||
OR $11 IS NULL
|
||||
)
|
||||
AND (
|
||||
source = $12
|
||||
OR $12 IS NULL
|
||||
)
|
||||
ORDER BY start_time ASC
|
||||
LIMIT $14 OFFSET $13
|
||||
`
|
||||
|
||||
type GetEventsWithSettingsParams struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
LeagueID pgtype.Int8 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
Query pgtype.Text `json:"query"`
|
||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
Offset pgtype.Int4 `json:"offset"`
|
||||
Limit pgtype.Int4 `json:"limit"`
|
||||
}
|
||||
|
||||
type GetEventsWithSettingsRow struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeKitImage string `json:"home_kit_image"`
|
||||
AwayKitImage string `json:"away_kit_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
Score pgtype.Text `json:"score"`
|
||||
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||
TimerStatus pgtype.Text `json:"timer_status"`
|
||||
AddedTime pgtype.Int4 `json:"added_time"`
|
||||
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||
IsLive bool `json:"is_live"`
|
||||
Status string `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
Source string `json:"source"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||
UpdatedAt_2 pgtype.Timestamp `json:"updated_at_2"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount int64 `json:"total_amount"`
|
||||
AvgBetAmount float64 `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings int64 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSettingsParams) ([]GetEventsWithSettingsRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetEventsWithSettings,
|
||||
arg.CompanyID,
|
||||
arg.IsLive,
|
||||
arg.Status,
|
||||
arg.LeagueID,
|
||||
arg.SportID,
|
||||
arg.Query,
|
||||
arg.LastStartTime,
|
||||
arg.FirstStartTime,
|
||||
arg.CountryCode,
|
||||
arg.IsFeatured,
|
||||
arg.IsActive,
|
||||
arg.Source,
|
||||
arg.Offset,
|
||||
arg.Limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetEventsWithSettingsRow
|
||||
for rows.Next() {
|
||||
var i GetEventsWithSettingsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.SourceEventID,
|
||||
&i.SportID,
|
||||
&i.MatchName,
|
||||
&i.HomeTeam,
|
||||
&i.AwayTeam,
|
||||
&i.HomeTeamID,
|
||||
&i.AwayTeamID,
|
||||
&i.HomeKitImage,
|
||||
&i.AwayKitImage,
|
||||
&i.LeagueID,
|
||||
&i.LeagueName,
|
||||
&i.StartTime,
|
||||
&i.Score,
|
||||
&i.MatchMinute,
|
||||
&i.TimerStatus,
|
||||
&i.AddedTime,
|
||||
&i.MatchPeriod,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.FetchedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Source,
|
||||
&i.DefaultIsActive,
|
||||
&i.DefaultIsFeatured,
|
||||
&i.DefaultWinningUpperLimit,
|
||||
&i.IsMonitored,
|
||||
&i.CompanyID,
|
||||
&i.IsActive,
|
||||
&i.IsFeatured,
|
||||
&i.WinningUpperLimit,
|
||||
&i.UpdatedAt_2,
|
||||
&i.LeagueCc,
|
||||
&i.TotalOutcomes,
|
||||
&i.NumberOfBets,
|
||||
&i.TotalAmount,
|
||||
&i.AvgBetAmount,
|
||||
&i.TotalPotentialWinnings,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetTotalCompanyEvents = `-- name: GetTotalCompanyEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM events e
|
||||
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
|
||||
AND ces.company_id = $1
|
||||
JOIN leagues l ON l.id = e.league_id
|
||||
WHERE (
|
||||
is_live = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
status = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND(
|
||||
league_id = $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
e.sport_id = $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
AND (
|
||||
match_name ILIKE '%' || $6 || '%'
|
||||
OR league_name ILIKE '%' || $6 || '%'
|
||||
OR $6 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time < $7
|
||||
OR $7 IS NULL
|
||||
)
|
||||
AND (
|
||||
start_time > $8
|
||||
OR $8 IS NULL
|
||||
)
|
||||
AND (
|
||||
l.country_code = $9
|
||||
OR $9 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_featured = $10
|
||||
OR e.default_is_featured = $10
|
||||
OR $10 IS NULL
|
||||
)
|
||||
AND (
|
||||
ces.is_active = $11
|
||||
OR e.default_is_active = $11
|
||||
OR $11 IS NULL
|
||||
)
|
||||
AND (
|
||||
source = $12
|
||||
OR $12 IS NULL
|
||||
)
|
||||
`
|
||||
|
||||
type GetTotalCompanyEventsParams struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
LeagueID pgtype.Int8 `json:"league_id"`
|
||||
SportID pgtype.Int4 `json:"sport_id"`
|
||||
Query pgtype.Text `json:"query"`
|
||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||
CountryCode pgtype.Text `json:"country_code"`
|
||||
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
Source pgtype.Text `json:"source"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTotalCompanyEvents(ctx context.Context, arg GetTotalCompanyEventsParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, GetTotalCompanyEvents,
|
||||
arg.CompanyID,
|
||||
arg.IsLive,
|
||||
arg.Status,
|
||||
arg.LeagueID,
|
||||
arg.SportID,
|
||||
arg.Query,
|
||||
arg.LastStartTime,
|
||||
arg.FirstStartTime,
|
||||
arg.CountryCode,
|
||||
arg.IsFeatured,
|
||||
arg.IsActive,
|
||||
arg.Source,
|
||||
)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const SaveTenantEventSettings = `-- name: SaveTenantEventSettings :exec
|
||||
INSERT INTO company_event_settings (
|
||||
company_id,
|
||||
event_id,
|
||||
is_active,
|
||||
is_featured,
|
||||
winning_upper_limit
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
|
||||
UPDATE
|
||||
SET is_active = EXCLUDED.is_active,
|
||||
is_featured = EXCLUDED.is_featured,
|
||||
winning_upper_limit = EXCLUDED.winning_upper_limit
|
||||
`
|
||||
|
||||
type SaveTenantEventSettingsParams struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
EventID int64 `json:"event_id"`
|
||||
IsActive pgtype.Bool `json:"is_active"`
|
||||
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||
WinningUpperLimit pgtype.Int8 `json:"winning_upper_limit"`
|
||||
}
|
||||
|
||||
func (q *Queries) SaveTenantEventSettings(ctx context.Context, arg SaveTenantEventSettingsParams) error {
|
||||
_, err := q.db.Exec(ctx, SaveTenantEventSettings,
|
||||
arg.CompanyID,
|
||||
arg.EventID,
|
||||
arg.IsActive,
|
||||
arg.IsFeatured,
|
||||
arg.WinningUpperLimit,
|
||||
)
|
||||
return err
|
||||
}
|
||||
115
gen/db/league_stats.sql.go
Normal file
115
gen/db/league_stats.sql.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: league_stats.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const GetLeagueEventStat = `-- name: GetLeagueEventStat :many
|
||||
SELECT leagues.id,
|
||||
leagues.name,
|
||||
COUNT(*) AS total_events,
|
||||
COUNT(*) FILTER (
|
||||
WHERE events.status = 'upcoming'
|
||||
) 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
|
||||
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) ([]GetLeagueEventStatRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetLeagueEventStat)
|
||||
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
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ type Bet struct {
|
|||
CompanyID int64 `json:"company_id"`
|
||||
Amount int64 `json:"amount"`
|
||||
TotalOdds float32 `json:"total_odds"`
|
||||
PotentialWin pgtype.Int8 `json:"potential_win"`
|
||||
Status int32 `json:"status"`
|
||||
UserID int64 `json:"user_id"`
|
||||
IsShopBet bool `json:"is_shop_bet"`
|
||||
|
|
@ -70,6 +71,7 @@ type BetWithOutcome struct {
|
|||
CompanyID int64 `json:"company_id"`
|
||||
Amount int64 `json:"amount"`
|
||||
TotalOdds float32 `json:"total_odds"`
|
||||
PotentialWin pgtype.Int8 `json:"potential_win"`
|
||||
Status int32 `json:"status"`
|
||||
UserID int64 `json:"user_id"`
|
||||
IsShopBet bool `json:"is_shop_bet"`
|
||||
|
|
@ -208,6 +210,15 @@ type CompanySetting struct {
|
|||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type CompanyStat struct {
|
||||
CompanyID int64 `json:"company_id"`
|
||||
TotalBets pgtype.Int8 `json:"total_bets"`
|
||||
TotalCashMade pgtype.Int8 `json:"total_cash_made"`
|
||||
TotalCashOut pgtype.Int8 `json:"total_cash_out"`
|
||||
TotalCashBacks pgtype.Int8 `json:"total_cash_backs"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type CustomerWallet struct {
|
||||
ID int64 `json:"id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
|
|
@ -340,14 +351,16 @@ type Event struct {
|
|||
IsMonitored bool `json:"is_monitored"`
|
||||
}
|
||||
|
||||
type EventHistory struct {
|
||||
ID int64 `json:"id"`
|
||||
EventID int64 `json:"event_id"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
type EventBetStat struct {
|
||||
EventID int64 `json:"event_id"`
|
||||
NumberOfBets pgtype.Int8 `json:"number_of_bets"`
|
||||
TotalAmount pgtype.Int8 `json:"total_amount"`
|
||||
AvgBetAmount pgtype.Float8 `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings pgtype.Int8 `json:"total_potential_winnings"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type EventWithCountry struct {
|
||||
type EventDetailed struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
|
|
@ -377,6 +390,53 @@ type EventWithCountry struct {
|
|||
IsMonitored bool `json:"is_monitored"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount int64 `json:"total_amount"`
|
||||
AvgBetAmount float64 `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings int64 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
type EventDetailedMat struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeKitImage string `json:"home_kit_image"`
|
||||
AwayKitImage string `json:"away_kit_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
Score pgtype.Text `json:"score"`
|
||||
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||
TimerStatus pgtype.Text `json:"timer_status"`
|
||||
AddedTime pgtype.Int4 `json:"added_time"`
|
||||
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||
IsLive bool `json:"is_live"`
|
||||
Status string `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
Source string `json:"source"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount int64 `json:"total_amount"`
|
||||
AvgBetAmount float64 `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings int64 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
type EventHistory struct {
|
||||
ID int64 `json:"id"`
|
||||
EventID int64 `json:"event_id"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
}
|
||||
|
||||
type EventWithSetting struct {
|
||||
|
|
@ -414,6 +474,10 @@ type EventWithSetting struct {
|
|||
CompanyUpdatedAt pgtype.Timestamp `json:"company_updated_at"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
TotalOutcomes int64 `json:"total_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount int64 `json:"total_amount"`
|
||||
AvgBetAmount float64 `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings int64 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
type ExchangeRate struct {
|
||||
|
|
@ -624,6 +688,16 @@ type RefreshToken struct {
|
|||
Revoked bool `json:"revoked"`
|
||||
}
|
||||
|
||||
type Report struct {
|
||||
ID int64 `json:"id"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
RequestedBy pgtype.Int8 `json:"requested_by"`
|
||||
FilePath pgtype.Text `json:"file_path"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
CompletedAt pgtype.Timestamp `json:"completed_at"`
|
||||
}
|
||||
|
||||
type ReportedIssue struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
|
|
|
|||
12
internal/domain/branch_report.go
Normal file
12
internal/domain/branch_report.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package domain
|
||||
|
||||
// Branch-level aggregated report
|
||||
type BranchStats struct {
|
||||
BranchID int64
|
||||
BranchName string
|
||||
CompanyID int64
|
||||
TotalBets int64
|
||||
TotalCashIn float64
|
||||
TotalCashOut float64
|
||||
TotalCashBacks float64
|
||||
}
|
||||
11
internal/domain/company_report.go
Normal file
11
internal/domain/company_report.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package domain
|
||||
|
||||
// Company-level aggregated report
|
||||
type CompanyStats struct {
|
||||
CompanyID int64
|
||||
CompanyName string
|
||||
TotalBets int64
|
||||
TotalCashIn float64
|
||||
TotalCashOut float64
|
||||
TotalCashBacks float64
|
||||
}
|
||||
|
|
@ -1,108 +1,11 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TODO: turn status into an enum
|
||||
// Status represents the status of an event.
|
||||
// 0 Not Started
|
||||
// 1 InPlay
|
||||
// 2 TO BE FIXED
|
||||
// 3 Ended
|
||||
// 4 Postponed
|
||||
// 5 Cancelled
|
||||
// 6 Walkover
|
||||
// 7 Interrupted
|
||||
// 8 Abandoned
|
||||
// 9 Retired
|
||||
// 10 Suspended
|
||||
// 11 Decided by FA
|
||||
// 99 Removed
|
||||
type EventStatus string
|
||||
|
||||
const (
|
||||
STATUS_PENDING EventStatus = "upcoming"
|
||||
STATUS_IN_PLAY EventStatus = "in_play"
|
||||
STATUS_TO_BE_FIXED EventStatus = "to_be_fixed"
|
||||
STATUS_ENDED EventStatus = "ended"
|
||||
STATUS_POSTPONED EventStatus = "postponed"
|
||||
STATUS_CANCELLED EventStatus = "cancelled"
|
||||
STATUS_WALKOVER EventStatus = "walkover"
|
||||
STATUS_INTERRUPTED EventStatus = "interrupted"
|
||||
STATUS_ABANDONED EventStatus = "abandoned"
|
||||
STATUS_RETIRED EventStatus = "retired"
|
||||
STATUS_SUSPENDED EventStatus = "suspended"
|
||||
STATUS_DECIDED_BY_FA EventStatus = "decided_by_fa"
|
||||
STATUS_REMOVED EventStatus = "removed"
|
||||
)
|
||||
|
||||
type EventSource string
|
||||
|
||||
const (
|
||||
EVENT_SOURCE_BET365 EventSource = "b365api"
|
||||
EVENT_SOURCE_BWIN EventSource = "bwin"
|
||||
EVENT_SOURCE_BETFAIR EventSource = "bfair"
|
||||
EVENT_SOURCE_1XBET EventSource = "1xbet"
|
||||
EVENT_SOURCE_ENET EventSource = "enetpulse"
|
||||
)
|
||||
|
||||
// --- EventStatus Validation ---
|
||||
func (s EventStatus) IsValid() bool {
|
||||
switch s {
|
||||
case STATUS_PENDING,
|
||||
STATUS_IN_PLAY,
|
||||
STATUS_TO_BE_FIXED,
|
||||
STATUS_ENDED,
|
||||
STATUS_POSTPONED,
|
||||
STATUS_CANCELLED,
|
||||
STATUS_WALKOVER,
|
||||
STATUS_INTERRUPTED,
|
||||
STATUS_ABANDONED,
|
||||
STATUS_RETIRED,
|
||||
STATUS_SUSPENDED,
|
||||
STATUS_DECIDED_BY_FA,
|
||||
STATUS_REMOVED:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func ParseEventStatus(val string) (EventStatus, error) {
|
||||
s := EventStatus(val)
|
||||
if !s.IsValid() {
|
||||
return "", fmt.Errorf("invalid EventStatus: %q", val)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// --- EventSource Validation ---
|
||||
func (s EventSource) IsValid() bool {
|
||||
switch s {
|
||||
case EVENT_SOURCE_BET365,
|
||||
EVENT_SOURCE_BWIN,
|
||||
EVENT_SOURCE_BETFAIR,
|
||||
EVENT_SOURCE_1XBET,
|
||||
EVENT_SOURCE_ENET:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func ParseEventSource(val string) (EventSource, error) {
|
||||
s := EventSource(val)
|
||||
if !s.IsValid() {
|
||||
return "", fmt.Errorf("invalid EventSource: %q", val)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type BaseEvent struct {
|
||||
ID int64
|
||||
SourceEventID string
|
||||
|
|
@ -120,7 +23,6 @@ type BaseEvent struct {
|
|||
StartTime time.Time
|
||||
Source EventSource
|
||||
Status EventStatus
|
||||
TotalOddOutcomes int64
|
||||
IsMonitored bool
|
||||
DefaultIsFeatured bool
|
||||
DefaultIsActive bool
|
||||
|
|
@ -132,7 +34,13 @@ type BaseEvent struct {
|
|||
MatchPeriod ValidInt
|
||||
IsLive bool
|
||||
FetchedAt time.Time
|
||||
TotalOddOutcomes int64
|
||||
NumberOfBets int64
|
||||
TotalAmount Currency
|
||||
AvgBetAmount Currency
|
||||
TotalPotentialWinnings Currency
|
||||
}
|
||||
|
||||
type BaseEventRes struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
|
|
@ -150,7 +58,6 @@ type BaseEventRes struct {
|
|||
StartTime time.Time `json:"start_time"`
|
||||
Source EventSource `json:"source"`
|
||||
Status EventStatus `json:"status"`
|
||||
TotalOddOutcomes int64 `json:"total_odd_outcomes"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
|
|
@ -162,40 +69,11 @@ type BaseEventRes struct {
|
|||
MatchPeriod int `json:"match_period"`
|
||||
IsLive bool `json:"is_live"`
|
||||
FetchedAt time.Time `json:"fetched_at"`
|
||||
}
|
||||
type EventWithSettings struct {
|
||||
ID int64
|
||||
SourceEventID string
|
||||
SportID int32
|
||||
MatchName string
|
||||
HomeTeam string
|
||||
AwayTeam string
|
||||
HomeTeamID int64
|
||||
AwayTeamID int64
|
||||
HomeTeamImage string
|
||||
AwayTeamImage string
|
||||
LeagueID int64
|
||||
LeagueName string
|
||||
LeagueCC ValidString
|
||||
StartTime time.Time
|
||||
Source EventSource
|
||||
Status EventStatus
|
||||
TotalOddOutcomes int64
|
||||
IsMonitored bool
|
||||
IsFeatured bool
|
||||
IsActive bool
|
||||
WinningUpperLimit int64
|
||||
DefaultIsFeatured bool
|
||||
DefaultIsActive bool
|
||||
DefaultWinningUpperLimit int64
|
||||
Score ValidString
|
||||
MatchMinute ValidInt
|
||||
TimerStatus ValidString
|
||||
AddedTime ValidInt
|
||||
MatchPeriod ValidInt
|
||||
IsLive bool
|
||||
UpdatedAt time.Time
|
||||
FetchedAt time.Time
|
||||
TotalOddOutcomes int64 `json:"total_odd_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount float32 `json:"total_amount"`
|
||||
AvgBetAmount float32 `json:"average_bet_amount"`
|
||||
TotalPotentialWinnings float32 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
type CreateEvent struct {
|
||||
|
|
@ -216,89 +94,6 @@ type CreateEvent struct {
|
|||
Source EventSource
|
||||
DefaultWinningUpperLimit int64
|
||||
}
|
||||
|
||||
type EventWithSettingsRes struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeTeamImage string `json:"home_team_image"`
|
||||
AwayTeamImage string `json:"away_team_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
LeagueCC string `json:"league_cc"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
Source EventSource `json:"source"`
|
||||
Status EventStatus `json:"status"`
|
||||
TotalOddOutcomes int64 `json:"total_odd_outcomes"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
IsActive bool `json:"is_active"`
|
||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
Score string `json:"score,omitempty"`
|
||||
MatchMinute int `json:"match_minute,omitempty"`
|
||||
TimerStatus string `json:"timer_status,omitempty"`
|
||||
AddedTime int `json:"added_time,omitempty"`
|
||||
MatchPeriod int `json:"match_period,omitempty"`
|
||||
IsLive bool `json:"is_live"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
FetchedAt time.Time `json:"fetched_at"`
|
||||
}
|
||||
|
||||
type EventSettings struct {
|
||||
CompanyID int64
|
||||
EventID int64
|
||||
IsActive ValidBool
|
||||
IsFeatured ValidBool
|
||||
WinningUpperLimit ValidInt
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type UpdateTenantEventSettings struct {
|
||||
CompanyID int64
|
||||
EventID int64
|
||||
IsActive ValidBool
|
||||
IsFeatured ValidBool
|
||||
WinningUpperLimit ValidInt64
|
||||
}
|
||||
type UpdateGlobalEventSettings struct {
|
||||
EventID int64
|
||||
IsActive ValidBool
|
||||
IsFeatured ValidBool
|
||||
WinningUpperLimit ValidInt64
|
||||
}
|
||||
|
||||
type ValidEventStatus struct {
|
||||
Value EventStatus
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (v ValidEventStatus) ToPG() pgtype.Text {
|
||||
return pgtype.Text{
|
||||
String: string(v.Value),
|
||||
Valid: v.Valid,
|
||||
}
|
||||
}
|
||||
|
||||
type ValidEventSource struct {
|
||||
Value EventSource
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (v ValidEventSource) ToPG() pgtype.Text {
|
||||
return pgtype.Text{
|
||||
String: string(v.Value),
|
||||
Valid: v.Valid,
|
||||
}
|
||||
}
|
||||
|
||||
type EventFilter struct {
|
||||
Query ValidString
|
||||
SportID ValidInt32
|
||||
|
|
@ -315,7 +110,7 @@ type EventFilter struct {
|
|||
Source ValidEventSource
|
||||
}
|
||||
|
||||
func ConvertDBEvent(event dbgen.EventWithCountry) BaseEvent {
|
||||
func ConvertDBEvent(event dbgen.EventDetailed) BaseEvent {
|
||||
return BaseEvent{
|
||||
ID: event.ID,
|
||||
SourceEventID: event.SourceEventID,
|
||||
|
|
@ -336,7 +131,6 @@ func ConvertDBEvent(event dbgen.EventWithCountry) BaseEvent {
|
|||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: EventSource(event.Source),
|
||||
Status: EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
|
|
@ -361,12 +155,17 @@ func ConvertDBEvent(event dbgen.EventWithCountry) BaseEvent {
|
|||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
IsLive: event.IsLive,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
NumberOfBets: event.NumberOfBets,
|
||||
TotalAmount: Currency(event.TotalAmount),
|
||||
AvgBetAmount: Currency(event.AvgBetAmount),
|
||||
TotalPotentialWinnings: Currency(event.TotalPotentialWinnings),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEvents(events []dbgen.EventWithCountry) []BaseEvent {
|
||||
func ConvertDBEvents(events []dbgen.EventDetailed) []BaseEvent {
|
||||
result := make([]BaseEvent, len(events))
|
||||
for i, e := range events {
|
||||
result[i] = ConvertDBEvent(e)
|
||||
|
|
@ -395,96 +194,6 @@ func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams {
|
|||
}
|
||||
}
|
||||
|
||||
func ConvertCreateEventSettings(eventSettings UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams {
|
||||
return dbgen.SaveTenantEventSettingsParams{
|
||||
CompanyID: eventSettings.CompanyID,
|
||||
EventID: eventSettings.EventID,
|
||||
IsActive: eventSettings.IsActive.ToPG(),
|
||||
IsFeatured: eventSettings.IsFeatured.ToPG(),
|
||||
WinningUpperLimit: eventSettings.WinningUpperLimit.ToPG(),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings {
|
||||
return EventWithSettings{
|
||||
ID: event.ID,
|
||||
SourceEventID: event.SourceEventID,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeKitImage,
|
||||
AwayTeamImage: event.AwayKitImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: ValidString{
|
||||
Value: event.LeagueCc.String,
|
||||
Valid: event.LeagueCc.Valid,
|
||||
},
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: EventSource(event.Source),
|
||||
Status: EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
Score: ValidString{
|
||||
Value: event.Score.String,
|
||||
Valid: event.Score.Valid,
|
||||
},
|
||||
MatchMinute: ValidInt{
|
||||
Value: int(event.MatchMinute.Int32),
|
||||
Valid: event.MatchMinute.Valid,
|
||||
},
|
||||
TimerStatus: ValidString{
|
||||
Value: event.TimerStatus.String,
|
||||
Valid: event.TimerStatus.Valid,
|
||||
},
|
||||
AddedTime: ValidInt{
|
||||
Value: int(event.AddedTime.Int32),
|
||||
Valid: event.AddedTime.Valid,
|
||||
},
|
||||
MatchPeriod: ValidInt{
|
||||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
UpdatedAt: event.UpdatedAt.Time,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSettings {
|
||||
result := make([]EventWithSettings, len(events))
|
||||
for i, e := range events {
|
||||
result[i] = ConvertDBEventWithSetting(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ConvertUpdateTenantEventSettings(event UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams {
|
||||
return dbgen.SaveTenantEventSettingsParams{
|
||||
EventID: event.EventID,
|
||||
CompanyID: event.CompanyID,
|
||||
IsActive: event.IsActive.ToPG(),
|
||||
IsFeatured: event.IsFeatured.ToPG(),
|
||||
WinningUpperLimit: event.WinningUpperLimit.ToPG(),
|
||||
}
|
||||
}
|
||||
func ConvertUpdateGlobalEventSettings(event UpdateGlobalEventSettings) dbgen.UpdateGlobalEventSettingsParams {
|
||||
return dbgen.UpdateGlobalEventSettingsParams{
|
||||
ID: event.EventID,
|
||||
DefaultIsActive: event.IsActive.ToPG(),
|
||||
DefaultIsFeatured: event.IsFeatured.ToPG(),
|
||||
DefaultWinningUpperLimit: event.WinningUpperLimit.ToPG(),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertEventRes(event BaseEvent) BaseEventRes {
|
||||
return BaseEventRes{
|
||||
|
|
@ -504,7 +213,6 @@ func ConvertEventRes(event BaseEvent) BaseEventRes {
|
|||
StartTime: event.StartTime.UTC(),
|
||||
Source: EventSource(event.Source),
|
||||
Status: EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOddOutcomes,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
|
|
@ -516,6 +224,11 @@ func ConvertEventRes(event BaseEvent) BaseEventRes {
|
|||
MatchPeriod: event.MatchPeriod.Value,
|
||||
IsLive: event.IsLive,
|
||||
FetchedAt: event.FetchedAt.UTC(),
|
||||
TotalOddOutcomes: event.TotalOddOutcomes,
|
||||
NumberOfBets: event.NumberOfBets,
|
||||
TotalAmount: event.TotalAmount.Float32(),
|
||||
AvgBetAmount: event.AvgBetAmount.Float32(),
|
||||
TotalPotentialWinnings: event.TotalPotentialWinnings.Float32(),
|
||||
}
|
||||
}
|
||||
func ConvertEventResList(events []BaseEvent) []BaseEventRes {
|
||||
|
|
@ -526,47 +239,3 @@ func ConvertEventResList(events []BaseEvent) []BaseEventRes {
|
|||
return result
|
||||
}
|
||||
|
||||
func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
|
||||
return EventWithSettingsRes{
|
||||
ID: event.ID,
|
||||
SourceEventID: event.SourceEventID,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeTeamImage,
|
||||
AwayTeamImage: event.AwayTeamImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: event.LeagueCC.Value,
|
||||
StartTime: event.StartTime.UTC(),
|
||||
Source: EventSource(event.Source),
|
||||
Status: EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOddOutcomes,
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
Score: event.Score.Value,
|
||||
MatchMinute: event.MatchMinute.Value,
|
||||
TimerStatus: event.TimerStatus.Value,
|
||||
AddedTime: event.AddedTime.Value,
|
||||
MatchPeriod: event.MatchPeriod.Value,
|
||||
IsLive: event.IsLive,
|
||||
FetchedAt: event.FetchedAt.UTC(),
|
||||
UpdatedAt: event.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertEventWithSettingResList(events []EventWithSettings) []EventWithSettingsRes {
|
||||
result := make([]EventWithSettingsRes, 0, len(events))
|
||||
for _, event := range events {
|
||||
result = append(result, ConvertEventWitSettingRes(event))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
51
internal/domain/event_source.go
Normal file
51
internal/domain/event_source.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type EventSource string
|
||||
|
||||
const (
|
||||
EVENT_SOURCE_BET365 EventSource = "b365api"
|
||||
EVENT_SOURCE_BWIN EventSource = "bwin"
|
||||
EVENT_SOURCE_BETFAIR EventSource = "bfair"
|
||||
EVENT_SOURCE_1XBET EventSource = "1xbet"
|
||||
EVENT_SOURCE_ENET EventSource = "enetpulse"
|
||||
)
|
||||
|
||||
// --- EventSource Validation ---
|
||||
func (s EventSource) IsValid() bool {
|
||||
switch s {
|
||||
case EVENT_SOURCE_BET365,
|
||||
EVENT_SOURCE_BWIN,
|
||||
EVENT_SOURCE_BETFAIR,
|
||||
EVENT_SOURCE_1XBET,
|
||||
EVENT_SOURCE_ENET:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func ParseEventSource(val string) (EventSource, error) {
|
||||
s := EventSource(val)
|
||||
if !s.IsValid() {
|
||||
return "", fmt.Errorf("invalid EventSource: %q", val)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type ValidEventSource struct {
|
||||
Value EventSource
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (v ValidEventSource) ToPG() pgtype.Text {
|
||||
return pgtype.Text{
|
||||
String: string(v.Value),
|
||||
Valid: v.Valid,
|
||||
}
|
||||
}
|
||||
125
internal/domain/event_stats.go
Normal file
125
internal/domain/event_stats.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
)
|
||||
|
||||
type EventStats struct {
|
||||
EventCount int64 `json:"event_count"`
|
||||
TotalActiveEvents int64 `json:"total_active_events"`
|
||||
TotalInActiveEvents int64 `json:"total_inactive_events"`
|
||||
TotalFeaturedEvents int64 `json:"total_featured_events"`
|
||||
TotalLeagues int64 `json:"total_leagues"`
|
||||
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"`
|
||||
}
|
||||
|
||||
type EventStatsFilter struct {
|
||||
Interval DateInterval
|
||||
LeagueID ValidInt64
|
||||
SportID ValidInt32
|
||||
}
|
||||
type EventStatsByIntervalFilter struct {
|
||||
Interval DateInterval
|
||||
LeagueID ValidInt64
|
||||
SportID ValidInt32
|
||||
}
|
||||
|
||||
type EventStatsByInterval struct {
|
||||
Date time.Time `json:"date"`
|
||||
EventCount int64 `json:"event_count"`
|
||||
TotalActiveEvents int64 `json:"total_active_events"`
|
||||
TotalInActiveEvents int64 `json:"total_inactive_events"`
|
||||
TotalFeaturedEvents int64 `json:"total_featured_events"`
|
||||
TotalLeagues int64 `json:"total_leagues"`
|
||||
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 ConvertDBEventStats(stats dbgen.GetEventStatsRow) EventStats {
|
||||
return EventStats{
|
||||
EventCount: stats.EventCount,
|
||||
TotalActiveEvents: stats.TotalActiveEvents,
|
||||
TotalInActiveEvents: stats.TotalInactiveEvents,
|
||||
TotalFeaturedEvents: stats.TotalFeaturedEvents,
|
||||
TotalLeagues: stats.TotalLeagues,
|
||||
Pending: stats.Pending,
|
||||
InPlay: stats.InPlay,
|
||||
ToBeFixed: stats.ToBeFixed,
|
||||
Ended: stats.Ended,
|
||||
Postponed: stats.Postponed,
|
||||
Cancelled: stats.Cancelled,
|
||||
Walkover: stats.Walkover,
|
||||
Interrupted: stats.Interrupted,
|
||||
Abandoned: stats.Abandoned,
|
||||
Retired: stats.Retired,
|
||||
Suspended: stats.Suspended,
|
||||
DecidedByFa: stats.DecidedByFa,
|
||||
Removed: stats.Removed,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEventStatsByInterval(stats dbgen.GetEventStatsByIntervalRow) EventStatsByInterval {
|
||||
return EventStatsByInterval{
|
||||
Date: stats.Date.Time,
|
||||
EventCount: stats.EventCount,
|
||||
TotalActiveEvents: stats.TotalActiveEvents,
|
||||
TotalInActiveEvents: stats.TotalInactiveEvents,
|
||||
TotalFeaturedEvents: stats.TotalFeaturedEvents,
|
||||
TotalLeagues: stats.TotalLeagues,
|
||||
Pending: stats.Pending,
|
||||
InPlay: stats.InPlay,
|
||||
ToBeFixed: stats.ToBeFixed,
|
||||
Ended: stats.Ended,
|
||||
Postponed: stats.Postponed,
|
||||
Cancelled: stats.Cancelled,
|
||||
Walkover: stats.Walkover,
|
||||
Interrupted: stats.Interrupted,
|
||||
Abandoned: stats.Abandoned,
|
||||
Retired: stats.Retired,
|
||||
Suspended: stats.Suspended,
|
||||
DecidedByFa: stats.DecidedByFa,
|
||||
Removed: stats.Removed,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEventStatsByIntervalList(stats []dbgen.GetEventStatsByIntervalRow) []EventStatsByInterval {
|
||||
result := make([]EventStatsByInterval, len(stats))
|
||||
for i, e := range stats {
|
||||
result[i] = ConvertDBEventStatsByInterval(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type AggregateEventBetStats struct {
|
||||
ID int64 `json:"id"`
|
||||
MatchName string `json:"match_name"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount Currency `json:"total_amount"`
|
||||
AvgBetAmount Currency `json:"avg_bet_amount"`
|
||||
TotalPotentialWinnings Currency `json:"total_potential_winnings"`
|
||||
}
|
||||
69
internal/domain/event_status.go
Normal file
69
internal/domain/event_status.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type EventStatus string
|
||||
|
||||
const (
|
||||
STATUS_PENDING EventStatus = "upcoming"
|
||||
STATUS_IN_PLAY EventStatus = "in_play"
|
||||
STATUS_TO_BE_FIXED EventStatus = "to_be_fixed"
|
||||
STATUS_ENDED EventStatus = "ended"
|
||||
STATUS_POSTPONED EventStatus = "postponed"
|
||||
STATUS_CANCELLED EventStatus = "cancelled"
|
||||
STATUS_WALKOVER EventStatus = "walkover"
|
||||
STATUS_INTERRUPTED EventStatus = "interrupted"
|
||||
STATUS_ABANDONED EventStatus = "abandoned"
|
||||
STATUS_RETIRED EventStatus = "retired"
|
||||
STATUS_SUSPENDED EventStatus = "suspended"
|
||||
STATUS_DECIDED_BY_FA EventStatus = "decided_by_fa"
|
||||
STATUS_REMOVED EventStatus = "removed"
|
||||
)
|
||||
|
||||
func (s EventStatus) IsValid() bool {
|
||||
switch s {
|
||||
case STATUS_PENDING,
|
||||
STATUS_IN_PLAY,
|
||||
STATUS_TO_BE_FIXED,
|
||||
STATUS_ENDED,
|
||||
STATUS_POSTPONED,
|
||||
STATUS_CANCELLED,
|
||||
STATUS_WALKOVER,
|
||||
STATUS_INTERRUPTED,
|
||||
STATUS_ABANDONED,
|
||||
STATUS_RETIRED,
|
||||
STATUS_SUSPENDED,
|
||||
STATUS_DECIDED_BY_FA,
|
||||
STATUS_REMOVED:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func ParseEventStatus(val string) (EventStatus, error) {
|
||||
s := EventStatus(val)
|
||||
if !s.IsValid() {
|
||||
return "", fmt.Errorf("invalid EventStatus: %q", val)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
type ValidEventStatus struct {
|
||||
Value EventStatus
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (v ValidEventStatus) ToPG() pgtype.Text {
|
||||
return pgtype.Text{
|
||||
String: string(v.Value),
|
||||
Valid: v.Valid,
|
||||
}
|
||||
}
|
||||
|
||||
252
internal/domain/event_with_settings.go
Normal file
252
internal/domain/event_with_settings.go
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
)
|
||||
|
||||
type EventWithSettings struct {
|
||||
ID int64
|
||||
SourceEventID string
|
||||
SportID int32
|
||||
MatchName string
|
||||
HomeTeam string
|
||||
AwayTeam string
|
||||
HomeTeamID int64
|
||||
AwayTeamID int64
|
||||
HomeTeamImage string
|
||||
AwayTeamImage string
|
||||
LeagueID int64
|
||||
LeagueName string
|
||||
LeagueCC ValidString
|
||||
StartTime time.Time
|
||||
Source EventSource
|
||||
Status EventStatus
|
||||
IsMonitored bool
|
||||
IsFeatured bool
|
||||
IsActive bool
|
||||
WinningUpperLimit int64
|
||||
DefaultIsFeatured bool
|
||||
DefaultIsActive bool
|
||||
DefaultWinningUpperLimit int64
|
||||
Score ValidString
|
||||
MatchMinute ValidInt
|
||||
TimerStatus ValidString
|
||||
AddedTime ValidInt
|
||||
MatchPeriod ValidInt
|
||||
IsLive bool
|
||||
UpdatedAt time.Time
|
||||
FetchedAt time.Time
|
||||
TotalOddOutcomes int64
|
||||
NumberOfBets int64
|
||||
TotalAmount Currency
|
||||
AvgBetAmount Currency
|
||||
TotalPotentialWinnings Currency
|
||||
}
|
||||
|
||||
type EventWithSettingsRes struct {
|
||||
ID int64 `json:"id"`
|
||||
SourceEventID string `json:"source_event_id"`
|
||||
SportID int32 `json:"sport_id"`
|
||||
MatchName string `json:"match_name"`
|
||||
HomeTeam string `json:"home_team"`
|
||||
AwayTeam string `json:"away_team"`
|
||||
HomeTeamID int64 `json:"home_team_id"`
|
||||
AwayTeamID int64 `json:"away_team_id"`
|
||||
HomeTeamImage string `json:"home_team_image"`
|
||||
AwayTeamImage string `json:"away_team_image"`
|
||||
LeagueID int64 `json:"league_id"`
|
||||
LeagueName string `json:"league_name"`
|
||||
LeagueCC string `json:"league_cc"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
Source EventSource `json:"source"`
|
||||
Status EventStatus `json:"status"`
|
||||
IsMonitored bool `json:"is_monitored"`
|
||||
IsFeatured bool `json:"is_featured"`
|
||||
IsActive bool `json:"is_active"`
|
||||
WinningUpperLimit int64 `json:"winning_upper_limit"`
|
||||
DefaultIsFeatured bool `json:"default_is_featured"`
|
||||
DefaultIsActive bool `json:"default_is_active"`
|
||||
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
|
||||
Score string `json:"score,omitempty"`
|
||||
MatchMinute int `json:"match_minute,omitempty"`
|
||||
TimerStatus string `json:"timer_status,omitempty"`
|
||||
AddedTime int `json:"added_time,omitempty"`
|
||||
MatchPeriod int `json:"match_period,omitempty"`
|
||||
IsLive bool `json:"is_live"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
FetchedAt time.Time `json:"fetched_at"`
|
||||
TotalOddOutcomes int64 `json:"total_odd_outcomes"`
|
||||
NumberOfBets int64 `json:"number_of_bets"`
|
||||
TotalAmount float32 `json:"total_amount"`
|
||||
AvgBetAmount float32 `json:"average_bet_amount"`
|
||||
TotalPotentialWinnings float32 `json:"total_potential_winnings"`
|
||||
}
|
||||
|
||||
type EventSettings struct {
|
||||
CompanyID int64
|
||||
EventID int64
|
||||
IsActive ValidBool
|
||||
IsFeatured ValidBool
|
||||
WinningUpperLimit ValidInt
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type UpdateTenantEventSettings struct {
|
||||
CompanyID int64
|
||||
EventID int64
|
||||
IsActive ValidBool
|
||||
IsFeatured ValidBool
|
||||
WinningUpperLimit ValidInt64
|
||||
}
|
||||
type UpdateGlobalEventSettings struct {
|
||||
EventID int64
|
||||
IsActive ValidBool
|
||||
IsFeatured ValidBool
|
||||
WinningUpperLimit ValidInt64
|
||||
}
|
||||
|
||||
func ConvertCreateEventSettings(eventSettings UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams {
|
||||
return dbgen.SaveTenantEventSettingsParams{
|
||||
CompanyID: eventSettings.CompanyID,
|
||||
EventID: eventSettings.EventID,
|
||||
IsActive: eventSettings.IsActive.ToPG(),
|
||||
IsFeatured: eventSettings.IsFeatured.ToPG(),
|
||||
WinningUpperLimit: eventSettings.WinningUpperLimit.ToPG(),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings {
|
||||
return EventWithSettings{
|
||||
ID: event.ID,
|
||||
SourceEventID: event.SourceEventID,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeKitImage,
|
||||
AwayTeamImage: event.AwayKitImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: ValidString{
|
||||
Value: event.LeagueCc.String,
|
||||
Valid: event.LeagueCc.Valid,
|
||||
},
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: EventSource(event.Source),
|
||||
Status: EventStatus(event.Status),
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
Score: ValidString{
|
||||
Value: event.Score.String,
|
||||
Valid: event.Score.Valid,
|
||||
},
|
||||
MatchMinute: ValidInt{
|
||||
Value: int(event.MatchMinute.Int32),
|
||||
Valid: event.MatchMinute.Valid,
|
||||
},
|
||||
TimerStatus: ValidString{
|
||||
Value: event.TimerStatus.String,
|
||||
Valid: event.TimerStatus.Valid,
|
||||
},
|
||||
AddedTime: ValidInt{
|
||||
Value: int(event.AddedTime.Int32),
|
||||
Valid: event.AddedTime.Valid,
|
||||
},
|
||||
MatchPeriod: ValidInt{
|
||||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
UpdatedAt: event.UpdatedAt.Time,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
NumberOfBets: event.NumberOfBets,
|
||||
TotalAmount: Currency(event.TotalAmount),
|
||||
AvgBetAmount: Currency(event.AvgBetAmount),
|
||||
TotalPotentialWinnings: Currency(event.TotalPotentialWinnings),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSettings {
|
||||
result := make([]EventWithSettings, len(events))
|
||||
for i, e := range events {
|
||||
result[i] = ConvertDBEventWithSetting(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ConvertUpdateTenantEventSettings(event UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams {
|
||||
return dbgen.SaveTenantEventSettingsParams{
|
||||
EventID: event.EventID,
|
||||
CompanyID: event.CompanyID,
|
||||
IsActive: event.IsActive.ToPG(),
|
||||
IsFeatured: event.IsFeatured.ToPG(),
|
||||
WinningUpperLimit: event.WinningUpperLimit.ToPG(),
|
||||
}
|
||||
}
|
||||
func ConvertUpdateGlobalEventSettings(event UpdateGlobalEventSettings) dbgen.UpdateGlobalEventSettingsParams {
|
||||
return dbgen.UpdateGlobalEventSettingsParams{
|
||||
ID: event.EventID,
|
||||
DefaultIsActive: event.IsActive.ToPG(),
|
||||
DefaultIsFeatured: event.IsFeatured.ToPG(),
|
||||
DefaultWinningUpperLimit: event.WinningUpperLimit.ToPG(),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
|
||||
return EventWithSettingsRes{
|
||||
ID: event.ID,
|
||||
SourceEventID: event.SourceEventID,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeTeamImage,
|
||||
AwayTeamImage: event.AwayTeamImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: event.LeagueCC.Value,
|
||||
StartTime: event.StartTime.UTC(),
|
||||
Source: EventSource(event.Source),
|
||||
Status: EventStatus(event.Status),
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
Score: event.Score.Value,
|
||||
MatchMinute: event.MatchMinute.Value,
|
||||
TimerStatus: event.TimerStatus.Value,
|
||||
AddedTime: event.AddedTime.Value,
|
||||
MatchPeriod: event.MatchPeriod.Value,
|
||||
IsLive: event.IsLive,
|
||||
FetchedAt: event.FetchedAt.UTC(),
|
||||
UpdatedAt: event.UpdatedAt,
|
||||
TotalOddOutcomes: event.TotalOddOutcomes,
|
||||
NumberOfBets: event.NumberOfBets,
|
||||
TotalAmount: event.TotalAmount.Float32(),
|
||||
AvgBetAmount: event.AvgBetAmount.Float32(),
|
||||
TotalPotentialWinnings: event.TotalPotentialWinnings.Float32(),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertEventWithSettingResList(events []EventWithSettings) []EventWithSettingsRes {
|
||||
result := make([]EventWithSettingsRes, 0, len(events))
|
||||
for _, event := range events {
|
||||
result = append(result, ConvertEventWitSettingRes(event))
|
||||
}
|
||||
return result
|
||||
}
|
||||
31
internal/domain/interval.go
Normal file
31
internal/domain/interval.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package domain
|
||||
|
||||
import "fmt"
|
||||
|
||||
type DateInterval string
|
||||
|
||||
var (
|
||||
MonthInterval DateInterval = "month"
|
||||
WeekInterval DateInterval = "week"
|
||||
DayInterval DateInterval = "day"
|
||||
)
|
||||
|
||||
func (d DateInterval) IsValid() bool {
|
||||
switch d {
|
||||
case MonthInterval,
|
||||
WeekInterval,
|
||||
DayInterval:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ParseDateInterval(val string) (DateInterval, error) {
|
||||
d := DateInterval(val)
|
||||
if !d.IsValid() {
|
||||
return "", fmt.Errorf("invalid date interval: %q", val)
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
|
@ -2,12 +2,12 @@ package domain
|
|||
|
||||
import "time"
|
||||
|
||||
type TimeFrame string
|
||||
type ReportTimeFrame string
|
||||
|
||||
const (
|
||||
Daily TimeFrame = "daily"
|
||||
Weekly TimeFrame = "weekly"
|
||||
Monthly TimeFrame = "monthly"
|
||||
Daily ReportTimeFrame = "daily"
|
||||
Weekly ReportTimeFrame = "weekly"
|
||||
Monthly ReportTimeFrame = "monthly"
|
||||
)
|
||||
|
||||
type ReportFrequency string
|
||||
|
|
@ -39,8 +39,8 @@ type ReportData struct {
|
|||
Deposits float64
|
||||
TotalTickets int64
|
||||
VirtualGameStats []VirtualGameStat
|
||||
CompanyReports []CompanyReport
|
||||
BranchReports []BranchReport
|
||||
CompanyReports []CompanyStats
|
||||
BranchReports []BranchStats
|
||||
}
|
||||
|
||||
type VirtualGameStat struct {
|
||||
|
|
@ -51,7 +51,7 @@ type VirtualGameStat struct {
|
|||
|
||||
type Report struct {
|
||||
ID string
|
||||
TimeFrame TimeFrame
|
||||
TimeFrame ReportTimeFrame
|
||||
PeriodStart time.Time
|
||||
PeriodEnd time.Time
|
||||
TotalBets int
|
||||
|
|
@ -282,7 +282,6 @@ type BetAnalysis struct {
|
|||
AverageOdds float64 `json:"average_odds"`
|
||||
}
|
||||
|
||||
|
||||
// ReportFilter contains filters for report generation
|
||||
type ReportFilter struct {
|
||||
StartTime ValidTime `json:"start_time"`
|
||||
|
|
@ -484,27 +483,6 @@ type LiveWalletMetrics struct {
|
|||
BranchBalances []BranchWalletBalance `json:"branch_balances"`
|
||||
}
|
||||
|
||||
// Company-level aggregated report
|
||||
type CompanyReport struct {
|
||||
CompanyID int64
|
||||
CompanyName string
|
||||
TotalBets int64
|
||||
TotalCashIn float64
|
||||
TotalCashOut float64
|
||||
TotalCashBacks float64
|
||||
}
|
||||
|
||||
// Branch-level aggregated report
|
||||
type BranchReport struct {
|
||||
BranchID int64
|
||||
BranchName string
|
||||
CompanyID int64
|
||||
TotalBets int64
|
||||
TotalCashIn float64
|
||||
TotalCashOut float64
|
||||
TotalCashBacks float64
|
||||
}
|
||||
|
||||
|
||||
// type CompanyReport struct {
|
||||
// CompanyID int64
|
||||
|
|
@ -100,6 +100,8 @@ func (s *Store) DeleteCompany(ctx context.Context, id int64) error {
|
|||
return s.queries.DeleteCompany(ctx, id)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (s *Store) GetCompanyCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) {
|
||||
query := `SELECT
|
||||
COUNT(*) as total,
|
||||
|
|
|
|||
10
internal/repository/company_stats.go
Normal file
10
internal/repository/company_stats.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package repository
|
||||
|
||||
|
||||
func (r *ReportRepo) GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error) {
|
||||
params := dbgen.GetCompanyWiseReportParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
return r.store.queries.GetCompanyWiseReport(ctx, params)
|
||||
}
|
||||
|
|
@ -61,108 +61,6 @@ func (s *Store) GetAllEvents(ctx context.Context, filter domain.EventFilter) ([]
|
|||
return domain.ConvertDBEvents(events), totalCount, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
|
||||
events, err := s.queries.GetEventsWithSettings(ctx, dbgen.GetEventsWithSettingsParams{
|
||||
CompanyID: companyID,
|
||||
LeagueID: filter.LeagueID.ToPG(),
|
||||
SportID: filter.SportID.ToPG(),
|
||||
Query: filter.Query.ToPG(),
|
||||
Limit: filter.Limit.ToPG(),
|
||||
Offset: pgtype.Int4{
|
||||
Int32: int32(filter.Offset.Value * filter.Limit.Value),
|
||||
Valid: filter.Offset.Valid,
|
||||
},
|
||||
FirstStartTime: filter.FirstStartTime.ToPG(),
|
||||
LastStartTime: filter.LastStartTime.ToPG(),
|
||||
CountryCode: filter.CountryCode.ToPG(),
|
||||
IsFeatured: filter.Featured.ToPG(),
|
||||
IsActive: filter.Active.ToPG(),
|
||||
IsLive: filter.IsLive.ToPG(),
|
||||
Status: filter.Status.ToPG(),
|
||||
Source: filter.Source.ToPG(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
totalCount, err := s.queries.GetTotalCompanyEvents(ctx, dbgen.GetTotalCompanyEventsParams{
|
||||
CompanyID: companyID,
|
||||
LeagueID: filter.LeagueID.ToPG(),
|
||||
SportID: filter.SportID.ToPG(),
|
||||
Query: filter.Query.ToPG(),
|
||||
FirstStartTime: filter.FirstStartTime.ToPG(),
|
||||
LastStartTime: filter.LastStartTime.ToPG(),
|
||||
CountryCode: filter.CountryCode.ToPG(),
|
||||
IsFeatured: filter.Featured.ToPG(),
|
||||
IsActive: filter.Active.ToPG(),
|
||||
IsLive: filter.IsLive.ToPG(),
|
||||
Status: filter.Status.ToPG(),
|
||||
Source: filter.Source.ToPG(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]domain.EventWithSettings, len(events))
|
||||
|
||||
for i, event := range events {
|
||||
result[i] = domain.EventWithSettings{
|
||||
ID: event.ID,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeKitImage,
|
||||
AwayTeamImage: event.AwayKitImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: domain.ValidString{
|
||||
Value: event.LeagueCc.String,
|
||||
Valid: event.LeagueCc.Valid,
|
||||
},
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: domain.EventSource(event.Source),
|
||||
Status: domain.EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
SourceEventID: event.SourceEventID,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
Score: domain.ValidString{
|
||||
Value: event.Score.String,
|
||||
Valid: event.Score.Valid,
|
||||
},
|
||||
MatchMinute: domain.ValidInt{
|
||||
Value: int(event.MatchMinute.Int32),
|
||||
Valid: event.MatchMinute.Valid,
|
||||
},
|
||||
TimerStatus: domain.ValidString{
|
||||
Value: event.TimerStatus.String,
|
||||
Valid: event.TimerStatus.Valid,
|
||||
},
|
||||
AddedTime: domain.ValidInt{
|
||||
Value: int(event.AddedTime.Int32),
|
||||
Valid: event.AddedTime.Valid,
|
||||
},
|
||||
MatchPeriod: domain.ValidInt{
|
||||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
UpdatedAt: event.UpdatedAt.Time,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
return result, totalCount, nil
|
||||
}
|
||||
func (s *Store) GetEventByID(ctx context.Context, ID int64) (domain.BaseEvent, error) {
|
||||
event, err := s.queries.GetEventByID(ctx, ID)
|
||||
if err != nil {
|
||||
|
|
@ -182,69 +80,6 @@ func (s *Store) GetEventBySourceID(ctx context.Context, id string, source domain
|
|||
|
||||
return domain.ConvertDBEvent(event), nil
|
||||
}
|
||||
func (s *Store) GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error) {
|
||||
event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{
|
||||
ID: ID,
|
||||
CompanyID: companyID,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.EventWithSettings{}, err
|
||||
}
|
||||
|
||||
res := domain.EventWithSettings{
|
||||
ID: event.ID,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeKitImage,
|
||||
AwayTeamImage: event.AwayKitImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: domain.ValidString{
|
||||
Value: event.LeagueCc.String,
|
||||
Valid: event.LeagueCc.Valid,
|
||||
},
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: domain.EventSource(event.Source),
|
||||
Status: domain.EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
SourceEventID: event.SourceEventID,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
Score: domain.ValidString{
|
||||
Value: event.Score.String,
|
||||
Valid: event.Score.Valid,
|
||||
},
|
||||
MatchMinute: domain.ValidInt{
|
||||
Value: int(event.MatchMinute.Int32),
|
||||
Valid: event.MatchMinute.Valid,
|
||||
},
|
||||
TimerStatus: domain.ValidString{
|
||||
Value: event.TimerStatus.String,
|
||||
Valid: event.TimerStatus.Valid,
|
||||
},
|
||||
AddedTime: domain.ValidInt{
|
||||
Value: int(event.AddedTime.Int32),
|
||||
Valid: event.AddedTime.Valid,
|
||||
},
|
||||
MatchPeriod: domain.ValidInt{
|
||||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
UpdatedAt: event.UpdatedAt.Time,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
func (s *Store) UpdateFinalScore(ctx context.Context, eventID int64, fullScore string, status domain.EventStatus) error {
|
||||
params := dbgen.UpdateMatchResultParams{
|
||||
Score: pgtype.Text{String: fullScore, Valid: true},
|
||||
|
|
@ -290,13 +125,7 @@ func (s *Store) UpdateEventMonitored(ctx context.Context, eventID int64, IsMonit
|
|||
})
|
||||
}
|
||||
|
||||
func (s *Store) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error {
|
||||
return s.queries.SaveTenantEventSettings(ctx, domain.ConvertUpdateTenantEventSettings(event))
|
||||
}
|
||||
|
||||
func (s *Store) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error {
|
||||
return s.queries.UpdateGlobalEventSettings(ctx, domain.ConvertUpdateGlobalEventSettings(event))
|
||||
}
|
||||
func (s *Store) DeleteEvent(ctx context.Context, eventID int64) error {
|
||||
err := s.queries.DeleteEvent(ctx, eventID)
|
||||
if err != nil {
|
||||
|
|
|
|||
38
internal/repository/event_stats.go
Normal file
38
internal/repository/event_stats.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) GetEventStats(ctx context.Context, filter domain.EventStatsFilter) (domain.EventStats, error) {
|
||||
stats, err := s.queries.GetEventStats(ctx, dbgen.GetEventStatsParams{
|
||||
LeagueID: filter.LeagueID.ToPG(),
|
||||
SportID: filter.SportID.ToPG(),
|
||||
})
|
||||
if err != nil {
|
||||
return domain.EventStats{}, err
|
||||
}
|
||||
|
||||
return domain.ConvertDBEventStats(stats), nil
|
||||
}
|
||||
|
||||
func (s *Store) GetEventStatsByInterval(ctx context.Context, filter domain.EventStatsByIntervalFilter) ([]domain.EventStatsByInterval, error) {
|
||||
stats, err := s.queries.GetEventStatsByInterval(ctx, dbgen.GetEventStatsByIntervalParams{
|
||||
Interval: pgtype.Text{
|
||||
String: string(filter.Interval),
|
||||
Valid: true,
|
||||
},
|
||||
LeagueID: filter.LeagueID.ToPG(),
|
||||
SportID: filter.SportID.ToPG(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return domain.ConvertDBEventStatsByIntervalList(stats), nil
|
||||
}
|
||||
183
internal/repository/event_with_settings.go
Normal file
183
internal/repository/event_with_settings.go
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
package repository
|
||||
import (
|
||||
"context"
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
|
||||
func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
|
||||
events, err := s.queries.GetEventsWithSettings(ctx, dbgen.GetEventsWithSettingsParams{
|
||||
CompanyID: companyID,
|
||||
LeagueID: filter.LeagueID.ToPG(),
|
||||
SportID: filter.SportID.ToPG(),
|
||||
Query: filter.Query.ToPG(),
|
||||
Limit: filter.Limit.ToPG(),
|
||||
Offset: pgtype.Int4{
|
||||
Int32: int32(filter.Offset.Value * filter.Limit.Value),
|
||||
Valid: filter.Offset.Valid,
|
||||
},
|
||||
FirstStartTime: filter.FirstStartTime.ToPG(),
|
||||
LastStartTime: filter.LastStartTime.ToPG(),
|
||||
CountryCode: filter.CountryCode.ToPG(),
|
||||
IsFeatured: filter.Featured.ToPG(),
|
||||
IsActive: filter.Active.ToPG(),
|
||||
IsLive: filter.IsLive.ToPG(),
|
||||
Status: filter.Status.ToPG(),
|
||||
Source: filter.Source.ToPG(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
totalCount, err := s.queries.GetTotalCompanyEvents(ctx, dbgen.GetTotalCompanyEventsParams{
|
||||
CompanyID: companyID,
|
||||
LeagueID: filter.LeagueID.ToPG(),
|
||||
SportID: filter.SportID.ToPG(),
|
||||
Query: filter.Query.ToPG(),
|
||||
FirstStartTime: filter.FirstStartTime.ToPG(),
|
||||
LastStartTime: filter.LastStartTime.ToPG(),
|
||||
CountryCode: filter.CountryCode.ToPG(),
|
||||
IsFeatured: filter.Featured.ToPG(),
|
||||
IsActive: filter.Active.ToPG(),
|
||||
IsLive: filter.IsLive.ToPG(),
|
||||
Status: filter.Status.ToPG(),
|
||||
Source: filter.Source.ToPG(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]domain.EventWithSettings, len(events))
|
||||
|
||||
for i, event := range events {
|
||||
result[i] = domain.EventWithSettings{
|
||||
ID: event.ID,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeKitImage,
|
||||
AwayTeamImage: event.AwayKitImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: domain.ValidString{
|
||||
Value: event.LeagueCc.String,
|
||||
Valid: event.LeagueCc.Valid,
|
||||
},
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: domain.EventSource(event.Source),
|
||||
Status: domain.EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
SourceEventID: event.SourceEventID,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
Score: domain.ValidString{
|
||||
Value: event.Score.String,
|
||||
Valid: event.Score.Valid,
|
||||
},
|
||||
MatchMinute: domain.ValidInt{
|
||||
Value: int(event.MatchMinute.Int32),
|
||||
Valid: event.MatchMinute.Valid,
|
||||
},
|
||||
TimerStatus: domain.ValidString{
|
||||
Value: event.TimerStatus.String,
|
||||
Valid: event.TimerStatus.Valid,
|
||||
},
|
||||
AddedTime: domain.ValidInt{
|
||||
Value: int(event.AddedTime.Int32),
|
||||
Valid: event.AddedTime.Valid,
|
||||
},
|
||||
MatchPeriod: domain.ValidInt{
|
||||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
UpdatedAt: event.UpdatedAt.Time,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
return result, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error) {
|
||||
event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{
|
||||
ID: ID,
|
||||
CompanyID: companyID,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.EventWithSettings{}, err
|
||||
}
|
||||
|
||||
res := domain.EventWithSettings{
|
||||
ID: event.ID,
|
||||
SportID: event.SportID,
|
||||
MatchName: event.MatchName,
|
||||
HomeTeam: event.HomeTeam,
|
||||
AwayTeam: event.AwayTeam,
|
||||
HomeTeamID: event.HomeTeamID,
|
||||
AwayTeamID: event.AwayTeamID,
|
||||
HomeTeamImage: event.HomeKitImage,
|
||||
AwayTeamImage: event.AwayKitImage,
|
||||
LeagueID: event.LeagueID,
|
||||
LeagueName: event.LeagueName,
|
||||
LeagueCC: domain.ValidString{
|
||||
Value: event.LeagueCc.String,
|
||||
Valid: event.LeagueCc.Valid,
|
||||
},
|
||||
StartTime: event.StartTime.Time.UTC(),
|
||||
Source: domain.EventSource(event.Source),
|
||||
Status: domain.EventStatus(event.Status),
|
||||
TotalOddOutcomes: event.TotalOutcomes,
|
||||
SourceEventID: event.SourceEventID,
|
||||
WinningUpperLimit: event.WinningUpperLimit,
|
||||
IsFeatured: event.IsFeatured,
|
||||
IsMonitored: event.IsMonitored,
|
||||
IsActive: event.IsActive,
|
||||
DefaultIsFeatured: event.DefaultIsFeatured,
|
||||
DefaultIsActive: event.DefaultIsActive,
|
||||
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
|
||||
Score: domain.ValidString{
|
||||
Value: event.Score.String,
|
||||
Valid: event.Score.Valid,
|
||||
},
|
||||
MatchMinute: domain.ValidInt{
|
||||
Value: int(event.MatchMinute.Int32),
|
||||
Valid: event.MatchMinute.Valid,
|
||||
},
|
||||
TimerStatus: domain.ValidString{
|
||||
Value: event.TimerStatus.String,
|
||||
Valid: event.TimerStatus.Valid,
|
||||
},
|
||||
AddedTime: domain.ValidInt{
|
||||
Value: int(event.AddedTime.Int32),
|
||||
Valid: event.AddedTime.Valid,
|
||||
},
|
||||
MatchPeriod: domain.ValidInt{
|
||||
Value: int(event.MatchPeriod.Int32),
|
||||
Valid: event.MatchPeriod.Valid,
|
||||
},
|
||||
IsLive: event.IsLive,
|
||||
UpdatedAt: event.UpdatedAt.Time,
|
||||
FetchedAt: event.FetchedAt.Time,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error {
|
||||
return s.queries.SaveTenantEventSettings(ctx, domain.ConvertUpdateTenantEventSettings(event))
|
||||
}
|
||||
|
||||
func (s *Store) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error {
|
||||
return s.queries.UpdateGlobalEventSettings(ctx, domain.ConvertUpdateGlobalEventSettings(event))
|
||||
}
|
||||
|
|
@ -1,29 +1,29 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
// "context"
|
||||
// "fmt"
|
||||
// "time"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
// dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
// "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
// "github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type ReportRepository interface {
|
||||
GenerateReport(timeFrame domain.TimeFrame, start, end time.Time) (*domain.Report, error)
|
||||
SaveReport(report *domain.Report) error
|
||||
FindReportsByTimeFrame(timeFrame domain.TimeFrame, limit int) ([]*domain.Report, error)
|
||||
// GenerateReport(timeFrame domain.ReportTimeFrame, start, end time.Time) (*domain.Report, error)
|
||||
// SaveReport(report *domain.Report) error
|
||||
// FindReportsByTimeFrame(timeFrame domain.ReportTimeFrame, limit int) ([]*domain.Report, error)
|
||||
|
||||
GetTotalCashOutInRange(ctx context.Context, from, to time.Time) (float64, error)
|
||||
GetTotalCashMadeInRange(ctx context.Context, from, to time.Time) (float64, error)
|
||||
GetTotalCashBacksInRange(ctx context.Context, from, to time.Time) (float64, error)
|
||||
GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time) (int64, error)
|
||||
GetVirtualGameSummaryInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetVirtualGameSummaryInRangeRow, error)
|
||||
GetAllTicketsInRange(ctx context.Context, from, to time.Time) (dbgen.GetAllTicketsInRangeRow, error)
|
||||
GetWalletTransactionsInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetWalletTransactionsInRangeRow, error)
|
||||
GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error)
|
||||
GetBranchWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetBranchWiseReportRow, error)
|
||||
// GetTotalCashOutInRange(ctx context.Context, from, to time.Time) (float64, error)
|
||||
// GetTotalCashMadeInRange(ctx context.Context, from, to time.Time) (float64, error)
|
||||
// GetTotalCashBacksInRange(ctx context.Context, from, to time.Time) (float64, error)
|
||||
// GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time) (int64, error)
|
||||
// GetVirtualGameSummaryInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetVirtualGameSummaryInRangeRow, error)
|
||||
// GetAllTicketsInRange(ctx context.Context, from, to time.Time) (dbgen.GetAllTicketsInRangeRow, error)
|
||||
// GetWalletTransactionsInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetWalletTransactionsInRangeRow, error)
|
||||
// GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error)
|
||||
// GetBranchWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetBranchWiseReportRow, error)
|
||||
}
|
||||
|
||||
type ReportRepo struct {
|
||||
|
|
@ -34,201 +34,201 @@ func NewReportRepo(store *Store) ReportRepository {
|
|||
return &ReportRepo{store: store}
|
||||
}
|
||||
|
||||
func (r *ReportRepo) GenerateReport(timeFrame domain.TimeFrame, start, end time.Time) (*domain.Report, error) {
|
||||
// Implement SQL queries to calculate metrics
|
||||
var report domain.Report
|
||||
// func (r *ReportRepo) GenerateReport(timeFrame domain.ReportTimeFrame, start, end time.Time) (*domain.Report, error) {
|
||||
// // Implement SQL queries to calculate metrics
|
||||
// var report domain.Report
|
||||
|
||||
// Total Bets
|
||||
err := r.store.conn.QueryRow(
|
||||
context.Background(),
|
||||
`SELECT COUNT(*) FROM bets
|
||||
WHERE created_at BETWEEN $1 AND $2`, start, end).Scan(&report.TotalBets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// // Total Bets
|
||||
// err := r.store.conn.QueryRow(
|
||||
// context.Background(),
|
||||
// `SELECT COUNT(*) FROM bets
|
||||
// WHERE created_at BETWEEN $1 AND $2`, start, end).Scan(&report.TotalBets)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// Total Cash In
|
||||
err = r.store.conn.QueryRow(
|
||||
context.Background(),
|
||||
`SELECT COALESCE(SUM(amount), 0) FROM transactions
|
||||
WHERE type = 'stake' AND created_at BETWEEN $1 AND $2`, start, end).Scan(&report.TotalCashIn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// // Total Cash In
|
||||
// err = r.store.conn.QueryRow(
|
||||
// context.Background(),
|
||||
// `SELECT COALESCE(SUM(amount), 0) FROM transactions
|
||||
// WHERE type = 'stake' AND created_at BETWEEN $1 AND $2`, start, end).Scan(&report.TotalCashIn)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// Similar queries for Cash Out and Cash Back...
|
||||
// // Similar queries for Cash Out and Cash Back...
|
||||
|
||||
report.TimeFrame = timeFrame
|
||||
report.PeriodStart = start
|
||||
report.PeriodEnd = end
|
||||
report.GeneratedAt = time.Now()
|
||||
// report.TimeFrame = timeFrame
|
||||
// report.PeriodStart = start
|
||||
// report.PeriodEnd = end
|
||||
// report.GeneratedAt = time.Now()
|
||||
|
||||
return &report, nil
|
||||
}
|
||||
// return &report, nil
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) SaveReport(report *domain.Report) error {
|
||||
_, err := r.store.conn.Exec(
|
||||
context.Background(),
|
||||
`INSERT INTO reports
|
||||
(id, time_frame, period_start, period_end, total_bets, total_cash_in, total_cash_out, total_cash_back, generated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
report.ID, report.TimeFrame, report.PeriodStart, report.PeriodEnd,
|
||||
report.TotalBets, report.TotalCashIn, report.TotalCashOut, report.TotalCashBack, report.GeneratedAt)
|
||||
return err
|
||||
}
|
||||
// func (r *ReportRepo) SaveReport(report *domain.Report) error {
|
||||
// _, err := r.store.conn.Exec(
|
||||
// context.Background(),
|
||||
// `INSERT INTO reports
|
||||
// (id, time_frame, period_start, period_end, total_bets, total_cash_in, total_cash_out, total_cash_back, generated_at)
|
||||
// VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
// report.ID, report.TimeFrame, report.PeriodStart, report.PeriodEnd,
|
||||
// report.TotalBets, report.TotalCashIn, report.TotalCashOut, report.TotalCashBack, report.GeneratedAt)
|
||||
// return err
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) FindReportsByTimeFrame(timeFrame domain.TimeFrame, limit int) ([]*domain.Report, error) {
|
||||
rows, err := r.store.conn.Query(
|
||||
context.Background(),
|
||||
`SELECT id, time_frame, period_start, period_end, total_bets,
|
||||
total_cash_in, total_cash_out, total_cash_back, generated_at
|
||||
FROM reports
|
||||
WHERE time_frame = $1
|
||||
ORDER BY generated_at DESC
|
||||
LIMIT $2`,
|
||||
timeFrame, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
// func (r *ReportRepo) FindReportsByTimeFrame(timeFrame domain.ReportTimeFrame, limit int) ([]*domain.Report, error) {
|
||||
// rows, err := r.store.conn.Query(
|
||||
// context.Background(),
|
||||
// `SELECT id, time_frame, period_start, period_end, total_bets,
|
||||
// total_cash_in, total_cash_out, total_cash_back, generated_at
|
||||
// FROM reports
|
||||
// WHERE time_frame = $1
|
||||
// ORDER BY generated_at DESC
|
||||
// LIMIT $2`,
|
||||
// timeFrame, limit)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// defer rows.Close()
|
||||
|
||||
var reports []*domain.Report
|
||||
for rows.Next() {
|
||||
var report domain.Report
|
||||
err := rows.Scan(
|
||||
&report.ID,
|
||||
&report.TimeFrame,
|
||||
&report.PeriodStart,
|
||||
&report.PeriodEnd,
|
||||
&report.TotalBets,
|
||||
&report.TotalCashIn,
|
||||
&report.TotalCashOut,
|
||||
&report.TotalCashBack,
|
||||
&report.GeneratedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reports = append(reports, &report)
|
||||
}
|
||||
// var reports []*domain.Report
|
||||
// for rows.Next() {
|
||||
// var report domain.Report
|
||||
// err := rows.Scan(
|
||||
// &report.ID,
|
||||
// &report.TimeFrame,
|
||||
// &report.PeriodStart,
|
||||
// &report.PeriodEnd,
|
||||
// &report.TotalBets,
|
||||
// &report.TotalCashIn,
|
||||
// &report.TotalCashOut,
|
||||
// &report.TotalCashBack,
|
||||
// &report.GeneratedAt,
|
||||
// )
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// reports = append(reports, &report)
|
||||
// }
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if err := rows.Err(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
return reports, nil
|
||||
}
|
||||
// return reports, nil
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time) (int64, error) {
|
||||
params := dbgen.GetTotalBetsMadeInRangeParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
return r.store.queries.GetTotalBetsMadeInRange(ctx, params)
|
||||
}
|
||||
// func (r *ReportRepo) GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time) (int64, error) {
|
||||
// params := dbgen.GetTotalBetsMadeInRangeParams{
|
||||
// From: ToPgTimestamp(from),
|
||||
// To: ToPgTimestamp(to),
|
||||
// }
|
||||
// return r.store.queries.GetTotalBetsMadeInRange(ctx, params)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetTotalCashBacksInRange(ctx context.Context, from, to time.Time) (float64, error) {
|
||||
params := dbgen.GetTotalCashBacksInRangeParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
value, err := r.store.queries.GetTotalCashBacksInRange(ctx, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return parseFloat(value)
|
||||
}
|
||||
// func (r *ReportRepo) GetTotalCashBacksInRange(ctx context.Context, from, to time.Time) (float64, error) {
|
||||
// params := dbgen.GetTotalCashBacksInRangeParams{
|
||||
// From: ToPgTimestamp(from),
|
||||
// To: ToPgTimestamp(to),
|
||||
// }
|
||||
// value, err := r.store.queries.GetTotalCashBacksInRange(ctx, params)
|
||||
// if err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
// return parseFloat(value)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetTotalCashMadeInRange(ctx context.Context, from, to time.Time) (float64, error) {
|
||||
params := dbgen.GetTotalCashMadeInRangeParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
value, err := r.store.queries.GetTotalCashMadeInRange(ctx, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return parseFloat(value)
|
||||
}
|
||||
// func (r *ReportRepo) GetTotalCashMadeInRange(ctx context.Context, from, to time.Time) (float64, error) {
|
||||
// params := dbgen.GetTotalCashMadeInRangeParams{
|
||||
// From: ToPgTimestamp(from),
|
||||
// To: ToPgTimestamp(to),
|
||||
// }
|
||||
// value, err := r.store.queries.GetTotalCashMadeInRange(ctx, params)
|
||||
// if err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
// return parseFloat(value)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetTotalCashOutInRange(ctx context.Context, from, to time.Time) (float64, error) {
|
||||
params := dbgen.GetTotalCashOutInRangeParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
value, err := r.store.queries.GetTotalCashOutInRange(ctx, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return parseFloat(value)
|
||||
}
|
||||
// func (r *ReportRepo) GetTotalCashOutInRange(ctx context.Context, from, to time.Time) (float64, error) {
|
||||
// params := dbgen.GetTotalCashOutInRangeParams{
|
||||
// From: ToPgTimestamp(from),
|
||||
// To: ToPgTimestamp(to),
|
||||
// }
|
||||
// value, err := r.store.queries.GetTotalCashOutInRange(ctx, params)
|
||||
// if err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
// return parseFloat(value)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetWalletTransactionsInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetWalletTransactionsInRangeRow, error) {
|
||||
params := dbgen.GetWalletTransactionsInRangeParams{
|
||||
CreatedAt: ToPgTimestamp(from),
|
||||
CreatedAt_2: ToPgTimestamp(to),
|
||||
}
|
||||
return r.store.queries.GetWalletTransactionsInRange(ctx, params)
|
||||
}
|
||||
// func (r *ReportRepo) GetWalletTransactionsInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetWalletTransactionsInRangeRow, error) {
|
||||
// params := dbgen.GetWalletTransactionsInRangeParams{
|
||||
// CreatedAt: ToPgTimestamp(from),
|
||||
// CreatedAt_2: ToPgTimestamp(to),
|
||||
// }
|
||||
// return r.store.queries.GetWalletTransactionsInRange(ctx, params)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetAllTicketsInRange(ctx context.Context, from, to time.Time) (dbgen.GetAllTicketsInRangeRow, error) {
|
||||
params := dbgen.GetAllTicketsInRangeParams{
|
||||
CreatedAt: ToPgTimestamp(from),
|
||||
CreatedAt_2: ToPgTimestamp(to),
|
||||
}
|
||||
return r.store.queries.GetAllTicketsInRange(ctx, params)
|
||||
}
|
||||
// func (r *ReportRepo) GetAllTicketsInRange(ctx context.Context, from, to time.Time) (dbgen.GetAllTicketsInRangeRow, error) {
|
||||
// params := dbgen.GetAllTicketsInRangeParams{
|
||||
// CreatedAt: ToPgTimestamp(from),
|
||||
// CreatedAt_2: ToPgTimestamp(to),
|
||||
// }
|
||||
// return r.store.queries.GetAllTicketsInRange(ctx, params)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetVirtualGameSummaryInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetVirtualGameSummaryInRangeRow, error) {
|
||||
params := dbgen.GetVirtualGameSummaryInRangeParams{
|
||||
CreatedAt: ToPgTimestamptz(from),
|
||||
CreatedAt_2: ToPgTimestamptz(to),
|
||||
}
|
||||
return r.store.queries.GetVirtualGameSummaryInRange(ctx, params)
|
||||
}
|
||||
// func (r *ReportRepo) GetVirtualGameSummaryInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetVirtualGameSummaryInRangeRow, error) {
|
||||
// params := dbgen.GetVirtualGameSummaryInRangeParams{
|
||||
// CreatedAt: ToPgTimestamptz(from),
|
||||
// CreatedAt_2: ToPgTimestamptz(to),
|
||||
// }
|
||||
// return r.store.queries.GetVirtualGameSummaryInRange(ctx, params)
|
||||
// }
|
||||
|
||||
func ToPgTimestamp(t time.Time) pgtype.Timestamp {
|
||||
return pgtype.Timestamp{Time: t, Valid: true}
|
||||
}
|
||||
// func ToPgTimestamp(t time.Time) pgtype.Timestamp {
|
||||
// return pgtype.Timestamp{Time: t, Valid: true}
|
||||
// }
|
||||
|
||||
func ToPgTimestamptz(t time.Time) pgtype.Timestamptz {
|
||||
return pgtype.Timestamptz{Time: t, Valid: true}
|
||||
}
|
||||
// func ToPgTimestamptz(t time.Time) pgtype.Timestamptz {
|
||||
// return pgtype.Timestamptz{Time: t, Valid: true}
|
||||
// }
|
||||
|
||||
func parseFloat(value interface{}) (float64, error) {
|
||||
switch v := value.(type) {
|
||||
case float64:
|
||||
return v, nil
|
||||
case int64:
|
||||
return float64(v), nil
|
||||
case pgtype.Numeric:
|
||||
if !v.Valid {
|
||||
return 0, nil
|
||||
}
|
||||
f, err := v.Float64Value()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to convert pgtype.Numeric to float64: %w", err)
|
||||
}
|
||||
return f.Float64, nil
|
||||
case nil:
|
||||
return 0, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unexpected type %T for value: %+v", v, v)
|
||||
}
|
||||
}
|
||||
// func parseFloat(value interface{}) (float64, error) {
|
||||
// switch v := value.(type) {
|
||||
// case float64:
|
||||
// return v, nil
|
||||
// case int64:
|
||||
// return float64(v), nil
|
||||
// case pgtype.Numeric:
|
||||
// if !v.Valid {
|
||||
// return 0, nil
|
||||
// }
|
||||
// f, err := v.Float64Value()
|
||||
// if err != nil {
|
||||
// return 0, fmt.Errorf("failed to convert pgtype.Numeric to float64: %w", err)
|
||||
// }
|
||||
// return f.Float64, nil
|
||||
// case nil:
|
||||
// return 0, nil
|
||||
// default:
|
||||
// return 0, fmt.Errorf("unexpected type %T for value: %+v", v, v)
|
||||
// }
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error) {
|
||||
params := dbgen.GetCompanyWiseReportParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
return r.store.queries.GetCompanyWiseReport(ctx, params)
|
||||
}
|
||||
// func (r *ReportRepo) GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error) {
|
||||
// params := dbgen.GetCompanyWiseReportParams{
|
||||
// From: ToPgTimestamp(from),
|
||||
// To: ToPgTimestamp(to),
|
||||
// }
|
||||
// return r.store.queries.GetCompanyWiseReport(ctx, params)
|
||||
// }
|
||||
|
||||
func (r *ReportRepo) GetBranchWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetBranchWiseReportRow, error) {
|
||||
params := dbgen.GetBranchWiseReportParams{
|
||||
From: ToPgTimestamp(from),
|
||||
To: ToPgTimestamp(to),
|
||||
}
|
||||
return r.store.queries.GetBranchWiseReport(ctx, params)
|
||||
}
|
||||
// func (r *ReportRepo) GetBranchWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetBranchWiseReportRow, error) {
|
||||
// params := dbgen.GetBranchWiseReportParams{
|
||||
// From: ToPgTimestamp(from),
|
||||
// To: ToPgTimestamp(to),
|
||||
// }
|
||||
// return r.store.queries.GetBranchWiseReport(ctx, params)
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -557,31 +557,31 @@ func (s *Service) DeductBetFromBranchWallet(ctx context.Context, amount float32,
|
|||
|
||||
// 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
|
||||
// deductedAmount := amount * company.DeductedPercentage
|
||||
|
||||
if deductedAmount == 0 {
|
||||
s.mongoLogger.Fatal("Amount",
|
||||
zap.Int64("wallet_id", walletID),
|
||||
zap.Float32("amount", deductedAmount),
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
}
|
||||
_, err = s.walletSvc.DeductFromWallet(ctx,
|
||||
walletID, domain.ToCurrency(deductedAmount), domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
}, domain.TRANSFER_DIRECT,
|
||||
fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount))
|
||||
// if deductedAmount == 0 {
|
||||
// s.mongoLogger.Fatal("Amount",
|
||||
// zap.Int64("wallet_id", walletID),
|
||||
// zap.Float32("amount", deductedAmount),
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// return err
|
||||
// }
|
||||
// _, err = s.walletSvc.DeductFromWallet(ctx,
|
||||
// walletID, domain.ToCurrency(deductedAmount), domain.ValidInt64{
|
||||
// Value: userID,
|
||||
// Valid: true,
|
||||
// }, domain.TRANSFER_DIRECT,
|
||||
// fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount))
|
||||
|
||||
if err != nil {
|
||||
s.mongoLogger.Error("failed to deduct from wallet",
|
||||
zap.Int64("wallet_id", walletID),
|
||||
zap.Float32("amount", deductedAmount),
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
}
|
||||
// if err != nil {
|
||||
// s.mongoLogger.Error("failed to deduct from wallet",
|
||||
// zap.Int64("wallet_id", walletID),
|
||||
// zap.Float32("amount", deductedAmount),
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// return err
|
||||
// }
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,15 @@ type Service interface {
|
|||
UpdateEventStatus(ctx context.Context, eventID int64, status domain.EventStatus) error
|
||||
IsEventMonitored(ctx context.Context, eventID int64) (bool, error)
|
||||
UpdateEventMonitored(ctx context.Context, eventID int64, IsMonitored bool) error
|
||||
GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error)
|
||||
|
||||
// Event Settings Views
|
||||
GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error)
|
||||
GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error)
|
||||
UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error
|
||||
UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error
|
||||
GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error)
|
||||
|
||||
// Stats
|
||||
GetEventStats(ctx context.Context, filter domain.EventStatsFilter) (domain.EventStats, error)
|
||||
GetEventStatsByInterval(ctx context.Context, filter domain.EventStatsByIntervalFilter) ([]domain.EventStatsByInterval, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -483,21 +483,8 @@ func (s *service) UpdateEventMonitored(ctx context.Context, eventID int64, IsMon
|
|||
return s.store.UpdateEventMonitored(ctx, eventID, IsMonitored)
|
||||
}
|
||||
|
||||
func (s *service) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
|
||||
return s.store.GetEventsWithSettings(ctx, companyID, filter)
|
||||
}
|
||||
|
||||
func (s *service) GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error) {
|
||||
return s.store.GetEventWithSettingByID(ctx, ID, companyID)
|
||||
}
|
||||
|
||||
func (s *service) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error {
|
||||
return s.store.UpdateTenantEventSettings(ctx, event)
|
||||
}
|
||||
func (s *service) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error {
|
||||
return s.store.UpdateGlobalEventSettings(ctx, event)
|
||||
}
|
||||
|
||||
func (s *service) GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error) {
|
||||
return s.store.GetSportAndLeagueIDs(ctx, eventID)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
22
internal/services/event/settings.go
Normal file
22
internal/services/event/settings.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
func (s *service) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) {
|
||||
return s.store.GetEventsWithSettings(ctx, companyID, filter)
|
||||
}
|
||||
|
||||
func (s *service) GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error) {
|
||||
return s.store.GetEventWithSettingByID(ctx, ID, companyID)
|
||||
}
|
||||
|
||||
func (s *service) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error {
|
||||
return s.store.UpdateTenantEventSettings(ctx, event)
|
||||
}
|
||||
func (s *service) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error {
|
||||
return s.store.UpdateGlobalEventSettings(ctx, event)
|
||||
}
|
||||
14
internal/services/event/stats.go
Normal file
14
internal/services/event/stats.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
func (s *service) GetEventStats(ctx context.Context, filter domain.EventStatsFilter) (domain.EventStats, error) {
|
||||
return s.store.GetEventStats(ctx, filter)
|
||||
}
|
||||
func (s *service) GetEventStatsByInterval(ctx context.Context, filter domain.EventStatsByIntervalFilter) ([]domain.EventStatsByInterval, error) {
|
||||
return s.store.GetEventStatsByInterval(ctx, filter)
|
||||
}
|
||||
|
|
@ -461,7 +461,7 @@ func (s *Service) GetSportPerformance(ctx context.Context, filter domain.ReportF
|
|||
|
||||
func (s *Service) GenerateReport(ctx context.Context, from, to time.Time) error {
|
||||
// Hardcoded output directory
|
||||
outputDir := "C:/Users/User/Desktop/reports"
|
||||
outputDir := "reports"
|
||||
|
||||
// Ensure directory exists
|
||||
if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
|
||||
|
|
@ -609,7 +609,6 @@ func writeSummaryCSV(companies []domain.CompanyReport, from, to time.Time, outpu
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (s *Service) fetchReportData(ctx context.Context, from, to time.Time) (
|
||||
[]domain.CompanyReport, map[int64][]domain.BranchReport, error,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -28,58 +28,58 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
spec string
|
||||
task func()
|
||||
}{
|
||||
{
|
||||
spec: "0 0 * * * *", // Every 1 hour
|
||||
task: func() {
|
||||
mongoLogger.Info("Began fetching upcoming events cron task")
|
||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||
mongoLogger.Error("Failed to fetch upcoming events",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
mongoLogger.Info("Completed fetching upcoming events without errors")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
|
||||
task: func() {
|
||||
mongoLogger.Info("Began fetching non live odds cron task")
|
||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||
mongoLogger.Error("Failed to fetch non live odds",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
mongoLogger.Info("Completed fetching non live odds without errors")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 */5 * * * *", // Every 5 Minutes
|
||||
task: func() {
|
||||
mongoLogger.Info("Began update all expired events status cron task")
|
||||
if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil {
|
||||
mongoLogger.Error("Failed to update expired events status",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
mongoLogger.Info("Completed expired events without errors")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: "0 */15 * * * *", // Every 15 Minutes
|
||||
task: func() {
|
||||
mongoLogger.Info("Began updating bets based on event results cron task")
|
||||
if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil {
|
||||
mongoLogger.Error("Failed to process result",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
mongoLogger.Info("Completed processing all event result outcomes without errors")
|
||||
}
|
||||
},
|
||||
},
|
||||
// {
|
||||
// spec: "0 0 * * * *", // Every 1 hour
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began fetching upcoming events cron task")
|
||||
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to fetch upcoming events",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Completed fetching upcoming events without errors")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began fetching non live odds cron task")
|
||||
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to fetch non live odds",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Completed fetching non live odds without errors")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 */5 * * * *", // Every 5 Minutes
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began update all expired events status cron task")
|
||||
// if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to update expired events status",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Completed expired events without errors")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 */15 * * * *", // Every 15 Minutes
|
||||
// task: func() {
|
||||
// mongoLogger.Info("Began updating bets based on event results cron task")
|
||||
// if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil {
|
||||
// mongoLogger.Error("Failed to process result",
|
||||
// zap.Error(err),
|
||||
// )
|
||||
// } else {
|
||||
// mongoLogger.Info("Completed processing all event result outcomes without errors")
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 0 0 * * 1", // Every Monday
|
||||
// task: func() {
|
||||
|
|
@ -96,7 +96,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
}
|
||||
|
||||
for _, job := range schedule {
|
||||
job.task()
|
||||
// job.task()
|
||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||
mongoLogger.Error("Failed to schedule data fetching cron job",
|
||||
zap.Error(err),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,23 @@ import (
|
|||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
||||
|
||||
func ParseLeagueIDFromQuery(c *fiber.Ctx) (domain.ValidInt64, error) {
|
||||
leagueIDQuery := c.Query("league_id")
|
||||
if leagueIDQuery != "" {
|
||||
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
|
||||
if err != nil {
|
||||
return domain.ValidInt64{}, fmt.Errorf("Failed to parse league_id %v: %w", leagueIDQuery, err)
|
||||
}
|
||||
return domain.ValidInt64{
|
||||
Value: leagueIDInt,
|
||||
Valid: true,
|
||||
}, nil
|
||||
}
|
||||
return domain.ValidInt64{}, nil
|
||||
}
|
||||
|
||||
// @Summary Retrieve all upcoming events
|
||||
// @Description Retrieve all upcoming events from the database
|
||||
// @Tags prematch
|
||||
|
|
@ -54,6 +71,14 @@ func (h *Handler) GetAllEvents(c *fiber.Ctx) error {
|
|||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Go through the all the handler functions and change them into something like this
|
||||
// leagueID, err := ParseLeagueIDFromQuery(c)
|
||||
// if err != nil {
|
||||
// h.BadRequestLogger().Info("invalid league id", zap.Error(err))
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
|
||||
// }
|
||||
|
||||
sportIDQuery := c.Query("sport_id")
|
||||
var sportID domain.ValidInt32
|
||||
if sportIDQuery != "" {
|
||||
|
|
@ -195,9 +220,207 @@ func (h *Handler) GetAllEvents(c *fiber.Ctx) error {
|
|||
res := domain.ConvertEventResList(events)
|
||||
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", res, nil, page, int(total))
|
||||
}
|
||||
|
||||
// @Summary Retrieve all upcoming events
|
||||
// @Description Retrieve all upcoming events from the database
|
||||
// @Tags prematch
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number"
|
||||
// @Param page_size query int false "Page size"
|
||||
// @Param league_id query string false "League ID Filter"
|
||||
// @Param sport_id query string false "Sport ID Filter"
|
||||
// @Param cc query string false "Country Code Filter"
|
||||
// @Param first_start_time query string false "Start Time"
|
||||
// @Param last_start_time query string false "End Time"
|
||||
// @Success 200 {array} domain.BaseEvent
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/detailed/events [get]
|
||||
func (h *Handler) GetAllDetailedEvents(c *fiber.Ctx) error {
|
||||
page := c.QueryInt("page", 1)
|
||||
pageSize := c.QueryInt("page_size", 10)
|
||||
limit := domain.ValidInt32{
|
||||
Value: int32(pageSize),
|
||||
Valid: true,
|
||||
}
|
||||
offset := domain.ValidInt32{
|
||||
Value: int32(page - 1),
|
||||
Valid: true,
|
||||
}
|
||||
|
||||
leagueIDQuery := c.Query("league_id")
|
||||
var leagueID domain.ValidInt64
|
||||
if leagueIDQuery != "" {
|
||||
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("invalid league id",
|
||||
zap.String("league_id", leagueIDQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
|
||||
}
|
||||
leagueID = domain.ValidInt64{
|
||||
Value: leagueIDInt,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Go through the all the handler functions and change them into something like this
|
||||
// leagueID, err := ParseLeagueIDFromQuery(c)
|
||||
// if err != nil {
|
||||
// h.BadRequestLogger().Info("invalid league id", zap.Error(err))
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
|
||||
// }
|
||||
|
||||
sportIDQuery := c.Query("sport_id")
|
||||
var sportID domain.ValidInt32
|
||||
if sportIDQuery != "" {
|
||||
sportIDint, err := strconv.Atoi(sportIDQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Info("invalid sport id",
|
||||
zap.String("sportID", sportIDQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid sport id")
|
||||
}
|
||||
sportID = domain.ValidInt32{
|
||||
Value: int32(sportIDint),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
searchQuery := c.Query("query")
|
||||
searchString := domain.ValidString{
|
||||
Value: searchQuery,
|
||||
Valid: searchQuery != "",
|
||||
}
|
||||
|
||||
firstStartTimeQuery := c.Query("first_start_time")
|
||||
var firstStartTime domain.ValidTime
|
||||
if firstStartTimeQuery != "" {
|
||||
firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Info("invalid start_time format",
|
||||
zap.String("first_start_time", firstStartTimeQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||
}
|
||||
firstStartTime = domain.ValidTime{
|
||||
Value: firstStartTimeParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
lastStartTimeQuery := c.Query("last_start_time")
|
||||
var lastStartTime domain.ValidTime
|
||||
if lastStartTimeQuery != "" {
|
||||
lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Info("invalid last_start_time format",
|
||||
zap.String("last_start_time", lastStartTimeQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||
}
|
||||
lastStartTime = domain.ValidTime{
|
||||
Value: lastStartTimeParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
countryCodeQuery := c.Query("cc")
|
||||
countryCode := domain.ValidString{
|
||||
Value: countryCodeQuery,
|
||||
Valid: countryCodeQuery != "",
|
||||
}
|
||||
|
||||
isFeaturedQuery := c.Query("is_featured")
|
||||
var isFeatured domain.ValidBool
|
||||
if isFeaturedQuery != "" {
|
||||
isFeaturedParsed, err := strconv.ParseBool(isFeaturedQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("Failed to parse isFeatured",
|
||||
zap.String("is_featured", isFeaturedQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_shop_bet")
|
||||
}
|
||||
|
||||
isFeatured = domain.ValidBool{
|
||||
Value: isFeaturedParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
isActiveQuery := c.Query("is_active")
|
||||
var isActive domain.ValidBool
|
||||
if isActiveQuery != "" {
|
||||
isActiveParsed, err := strconv.ParseBool(isActiveQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("Failed to parse isActive",
|
||||
zap.String("is_active", isActiveQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_active")
|
||||
}
|
||||
|
||||
isActive = domain.ValidBool{
|
||||
Value: isActiveParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
statusQuery := c.Query("status")
|
||||
var eventStatus domain.ValidEventStatus
|
||||
if statusQuery != "" {
|
||||
eventStatusParsed, err := domain.ParseEventStatus(statusQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("Failed to parse statusQuery",
|
||||
zap.String("is_featured", isFeaturedQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid event status string")
|
||||
}
|
||||
eventStatus = domain.ValidEventStatus{
|
||||
Value: eventStatusParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
events, total, err := h.eventSvc.GetAllDetailedEvents(
|
||||
c.Context(), domain.EventFilter{
|
||||
SportID: sportID,
|
||||
LeagueID: leagueID,
|
||||
Query: searchString,
|
||||
FirstStartTime: firstStartTime,
|
||||
LastStartTime: lastStartTime,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
CountryCode: countryCode,
|
||||
Featured: isFeatured,
|
||||
Active: isActive,
|
||||
Status: eventStatus,
|
||||
})
|
||||
|
||||
// fmt.Printf("League ID: %v", leagueID)
|
||||
if err != nil {
|
||||
h.InternalServerErrorLogger().Error("Failed to retrieve all upcoming events",
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
res := domain.ConvertDetailedEventResList(events)
|
||||
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", res, nil, page, int(total))
|
||||
}
|
||||
|
||||
func (h *Handler) ExportEvents(c *fiber.Ctx) error {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// @Summary Retrieve all upcoming events with settings
|
||||
// @Description Retrieve all upcoming events settings from the database
|
||||
// @Tags prematch
|
||||
|
|
@ -676,6 +899,40 @@ func (h *Handler) GetEventByID(c *fiber.Ctx) error {
|
|||
|
||||
}
|
||||
|
||||
// @Summary Retrieve an upcoming by ID
|
||||
// @Description Retrieve an upcoming event by ID
|
||||
// @Tags prematch
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID"
|
||||
// @Success 200 {object} domain.BaseEvent
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/detailed/events/{id} [get]
|
||||
func (h *Handler) GetDetailedEventByID(c *fiber.Ctx) error {
|
||||
|
||||
idStr := c.Params("id")
|
||||
eventID, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
|
||||
}
|
||||
|
||||
event, err := h.eventSvc.GetDetailedEventByID(c.Context(), eventID)
|
||||
if err != nil {
|
||||
h.InternalServerErrorLogger().Error("Failed to get event by id",
|
||||
zap.Int64("eventID", eventID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
res := domain.ConvertDetailedEventRes(event)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", res, nil)
|
||||
|
||||
}
|
||||
|
||||
// @Summary Retrieve an upcoming by ID
|
||||
// @Description Retrieve an upcoming event by ID
|
||||
// @Tags prematch
|
||||
|
|
|
|||
120
internal/web_server/handlers/event_stats_handler.go
Normal file
120
internal/web_server/handlers/event_stats_handler.go
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (h *Handler) GetEventStats(c *fiber.Ctx) error {
|
||||
leagueIDQuery := c.Query("league_id")
|
||||
var leagueID domain.ValidInt64
|
||||
if leagueIDQuery != "" {
|
||||
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("invalid league id",
|
||||
zap.String("league_id", leagueIDQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
|
||||
}
|
||||
leagueID = domain.ValidInt64{
|
||||
Value: leagueIDInt,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
sportIDQuery := c.Query("sport_id")
|
||||
var sportID domain.ValidInt32
|
||||
if sportIDQuery != "" {
|
||||
sportIDint, err := strconv.Atoi(sportIDQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Info("invalid sport id",
|
||||
zap.String("sportID", sportIDQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid sport id")
|
||||
}
|
||||
sportID = domain.ValidInt32{
|
||||
Value: int32(sportIDint),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
stats, err := h.eventSvc.GetEventStats(c.Context(), domain.EventStatsFilter{
|
||||
LeagueID: leagueID,
|
||||
SportID: sportID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
h.InternalServerErrorLogger().Error("Failed to retrieve event status",
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Event Statistics retrieved successfully", stats, nil)
|
||||
}
|
||||
|
||||
func (h *Handler) GetEventStatsByInterval(c *fiber.Ctx) error {
|
||||
intervalParam := c.Query("interval", "day")
|
||||
interval, err := domain.ParseDateInterval(intervalParam)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("invalid date interval",
|
||||
zap.String("interval", c.Query("interval", "day")),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid date interval")
|
||||
}
|
||||
leagueIDQuery := c.Query("league_id")
|
||||
var leagueID domain.ValidInt64
|
||||
if leagueIDQuery != "" {
|
||||
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Error("invalid league id",
|
||||
zap.String("league_id", leagueIDQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
|
||||
}
|
||||
leagueID = domain.ValidInt64{
|
||||
Value: leagueIDInt,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
sportIDQuery := c.Query("sport_id")
|
||||
var sportID domain.ValidInt32
|
||||
if sportIDQuery != "" {
|
||||
sportIDint, err := strconv.Atoi(sportIDQuery)
|
||||
if err != nil {
|
||||
h.BadRequestLogger().Info("invalid sport id",
|
||||
zap.String("sportID", sportIDQuery),
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid sport id")
|
||||
}
|
||||
sportID = domain.ValidInt32{
|
||||
Value: int32(sportIDint),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
stats, err := h.eventSvc.GetEventStatsByInterval(c.Context(), domain.EventStatsByIntervalFilter{
|
||||
Interval: interval,
|
||||
LeagueID: leagueID,
|
||||
SportID: sportID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
h.InternalServerErrorLogger().Error("Failed to retrieve event status interval",
|
||||
zap.Error(err),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Event Statistics retrieved successfully", stats, nil)
|
||||
}
|
||||
|
|
@ -276,6 +276,12 @@ func (a *App) initAppRoutes() {
|
|||
groupV1.Put("/events/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
|
||||
groupV1.Get("/events/:id/bets", a.authMiddleware, a.SuperAdminOnly, h.GetBetsByEventID)
|
||||
|
||||
groupV1.Get("/detailed/events", a.authMiddleware, h.GetAllDetailedEvents)
|
||||
groupV1.Get("/detailed/events/:id", a.authMiddleware, h.GetDetailedEventByID)
|
||||
|
||||
groupV1.Get("/stats/total/events", h.GetEventStats)
|
||||
groupV1.Get("/stats/interval/events", h.GetEventStatsByInterval)
|
||||
|
||||
tenant.Get("/upcoming-events", h.GetTenantUpcomingEvents)
|
||||
tenant.Get("/top-leagues", h.GetTopLeagues)
|
||||
tenant.Get("/events", h.GetTenantEvents)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user