gitignore fix
This commit is contained in:
commit
49527cbf2a
|
|
@ -119,8 +119,8 @@ func main() {
|
||||||
branchSvc := branch.NewService(store)
|
branchSvc := branch.NewService(store)
|
||||||
companySvc := company.NewService(store)
|
companySvc := company.NewService(store)
|
||||||
leagueSvc := league.New(store)
|
leagueSvc := league.New(store)
|
||||||
betSvc := bet.NewService(store, eventSvc, oddsSvc, *walletSvc, *branchSvc, logger, domain.MongoDBLogger)
|
betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, logger, domain.MongoDBLogger)
|
||||||
resultSvc := result.NewService(store, cfg, logger, *betSvc)
|
resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc)
|
||||||
referalRepo := repository.NewReferralRepository(store)
|
referalRepo := repository.NewReferralRepository(store)
|
||||||
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
||||||
recommendationRepo := repository.NewRecommendationRepository(store)
|
recommendationRepo := repository.NewRecommendationRepository(store)
|
||||||
|
|
@ -177,8 +177,7 @@ func main() {
|
||||||
)
|
)
|
||||||
walletMonitorSvc.Start()
|
walletMonitorSvc.Start()
|
||||||
|
|
||||||
// Start other cron jobs
|
httpserver.StartDataFetchingCrons(eventSvc, *oddsSvc, resultSvc)
|
||||||
httpserver.StartDataFetchingCrons(eventSvc, oddsSvc, resultSvc)
|
|
||||||
httpserver.StartTicketCrons(*ticketSvc)
|
httpserver.StartTicketCrons(*ticketSvc)
|
||||||
go httpserver.SetupReportCronJob(reportWorker)
|
go httpserver.SetupReportCronJob(reportWorker)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ CREATE TABLE IF NOT EXISTS tickets (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
amount BIGINT NOT NULL,
|
amount BIGINT NOT NULL,
|
||||||
total_odds REAL NOT NULL,
|
total_odds REAL NOT NULL,
|
||||||
|
IP VARCHAR(255) NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
@ -240,6 +241,7 @@ CREATE TABLE leagues (
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
country_code TEXT,
|
country_code TEXT,
|
||||||
bet365_id INT,
|
bet365_id INT,
|
||||||
|
sport_id INT NOT NULL,
|
||||||
is_active BOOLEAN DEFAULT true
|
is_active BOOLEAN DEFAULT true
|
||||||
);
|
);
|
||||||
CREATE TABLE teams (
|
CREATE TABLE teams (
|
||||||
|
|
@ -265,9 +267,11 @@ FROM companies
|
||||||
CREATE VIEW branch_details AS
|
CREATE VIEW branch_details AS
|
||||||
SELECT branches.*,
|
SELECT branches.*,
|
||||||
CONCAT(users.first_name, ' ', users.last_name) AS manager_name,
|
CONCAT(users.first_name, ' ', users.last_name) AS manager_name,
|
||||||
users.phone_number AS manager_phone_number
|
users.phone_number AS manager_phone_number,
|
||||||
|
wallets.balance
|
||||||
FROM branches
|
FROM branches
|
||||||
LEFT JOIN users ON branches.branch_manager_id = users.id;
|
LEFT JOIN users ON branches.branch_manager_id = users.id
|
||||||
|
LEFT JOin wallets ON wallets.id = branches.wallet_id;
|
||||||
CREATE TABLE IF NOT EXISTS supported_operations (
|
CREATE TABLE IF NOT EXISTS supported_operations (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,24 @@
|
||||||
SELECT users.*
|
SELECT users.*
|
||||||
FROM branch_cashiers
|
FROM branch_cashiers
|
||||||
JOIN users ON branch_cashiers.user_id = users.id
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
JOIN branches ON branches.id = branch_id
|
||||||
WHERE branch_cashiers.branch_id = $1;
|
WHERE branch_cashiers.branch_id = $1;
|
||||||
-- name: GetAllCashiers :many
|
-- name: GetAllCashiers :many
|
||||||
SELECT users.*,
|
SELECT users.*,
|
||||||
branch_id
|
branch_id,
|
||||||
|
branches.name AS branch_name,
|
||||||
|
branches.wallet_id AS branch_wallet,
|
||||||
|
branches.location As branch_location
|
||||||
FROM branch_cashiers
|
FROM branch_cashiers
|
||||||
JOIN users ON branch_cashiers.user_id = users.id;
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
JOIN branches ON branches.id = branch_id;
|
||||||
-- name: GetCashierByID :one
|
-- name: GetCashierByID :one
|
||||||
SELECT users.*,
|
SELECT users.*,
|
||||||
branch_id
|
branch_id,
|
||||||
|
branches.name AS branch_name,
|
||||||
|
branches.wallet_id AS branch_wallet,
|
||||||
|
branches.location As branch_location
|
||||||
FROM branch_cashiers
|
FROM branch_cashiers
|
||||||
JOIN users ON branch_cashiers.user_id = $1;
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
JOIN branches ON branches.id = branch_id
|
||||||
|
WHERE users.id = $1;
|
||||||
|
|
@ -144,33 +144,40 @@ SELECT id,
|
||||||
source,
|
source,
|
||||||
fetched_at
|
fetched_at
|
||||||
FROM events
|
FROM events
|
||||||
WHERE is_live = false
|
WHERE start_time > now()
|
||||||
|
AND is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
ORDER BY start_time ASC;
|
ORDER BY start_time ASC;
|
||||||
-- name: GetExpiredUpcomingEvents :many
|
-- name: GetExpiredUpcomingEvents :many
|
||||||
SELECT id,
|
SELECT events.id,
|
||||||
sport_id,
|
events.sport_id,
|
||||||
match_name,
|
events.match_name,
|
||||||
home_team,
|
events.home_team,
|
||||||
away_team,
|
events.away_team,
|
||||||
home_team_id,
|
events.home_team_id,
|
||||||
away_team_id,
|
events.away_team_id,
|
||||||
home_kit_image,
|
events.home_kit_image,
|
||||||
away_kit_image,
|
events.away_kit_image,
|
||||||
league_id,
|
events.league_id,
|
||||||
league_name,
|
events.league_name,
|
||||||
league_cc,
|
events.start_time,
|
||||||
start_time,
|
events.is_live,
|
||||||
is_live,
|
events.status,
|
||||||
status,
|
events.source,
|
||||||
source,
|
events.fetched_at,
|
||||||
fetched_at
|
leagues.country_code as league_cc
|
||||||
FROM events
|
FROM events
|
||||||
|
LEFT JOIN leagues ON leagues.id = league_id
|
||||||
WHERE start_time < now()
|
WHERE start_time < now()
|
||||||
|
and (
|
||||||
|
status = sqlc.narg('status')
|
||||||
|
OR sqlc.narg('status') IS NULL
|
||||||
|
)
|
||||||
ORDER BY start_time ASC;
|
ORDER BY start_time ASC;
|
||||||
-- name: GetTotalEvents :one
|
-- name: GetTotalEvents :one
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM events
|
FROM events
|
||||||
|
LEFT JOIN leagues ON leagues.id = league_id
|
||||||
WHERE is_live = false
|
WHERE is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
AND (
|
AND (
|
||||||
|
|
@ -178,7 +185,7 @@ WHERE is_live = false
|
||||||
OR sqlc.narg('league_id') IS NULL
|
OR sqlc.narg('league_id') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
sport_id = sqlc.narg('sport_id')
|
events.sport_id = sqlc.narg('sport_id')
|
||||||
OR sqlc.narg('sport_id') IS NULL
|
OR sqlc.narg('sport_id') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
|
|
@ -188,34 +195,40 @@ WHERE is_live = false
|
||||||
AND (
|
AND (
|
||||||
start_time > sqlc.narg('first_start_time')
|
start_time > sqlc.narg('first_start_time')
|
||||||
OR sqlc.narg('first_start_time') IS NULL
|
OR sqlc.narg('first_start_time') IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
leagues.country_code = sqlc.narg('country_code')
|
||||||
|
OR sqlc.narg('country_code') IS NULL
|
||||||
);
|
);
|
||||||
-- name: GetPaginatedUpcomingEvents :many
|
-- name: GetPaginatedUpcomingEvents :many
|
||||||
SELECT id,
|
SELECT events.id,
|
||||||
sport_id,
|
events.sport_id,
|
||||||
match_name,
|
events.match_name,
|
||||||
home_team,
|
events.home_team,
|
||||||
away_team,
|
events.away_team,
|
||||||
home_team_id,
|
events.home_team_id,
|
||||||
away_team_id,
|
events.away_team_id,
|
||||||
home_kit_image,
|
events.home_kit_image,
|
||||||
away_kit_image,
|
events.away_kit_image,
|
||||||
league_id,
|
events.league_id,
|
||||||
league_name,
|
events.league_name,
|
||||||
league_cc,
|
events.start_time,
|
||||||
start_time,
|
events.is_live,
|
||||||
is_live,
|
events.status,
|
||||||
status,
|
events.source,
|
||||||
source,
|
events.fetched_at,
|
||||||
fetched_at
|
leagues.country_code as league_cc
|
||||||
FROM events
|
FROM events
|
||||||
WHERE is_live = false
|
LEFT JOIN leagues ON leagues.id = league_id
|
||||||
|
WHERE start_time > now()
|
||||||
|
AND is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
AND (
|
AND (
|
||||||
league_id = sqlc.narg('league_id')
|
league_id = sqlc.narg('league_id')
|
||||||
OR sqlc.narg('league_id') IS NULL
|
OR sqlc.narg('league_id') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
sport_id = sqlc.narg('sport_id')
|
events.sport_id = sqlc.narg('sport_id')
|
||||||
OR sqlc.narg('sport_id') IS NULL
|
OR sqlc.narg('sport_id') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
|
|
@ -226,6 +239,10 @@ WHERE is_live = false
|
||||||
start_time > sqlc.narg('first_start_time')
|
start_time > sqlc.narg('first_start_time')
|
||||||
OR sqlc.narg('first_start_time') IS NULL
|
OR sqlc.narg('first_start_time') IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
leagues.country_code = sqlc.narg('country_code')
|
||||||
|
OR sqlc.narg('country_code') IS NULL
|
||||||
|
)
|
||||||
ORDER BY start_time ASC
|
ORDER BY start_time ASC
|
||||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||||
-- name: GetUpcomingByID :one
|
-- name: GetUpcomingByID :one
|
||||||
|
|
|
||||||
|
|
@ -4,45 +4,61 @@ INSERT INTO leagues (
|
||||||
name,
|
name,
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
|
sport_id,
|
||||||
is_active
|
is_active
|
||||||
) VALUES (
|
)
|
||||||
$1, $2, $3, $4, $5
|
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO
|
||||||
)
|
UPDATE
|
||||||
ON CONFLICT (id) DO UPDATE
|
|
||||||
SET name = EXCLUDED.name,
|
SET name = EXCLUDED.name,
|
||||||
country_code = EXCLUDED.country_code,
|
country_code = EXCLUDED.country_code,
|
||||||
bet365_id = EXCLUDED.bet365_id,
|
bet365_id = EXCLUDED.bet365_id,
|
||||||
is_active = EXCLUDED.is_active;
|
is_active = EXCLUDED.is_active,
|
||||||
-- name: GetSupportedLeagues :many
|
sport_id = EXCLUDED.sport_id;
|
||||||
SELECT id,
|
|
||||||
name,
|
|
||||||
country_code,
|
|
||||||
bet365_id,
|
|
||||||
is_active
|
|
||||||
FROM leagues
|
|
||||||
WHERE is_active = true;
|
|
||||||
-- name: GetAllLeagues :many
|
-- name: GetAllLeagues :many
|
||||||
SELECT id,
|
SELECT id,
|
||||||
name,
|
name,
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
is_active
|
is_active,
|
||||||
FROM leagues;
|
sport_id
|
||||||
|
FROM leagues
|
||||||
|
WHERE (
|
||||||
|
country_code = sqlc.narg('country_code')
|
||||||
|
OR sqlc.narg('country_code') IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
sport_id = sqlc.narg('sport_id')
|
||||||
|
OR sqlc.narg('sport_id') IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
is_active = sqlc.narg('is_active')
|
||||||
|
OR sqlc.narg('is_active') IS NULL
|
||||||
|
)
|
||||||
|
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||||
-- name: CheckLeagueSupport :one
|
-- name: CheckLeagueSupport :one
|
||||||
SELECT EXISTS(
|
SELECT EXISTS(
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM leagues
|
FROM leagues
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
AND is_active = true
|
AND is_active = true
|
||||||
);
|
);
|
||||||
-- name: UpdateLeague :exec
|
-- name: UpdateLeague :exec
|
||||||
UPDATE leagues
|
UPDATE leagues
|
||||||
SET name = $1,
|
SET name = COALESCE(sqlc.narg('name'), name),
|
||||||
country_code = $2,
|
country_code = COALESCE(sqlc.narg('country_code'), country_code),
|
||||||
bet365_id = $3,
|
bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id),
|
||||||
is_active = $4
|
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
||||||
WHERE id = $5;
|
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: UpdateLeagueByBet365ID :exec
|
||||||
|
UPDATE leagues
|
||||||
|
SET name = COALESCE(sqlc.narg('name'), name),
|
||||||
|
id = COALESCE(sqlc.narg('id'), id),
|
||||||
|
country_code = COALESCE(sqlc.narg('country_code'), country_code),
|
||||||
|
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
||||||
|
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
|
||||||
|
WHERE bet365_id = $1;
|
||||||
-- name: SetLeagueActive :exec
|
-- name: SetLeagueActive :exec
|
||||||
UPDATE leagues
|
UPDATE leagues
|
||||||
SET is_active = true
|
SET is_active = $2
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
@ -63,7 +63,7 @@ SELECT event_id,
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE is_active = true
|
WHERE is_active = true
|
||||||
AND source = 'b365api';
|
AND source = 'bet365';
|
||||||
-- name: GetALLPrematchOdds :many
|
-- name: GetALLPrematchOdds :many
|
||||||
SELECT event_id,
|
SELECT event_id,
|
||||||
fi,
|
fi,
|
||||||
|
|
@ -82,7 +82,7 @@ SELECT event_id,
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE is_active = true
|
WHERE is_active = true
|
||||||
AND source = 'b365api';
|
AND source = 'bet365';
|
||||||
-- name: GetRawOddsByMarketID :one
|
-- name: GetRawOddsByMarketID :one
|
||||||
SELECT id,
|
SELECT id,
|
||||||
market_name,
|
market_name,
|
||||||
|
|
@ -93,7 +93,7 @@ FROM odds
|
||||||
WHERE market_id = $1
|
WHERE market_id = $1
|
||||||
AND fi = $2
|
AND fi = $2
|
||||||
AND is_active = true
|
AND is_active = true
|
||||||
AND source = 'b365api';
|
AND source = 'bet365';
|
||||||
-- name: GetPrematchOddsByUpcomingID :many
|
-- name: GetPrematchOddsByUpcomingID :many
|
||||||
SELECT o.*
|
SELECT o.*
|
||||||
FROM odds o
|
FROM odds o
|
||||||
|
|
@ -102,7 +102,7 @@ WHERE e.id = $1
|
||||||
AND e.is_live = false
|
AND e.is_live = false
|
||||||
AND e.status = 'upcoming'
|
AND e.status = 'upcoming'
|
||||||
AND o.is_active = true
|
AND o.is_active = true
|
||||||
AND o.source = 'b365api';
|
AND o.source = 'bet365';
|
||||||
-- name: GetPaginatedPrematchOddsByUpcomingID :many
|
-- name: GetPaginatedPrematchOddsByUpcomingID :many
|
||||||
SELECT o.*
|
SELECT o.*
|
||||||
FROM odds o
|
FROM odds o
|
||||||
|
|
@ -111,5 +111,8 @@ WHERE e.id = $1
|
||||||
AND e.is_live = false
|
AND e.is_live = false
|
||||||
AND e.status = 'upcoming'
|
AND e.status = 'upcoming'
|
||||||
AND o.is_active = true
|
AND o.is_active = true
|
||||||
AND o.source = 'b365api'
|
AND o.source = 'bet365'
|
||||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||||
|
-- name: DeleteOddsForEvent :exec
|
||||||
|
DELETE FROM odds
|
||||||
|
Where fi = $1;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
-- name: CreateTicket :one
|
-- name: CreateTicket :one
|
||||||
INSERT INTO tickets (amount, total_odds)
|
INSERT INTO tickets (amount, total_odds, ip)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2, $3)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
-- name: CreateTicketOutcome :copyfrom
|
-- name: CreateTicketOutcome :copyfrom
|
||||||
INSERT INTO ticket_outcomes (
|
INSERT INTO ticket_outcomes (
|
||||||
|
|
@ -42,6 +42,10 @@ WHERE id = $1;
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM ticket_outcomes
|
FROM ticket_outcomes
|
||||||
WHERE ticket_id = $1;
|
WHERE ticket_id = $1;
|
||||||
|
-- name: CountTicketByIP :one
|
||||||
|
SELECT count(id)
|
||||||
|
FROM tickets
|
||||||
|
WHERE IP = $1;
|
||||||
-- name: UpdateTicketOutcomeStatus :exec
|
-- name: UpdateTicketOutcomeStatus :exec
|
||||||
UPDATE ticket_outcomes
|
UPDATE ticket_outcomes
|
||||||
SET status = $1
|
SET status = $1
|
||||||
|
|
|
||||||
47
docs/docs.go
47
docs/docs.go
|
|
@ -2850,6 +2850,53 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/result/{id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get results for an event",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"result"
|
||||||
|
],
|
||||||
|
"summary": "Get results for an event",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Event ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.BetOutcome"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/search/branch": {
|
"/search/branch": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Search branches by name or location",
|
"description": "Search branches by name or location",
|
||||||
|
|
|
||||||
|
|
@ -2842,6 +2842,53 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/result/{id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get results for an event",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"result"
|
||||||
|
],
|
||||||
|
"summary": "Get results for an event",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Event ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.BetOutcome"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/search/branch": {
|
"/search/branch": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Search branches by name or location",
|
"description": "Search branches by name or location",
|
||||||
|
|
|
||||||
|
|
@ -3318,6 +3318,37 @@ paths:
|
||||||
summary: Get referral statistics
|
summary: Get referral statistics
|
||||||
tags:
|
tags:
|
||||||
- referral
|
- referral
|
||||||
|
/result/{id}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Get results for an event
|
||||||
|
parameters:
|
||||||
|
- description: Event ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.BetOutcome'
|
||||||
|
type: array
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Get results for an event
|
||||||
|
tags:
|
||||||
|
- result
|
||||||
/search/branch:
|
/search/branch:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: auth.sql
|
// source: auth.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: bet.sql
|
// source: bet.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: branch.sql
|
// source: branch.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -155,7 +155,7 @@ func (q *Queries) DeleteBranchOperation(ctx context.Context, arg DeleteBranchOpe
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllBranches = `-- name: GetAllBranches :many
|
const GetAllBranches = `-- name: GetAllBranches :many
|
||||||
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -181,6 +181,7 @@ func (q *Queries) GetAllBranches(ctx context.Context) ([]BranchDetail, error) {
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ManagerName,
|
&i.ManagerName,
|
||||||
&i.ManagerPhoneNumber,
|
&i.ManagerPhoneNumber,
|
||||||
|
&i.Balance,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +244,7 @@ func (q *Queries) GetBranchByCashier(ctx context.Context, userID int64) (Branch,
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBranchByCompanyID = `-- name: GetBranchByCompanyID :many
|
const GetBranchByCompanyID = `-- name: GetBranchByCompanyID :many
|
||||||
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
WHERE company_id = $1
|
WHERE company_id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -270,6 +271,7 @@ func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ManagerName,
|
&i.ManagerName,
|
||||||
&i.ManagerPhoneNumber,
|
&i.ManagerPhoneNumber,
|
||||||
|
&i.Balance,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -282,7 +284,7 @@ func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBranchByID = `-- name: GetBranchByID :one
|
const GetBranchByID = `-- name: GetBranchByID :one
|
||||||
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -303,12 +305,13 @@ func (q *Queries) GetBranchByID(ctx context.Context, id int64) (BranchDetail, er
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ManagerName,
|
&i.ManagerName,
|
||||||
&i.ManagerPhoneNumber,
|
&i.ManagerPhoneNumber,
|
||||||
|
&i.Balance,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBranchByManagerID = `-- name: GetBranchByManagerID :many
|
const GetBranchByManagerID = `-- name: GetBranchByManagerID :many
|
||||||
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
WHERE branch_manager_id = $1
|
WHERE branch_manager_id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -335,6 +338,7 @@ func (q *Queries) GetBranchByManagerID(ctx context.Context, branchManagerID int6
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ManagerName,
|
&i.ManagerName,
|
||||||
&i.ManagerPhoneNumber,
|
&i.ManagerPhoneNumber,
|
||||||
|
&i.Balance,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -394,7 +398,7 @@ func (q *Queries) GetBranchOperations(ctx context.Context, branchID int64) ([]Ge
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchBranchByName = `-- name: SearchBranchByName :many
|
const SearchBranchByName = `-- name: SearchBranchByName :many
|
||||||
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
WHERE name ILIKE '%' || $1 || '%'
|
WHERE name ILIKE '%' || $1 || '%'
|
||||||
`
|
`
|
||||||
|
|
@ -421,6 +425,7 @@ func (q *Queries) SearchBranchByName(ctx context.Context, dollar_1 pgtype.Text)
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.ManagerName,
|
&i.ManagerName,
|
||||||
&i.ManagerPhoneNumber,
|
&i.ManagerPhoneNumber,
|
||||||
|
&i.Balance,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: cashier.sql
|
// source: cashier.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -13,9 +13,13 @@ import (
|
||||||
|
|
||||||
const GetAllCashiers = `-- name: GetAllCashiers :many
|
const GetAllCashiers = `-- name: GetAllCashiers :many
|
||||||
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by,
|
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by,
|
||||||
branch_id
|
branch_id,
|
||||||
|
branches.name AS branch_name,
|
||||||
|
branches.wallet_id AS branch_wallet,
|
||||||
|
branches.location As branch_location
|
||||||
FROM branch_cashiers
|
FROM branch_cashiers
|
||||||
JOIN users ON branch_cashiers.user_id = users.id
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
JOIN branches ON branches.id = branch_id
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetAllCashiersRow struct {
|
type GetAllCashiersRow struct {
|
||||||
|
|
@ -36,6 +40,9 @@ type GetAllCashiersRow struct {
|
||||||
ReferralCode pgtype.Text `json:"referral_code"`
|
ReferralCode pgtype.Text `json:"referral_code"`
|
||||||
ReferredBy pgtype.Text `json:"referred_by"`
|
ReferredBy pgtype.Text `json:"referred_by"`
|
||||||
BranchID int64 `json:"branch_id"`
|
BranchID int64 `json:"branch_id"`
|
||||||
|
BranchName string `json:"branch_name"`
|
||||||
|
BranchWallet int64 `json:"branch_wallet"`
|
||||||
|
BranchLocation string `json:"branch_location"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetAllCashiers(ctx context.Context) ([]GetAllCashiersRow, error) {
|
func (q *Queries) GetAllCashiers(ctx context.Context) ([]GetAllCashiersRow, error) {
|
||||||
|
|
@ -65,6 +72,9 @@ func (q *Queries) GetAllCashiers(ctx context.Context) ([]GetAllCashiersRow, erro
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferredBy,
|
&i.ReferredBy,
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
|
&i.BranchName,
|
||||||
|
&i.BranchWallet,
|
||||||
|
&i.BranchLocation,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -78,9 +88,14 @@ func (q *Queries) GetAllCashiers(ctx context.Context) ([]GetAllCashiersRow, erro
|
||||||
|
|
||||||
const GetCashierByID = `-- name: GetCashierByID :one
|
const GetCashierByID = `-- name: GetCashierByID :one
|
||||||
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by,
|
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by,
|
||||||
branch_id
|
branch_id,
|
||||||
|
branches.name AS branch_name,
|
||||||
|
branches.wallet_id AS branch_wallet,
|
||||||
|
branches.location As branch_location
|
||||||
FROM branch_cashiers
|
FROM branch_cashiers
|
||||||
JOIN users ON branch_cashiers.user_id = $1
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
JOIN branches ON branches.id = branch_id
|
||||||
|
WHERE users.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetCashierByIDRow struct {
|
type GetCashierByIDRow struct {
|
||||||
|
|
@ -101,10 +116,13 @@ type GetCashierByIDRow struct {
|
||||||
ReferralCode pgtype.Text `json:"referral_code"`
|
ReferralCode pgtype.Text `json:"referral_code"`
|
||||||
ReferredBy pgtype.Text `json:"referred_by"`
|
ReferredBy pgtype.Text `json:"referred_by"`
|
||||||
BranchID int64 `json:"branch_id"`
|
BranchID int64 `json:"branch_id"`
|
||||||
|
BranchName string `json:"branch_name"`
|
||||||
|
BranchWallet int64 `json:"branch_wallet"`
|
||||||
|
BranchLocation string `json:"branch_location"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetCashierByID(ctx context.Context, userID int64) (GetCashierByIDRow, error) {
|
func (q *Queries) GetCashierByID(ctx context.Context, id int64) (GetCashierByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetCashierByID, userID)
|
row := q.db.QueryRow(ctx, GetCashierByID, id)
|
||||||
var i GetCashierByIDRow
|
var i GetCashierByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
|
@ -124,6 +142,9 @@ func (q *Queries) GetCashierByID(ctx context.Context, userID int64) (GetCashierB
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferredBy,
|
&i.ReferredBy,
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
|
&i.BranchName,
|
||||||
|
&i.BranchWallet,
|
||||||
|
&i.BranchLocation,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -132,6 +153,7 @@ const GetCashiersByBranch = `-- name: GetCashiersByBranch :many
|
||||||
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by
|
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by
|
||||||
FROM branch_cashiers
|
FROM branch_cashiers
|
||||||
JOIN users ON branch_cashiers.user_id = users.id
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
JOIN branches ON branches.id = branch_id
|
||||||
WHERE branch_cashiers.branch_id = $1
|
WHERE branch_cashiers.branch_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: company.sql
|
// source: company.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: copyfrom.go
|
// source: copyfrom.go
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: events.sql
|
// source: events.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -40,7 +40,8 @@ SELECT id,
|
||||||
source,
|
source,
|
||||||
fetched_at
|
fetched_at
|
||||||
FROM events
|
FROM events
|
||||||
WHERE is_live = false
|
WHERE start_time > now()
|
||||||
|
AND is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
ORDER BY start_time ASC
|
ORDER BY start_time ASC
|
||||||
`
|
`
|
||||||
|
|
@ -104,25 +105,30 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]GetAllUpcomingEve
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetExpiredUpcomingEvents = `-- name: GetExpiredUpcomingEvents :many
|
const GetExpiredUpcomingEvents = `-- name: GetExpiredUpcomingEvents :many
|
||||||
SELECT id,
|
SELECT events.id,
|
||||||
sport_id,
|
events.sport_id,
|
||||||
match_name,
|
events.match_name,
|
||||||
home_team,
|
events.home_team,
|
||||||
away_team,
|
events.away_team,
|
||||||
home_team_id,
|
events.home_team_id,
|
||||||
away_team_id,
|
events.away_team_id,
|
||||||
home_kit_image,
|
events.home_kit_image,
|
||||||
away_kit_image,
|
events.away_kit_image,
|
||||||
league_id,
|
events.league_id,
|
||||||
league_name,
|
events.league_name,
|
||||||
league_cc,
|
events.start_time,
|
||||||
start_time,
|
events.is_live,
|
||||||
is_live,
|
events.status,
|
||||||
status,
|
events.source,
|
||||||
source,
|
events.fetched_at,
|
||||||
fetched_at
|
leagues.country_code as league_cc
|
||||||
FROM events
|
FROM events
|
||||||
|
LEFT JOIN leagues ON leagues.id = league_id
|
||||||
WHERE start_time < now()
|
WHERE start_time < now()
|
||||||
|
and (
|
||||||
|
status = $1
|
||||||
|
OR $1 IS NULL
|
||||||
|
)
|
||||||
ORDER BY start_time ASC
|
ORDER BY start_time ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -138,16 +144,16 @@ type GetExpiredUpcomingEventsRow struct {
|
||||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
LeagueID pgtype.Int4 `json:"league_id"`
|
LeagueID pgtype.Int4 `json:"league_id"`
|
||||||
LeagueName pgtype.Text `json:"league_name"`
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
LeagueCc pgtype.Text `json:"league_cc"`
|
|
||||||
StartTime pgtype.Timestamp `json:"start_time"`
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
IsLive pgtype.Bool `json:"is_live"`
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
Status pgtype.Text `json:"status"`
|
Status pgtype.Text `json:"status"`
|
||||||
Source pgtype.Text `json:"source"`
|
Source pgtype.Text `json:"source"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context) ([]GetExpiredUpcomingEventsRow, error) {
|
func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context, status pgtype.Text) ([]GetExpiredUpcomingEventsRow, error) {
|
||||||
rows, err := q.db.Query(ctx, GetExpiredUpcomingEvents)
|
rows, err := q.db.Query(ctx, GetExpiredUpcomingEvents, status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -167,12 +173,12 @@ func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context) ([]GetExpiredUpc
|
||||||
&i.AwayKitImage,
|
&i.AwayKitImage,
|
||||||
&i.LeagueID,
|
&i.LeagueID,
|
||||||
&i.LeagueName,
|
&i.LeagueName,
|
||||||
&i.LeagueCc,
|
|
||||||
&i.StartTime,
|
&i.StartTime,
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.LeagueCc,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -185,32 +191,34 @@ func (q *Queries) GetExpiredUpcomingEvents(ctx context.Context) ([]GetExpiredUpc
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetPaginatedUpcomingEvents = `-- name: GetPaginatedUpcomingEvents :many
|
const GetPaginatedUpcomingEvents = `-- name: GetPaginatedUpcomingEvents :many
|
||||||
SELECT id,
|
SELECT events.id,
|
||||||
sport_id,
|
events.sport_id,
|
||||||
match_name,
|
events.match_name,
|
||||||
home_team,
|
events.home_team,
|
||||||
away_team,
|
events.away_team,
|
||||||
home_team_id,
|
events.home_team_id,
|
||||||
away_team_id,
|
events.away_team_id,
|
||||||
home_kit_image,
|
events.home_kit_image,
|
||||||
away_kit_image,
|
events.away_kit_image,
|
||||||
league_id,
|
events.league_id,
|
||||||
league_name,
|
events.league_name,
|
||||||
league_cc,
|
events.start_time,
|
||||||
start_time,
|
events.is_live,
|
||||||
is_live,
|
events.status,
|
||||||
status,
|
events.source,
|
||||||
source,
|
events.fetched_at,
|
||||||
fetched_at
|
leagues.country_code as league_cc
|
||||||
FROM events
|
FROM events
|
||||||
WHERE is_live = false
|
LEFT JOIN leagues ON leagues.id = league_id
|
||||||
|
WHERE start_time > now()
|
||||||
|
AND is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
AND (
|
AND (
|
||||||
league_id = $1
|
league_id = $1
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
sport_id = $2
|
events.sport_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
|
|
@ -221,8 +229,12 @@ WHERE is_live = false
|
||||||
start_time > $4
|
start_time > $4
|
||||||
OR $4 IS NULL
|
OR $4 IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
leagues.country_code = $5
|
||||||
|
OR $5 IS NULL
|
||||||
|
)
|
||||||
ORDER BY start_time ASC
|
ORDER BY start_time ASC
|
||||||
LIMIT $6 OFFSET $5
|
LIMIT $7 OFFSET $6
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetPaginatedUpcomingEventsParams struct {
|
type GetPaginatedUpcomingEventsParams struct {
|
||||||
|
|
@ -230,6 +242,7 @@ type GetPaginatedUpcomingEventsParams struct {
|
||||||
SportID pgtype.Int4 `json:"sport_id"`
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||||
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Offset pgtype.Int4 `json:"offset"`
|
Offset pgtype.Int4 `json:"offset"`
|
||||||
Limit pgtype.Int4 `json:"limit"`
|
Limit pgtype.Int4 `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
@ -246,12 +259,12 @@ type GetPaginatedUpcomingEventsRow struct {
|
||||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
LeagueID pgtype.Int4 `json:"league_id"`
|
LeagueID pgtype.Int4 `json:"league_id"`
|
||||||
LeagueName pgtype.Text `json:"league_name"`
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
LeagueCc pgtype.Text `json:"league_cc"`
|
|
||||||
StartTime pgtype.Timestamp `json:"start_time"`
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
IsLive pgtype.Bool `json:"is_live"`
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
Status pgtype.Text `json:"status"`
|
Status pgtype.Text `json:"status"`
|
||||||
Source pgtype.Text `json:"source"`
|
Source pgtype.Text `json:"source"`
|
||||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginatedUpcomingEventsParams) ([]GetPaginatedUpcomingEventsRow, error) {
|
func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginatedUpcomingEventsParams) ([]GetPaginatedUpcomingEventsRow, error) {
|
||||||
|
|
@ -260,6 +273,7 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat
|
||||||
arg.SportID,
|
arg.SportID,
|
||||||
arg.LastStartTime,
|
arg.LastStartTime,
|
||||||
arg.FirstStartTime,
|
arg.FirstStartTime,
|
||||||
|
arg.CountryCode,
|
||||||
arg.Offset,
|
arg.Offset,
|
||||||
arg.Limit,
|
arg.Limit,
|
||||||
)
|
)
|
||||||
|
|
@ -282,12 +296,12 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat
|
||||||
&i.AwayKitImage,
|
&i.AwayKitImage,
|
||||||
&i.LeagueID,
|
&i.LeagueID,
|
||||||
&i.LeagueName,
|
&i.LeagueName,
|
||||||
&i.LeagueCc,
|
|
||||||
&i.StartTime,
|
&i.StartTime,
|
||||||
&i.IsLive,
|
&i.IsLive,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
&i.Source,
|
&i.Source,
|
||||||
&i.FetchedAt,
|
&i.FetchedAt,
|
||||||
|
&i.LeagueCc,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -302,6 +316,7 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat
|
||||||
const GetTotalEvents = `-- name: GetTotalEvents :one
|
const GetTotalEvents = `-- name: GetTotalEvents :one
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM events
|
FROM events
|
||||||
|
LEFT JOIN leagues ON leagues.id = league_id
|
||||||
WHERE is_live = false
|
WHERE is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
AND (
|
AND (
|
||||||
|
|
@ -309,7 +324,7 @@ WHERE is_live = false
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
sport_id = $2
|
events.sport_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
|
|
@ -320,6 +335,10 @@ WHERE is_live = false
|
||||||
start_time > $4
|
start_time > $4
|
||||||
OR $4 IS NULL
|
OR $4 IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
leagues.country_code = $5
|
||||||
|
OR $5 IS NULL
|
||||||
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetTotalEventsParams struct {
|
type GetTotalEventsParams struct {
|
||||||
|
|
@ -327,6 +346,7 @@ type GetTotalEventsParams struct {
|
||||||
SportID pgtype.Int4 `json:"sport_id"`
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
LastStartTime pgtype.Timestamp `json:"last_start_time"`
|
||||||
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
FirstStartTime pgtype.Timestamp `json:"first_start_time"`
|
||||||
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams) (int64, error) {
|
func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams) (int64, error) {
|
||||||
|
|
@ -335,6 +355,7 @@ func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams)
|
||||||
arg.SportID,
|
arg.SportID,
|
||||||
arg.LastStartTime,
|
arg.LastStartTime,
|
||||||
arg.FirstStartTime,
|
arg.FirstStartTime,
|
||||||
|
arg.CountryCode,
|
||||||
)
|
)
|
||||||
var count int64
|
var count int64
|
||||||
err := row.Scan(&count)
|
err := row.Scan(&count)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: leagues.sql
|
// source: leagues.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -17,7 +17,7 @@ SELECT EXISTS(
|
||||||
FROM leagues
|
FROM leagues
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
AND is_active = true
|
AND is_active = true
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) CheckLeagueSupport(ctx context.Context, id int64) (bool, error) {
|
func (q *Queries) CheckLeagueSupport(ctx context.Context, id int64) (bool, error) {
|
||||||
|
|
@ -32,61 +32,63 @@ SELECT id,
|
||||||
name,
|
name,
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
is_active
|
is_active,
|
||||||
|
sport_id
|
||||||
FROM leagues
|
FROM leagues
|
||||||
|
WHERE (
|
||||||
|
country_code = $1
|
||||||
|
OR $1 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
sport_id = $2
|
||||||
|
OR $2 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
is_active = $3
|
||||||
|
OR $3 IS NULL
|
||||||
|
)
|
||||||
|
LIMIT $5 OFFSET $4
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllLeagues(ctx context.Context) ([]League, error) {
|
type GetAllLeaguesParams struct {
|
||||||
rows, err := q.db.Query(ctx, GetAllLeagues)
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
if err != nil {
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
return nil, err
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
}
|
Offset pgtype.Int4 `json:"offset"`
|
||||||
defer rows.Close()
|
Limit pgtype.Int4 `json:"limit"`
|
||||||
var items []League
|
|
||||||
for rows.Next() {
|
|
||||||
var i League
|
|
||||||
if err := rows.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.Name,
|
|
||||||
&i.CountryCode,
|
|
||||||
&i.Bet365ID,
|
|
||||||
&i.IsActive,
|
|
||||||
); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
items = append(items, i)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return items, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetSupportedLeagues = `-- name: GetSupportedLeagues :many
|
type GetAllLeaguesRow struct {
|
||||||
SELECT id,
|
ID int64 `json:"id"`
|
||||||
name,
|
Name string `json:"name"`
|
||||||
country_code,
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
bet365_id,
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
is_active
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
FROM leagues
|
SportID int32 `json:"sport_id"`
|
||||||
WHERE is_active = true
|
}
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) GetSupportedLeagues(ctx context.Context) ([]League, error) {
|
func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([]GetAllLeaguesRow, error) {
|
||||||
rows, err := q.db.Query(ctx, GetSupportedLeagues)
|
rows, err := q.db.Query(ctx, GetAllLeagues,
|
||||||
|
arg.CountryCode,
|
||||||
|
arg.SportID,
|
||||||
|
arg.IsActive,
|
||||||
|
arg.Offset,
|
||||||
|
arg.Limit,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []League
|
var items []GetAllLeaguesRow
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i League
|
var i GetAllLeaguesRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.CountryCode,
|
&i.CountryCode,
|
||||||
&i.Bet365ID,
|
&i.Bet365ID,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
|
&i.SportID,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -104,15 +106,16 @@ INSERT INTO leagues (
|
||||||
name,
|
name,
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
|
sport_id,
|
||||||
is_active
|
is_active
|
||||||
) VALUES (
|
)
|
||||||
$1, $2, $3, $4, $5
|
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO
|
||||||
)
|
UPDATE
|
||||||
ON CONFLICT (id) DO UPDATE
|
|
||||||
SET name = EXCLUDED.name,
|
SET name = EXCLUDED.name,
|
||||||
country_code = EXCLUDED.country_code,
|
country_code = EXCLUDED.country_code,
|
||||||
bet365_id = EXCLUDED.bet365_id,
|
bet365_id = EXCLUDED.bet365_id,
|
||||||
is_active = EXCLUDED.is_active
|
is_active = EXCLUDED.is_active,
|
||||||
|
sport_id = EXCLUDED.sport_id
|
||||||
`
|
`
|
||||||
|
|
||||||
type InsertLeagueParams struct {
|
type InsertLeagueParams struct {
|
||||||
|
|
@ -120,6 +123,7 @@ type InsertLeagueParams struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
|
SportID int32 `json:"sport_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,6 +133,7 @@ func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) erro
|
||||||
arg.Name,
|
arg.Name,
|
||||||
arg.CountryCode,
|
arg.CountryCode,
|
||||||
arg.Bet365ID,
|
arg.Bet365ID,
|
||||||
|
arg.SportID,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
|
|
@ -136,39 +141,78 @@ func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) erro
|
||||||
|
|
||||||
const SetLeagueActive = `-- name: SetLeagueActive :exec
|
const SetLeagueActive = `-- name: SetLeagueActive :exec
|
||||||
UPDATE leagues
|
UPDATE leagues
|
||||||
SET is_active = true
|
SET is_active = $2
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) SetLeagueActive(ctx context.Context, id int64) error {
|
type SetLeagueActiveParams struct {
|
||||||
_, err := q.db.Exec(ctx, SetLeagueActive, id)
|
ID int64 `json:"id"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SetLeagueActive(ctx context.Context, arg SetLeagueActiveParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, SetLeagueActive, arg.ID, arg.IsActive)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateLeague = `-- name: UpdateLeague :exec
|
const UpdateLeague = `-- name: UpdateLeague :exec
|
||||||
UPDATE leagues
|
UPDATE leagues
|
||||||
SET name = $1,
|
SET name = COALESCE($2, name),
|
||||||
country_code = $2,
|
country_code = COALESCE($3, country_code),
|
||||||
bet365_id = $3,
|
bet365_id = COALESCE($4, bet365_id),
|
||||||
is_active = $4
|
is_active = COALESCE($5, is_active),
|
||||||
WHERE id = $5
|
sport_id = COALESCE($6, sport_id)
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateLeagueParams struct {
|
type UpdateLeagueParams struct {
|
||||||
Name string `json:"name"`
|
ID int64 `json:"id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
ID int64 `json:"id"`
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) error {
|
func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) error {
|
||||||
_, err := q.db.Exec(ctx, UpdateLeague,
|
_, err := q.db.Exec(ctx, UpdateLeague,
|
||||||
|
arg.ID,
|
||||||
arg.Name,
|
arg.Name,
|
||||||
arg.CountryCode,
|
arg.CountryCode,
|
||||||
arg.Bet365ID,
|
arg.Bet365ID,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
arg.ID,
|
arg.SportID,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateLeagueByBet365ID = `-- name: UpdateLeagueByBet365ID :exec
|
||||||
|
UPDATE leagues
|
||||||
|
SET name = COALESCE($2, name),
|
||||||
|
id = COALESCE($3, id),
|
||||||
|
country_code = COALESCE($4, country_code),
|
||||||
|
is_active = COALESCE($5, is_active),
|
||||||
|
sport_id = COALESCE($6, sport_id)
|
||||||
|
WHERE bet365_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateLeagueByBet365IDParams struct {
|
||||||
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
ID pgtype.Int8 `json:"id"`
|
||||||
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateLeagueByBet365ID(ctx context.Context, arg UpdateLeagueByBet365IDParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateLeagueByBet365ID,
|
||||||
|
arg.Bet365ID,
|
||||||
|
arg.Name,
|
||||||
|
arg.ID,
|
||||||
|
arg.CountryCode,
|
||||||
|
arg.IsActive,
|
||||||
|
arg.SportID,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
||||||
|
|
@ -140,6 +140,7 @@ type BranchDetail struct {
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
ManagerName interface{} `json:"manager_name"`
|
ManagerName interface{} `json:"manager_name"`
|
||||||
ManagerPhoneNumber pgtype.Text `json:"manager_phone_number"`
|
ManagerPhoneNumber pgtype.Text `json:"manager_phone_number"`
|
||||||
|
Balance pgtype.Int8 `json:"balance"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BranchOperation struct {
|
type BranchOperation struct {
|
||||||
|
|
@ -208,6 +209,7 @@ type League struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
|
SportID int32 `json:"sport_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,6 +329,7 @@ type Ticket struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32 `json:"total_odds"`
|
TotalOdds float32 `json:"total_odds"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -352,6 +355,7 @@ type TicketWithOutcome struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32 `json:"total_odds"`
|
TotalOdds float32 `json:"total_odds"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
Outcomes []TicketOutcome `json:"outcomes"`
|
Outcomes []TicketOutcome `json:"outcomes"`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: monitor.sql
|
// source: monitor.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: notification.sql
|
// source: notification.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: odds.sql
|
// source: odds.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -11,6 +11,16 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DeleteOddsForEvent = `-- name: DeleteOddsForEvent :exec
|
||||||
|
DELETE FROM odds
|
||||||
|
Where fi = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteOddsForEvent(ctx context.Context, fi pgtype.Text) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteOddsForEvent, fi)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many
|
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many
|
||||||
SELECT event_id,
|
SELECT event_id,
|
||||||
fi,
|
fi,
|
||||||
|
|
@ -29,7 +39,7 @@ SELECT event_id,
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE is_active = true
|
WHERE is_active = true
|
||||||
AND source = 'b365api'
|
AND source = 'bet365'
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetALLPrematchOddsRow struct {
|
type GetALLPrematchOddsRow struct {
|
||||||
|
|
@ -94,7 +104,7 @@ WHERE e.id = $1
|
||||||
AND e.is_live = false
|
AND e.is_live = false
|
||||||
AND e.status = 'upcoming'
|
AND e.status = 'upcoming'
|
||||||
AND o.is_active = true
|
AND o.is_active = true
|
||||||
AND o.source = 'b365api'
|
AND o.source = 'bet365'
|
||||||
LIMIT $3 OFFSET $2
|
LIMIT $3 OFFSET $2
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -159,7 +169,7 @@ SELECT event_id,
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE is_active = true
|
WHERE is_active = true
|
||||||
AND source = 'b365api'
|
AND source = 'bet365'
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetPrematchOddsRow struct {
|
type GetPrematchOddsRow struct {
|
||||||
|
|
@ -224,7 +234,7 @@ WHERE e.id = $1
|
||||||
AND e.is_live = false
|
AND e.is_live = false
|
||||||
AND e.status = 'upcoming'
|
AND e.status = 'upcoming'
|
||||||
AND o.is_active = true
|
AND o.is_active = true
|
||||||
AND o.source = 'b365api'
|
AND o.source = 'bet365'
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, id string) ([]Odd, error) {
|
func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, id string) ([]Odd, error) {
|
||||||
|
|
@ -274,7 +284,7 @@ FROM odds
|
||||||
WHERE market_id = $1
|
WHERE market_id = $1
|
||||||
AND fi = $2
|
AND fi = $2
|
||||||
AND is_active = true
|
AND is_active = true
|
||||||
AND source = 'b365api'
|
AND source = 'bet365'
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetRawOddsByMarketIDParams struct {
|
type GetRawOddsByMarketIDParams struct {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: otp.sql
|
// source: otp.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: referal.sql
|
// source: referal.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: result.sql
|
// source: result.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: ticket.sql
|
// source: ticket.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -11,24 +11,39 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const CountTicketByIP = `-- name: CountTicketByIP :one
|
||||||
|
SELECT count(id)
|
||||||
|
FROM tickets
|
||||||
|
WHERE IP = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountTicketByIP(ctx context.Context, ip string) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountTicketByIP, ip)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
const CreateTicket = `-- name: CreateTicket :one
|
const CreateTicket = `-- name: CreateTicket :one
|
||||||
INSERT INTO tickets (amount, total_odds)
|
INSERT INTO tickets (amount, total_odds, ip)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2, $3)
|
||||||
RETURNING id, amount, total_odds, created_at, updated_at
|
RETURNING id, amount, total_odds, ip, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateTicketParams struct {
|
type CreateTicketParams struct {
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32 `json:"total_odds"`
|
TotalOdds float32 `json:"total_odds"`
|
||||||
|
Ip string `json:"ip"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) {
|
func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) {
|
||||||
row := q.db.QueryRow(ctx, CreateTicket, arg.Amount, arg.TotalOdds)
|
row := q.db.QueryRow(ctx, CreateTicket, arg.Amount, arg.TotalOdds, arg.Ip)
|
||||||
var i Ticket
|
var i Ticket
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.TotalOdds,
|
&i.TotalOdds,
|
||||||
|
&i.Ip,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
)
|
)
|
||||||
|
|
@ -81,7 +96,7 @@ func (q *Queries) DeleteTicketOutcome(ctx context.Context, ticketID int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllTickets = `-- name: GetAllTickets :many
|
const GetAllTickets = `-- name: GetAllTickets :many
|
||||||
SELECT id, amount, total_odds, created_at, updated_at, outcomes
|
SELECT id, amount, total_odds, ip, created_at, updated_at, outcomes
|
||||||
FROM ticket_with_outcomes
|
FROM ticket_with_outcomes
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -98,6 +113,7 @@ func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.TotalOdds,
|
&i.TotalOdds,
|
||||||
|
&i.Ip,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
|
@ -113,7 +129,7 @@ func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetTicketByID = `-- name: GetTicketByID :one
|
const GetTicketByID = `-- name: GetTicketByID :one
|
||||||
SELECT id, amount, total_odds, created_at, updated_at, outcomes
|
SELECT id, amount, total_odds, ip, created_at, updated_at, outcomes
|
||||||
FROM ticket_with_outcomes
|
FROM ticket_with_outcomes
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -125,6 +141,7 @@ func (q *Queries) GetTicketByID(ctx context.Context, id int64) (TicketWithOutcom
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.TotalOdds,
|
&i.TotalOdds,
|
||||||
|
&i.Ip,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.Outcomes,
|
&i.Outcomes,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: transactions.sql
|
// source: transactions.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: transfer.sql
|
// source: transfer.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: user.sql
|
// source: user.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: virtual_games.sql
|
// source: virtual_games.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: wallet.sql
|
// source: wallet.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ type BranchDetail struct {
|
||||||
Name string
|
Name string
|
||||||
Location string
|
Location string
|
||||||
WalletID int64
|
WalletID int64
|
||||||
|
Balance Currency
|
||||||
BranchManagerID int64
|
BranchManagerID int64
|
||||||
CompanyID int64
|
CompanyID int64
|
||||||
IsSuspended bool
|
IsSuspended bool
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,39 @@ package domain
|
||||||
|
|
||||||
import "time"
|
import "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 Event struct {
|
type Event struct {
|
||||||
ID string
|
ID string
|
||||||
SportID int32
|
SportID int32
|
||||||
|
|
@ -53,20 +86,21 @@ type BetResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpcomingEvent struct {
|
type UpcomingEvent struct {
|
||||||
ID string // Event ID
|
ID string `json:"id"` // Event ID
|
||||||
SportID int32 // Sport ID
|
SportID int32 `json:"sport_id"` // Sport ID
|
||||||
MatchName string // Match or event name
|
MatchName string `json:"match_name"` // Match or event name
|
||||||
HomeTeam string // Home team name (if available)
|
HomeTeam string `json:"home_team"` // Home team name (if available)
|
||||||
AwayTeam string // Away team name (can be empty/null)
|
AwayTeam string `json:"away_team"` // Away team name (can be empty/null)
|
||||||
HomeTeamID int32 // Home team ID
|
HomeTeamID int32 `json:"home_team_id"` // Home team ID
|
||||||
AwayTeamID int32 // Away team ID (can be empty/null)
|
AwayTeamID int32 `json:"away_team_id"` // Away team ID (can be empty/null)
|
||||||
HomeKitImage string // Kit or image for home team (optional)
|
HomeKitImage string `json:"home_kit_image"` // Kit or image for home team (optional)
|
||||||
AwayKitImage string // Kit or image for away team (optional)
|
AwayKitImage string `json:"away_kit_image"` // Kit or image for away team (optional)
|
||||||
LeagueID int32 // League ID
|
LeagueID int32 `json:"league_id"` // League ID
|
||||||
LeagueName string // League name
|
LeagueName string `json:"league_name"` // League name
|
||||||
LeagueCC string // League country code
|
LeagueCC string `json:"league_cc"` // League country code
|
||||||
StartTime time.Time // Converted from "time" field in UNIX format
|
StartTime time.Time `json:"start_time"` // Converted from "time" field in UNIX format
|
||||||
Source string // bet api provider (bet365, betfair)
|
Source string `json:"source"` // bet api provider (bet365, betfair)
|
||||||
|
Status EventStatus `json:"status"` //Match Status for event
|
||||||
}
|
}
|
||||||
type MatchResult struct {
|
type MatchResult struct {
|
||||||
EventID string
|
EventID string
|
||||||
|
|
@ -83,3 +117,14 @@ type Odds struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
HitStatus string `json:"hit_status"`
|
HitStatus string `json:"hit_status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EventFilter struct {
|
||||||
|
SportID ValidInt32
|
||||||
|
LeagueID ValidInt32
|
||||||
|
CountryCode ValidString
|
||||||
|
FirstStartTime ValidTime
|
||||||
|
LastStartTime ValidTime
|
||||||
|
Limit ValidInt64
|
||||||
|
Offset ValidInt64
|
||||||
|
MatchStatus ValidString // e.g., "upcoming", "in_play", "ended"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,27 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
type League struct {
|
type League struct {
|
||||||
ID int64
|
ID int64 `json:"id" example:"1"`
|
||||||
Name string
|
Name string `json:"name" example:"BPL"`
|
||||||
CountryCode string
|
CountryCode string `json:"cc" example:"uk"`
|
||||||
Bet365ID int32
|
Bet365ID int32 `json:"bet365_id" example:"1121"`
|
||||||
IsActive bool
|
IsActive bool `json:"is_active" example:"false"`
|
||||||
|
SportID int32 `json:"sport_id" example:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateLeague struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
Name ValidString `json:"name" example:"BPL"`
|
||||||
|
CountryCode ValidString `json:"cc" example:"uk"`
|
||||||
|
Bet365ID ValidInt32 `json:"bet365_id" example:"1121"`
|
||||||
|
IsActive ValidBool `json:"is_active" example:"false"`
|
||||||
|
SportID ValidInt32 `json:"sport_id" example:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LeagueFilter struct {
|
||||||
|
CountryCode ValidString
|
||||||
|
SportID ValidInt32
|
||||||
|
IsActive ValidBool
|
||||||
|
Limit ValidInt64
|
||||||
|
Offset ValidInt64
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,19 @@ type OddsSection struct {
|
||||||
Sp map[string]OddsMarket `json:"sp"`
|
Sp map[string]OddsMarket `json:"sp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ParseOddSectionsRes struct {
|
||||||
|
Sections map[string]OddsSection
|
||||||
|
OtherRes []OddsSection
|
||||||
|
EventFI string
|
||||||
|
}
|
||||||
|
type RawOdd struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Header string `json:"header,omitempty"`
|
||||||
|
Handicap string `json:"handicap,omitempty"`
|
||||||
|
Odds string `json:"odds"`
|
||||||
|
}
|
||||||
|
|
||||||
// The Market ID for the json data can be either string / int which is causing problems when UnMarshalling
|
// The Market ID for the json data can be either string / int which is causing problems when UnMarshalling
|
||||||
type OddsMarket struct {
|
type OddsMarket struct {
|
||||||
ID json.RawMessage `json:"id"`
|
ID json.RawMessage `json:"id"`
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,5 @@ type RawOddsByMarketID struct {
|
||||||
RawOdds []RawMessage `json:"raw_odds"`
|
RawOdds []RawMessage `json:"raw_odds"`
|
||||||
FetchedAt time.Time `json:"fetched_at"`
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,17 @@ type Score struct {
|
||||||
Away string `json:"away"`
|
Away string `json:"away"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommonResultResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID string `json:"sport_id"`
|
||||||
|
Time string `json:"time"`
|
||||||
|
TimeStatus string `json:"time_status"`
|
||||||
|
League LeagueRes `json:"league"`
|
||||||
|
Home Team `json:"home"`
|
||||||
|
Away Team `json:"away"`
|
||||||
|
SS string `json:"ss"`
|
||||||
|
}
|
||||||
|
|
||||||
type FootballResultResponse struct {
|
type FootballResultResponse struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
SportID string `json:"sport_id"`
|
SportID string `json:"sport_id"`
|
||||||
|
|
|
||||||
|
|
@ -51,4 +51,5 @@ type GetTicket struct {
|
||||||
type CreateTicket struct {
|
type CreateTicket struct {
|
||||||
Amount Currency
|
Amount Currency
|
||||||
TotalOdds float32
|
TotalOdds float32
|
||||||
|
IP string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,4 +86,7 @@ type GetCashier struct {
|
||||||
SuspendedAt time.Time `json:"suspended_at"`
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
Suspended bool `json:"suspended"`
|
Suspended bool `json:"suspended"`
|
||||||
BranchID int64 `json:"branch_id"`
|
BranchID int64 `json:"branch_id"`
|
||||||
|
BranchName string `json:"branch_name"`
|
||||||
|
BranchWallet int64 `json:"branch_wallet"`
|
||||||
|
BranchLocation string `json:"branch_location"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ func convertDBBranchDetail(dbBranch dbgen.BranchDetail) domain.BranchDetail {
|
||||||
IsSelfOwned: dbBranch.IsSelfOwned,
|
IsSelfOwned: dbBranch.IsSelfOwned,
|
||||||
ManagerName: dbBranch.ManagerName.(string),
|
ManagerName: dbBranch.ManagerName.(string),
|
||||||
ManagerPhoneNumber: dbBranch.ManagerPhoneNumber.String,
|
ManagerPhoneNumber: dbBranch.ManagerPhoneNumber.String,
|
||||||
|
Balance: domain.Currency(dbBranch.Balance.Int64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,13 +88,17 @@ func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEven
|
||||||
LeagueCC: e.LeagueCc.String,
|
LeagueCC: e.LeagueCc.String,
|
||||||
StartTime: e.StartTime.Time.UTC(),
|
StartTime: e.StartTime.Time.UTC(),
|
||||||
Source: e.Source.String,
|
Source: e.Source.String,
|
||||||
|
Status: domain.EventStatus(e.Status.String),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return upcomingEvents, nil
|
return upcomingEvents, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
|
func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error) {
|
||||||
events, err := s.queries.GetExpiredUpcomingEvents(ctx)
|
events, err := s.queries.GetExpiredUpcomingEvents(ctx, pgtype.Text{
|
||||||
|
String: filter.MatchStatus.Value,
|
||||||
|
Valid: filter.MatchStatus.Valid,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -116,37 +120,42 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.Upcoming
|
||||||
LeagueCC: e.LeagueCc.String,
|
LeagueCC: e.LeagueCc.String,
|
||||||
StartTime: e.StartTime.Time.UTC(),
|
StartTime: e.StartTime.Time.UTC(),
|
||||||
Source: e.Source.String,
|
Source: e.Source.String,
|
||||||
|
Status: domain.EventStatus(e.Status.String),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return upcomingEvents, nil
|
return upcomingEvents, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidInt32, sportID domain.ValidInt32, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error) {
|
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error) {
|
||||||
|
|
||||||
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
|
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
|
||||||
LeagueID: pgtype.Int4{
|
LeagueID: pgtype.Int4{
|
||||||
Int32: leagueID.Value,
|
Int32: int32(filter.LeagueID.Value),
|
||||||
Valid: leagueID.Valid,
|
Valid: filter.LeagueID.Valid,
|
||||||
},
|
},
|
||||||
SportID: pgtype.Int4{
|
SportID: pgtype.Int4{
|
||||||
Int32: sportID.Value,
|
Int32: int32(filter.SportID.Value),
|
||||||
Valid: sportID.Valid,
|
Valid: filter.SportID.Valid,
|
||||||
},
|
},
|
||||||
Limit: pgtype.Int4{
|
Limit: pgtype.Int4{
|
||||||
Int32: int32(limit.Value),
|
Int32: int32(filter.Limit.Value),
|
||||||
Valid: limit.Valid,
|
Valid: filter.Limit.Valid,
|
||||||
},
|
},
|
||||||
Offset: pgtype.Int4{
|
Offset: pgtype.Int4{
|
||||||
Int32: int32(offset.Value * limit.Value),
|
Int32: int32(filter.Offset.Value * filter.Limit.Value),
|
||||||
Valid: offset.Valid,
|
Valid: filter.Offset.Valid,
|
||||||
},
|
},
|
||||||
FirstStartTime: pgtype.Timestamp{
|
FirstStartTime: pgtype.Timestamp{
|
||||||
Time: firstStartTime.Value.UTC(),
|
Time: filter.FirstStartTime.Value.UTC(),
|
||||||
Valid: firstStartTime.Valid,
|
Valid: filter.FirstStartTime.Valid,
|
||||||
},
|
},
|
||||||
LastStartTime: pgtype.Timestamp{
|
LastStartTime: pgtype.Timestamp{
|
||||||
Time: lastStartTime.Value.UTC(),
|
Time: filter.LastStartTime.Value.UTC(),
|
||||||
Valid: lastStartTime.Valid,
|
Valid: filter.LastStartTime.Valid,
|
||||||
|
},
|
||||||
|
CountryCode: pgtype.Text{
|
||||||
|
String: filter.CountryCode.Value,
|
||||||
|
Valid: filter.CountryCode.Valid,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -170,31 +179,36 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.Val
|
||||||
LeagueCC: e.LeagueCc.String,
|
LeagueCC: e.LeagueCc.String,
|
||||||
StartTime: e.StartTime.Time.UTC(),
|
StartTime: e.StartTime.Time.UTC(),
|
||||||
Source: e.Source.String,
|
Source: e.Source.String,
|
||||||
|
Status: domain.EventStatus(e.Status.String),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
|
totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
|
||||||
LeagueID: pgtype.Int4{
|
LeagueID: pgtype.Int4{
|
||||||
Int32: leagueID.Value,
|
Int32: int32(filter.LeagueID.Value),
|
||||||
Valid: leagueID.Valid,
|
Valid: filter.LeagueID.Valid,
|
||||||
},
|
},
|
||||||
SportID: pgtype.Int4{
|
SportID: pgtype.Int4{
|
||||||
Int32: sportID.Value,
|
Int32: int32(filter.SportID.Value),
|
||||||
Valid: sportID.Valid,
|
Valid: filter.SportID.Valid,
|
||||||
},
|
},
|
||||||
FirstStartTime: pgtype.Timestamp{
|
FirstStartTime: pgtype.Timestamp{
|
||||||
Time: firstStartTime.Value.UTC(),
|
Time: filter.FirstStartTime.Value.UTC(),
|
||||||
Valid: firstStartTime.Valid,
|
Valid: filter.FirstStartTime.Valid,
|
||||||
},
|
},
|
||||||
LastStartTime: pgtype.Timestamp{
|
LastStartTime: pgtype.Timestamp{
|
||||||
Time: lastStartTime.Value.UTC(),
|
Time: filter.LastStartTime.Value.UTC(),
|
||||||
Valid: lastStartTime.Valid,
|
Valid: filter.LastStartTime.Valid,
|
||||||
|
},
|
||||||
|
CountryCode: pgtype.Text{
|
||||||
|
String: filter.CountryCode.Value,
|
||||||
|
Valid: filter.CountryCode.Valid,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfPages := math.Ceil(float64(totalCount) / float64(limit.Value))
|
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
|
||||||
return upcomingEvents, int64(numberOfPages), nil
|
return upcomingEvents, int64(numberOfPages), nil
|
||||||
}
|
}
|
||||||
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
|
|
@ -218,12 +232,13 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
||||||
LeagueCC: event.LeagueCc.String,
|
LeagueCC: event.LeagueCc.String,
|
||||||
StartTime: event.StartTime.Time.UTC(),
|
StartTime: event.StartTime.Time.UTC(),
|
||||||
Source: event.Source.String,
|
Source: event.Source.String,
|
||||||
|
Status: domain.EventStatus(event.Status.String),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore, status string) error {
|
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error {
|
||||||
params := dbgen.UpdateMatchResultParams{
|
params := dbgen.UpdateMatchResultParams{
|
||||||
Score: pgtype.Text{String: fullScore, Valid: true},
|
Score: pgtype.Text{String: fullScore, Valid: true},
|
||||||
Status: pgtype.Text{String: status, Valid: true},
|
Status: pgtype.Text{String: string(status), Valid: true},
|
||||||
ID: eventID,
|
ID: eventID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,6 +250,24 @@ func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore, status
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error {
|
||||||
|
params := dbgen.UpdateMatchResultParams{
|
||||||
|
Status: pgtype.Text{
|
||||||
|
String: string(status),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
ID: eventID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.queries.UpdateMatchResult(ctx, params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
|
func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
|
||||||
err := s.queries.DeleteEvent(ctx, eventID)
|
err := s.queries.DeleteEvent(ctx, eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -15,30 +15,33 @@ func (s *Store) SaveLeague(ctx context.Context, l domain.League) error {
|
||||||
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
||||||
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
||||||
IsActive: pgtype.Bool{Bool: l.IsActive, Valid: true},
|
IsActive: pgtype.Bool{Bool: l.IsActive, Valid: true},
|
||||||
|
SportID: l.SportID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetSupportedLeagues(ctx context.Context) ([]domain.League, error) {
|
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error) {
|
||||||
leagues, err := s.queries.GetSupportedLeagues(ctx)
|
l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{
|
||||||
if err != nil {
|
CountryCode: pgtype.Text{
|
||||||
return nil, err
|
String: filter.CountryCode.Value,
|
||||||
}
|
Valid: filter.CountryCode.Valid,
|
||||||
|
},
|
||||||
supportedLeagues := make([]domain.League, len(leagues))
|
SportID: pgtype.Int4{
|
||||||
for i, league := range leagues {
|
Int32: filter.SportID.Value,
|
||||||
supportedLeagues[i] = domain.League{
|
Valid: filter.SportID.Valid,
|
||||||
ID: league.ID,
|
},
|
||||||
Name: league.Name,
|
IsActive: pgtype.Bool{
|
||||||
CountryCode: league.CountryCode.String,
|
Bool: filter.IsActive.Value,
|
||||||
Bet365ID: league.Bet365ID.Int32,
|
Valid: filter.IsActive.Valid,
|
||||||
IsActive: league.IsActive.Bool,
|
},
|
||||||
}
|
Limit: pgtype.Int4{
|
||||||
}
|
Int32: int32(filter.Limit.Value),
|
||||||
return supportedLeagues, nil
|
Valid: filter.Limit.Valid,
|
||||||
}
|
},
|
||||||
|
Offset: pgtype.Int4{
|
||||||
func (s *Store) GetAllLeagues(ctx context.Context) ([]domain.League, error) {
|
Int32: int32(filter.Offset.Value * filter.Limit.Value),
|
||||||
l, err := s.queries.GetAllLeagues(ctx)
|
Valid: filter.Offset.Valid,
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +54,7 @@ func (s *Store) GetAllLeagues(ctx context.Context) ([]domain.League, error) {
|
||||||
CountryCode: league.CountryCode.String,
|
CountryCode: league.CountryCode.String,
|
||||||
Bet365ID: league.Bet365ID.Int32,
|
Bet365ID: league.Bet365ID.Int32,
|
||||||
IsActive: league.IsActive.Bool,
|
IsActive: league.IsActive.Bool,
|
||||||
|
SportID: league.SportID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return leagues, nil
|
return leagues, nil
|
||||||
|
|
@ -60,16 +64,40 @@ func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64) (bool, e
|
||||||
return s.queries.CheckLeagueSupport(ctx, leagueID)
|
return s.queries.CheckLeagueSupport(ctx, leagueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) SetLeagueActive(ctx context.Context, leagueId int64) error {
|
func (s *Store) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error {
|
||||||
return s.queries.SetLeagueActive(ctx, leagueId)
|
return s.queries.SetLeagueActive(ctx, dbgen.SetLeagueActiveParams{
|
||||||
}
|
ID: leagueId,
|
||||||
|
IsActive: pgtype.Bool{
|
||||||
// TODO: update based on id, no need for the entire league (same as the set active one)
|
Bool: isActive,
|
||||||
func (s *Store) SetLeagueInActive(ctx context.Context, l domain.League) error {
|
Valid: true,
|
||||||
return s.queries.UpdateLeague(ctx, dbgen.UpdateLeagueParams{
|
},
|
||||||
Name: l.Name,
|
|
||||||
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
|
||||||
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
|
||||||
IsActive: pgtype.Bool{Bool: false, Valid: true},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {
|
||||||
|
err := s.queries.UpdateLeague(ctx, dbgen.UpdateLeagueParams{
|
||||||
|
ID: league.ID,
|
||||||
|
Name: pgtype.Text{
|
||||||
|
String: league.Name.Value,
|
||||||
|
Valid: league.Name.Valid,
|
||||||
|
},
|
||||||
|
CountryCode: pgtype.Text{
|
||||||
|
String: league.CountryCode.Value,
|
||||||
|
Valid: league.CountryCode.Valid,
|
||||||
|
},
|
||||||
|
Bet365ID: pgtype.Int4{
|
||||||
|
Int32: league.Bet365ID.Value,
|
||||||
|
Valid: league.Bet365ID.Valid,
|
||||||
|
},
|
||||||
|
IsActive: pgtype.Bool{
|
||||||
|
Bool: league.IsActive.Value,
|
||||||
|
Valid: league.IsActive.Valid,
|
||||||
|
},
|
||||||
|
SportID: pgtype.Int4{
|
||||||
|
Int32: league.SportID.Value,
|
||||||
|
Valid: league.SportID.Valid,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package repository
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -274,6 +275,13 @@ func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID stri
|
||||||
return domainOdds, nil
|
return domainOdds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error {
|
||||||
|
return s.queries.DeleteOddsForEvent(ctx, pgtype.Text{
|
||||||
|
String: eventID,
|
||||||
|
Valid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func getString(v interface{}) string {
|
func getString(v interface{}) string {
|
||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
return s
|
return s
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package repository
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
|
@ -32,6 +33,7 @@ func (s *Store) GetOtp(ctx context.Context, sentTo string, sentfor domain.OtpFor
|
||||||
OtpFor: string(sentfor),
|
OtpFor: string(sentfor),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("OTP REPO error: %v sentTo: %v, medium: %v, otpFor: %v\n", err, sentTo, medium, sentfor)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return domain.Otp{}, domain.ErrOtpNotFound
|
return domain.Otp{}, domain.ErrOtpNotFound
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ func convertCreateTicket(ticket domain.CreateTicket) dbgen.CreateTicketParams {
|
||||||
return dbgen.CreateTicketParams{
|
return dbgen.CreateTicketParams{
|
||||||
Amount: int64(ticket.Amount),
|
Amount: int64(ticket.Amount),
|
||||||
TotalOdds: ticket.TotalOdds,
|
TotalOdds: ticket.TotalOdds,
|
||||||
|
Ip: ticket.IP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,6 +124,16 @@ func (s *Store) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) CountTicketByIP(ctx context.Context, IP string) (int64, error) {
|
||||||
|
count, err := s.queries.CountTicketByIP(ctx, IP)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
func (s *Store) UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
err := s.queries.UpdateTicketOutcomeStatus(ctx, dbgen.UpdateTicketOutcomeStatusParams{
|
err := s.queries.UpdateTicketOutcomeStatus(ctx, dbgen.UpdateTicketOutcomeStatusParams{
|
||||||
Status: int32(status),
|
Status: int32(status),
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,10 @@ func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||||
UpdatedAt: user.UpdatedAt.Time,
|
UpdatedAt: user.UpdatedAt.Time,
|
||||||
SuspendedAt: user.SuspendedAt.Time,
|
SuspendedAt: user.SuspendedAt.Time,
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
|
CompanyID: domain.ValidInt64{
|
||||||
|
Value: user.CompanyID.Int64,
|
||||||
|
Valid: user.CompanyID.Valid,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.User, int64, error) {
|
func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.User, int64, error) {
|
||||||
|
|
@ -118,6 +122,10 @@ func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.U
|
||||||
UpdatedAt: user.UpdatedAt.Time,
|
UpdatedAt: user.UpdatedAt.Time,
|
||||||
SuspendedAt: user.SuspendedAt.Time,
|
SuspendedAt: user.SuspendedAt.Time,
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
|
CompanyID: domain.ValidInt64{
|
||||||
|
Value: user.CompanyID.Int64,
|
||||||
|
Valid: user.CompanyID.Valid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalCount, err := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
totalCount, err := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
||||||
|
|
@ -130,10 +138,10 @@ func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.U
|
||||||
return userList, totalCount, nil
|
return userList, totalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error) {
|
func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, int64, error) {
|
||||||
users, err := s.queries.GetAllCashiers(ctx)
|
users, err := s.queries.GetAllCashiers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
userList := make([]domain.GetCashier, len(users))
|
userList := make([]domain.GetCashier, len(users))
|
||||||
for i, user := range users {
|
for i, user := range users {
|
||||||
|
|
@ -150,9 +158,16 @@ func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error)
|
||||||
UpdatedAt: user.UpdatedAt.Time,
|
UpdatedAt: user.UpdatedAt.Time,
|
||||||
SuspendedAt: user.SuspendedAt.Time,
|
SuspendedAt: user.SuspendedAt.Time,
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
|
BranchID: user.BranchID,
|
||||||
|
BranchName: user.BranchName,
|
||||||
|
BranchWallet: user.BranchWallet,
|
||||||
|
BranchLocation: user.BranchLocation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return userList, nil
|
totalCount, err := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
||||||
|
Role: string(domain.RoleCashier),
|
||||||
|
})
|
||||||
|
return userList, totalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) {
|
func (s *Store) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) {
|
||||||
|
|
@ -174,6 +189,9 @@ func (s *Store) GetCashierByID(ctx context.Context, cashierID int64) (domain.Get
|
||||||
SuspendedAt: user.SuspendedAt.Time,
|
SuspendedAt: user.SuspendedAt.Time,
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
BranchID: user.BranchID,
|
BranchID: user.BranchID,
|
||||||
|
BranchName: user.BranchName,
|
||||||
|
BranchWallet: user.BranchWallet,
|
||||||
|
BranchLocation: user.BranchLocation,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,14 @@ var (
|
||||||
type Service struct {
|
type Service struct {
|
||||||
betStore BetStore
|
betStore BetStore
|
||||||
eventSvc event.Service
|
eventSvc event.Service
|
||||||
prematchSvc odds.Service
|
prematchSvc odds.ServiceImpl
|
||||||
walletSvc wallet.Service
|
walletSvc wallet.Service
|
||||||
branchSvc branch.Service
|
branchSvc branch.Service
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
mongoLogger *zap.Logger
|
mongoLogger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(betStore BetStore, eventSvc event.Service, prematchSvc odds.Service, walletSvc wallet.Service, branchSvc branch.Service, logger *slog.Logger, mongoLogger *zap.Logger) *Service {
|
func NewService(betStore BetStore, eventSvc event.Service, prematchSvc odds.ServiceImpl, walletSvc wallet.Service, branchSvc branch.Service, logger *slog.Logger, mongoLogger *zap.Logger) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
betStore: betStore,
|
betStore: betStore,
|
||||||
eventSvc: eventSvc,
|
eventSvc: eventSvc,
|
||||||
|
|
@ -490,7 +490,12 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
// Get a unexpired event id
|
// Get a unexpired event id
|
||||||
|
|
||||||
events, _, err := s.eventSvc.GetPaginatedUpcomingEvents(ctx,
|
events, _, err := s.eventSvc.GetPaginatedUpcomingEvents(ctx,
|
||||||
domain.ValidInt64{}, domain.ValidInt64{}, leagueID, sportID, firstStartTime, lastStartTime)
|
domain.EventFilter{
|
||||||
|
SportID: sportID,
|
||||||
|
LeagueID: leagueID,
|
||||||
|
FirstStartTime: firstStartTime,
|
||||||
|
LastStartTime: lastStartTime,
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to get paginated upcoming events",
|
s.mongoLogger.Error("failed to get paginated upcoming events",
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ type Service interface {
|
||||||
FetchLiveEvents(ctx context.Context) error
|
FetchLiveEvents(ctx context.Context) error
|
||||||
FetchUpcomingEvents(ctx context.Context) error
|
FetchUpcomingEvents(ctx context.Context) error
|
||||||
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||||
GetExpiredUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error)
|
||||||
GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidInt32, sportID domain.ValidInt32, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error)
|
GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error)
|
||||||
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
||||||
// GetAndStoreMatchResult(ctx context.Context, eventID string) error
|
// GetAndStoreMatchResult(ctx context.Context, eventID string) error
|
||||||
|
UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error
|
||||||
|
UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -209,16 +209,17 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
||||||
// log.Printf("❌ Failed to open leagues file %v", err)
|
// log.Printf("❌ Failed to open leagues file %v", err)
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
for _, sportID := range sportIDs {
|
for sportIndex, sportID := range sportIDs {
|
||||||
var totalPages int = 1
|
var totalPages int = 1
|
||||||
var page int = 0
|
var page int = 0
|
||||||
var limit int = 100
|
var limit int = 200
|
||||||
var count int = 0
|
var count int = 0
|
||||||
log.Printf("Sport ID %d", sportID)
|
log.Printf("Sport ID %d", sportID)
|
||||||
for page <= totalPages {
|
for page <= totalPages {
|
||||||
page = page + 1
|
page = page + 1
|
||||||
url := fmt.Sprintf(url, sportID, s.token, page)
|
url := fmt.Sprintf(url, sportID, s.token, page)
|
||||||
log.Printf("📡 Fetching data from %s - sport %d, for event data page %d", source, sportID, page)
|
log.Printf("📡 Fetching data from %s - sport %d (%d/%d), for event data page (%d/%d)",
|
||||||
|
source, sportID, sportIndex+1, len(sportIDs), page, totalPages)
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("❌ Failed to fetch event data for page %d: %v", page, err)
|
log.Printf("❌ Failed to fetch event data for page %d: %v", page, err)
|
||||||
|
|
@ -249,13 +250,23 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
||||||
}
|
}
|
||||||
|
|
||||||
// doesn't make sense to save and check back to back, but for now it can be here
|
// doesn't make sense to save and check back to back, but for now it can be here
|
||||||
s.store.SaveLeague(ctx, domain.League{
|
// no this its fine to keep it here
|
||||||
|
// but change the league id to bet365 id later
|
||||||
|
err = s.store.SaveLeague(ctx, domain.League{
|
||||||
ID: leagueID,
|
ID: leagueID,
|
||||||
Name: ev.League.Name,
|
Name: ev.League.Name,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
|
SportID: convertInt32(ev.SportID),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Error Saving League on %v", ev.League.Name)
|
||||||
|
log.Printf("err:%v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if supported, err := s.store.CheckLeagueSupport(ctx, leagueID); !supported || err != nil {
|
if supported, err := s.store.CheckLeagueSupport(ctx, leagueID); !supported || err != nil {
|
||||||
|
log.Printf("Skipping league %v", ev.League.Name)
|
||||||
skippedLeague = append(skippedLeague, ev.League.Name)
|
skippedLeague = append(skippedLeague, ev.League.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -335,18 +346,25 @@ func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEv
|
||||||
return s.store.GetAllUpcomingEvents(ctx)
|
return s.store.GetAllUpcomingEvents(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetExpiredUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
|
func (s *service) GetExpiredUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, error) {
|
||||||
return s.store.GetExpiredUpcomingEvents(ctx)
|
return s.store.GetExpiredUpcomingEvents(ctx, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit domain.ValidInt64, offset domain.ValidInt64, leagueID domain.ValidInt32, sportID domain.ValidInt32, firstStartTime domain.ValidTime, lastStartTime domain.ValidTime) ([]domain.UpcomingEvent, int64, error) {
|
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.EventFilter) ([]domain.UpcomingEvent, int64, error) {
|
||||||
return s.store.GetPaginatedUpcomingEvents(ctx, limit, offset, leagueID, sportID, firstStartTime, lastStartTime)
|
return s.store.GetPaginatedUpcomingEvents(ctx, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
return s.store.GetUpcomingEventByID(ctx, ID)
|
return s.store.GetUpcomingEventByID(ctx, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error {
|
||||||
|
return s.store.UpdateFinalScore(ctx, eventID, fullScore, status)
|
||||||
|
}
|
||||||
|
func (s *service) UpdateEventStatus(ctx context.Context, eventID string, status domain.EventStatus) error {
|
||||||
|
return s.store.UpdateEventStatus(ctx, eventID, status)
|
||||||
|
}
|
||||||
|
|
||||||
// func (s *service) GetAndStoreMatchResult(ctx context.Context, eventID string) error {
|
// func (s *service) GetAndStoreMatchResult(ctx context.Context, eventID string) error {
|
||||||
// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%s", s.token, eventID)
|
// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%s", s.token, eventID)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
GetAllLeagues(ctx context.Context) ([]domain.League, error)
|
SaveLeague(ctx context.Context, l domain.League) error
|
||||||
SetLeagueActive(ctx context.Context, leagueId int64) error
|
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error)
|
||||||
|
SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error
|
||||||
|
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,18 @@ func New(store *repository.Store) Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) GetAllLeagues(ctx context.Context) ([]domain.League, error) {
|
func (s *service) SaveLeague(ctx context.Context, l domain.League) error {
|
||||||
return s.store.GetAllLeagues(ctx)
|
return s.store.SaveLeague(ctx, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) SetLeagueActive(ctx context.Context, leagueId int64) error {
|
func (s *service) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error) {
|
||||||
return s.store.SetLeagueActive(ctx, leagueId)
|
return s.store.GetAllLeagues(ctx, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error {
|
||||||
|
return s.store.SetLeagueActive(ctx, leagueId, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error {
|
||||||
|
return s.store.UpdateLeague(ctx, league)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,19 @@ package odds
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
FetchNonLiveOdds(ctx context.Context) error
|
FetchNonLiveOdds(ctx context.Context) error
|
||||||
|
FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr string) (domain.BaseNonLiveOddResponse, error)
|
||||||
|
ParseOddSections(ctx context.Context, res json.RawMessage, sportID int64) (domain.ParseOddSectionsRes, error)
|
||||||
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
||||||
GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error)
|
GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string) ([]domain.Odd, error)
|
||||||
GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.Odd, error)
|
GetPaginatedPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit domain.ValidInt64, offset domain.ValidInt64) ([]domain.Odd, error)
|
||||||
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
|
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
|
||||||
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error)
|
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error)
|
||||||
|
DeleteOddsForEvent(ctx context.Context, eventID string) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,18 +41,23 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
||||||
// wg.Add(2)
|
// wg.Add(2)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := s.fetchBet365Odds(ctx); err != nil {
|
||||||
|
errChan <- fmt.Errorf("bet365 odds fetching error: %w", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// go func() {
|
// go func() {
|
||||||
// defer wg.Done()
|
// defer wg.Done()
|
||||||
// if err := s.fetchBet365Odds(ctx); err != nil {
|
// if err := s.fetchBwinOdds(ctx); err != nil {
|
||||||
// errChan <- fmt.Errorf("bet365 odds fetching error: %w", err)
|
// errChan <- fmt.Errorf("bwin odds fetching error: %w", err)
|
||||||
// }
|
// }
|
||||||
// }()
|
// }()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
wg.Wait()
|
||||||
if err := s.fetchBwinOdds(ctx); err != nil {
|
close(errChan)
|
||||||
errChan <- fmt.Errorf("bwin odds fetching error: %w", err)
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
@ -77,98 +82,40 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
for index, event := range eventIDs {
|
for index, event := range eventIDs {
|
||||||
|
log.Printf("📡 Fetching prematch odds for event ID: %v (%d/%d) ", event.ID, index, len(eventIDs))
|
||||||
|
|
||||||
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
oddsData, err := s.FetchNonLiveOddsByEventID(ctx, event.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse event id", "error", err.Error())
|
s.logger.Error("Failed to fetch prematch odds", "eventID", event.ID, "error", err)
|
||||||
return err
|
errs = append(errs, fmt.Errorf("failed to fetch prematch odds for event %v: %w", event.ID, err))
|
||||||
}
|
|
||||||
|
|
||||||
url := fmt.Sprintf("https://api.b365api.com/v3/bet365/prematch?token=%s&FI=%d", s.config.Bet365Token, eventID)
|
|
||||||
|
|
||||||
log.Printf("📡 Fetching prematch odds for event ID: %d (%d/%d) ", eventID, index, len(eventIDs))
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("❌ Failed to create request for event %d: %v", eventID, err)
|
|
||||||
s.logger.Error("Failed to create request for event%d: %v", strconv.FormatInt(eventID, 10), err.Error())
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
parsedOddSections, err := s.ParseOddSections(ctx, oddsData.Results[0], event.SportID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("❌ Failed to fetch prematch odds for event %d: %v", eventID, err)
|
s.logger.Error("Failed to parse odd section", "error", err)
|
||||||
continue
|
errs = append(errs, fmt.Errorf("failed to parse odd section for event %v: %w", event.ID, err))
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("❌ Failed to read response body for event %d: %v", eventID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var oddsData domain.BaseNonLiveOddResponse
|
|
||||||
|
|
||||||
if err := json.Unmarshal(body, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
|
||||||
log.Printf("❌ Invalid prematch data for event %d", eventID)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch event.SportID {
|
if parsedOddSections.EventFI == "" {
|
||||||
case domain.FOOTBALL:
|
s.logger.Error("Skipping result with no valid Event FI field", "fi", parsedOddSections.EventFI)
|
||||||
if err := s.parseFootball(ctx, oddsData.Results[0]); err != nil {
|
errs = append(errs, errors.New("event FI is empty"))
|
||||||
s.logger.Error("Error while inserting football odd")
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for oddCategory, section := range parsedOddSections.Sections {
|
||||||
|
if err := s.storeSection(ctx, event.ID, parsedOddSections.EventFI, oddCategory, section); err != nil {
|
||||||
|
s.logger.Error("Error storing odd section", "eventID", event.ID, "odd", oddCategory)
|
||||||
|
log.Printf("⚠️ Error when storing %v", err)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
case domain.BASKETBALL:
|
|
||||||
if err := s.parseBasketball(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting basketball odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
}
|
||||||
case domain.ICE_HOCKEY:
|
for _, section := range parsedOddSections.OtherRes {
|
||||||
if err := s.parseIceHockey(ctx, oddsData.Results[0]); err != nil {
|
if err := s.storeSection(ctx, event.ID, parsedOddSections.EventFI, "others", section); err != nil {
|
||||||
s.logger.Error("Error while inserting ice hockey odd")
|
s.logger.Error("Skipping result with no valid Event ID")
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.CRICKET:
|
|
||||||
if err := s.parseCricket(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting cricket odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.VOLLEYBALL:
|
|
||||||
if err := s.parseVolleyball(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting volleyball odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.DARTS:
|
|
||||||
if err := s.parseDarts(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting darts odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.FUTSAL:
|
|
||||||
if err := s.parseFutsal(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting futsal odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.AMERICAN_FOOTBALL:
|
|
||||||
if err := s.parseAmericanFootball(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting american football odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.RUGBY_LEAGUE:
|
|
||||||
if err := s.parseRugbyLeague(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting rugby league odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.RUGBY_UNION:
|
|
||||||
if err := s.parseRugbyUnion(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting rugby union odd")
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
case domain.BASEBALL:
|
|
||||||
if err := s.parseBaseball(ctx, oddsData.Results[0]); err != nil {
|
|
||||||
s.logger.Error("Error while inserting baseball odd")
|
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,6 +123,10 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for err := range errs {
|
||||||
|
log.Printf("❌ Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,134 +217,99 @@ func (s *ServiceImpl) fetchBwinOdds(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) parseFootball(ctx context.Context, res json.RawMessage) error {
|
func (s *ServiceImpl) FetchNonLiveOddsByEventID(ctx context.Context, eventIDStr string) (domain.BaseNonLiveOddResponse, error) {
|
||||||
|
|
||||||
|
eventID, err := strconv.ParseInt(eventIDStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse event id")
|
||||||
|
return domain.BaseNonLiveOddResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("https://api.b365api.com/v3/bet365/prematch?token=%s&FI=%d", s.config.Bet365Token, eventID)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Failed to create request for event %d: %v", eventID, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Failed to fetch prematch odds for event %d: %v", eventID, err)
|
||||||
|
return domain.BaseNonLiveOddResponse{}, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Failed to read response body for event %d: %v", eventID, err)
|
||||||
|
return domain.BaseNonLiveOddResponse{}, err
|
||||||
|
}
|
||||||
|
var oddsData domain.BaseNonLiveOddResponse
|
||||||
|
|
||||||
|
if err := json.Unmarshal(body, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
||||||
|
log.Printf("❌ Invalid prematch data for event %d", eventID)
|
||||||
|
return domain.BaseNonLiveOddResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return oddsData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage, sportID int32) (domain.ParseOddSectionsRes, error) {
|
||||||
|
var sections map[string]domain.OddsSection
|
||||||
|
var OtherRes []domain.OddsSection
|
||||||
|
var eventFI string
|
||||||
|
switch sportID {
|
||||||
|
case domain.FOOTBALL:
|
||||||
var footballRes domain.FootballOddsResponse
|
var footballRes domain.FootballOddsResponse
|
||||||
if err := json.Unmarshal(res, &footballRes); err != nil {
|
if err := json.Unmarshal(res, &footballRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal football result", "error", err)
|
s.logger.Error("Failed to unmarshal football result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if footballRes.EventID == "" && footballRes.FI == "" {
|
eventFI = footballRes.FI
|
||||||
s.logger.Error("Skipping football result with no valid Event ID", "eventID", footballRes.EventID, "fi", footballRes.FI)
|
sections = map[string]domain.OddsSection{
|
||||||
return fmt.Errorf("Skipping football result with no valid Event ID Event ID %v", footballRes.EventID)
|
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": footballRes.Main,
|
"main": footballRes.Main,
|
||||||
"asian_lines": footballRes.AsianLines,
|
"asian_lines": footballRes.AsianLines,
|
||||||
"goals": footballRes.Goals,
|
"goals": footballRes.Goals,
|
||||||
"half": footballRes.Half,
|
"half": footballRes.Half,
|
||||||
}
|
}
|
||||||
|
case domain.BASKETBALL:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, footballRes.EventID, footballRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Error storing football section", "eventID", footballRes.FI, "odd", oddCategory)
|
|
||||||
log.Printf("⚠️ Error when storing football %v", err)
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseBasketball(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var basketballRes domain.BasketballOddsResponse
|
var basketballRes domain.BasketballOddsResponse
|
||||||
if err := json.Unmarshal(res, &basketballRes); err != nil {
|
if err := json.Unmarshal(res, &basketballRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal basketball result", "error", err)
|
s.logger.Error("Failed to unmarshal basketball result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if basketballRes.EventID == "" && basketballRes.FI == "" {
|
eventFI = basketballRes.FI
|
||||||
s.logger.Error("Skipping basketball result with no valid Event ID")
|
OtherRes = basketballRes.Others
|
||||||
return fmt.Errorf("Skipping basketball result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": basketballRes.Main,
|
"main": basketballRes.Main,
|
||||||
"half_props": basketballRes.HalfProps,
|
"half_props": basketballRes.HalfProps,
|
||||||
"quarter_props": basketballRes.QuarterProps,
|
"quarter_props": basketballRes.QuarterProps,
|
||||||
"team_props": basketballRes.TeamProps,
|
"team_props": basketballRes.TeamProps,
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
case domain.ICE_HOCKEY:
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, basketballRes.EventID, basketballRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range basketballRes.Others {
|
|
||||||
if err := s.storeSection(ctx, basketballRes.EventID, basketballRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (s *ServiceImpl) parseIceHockey(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var iceHockeyRes domain.IceHockeyOddsResponse
|
var iceHockeyRes domain.IceHockeyOddsResponse
|
||||||
if err := json.Unmarshal(res, &iceHockeyRes); err != nil {
|
if err := json.Unmarshal(res, &iceHockeyRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if iceHockeyRes.EventID == "" && iceHockeyRes.FI == "" {
|
eventFI = iceHockeyRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = iceHockeyRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": iceHockeyRes.Main,
|
"main": iceHockeyRes.Main,
|
||||||
"main_2": iceHockeyRes.Main2,
|
"main_2": iceHockeyRes.Main2,
|
||||||
"1st_period": iceHockeyRes.FirstPeriod,
|
"1st_period": iceHockeyRes.FirstPeriod,
|
||||||
}
|
}
|
||||||
|
case domain.CRICKET:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, iceHockeyRes.EventID, iceHockeyRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range iceHockeyRes.Others {
|
|
||||||
if err := s.storeSection(ctx, iceHockeyRes.EventID, iceHockeyRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseCricket(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var cricketRes domain.CricketOddsResponse
|
var cricketRes domain.CricketOddsResponse
|
||||||
if err := json.Unmarshal(res, &cricketRes); err != nil {
|
if err := json.Unmarshal(res, &cricketRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if cricketRes.EventID == "" && cricketRes.FI == "" {
|
eventFI = cricketRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = cricketRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"1st_over": cricketRes.Main,
|
"1st_over": cricketRes.Main,
|
||||||
"innings_1": cricketRes.First_Innings,
|
"innings_1": cricketRes.First_Innings,
|
||||||
"main": cricketRes.Main,
|
"main": cricketRes.Main,
|
||||||
|
|
@ -401,205 +317,65 @@ func (s *ServiceImpl) parseCricket(ctx context.Context, res json.RawMessage) err
|
||||||
"player": cricketRes.Player,
|
"player": cricketRes.Player,
|
||||||
"team": cricketRes.Team,
|
"team": cricketRes.Team,
|
||||||
}
|
}
|
||||||
|
case domain.VOLLEYBALL:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, cricketRes.EventID, cricketRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range cricketRes.Others {
|
|
||||||
if err := s.storeSection(ctx, cricketRes.EventID, cricketRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseVolleyball(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var volleyballRes domain.VolleyballOddsResponse
|
var volleyballRes domain.VolleyballOddsResponse
|
||||||
if err := json.Unmarshal(res, &volleyballRes); err != nil {
|
if err := json.Unmarshal(res, &volleyballRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if volleyballRes.EventID == "" && volleyballRes.FI == "" {
|
eventFI = volleyballRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = volleyballRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": volleyballRes.Main,
|
"main": volleyballRes.Main,
|
||||||
}
|
}
|
||||||
|
case domain.DARTS:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, volleyballRes.EventID, volleyballRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range volleyballRes.Others {
|
|
||||||
if err := s.storeSection(ctx, volleyballRes.EventID, volleyballRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseDarts(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var dartsRes domain.DartsOddsResponse
|
var dartsRes domain.DartsOddsResponse
|
||||||
if err := json.Unmarshal(res, &dartsRes); err != nil {
|
if err := json.Unmarshal(res, &dartsRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if dartsRes.EventID == "" && dartsRes.FI == "" {
|
eventFI = dartsRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = dartsRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"180s": dartsRes.OneEightys,
|
"180s": dartsRes.OneEightys,
|
||||||
"extra": dartsRes.Extra,
|
"extra": dartsRes.Extra,
|
||||||
"leg": dartsRes.Leg,
|
"leg": dartsRes.Leg,
|
||||||
"main": dartsRes.Main,
|
"main": dartsRes.Main,
|
||||||
}
|
}
|
||||||
|
case domain.FUTSAL:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, dartsRes.EventID, dartsRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range dartsRes.Others {
|
|
||||||
if err := s.storeSection(ctx, dartsRes.EventID, dartsRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseFutsal(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var futsalRes domain.FutsalOddsResponse
|
var futsalRes domain.FutsalOddsResponse
|
||||||
if err := json.Unmarshal(res, &futsalRes); err != nil {
|
if err := json.Unmarshal(res, &futsalRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if futsalRes.EventID == "" && futsalRes.FI == "" {
|
eventFI = futsalRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = futsalRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": futsalRes.Main,
|
"main": futsalRes.Main,
|
||||||
"score": futsalRes.Score,
|
"score": futsalRes.Score,
|
||||||
}
|
}
|
||||||
|
case domain.AMERICAN_FOOTBALL:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, futsalRes.EventID, futsalRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range futsalRes.Others {
|
|
||||||
if err := s.storeSection(ctx, futsalRes.EventID, futsalRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseAmericanFootball(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var americanFootballRes domain.AmericanFootballOddsResponse
|
var americanFootballRes domain.AmericanFootballOddsResponse
|
||||||
if err := json.Unmarshal(res, &americanFootballRes); err != nil {
|
if err := json.Unmarshal(res, &americanFootballRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if americanFootballRes.EventID == "" && americanFootballRes.FI == "" {
|
eventFI = americanFootballRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = americanFootballRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"half_props": americanFootballRes.HalfProps,
|
"half_props": americanFootballRes.HalfProps,
|
||||||
"main": americanFootballRes.Main,
|
"main": americanFootballRes.Main,
|
||||||
"quarter_props": americanFootballRes.QuarterProps,
|
"quarter_props": americanFootballRes.QuarterProps,
|
||||||
}
|
}
|
||||||
|
case domain.RUGBY_LEAGUE:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, americanFootballRes.EventID, americanFootballRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range americanFootballRes.Others {
|
|
||||||
if err := s.storeSection(ctx, americanFootballRes.EventID, americanFootballRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseRugbyLeague(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var rugbyLeagueRes domain.RugbyLeagueOddsResponse
|
var rugbyLeagueRes domain.RugbyLeagueOddsResponse
|
||||||
if err := json.Unmarshal(res, &rugbyLeagueRes); err != nil {
|
if err := json.Unmarshal(res, &rugbyLeagueRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if rugbyLeagueRes.EventID == "" && rugbyLeagueRes.FI == "" {
|
eventFI = rugbyLeagueRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = rugbyLeagueRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"10minute": rugbyLeagueRes.TenMinute,
|
"10minute": rugbyLeagueRes.TenMinute,
|
||||||
"main": rugbyLeagueRes.Main,
|
"main": rugbyLeagueRes.Main,
|
||||||
"main_2": rugbyLeagueRes.Main2,
|
"main_2": rugbyLeagueRes.Main2,
|
||||||
|
|
@ -607,105 +383,39 @@ func (s *ServiceImpl) parseRugbyLeague(ctx context.Context, res json.RawMessage)
|
||||||
"Score": rugbyLeagueRes.Score,
|
"Score": rugbyLeagueRes.Score,
|
||||||
"Team": rugbyLeagueRes.Team,
|
"Team": rugbyLeagueRes.Team,
|
||||||
}
|
}
|
||||||
|
case domain.RUGBY_UNION:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, rugbyLeagueRes.EventID, rugbyLeagueRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range rugbyLeagueRes.Others {
|
|
||||||
if err := s.storeSection(ctx, rugbyLeagueRes.EventID, rugbyLeagueRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseRugbyUnion(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var rugbyUnionRes domain.RugbyUnionOddsResponse
|
var rugbyUnionRes domain.RugbyUnionOddsResponse
|
||||||
if err := json.Unmarshal(res, &rugbyUnionRes); err != nil {
|
if err := json.Unmarshal(res, &rugbyUnionRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if rugbyUnionRes.EventID == "" && rugbyUnionRes.FI == "" {
|
eventFI = rugbyUnionRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
OtherRes = rugbyUnionRes.Others
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": rugbyUnionRes.Main,
|
"main": rugbyUnionRes.Main,
|
||||||
"main_2": rugbyUnionRes.Main2,
|
"main_2": rugbyUnionRes.Main2,
|
||||||
"player": rugbyUnionRes.Player,
|
"player": rugbyUnionRes.Player,
|
||||||
"Score": rugbyUnionRes.Score,
|
"Score": rugbyUnionRes.Score,
|
||||||
"Team": rugbyUnionRes.Team,
|
"Team": rugbyUnionRes.Team,
|
||||||
}
|
}
|
||||||
|
case domain.BASEBALL:
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, rugbyUnionRes.EventID, rugbyUnionRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, section := range rugbyUnionRes.Others {
|
|
||||||
if err := s.storeSection(ctx, rugbyUnionRes.EventID, rugbyUnionRes.FI, "others", section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServiceImpl) parseBaseball(ctx context.Context, res json.RawMessage) error {
|
|
||||||
var baseballRes domain.BaseballOddsResponse
|
var baseballRes domain.BaseballOddsResponse
|
||||||
if err := json.Unmarshal(res, &baseballRes); err != nil {
|
if err := json.Unmarshal(res, &baseballRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "error", err)
|
||||||
return err
|
return domain.ParseOddSectionsRes{}, err
|
||||||
}
|
}
|
||||||
if baseballRes.EventID == "" && baseballRes.FI == "" {
|
eventFI = baseballRes.FI
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
sections = map[string]domain.OddsSection{
|
||||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
|
||||||
}
|
|
||||||
sections := map[string]domain.OddsSection{
|
|
||||||
"main": baseballRes.Main,
|
"main": baseballRes.Main,
|
||||||
"mani_props": baseballRes.MainProps,
|
"mani_props": baseballRes.MainProps,
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for oddCategory, section := range sections {
|
|
||||||
if err := s.storeSection(ctx, baseballRes.EventID, baseballRes.FI, oddCategory, section); err != nil {
|
|
||||||
s.logger.Error("Skipping result with no valid Event ID")
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
return domain.ParseOddSectionsRes{
|
||||||
return errors.Join(errs...)
|
Sections: sections,
|
||||||
}
|
OtherRes: OtherRes,
|
||||||
|
EventFI: eventFI,
|
||||||
return nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section domain.OddsSection) error {
|
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section domain.OddsSection) error {
|
||||||
|
|
@ -725,22 +435,21 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
||||||
// Check if the market id is a string
|
// Check if the market id is a string
|
||||||
var marketIDstr string
|
var marketIDstr string
|
||||||
err := json.Unmarshal(market.ID, &marketIDstr)
|
err := json.Unmarshal(market.ID, &marketIDstr)
|
||||||
|
var marketIDint int64
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// check if its int
|
// check if its int
|
||||||
var marketIDint int
|
|
||||||
err := json.Unmarshal(market.ID, &marketIDint)
|
err := json.Unmarshal(market.ID, &marketIDint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||||
errs = append(errs, err)
|
continue
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
marketIDint, err = strconv.ParseInt(marketIDstr, 10, 64)
|
||||||
marketIDint, err := strconv.ParseInt(marketIDstr, 10, 64)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isSupported, ok := domain.SupportedMarkets[marketIDint]
|
isSupported, ok := domain.SupportedMarkets[marketIDint]
|
||||||
|
|
||||||
|
|
@ -808,6 +517,10 @@ func (s *ServiceImpl) GetPaginatedPrematchOddsByUpcomingID(ctx context.Context,
|
||||||
return s.store.GetPaginatedPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset)
|
return s.store.GetPaginatedPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID string) error {
|
||||||
|
return s.store.DeleteOddsForEvent(ctx, eventID)
|
||||||
|
}
|
||||||
|
|
||||||
func getString(v interface{}) string {
|
func getString(v interface{}) string {
|
||||||
if str, ok := v.(string); ok {
|
if str, ok := v.(string); ok {
|
||||||
return str
|
return str
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -14,6 +15,9 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
|
@ -22,43 +26,52 @@ type Service struct {
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
client *http.Client
|
client *http.Client
|
||||||
betSvc bet.Service
|
betSvc bet.Service
|
||||||
|
oddSvc odds.ServiceImpl
|
||||||
|
eventSvc event.Service
|
||||||
|
leagueSvc league.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger, betSvc bet.Service) *Service {
|
func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger, betSvc bet.Service, oddSvc odds.ServiceImpl, eventSvc event.Service, leagueSvc league.Service) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
client: &http.Client{Timeout: 10 * time.Second},
|
client: &http.Client{Timeout: 10 * time.Second},
|
||||||
betSvc: betSvc,
|
betSvc: betSvc,
|
||||||
|
oddSvc: oddSvc,
|
||||||
|
eventSvc: eventSvc,
|
||||||
|
leagueSvc: leagueSvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrEventIsNotActive = fmt.Errorf("Event has been cancelled or postponed")
|
ErrEventIsNotActive = fmt.Errorf("event has been cancelled or postponed")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
// TODO: Optimize this because there could be many bet outcomes for the same odd
|
// TODO: Optimize this because there could be many bet outcomes for the same odd
|
||||||
// Take market id and match result as param and update all the bet outcomes at the same time
|
// Take market id and match result as param and update all the bet outcomes at the same time
|
||||||
events, err := s.repo.GetExpiredUpcomingEvents(ctx)
|
events, err := s.repo.GetExpiredUpcomingEvents(ctx, domain.EventFilter{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to fetch events")
|
s.logger.Error("Failed to fetch events")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("⚠️ Expired Events: %d \n", len(events))
|
fmt.Printf("⚠️ Expired Events: %d \n", len(events))
|
||||||
removed := 0
|
removed := 0
|
||||||
|
errs := make([]error, 0, len(events))
|
||||||
for i, event := range events {
|
for i, event := range events {
|
||||||
|
|
||||||
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse event id")
|
s.logger.Error("Failed to parse event id")
|
||||||
return err
|
errs = append(errs, fmt.Errorf("failed to parse event id %s: %w", event.ID, err))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
|
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get pending bet outcomes", "error", err)
|
s.logger.Error("Failed to get pending bet outcomes", "error", err)
|
||||||
return err
|
errs = append(errs, fmt.Errorf("failed to get pending bet outcomes for event %d: %w", eventID, err))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(outcomes) == 0 {
|
if len(outcomes) == 0 {
|
||||||
|
|
@ -68,6 +81,40 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
isDeleted := true
|
isDeleted := true
|
||||||
|
result, err := s.fetchResult(ctx, eventID)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrEventIsNotActive {
|
||||||
|
s.logger.Warn("Event is not active", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var commonResp domain.CommonResultResponse
|
||||||
|
if err := json.Unmarshal(result.Results[0], &commonResp); err != nil {
|
||||||
|
s.logger.Error("Failed to unmarshal common result", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sportID, err := strconv.ParseInt(commonResp.SportID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse sport id", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
timeStatusParsed, err := strconv.ParseInt(strings.TrimSpace(commonResp.TimeStatus), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse time status", "time_status", commonResp.TimeStatus, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Figure out what to do with the events that have been cancelled or postponed, etc...
|
||||||
|
if timeStatusParsed != int64(domain.TIME_STATUS_ENDED) {
|
||||||
|
s.logger.Warn("Event is not ended yet", "event_id", eventID, "time_status", commonResp.TimeStatus)
|
||||||
|
fmt.Printf("⚠️ Event %v is not ended yet (%d/%d) \n", event.ID, i+1, len(events))
|
||||||
|
isDeleted = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for j, outcome := range outcomes {
|
for j, outcome := range outcomes {
|
||||||
fmt.Printf("⚙️ Processing 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
fmt.Printf("⚙️ Processing 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
||||||
outcome.MarketName,
|
outcome.MarketName,
|
||||||
|
|
@ -80,23 +127,14 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize this because the result is being fetched for each outcome which will have the same event id but different market id
|
parseResult, err := s.parseResult(ctx, result.Results[0], outcome, sportID)
|
||||||
result, err := s.fetchResult(ctx, outcome.EventID, outcome.OddID, outcome.MarketID, int64(event.SportID), outcome)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrEventIsNotActive {
|
|
||||||
s.logger.Warn("Event is not active", "event_id", outcome.EventID, "error", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Printf("❌ failed to parse 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
|
||||||
outcome.MarketName,
|
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
|
||||||
j+1, len(outcomes))
|
|
||||||
s.logger.Error("Failed to fetch result", "event_id", outcome.EventID, "outcome_id", outcome.ID, "market_id", outcome.MarketID, "market", outcome.MarketName, "error", err)
|
|
||||||
isDeleted = false
|
isDeleted = false
|
||||||
|
s.logger.Error("Failed to parse result", "event_id", outcome.EventID, "outcome_id", outcome.ID, "error", err)
|
||||||
|
errs = append(errs, fmt.Errorf("failed to parse result for event %d: %w", outcome.EventID, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, parseResult.Status)
|
||||||
outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, result.Status)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
isDeleted = false
|
isDeleted = false
|
||||||
s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
||||||
|
|
@ -147,113 +185,389 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
s.logger.Error("Failed to remove event", "event_id", event.ID, "error", err)
|
s.logger.Error("Failed to remove event", "event_id", event.ID, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = s.repo.DeleteOddsForEvent(ctx, event.ID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to remove odds for event", "event_id", event.ID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
fmt.Printf("🗑️ Removed Events: %d \n", removed)
|
fmt.Printf("🗑️ Removed Events: %d \n", removed)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
s.logger.Error("Errors occurred while processing results", "errors", errs)
|
||||||
|
for _, err := range errs {
|
||||||
|
fmt.Println("Error:", err)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("errors occurred while processing results: %v", errs)
|
||||||
|
}
|
||||||
|
s.logger.Info("Successfully processed results", "removed_events", removed, "total_events", len(events))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) fetchResult(ctx context.Context, eventID, oddID, marketID, sportID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
func (s *Service) CheckAndUpdateExpiredEvents(ctx context.Context) (int64, error) {
|
||||||
// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
events, err := s.repo.GetExpiredUpcomingEvents(ctx, domain.EventFilter{})
|
||||||
url := fmt.Sprintf("https://api.b365api.com/v1/event/view?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to fetch events")
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
fmt.Printf("⚠️ Expired Events: %d \n", len(events))
|
||||||
|
updated := 0
|
||||||
|
for i, event := range events {
|
||||||
|
fmt.Printf("⚙️ Processing event %v (%d/%d) \n", event.ID, i+1, len(events))
|
||||||
|
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse event id")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Status == domain.STATUS_REMOVED {
|
||||||
|
s.logger.Info("Skipping updating removed event")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result, err := s.fetchResult(ctx, eventID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result.Success != 1 || len(result.Results) == 0 {
|
||||||
|
s.logger.Error("Invalid API response", "event_id", eventID)
|
||||||
|
fmt.Printf("⚠️ Invalid API response for event %v \n", result)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonResp domain.CommonResultResponse
|
||||||
|
if err := json.Unmarshal(result.Results[0], &commonResp); err != nil {
|
||||||
|
s.logger.Error("Failed to unmarshal common result", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventStatus domain.EventStatus
|
||||||
|
// TODO Change event status to int64 enum
|
||||||
|
timeStatus, err := strconv.ParseInt(strings.TrimSpace(commonResp.TimeStatus), 10, 64)
|
||||||
|
switch timeStatus {
|
||||||
|
case int64(domain.TIME_STATUS_NOT_STARTED):
|
||||||
|
eventStatus = domain.STATUS_PENDING
|
||||||
|
case int64(domain.TIME_STATUS_IN_PLAY):
|
||||||
|
eventStatus = domain.STATUS_IN_PLAY
|
||||||
|
case int64(domain.TIME_STATUS_TO_BE_FIXED):
|
||||||
|
eventStatus = domain.STATUS_TO_BE_FIXED
|
||||||
|
case int64(domain.TIME_STATUS_ENDED):
|
||||||
|
eventStatus = domain.STATUS_ENDED
|
||||||
|
case int64(domain.TIME_STATUS_POSTPONED):
|
||||||
|
eventStatus = domain.STATUS_POSTPONED
|
||||||
|
case int64(domain.TIME_STATUS_CANCELLED):
|
||||||
|
eventStatus = domain.STATUS_CANCELLED
|
||||||
|
case int64(domain.TIME_STATUS_WALKOVER):
|
||||||
|
eventStatus = domain.STATUS_WALKOVER
|
||||||
|
case int64(domain.TIME_STATUS_INTERRUPTED):
|
||||||
|
eventStatus = domain.STATUS_INTERRUPTED
|
||||||
|
case int64(domain.TIME_STATUS_ABANDONED):
|
||||||
|
eventStatus = domain.STATUS_ABANDONED
|
||||||
|
case int64(domain.TIME_STATUS_RETIRED):
|
||||||
|
eventStatus = domain.STATUS_RETIRED
|
||||||
|
case int64(domain.TIME_STATUS_SUSPENDED):
|
||||||
|
eventStatus = domain.STATUS_SUSPENDED
|
||||||
|
case int64(domain.TIME_STATUS_DECIDED_BY_FA):
|
||||||
|
eventStatus = domain.STATUS_DECIDED_BY_FA
|
||||||
|
case int64(domain.TIME_STATUS_REMOVED):
|
||||||
|
eventStatus = domain.STATUS_REMOVED
|
||||||
|
default:
|
||||||
|
s.logger.Error("Invalid time status", "time_status", commonResp.TimeStatus, "event_id", eventID)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.eventSvc.UpdateFinalScore(ctx, strconv.FormatInt(eventID, 10), commonResp.SS, eventStatus)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to update final score", "event_id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
updated++
|
||||||
|
fmt.Printf("✅ Successfully updated event %v to %v (%d/%d) \n", event.ID, eventStatus, i+1, len(events))
|
||||||
|
|
||||||
|
// Update the league because the league country code is only found on the result response
|
||||||
|
leagueID, err := strconv.ParseInt(commonResp.League.ID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Invalid league id, leagueID %v", commonResp.League.ID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.leagueSvc.UpdateLeague(ctx, domain.UpdateLeague{
|
||||||
|
ID: int64(event.LeagueID),
|
||||||
|
CountryCode: domain.ValidString{
|
||||||
|
Value: commonResp.League.CC,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
Bet365ID: domain.ValidInt32{
|
||||||
|
Value: int32(leagueID),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Error Updating League %v", commonResp.League.Name)
|
||||||
|
log.Printf("err:%v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("✅ Updated League %v with country code %v \n", leagueID, commonResp.League.CC)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated == 0 {
|
||||||
|
s.logger.Info("No events were updated")
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Successfully updated live events", "updated_events", updated, "total_events", len(events))
|
||||||
|
return int64(updated), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetResultsForEvent(ctx context.Context, eventID string) (json.RawMessage, []domain.BetOutcome, error) {
|
||||||
|
id, err := strconv.ParseInt(eventID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse event id")
|
||||||
|
return json.RawMessage{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := s.fetchResult(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to fetch result", "event_id", id, "error", err)
|
||||||
|
}
|
||||||
|
if result.Success != 1 || len(result.Results) == 0 {
|
||||||
|
fmt.Printf("⚠️ Invalid API response for event %v \n", result)
|
||||||
|
s.logger.Error("Invalid API response", "event_id", id)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("invalid API response for event %d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonResp domain.CommonResultResponse
|
||||||
|
if err := json.Unmarshal(result.Results[0], &commonResp); err != nil {
|
||||||
|
s.logger.Error("Failed to unmarshal common result", "event_id", eventID, "error", err)
|
||||||
|
return json.RawMessage{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sportID, err := strconv.ParseInt(commonResp.SportID, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse sport id", "event_id", eventID, "error", err)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("failed to parse sport id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expireUnix, err := strconv.ParseInt(commonResp.Time, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse expire time", "event_id", eventID, "error", err)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("Failed to parse expire time for event %s: %w", eventID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expires := time.Unix(expireUnix, 0)
|
||||||
|
|
||||||
|
odds, err := s.oddSvc.FetchNonLiveOddsByEventID(ctx, eventID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to fetch non-live odds by event ID", "event_id", eventID, "error", err)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("failed to fetch non-live odds for event %s: %w", eventID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedOddSections, err := s.oddSvc.ParseOddSections(ctx, odds.Results[0], int32(sportID))
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse odd section", "error", err)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("failed to parse odd section for event %v: %w", eventID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outcomes := make([]domain.BetOutcome, 0)
|
||||||
|
for _, section := range parsedOddSections.Sections {
|
||||||
|
// TODO: Remove repeat code here, same as in odds service
|
||||||
|
for _, market := range section.Sp {
|
||||||
|
var marketIDstr string
|
||||||
|
err := json.Unmarshal(market.ID, &marketIDstr)
|
||||||
|
var marketIDint int64
|
||||||
|
if err != nil {
|
||||||
|
// check if its int
|
||||||
|
err := json.Unmarshal(market.ID, &marketIDint)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
marketIDint, err = strconv.ParseInt(marketIDstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isSupported, ok := domain.SupportedMarkets[marketIDint]
|
||||||
|
|
||||||
|
if !ok || !isSupported {
|
||||||
|
// s.logger.Info("Unsupported market_id", "marketID", marketIDint, "marketName", market.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, oddRes := range market.Odds {
|
||||||
|
var odd domain.RawOdd
|
||||||
|
if err := json.Unmarshal(oddRes, &odd); err != nil {
|
||||||
|
s.logger.Error("Failed to unmarshal odd", "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
oddID, err := strconv.ParseInt(odd.ID, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse odd id", "odd_id", odd.ID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
oddValue, err := strconv.ParseFloat(odd.Odds, 64)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse odd value", "odd_value", odd.Odds, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
outcome := domain.BetOutcome{
|
||||||
|
EventID: id,
|
||||||
|
MarketID: marketIDint,
|
||||||
|
OddID: oddID,
|
||||||
|
MarketName: market.Name,
|
||||||
|
OddHeader: odd.Header,
|
||||||
|
OddHandicap: odd.Handicap,
|
||||||
|
OddName: odd.Name,
|
||||||
|
Odd: float32(oddValue),
|
||||||
|
SportID: sportID,
|
||||||
|
HomeTeamName: commonResp.Home.Name,
|
||||||
|
AwayTeamName: commonResp.Away.Name,
|
||||||
|
Status: domain.OUTCOME_STATUS_PENDING,
|
||||||
|
Expires: expires,
|
||||||
|
BetID: 0, // This won't be set
|
||||||
|
}
|
||||||
|
outcomes = append(outcomes, outcome)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(outcomes) == 0 {
|
||||||
|
s.logger.Warn("No outcomes found for event", "event_id", eventID)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("no outcomes found for event %s", eventID)
|
||||||
|
}
|
||||||
|
s.logger.Info("Successfully fetched outcomes for event", "event_id", eventID, "outcomes_count", len(outcomes))
|
||||||
|
|
||||||
|
// Get results for outcome
|
||||||
|
for i, outcome := range outcomes {
|
||||||
|
// Parse the result based on sport type
|
||||||
|
parsedResult, err := s.parseResult(ctx, result.Results[0], outcome, sportID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse result for outcome", "event_id", outcome.EventID, "error", err)
|
||||||
|
return json.RawMessage{}, nil, fmt.Errorf("failed to parse result for outcome %d: %w", i, err)
|
||||||
|
}
|
||||||
|
outcomes[i].Status = parsedResult.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Results[0], outcomes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) fetchResult(ctx context.Context, eventID int64) (domain.BaseResultResponse, error) {
|
||||||
|
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
||||||
|
// url := fmt.Sprintf("https://api.b365api.com/v1/event/view?token=%s&event_id=%d", s.config.Bet365Token, eventID)
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to create request", "event_id", eventID, "error", err)
|
s.logger.Error("Failed to create request", "event_id", eventID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.BaseResultResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
|
s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.BaseResultResponse{}, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
s.logger.Error("Unexpected status code", "event_id", eventID, "status_code", resp.StatusCode)
|
s.logger.Error("Unexpected status code", "event_id", eventID, "status_code", resp.StatusCode)
|
||||||
return domain.CreateResult{}, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
return domain.BaseResultResponse{}, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultResp domain.BaseResultResponse
|
var resultResp domain.BaseResultResponse
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&resultResp); err != nil {
|
if err := json.NewDecoder(resp.Body).Decode(&resultResp); err != nil {
|
||||||
s.logger.Error("Failed to decode result", "event_id", eventID, "error", err)
|
s.logger.Error("Failed to decode result", "event_id", eventID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.BaseResultResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resultResp.Success != 1 || len(resultResp.Results) == 0 {
|
if resultResp.Success != 1 || len(resultResp.Results) == 0 {
|
||||||
s.logger.Error("Invalid API response", "event_id", eventID)
|
s.logger.Error("Invalid API response", "event_id", eventID)
|
||||||
return domain.CreateResult{}, fmt.Errorf("invalid API response")
|
fmt.Printf("⚠️ Invalid API response for event %v \n", resultResp)
|
||||||
|
return domain.BaseResultResponse{}, fmt.Errorf("invalid API response")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return resultResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) parseResult(ctx context.Context, resultResp json.RawMessage, outcome domain.BetOutcome, sportID int64) (domain.CreateResult, error) {
|
||||||
|
|
||||||
var result domain.CreateResult
|
var result domain.CreateResult
|
||||||
|
var err error
|
||||||
switch sportID {
|
switch sportID {
|
||||||
case domain.FOOTBALL:
|
case domain.FOOTBALL:
|
||||||
result, err = s.parseFootball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseFootball(resultResp, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse football", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse football", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.BASKETBALL:
|
case domain.BASKETBALL:
|
||||||
result, err = s.parseBasketball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseBasketball(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse basketball", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse basketball", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.ICE_HOCKEY:
|
case domain.ICE_HOCKEY:
|
||||||
result, err = s.parseIceHockey(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseIceHockey(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse ice hockey", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse ice hockey", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.CRICKET:
|
case domain.CRICKET:
|
||||||
result, err = s.parseCricket(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseCricket(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse cricket", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse cricket", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.VOLLEYBALL:
|
case domain.VOLLEYBALL:
|
||||||
result, err = s.parseVolleyball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseVolleyball(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse volleyball", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse volleyball", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.DARTS:
|
case domain.DARTS:
|
||||||
result, err = s.parseDarts(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseDarts(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse darts", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse darts", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.FUTSAL:
|
case domain.FUTSAL:
|
||||||
result, err = s.parseFutsal(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseFutsal(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse futsal", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse futsal", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.AMERICAN_FOOTBALL:
|
case domain.AMERICAN_FOOTBALL:
|
||||||
result, err = s.parseNFL(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseNFL(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse american football", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse american football", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.RUGBY_UNION:
|
case domain.RUGBY_UNION:
|
||||||
result, err = s.parseRugbyUnion(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseRugbyUnion(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse rugby_union", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse rugby_union", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.RUGBY_LEAGUE:
|
case domain.RUGBY_LEAGUE:
|
||||||
result, err = s.parseRugbyLeague(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseRugbyLeague(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse rugby_league", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse rugby_league", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
case domain.BASEBALL:
|
case domain.BASEBALL:
|
||||||
result, err = s.parseBaseball(resultResp.Results[0], eventID, oddID, marketID, outcome)
|
result, err = s.parseBaseball(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse baseball", "event id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to parse baseball", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -264,52 +578,14 @@ func (s *Service) fetchResult(ctx context.Context, eventID, oddID, marketID, spo
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) parseTimeStatus(timeStatusStr string) (bool, error) {
|
func (s *Service) parseFootball(resultRes json.RawMessage, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||||
timeStatusParsed, err := strconv.ParseInt(strings.TrimSpace(timeStatusStr), 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to parse time status", "time_status", timeStatusStr, "error", err)
|
|
||||||
return false, fmt.Errorf("failed to parse time status: %w", err)
|
|
||||||
}
|
|
||||||
timeStatus := domain.TimeStatus(timeStatusParsed)
|
|
||||||
|
|
||||||
switch timeStatus {
|
|
||||||
case domain.TIME_STATUS_NOT_STARTED, domain.TIME_STATUS_IN_PLAY, domain.TIME_STATUS_TO_BE_FIXED, domain.TIME_STATUS_ENDED:
|
|
||||||
return true, nil
|
|
||||||
case domain.TIME_STATUS_POSTPONED,
|
|
||||||
domain.TIME_STATUS_CANCELLED,
|
|
||||||
domain.TIME_STATUS_WALKOVER,
|
|
||||||
domain.TIME_STATUS_INTERRUPTED,
|
|
||||||
domain.TIME_STATUS_ABANDONED,
|
|
||||||
domain.TIME_STATUS_RETIRED,
|
|
||||||
domain.TIME_STATUS_SUSPENDED,
|
|
||||||
domain.TIME_STATUS_DECIDED_BY_FA,
|
|
||||||
domain.TIME_STATUS_REMOVED:
|
|
||||||
return false, nil
|
|
||||||
default:
|
|
||||||
s.logger.Error("Invalid time status", "time_status", timeStatus)
|
|
||||||
return false, fmt.Errorf("invalid time status: %d", timeStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) parseFootball(resultRes json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
|
||||||
var fbResp domain.FootballResultResponse
|
var fbResp domain.FootballResultResponse
|
||||||
if err := json.Unmarshal(resultRes, &fbResp); err != nil {
|
if err := json.Unmarshal(resultRes, &fbResp); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
|
s.logger.Error("Failed to unmarshal football result", "event_id", outcome.EventID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
result := fbResp
|
result := fbResp
|
||||||
|
|
||||||
isEventActive, err := s.parseTimeStatus(result.TimeStatus)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to parse time status", "event_id", eventID, "error", err)
|
|
||||||
return domain.CreateResult{}, err
|
|
||||||
}
|
|
||||||
if !isEventActive {
|
|
||||||
s.logger.Warn("Event is not active", "event_id", eventID)
|
|
||||||
return domain.CreateResult{}, ErrEventIsNotActive
|
|
||||||
}
|
|
||||||
|
|
||||||
finalScore := parseSS(result.SS)
|
finalScore := parseSS(result.SS)
|
||||||
firstHalfScore := parseScore(result.Scores.FirstHalf.Home, result.Scores.FirstHalf.Away)
|
firstHalfScore := parseScore(result.Scores.FirstHalf.Home, result.Scores.FirstHalf.Away)
|
||||||
secondHalfScore := parseScore(result.Scores.SecondHalf.Home, result.Scores.SecondHalf.Away)
|
secondHalfScore := parseScore(result.Scores.SecondHalf.Home, result.Scores.SecondHalf.Away)
|
||||||
|
|
@ -318,15 +594,15 @@ func (s *Service) parseFootball(resultRes json.RawMessage, eventID, oddID, marke
|
||||||
halfTimeCorners := parseStats(result.Stats.HalfTimeCorners)
|
halfTimeCorners := parseStats(result.Stats.HalfTimeCorners)
|
||||||
status, err := s.evaluateFootballOutcome(outcome, finalScore, firstHalfScore, secondHalfScore, corners, halfTimeCorners, result.Events)
|
status, err := s.evaluateFootballOutcome(outcome, finalScore, firstHalfScore, secondHalfScore, corners, halfTimeCorners, result.Events)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to evaluate football outcome", "event_id", eventID, "market_id", marketID, "error", err)
|
s.logger.Error("Failed to evaluate football outcome", "event_id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain.CreateResult{
|
return domain.CreateResult{
|
||||||
BetOutcomeID: 0,
|
BetOutcomeID: 0,
|
||||||
EventID: eventID,
|
EventID: outcome.EventID,
|
||||||
OddID: oddID,
|
OddID: outcome.OddID,
|
||||||
MarketID: marketID,
|
MarketID: outcome.MarketID,
|
||||||
Status: status,
|
Status: status,
|
||||||
Score: result.SS,
|
Score: result.SS,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
@ -340,15 +616,6 @@ func (s *Service) parseBasketball(response json.RawMessage, eventID, oddID, mark
|
||||||
s.logger.Error("Failed to unmarshal basketball result", "event_id", eventID, "error", err)
|
s.logger.Error("Failed to unmarshal basketball result", "event_id", eventID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
isEventActive, err := s.parseTimeStatus(basketBallRes.TimeStatus)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to parse time status", "event_id", eventID, "error", err)
|
|
||||||
return domain.CreateResult{}, err
|
|
||||||
}
|
|
||||||
if !isEventActive {
|
|
||||||
s.logger.Warn("Event is not active", "event_id", eventID)
|
|
||||||
return domain.CreateResult{}, ErrEventIsNotActive
|
|
||||||
}
|
|
||||||
|
|
||||||
status, err := s.evaluateBasketballOutcome(outcome, basketBallRes)
|
status, err := s.evaluateBasketballOutcome(outcome, basketBallRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -373,15 +640,6 @@ func (s *Service) parseIceHockey(response json.RawMessage, eventID, oddID, marke
|
||||||
s.logger.Error("Failed to unmarshal ice hockey result", "event_id", eventID, "error", err)
|
s.logger.Error("Failed to unmarshal ice hockey result", "event_id", eventID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
isEventActive, err := s.parseTimeStatus(iceHockeyRes.TimeStatus)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to parse time status", "event_id", eventID, "error", err)
|
|
||||||
return domain.CreateResult{}, err
|
|
||||||
}
|
|
||||||
if !isEventActive {
|
|
||||||
s.logger.Warn("Event is not active", "event_id", eventID)
|
|
||||||
return domain.CreateResult{}, ErrEventIsNotActive
|
|
||||||
}
|
|
||||||
|
|
||||||
status, err := s.evaluateIceHockeyOutcome(outcome, iceHockeyRes)
|
status, err := s.evaluateIceHockeyOutcome(outcome, iceHockeyRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ type TicketStore interface {
|
||||||
CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error)
|
CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error)
|
||||||
GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error)
|
GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error)
|
||||||
GetAllTickets(ctx context.Context) ([]domain.GetTicket, error)
|
GetAllTickets(ctx context.Context) ([]domain.GetTicket, error)
|
||||||
|
CountTicketByIP(ctx context.Context, IP string) (int64, error)
|
||||||
UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||||
DeleteOldTickets(ctx context.Context) error
|
DeleteOldTickets(ctx context.Context) error
|
||||||
DeleteTicket(ctx context.Context, id int64) error
|
DeleteTicket(ctx context.Context, id int64) error
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,10 @@ func (s *Service) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error)
|
||||||
return s.ticketStore.GetAllTickets(ctx)
|
return s.ticketStore.GetAllTickets(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) CountTicketByIP(ctx context.Context, IP string) (int64, error) {
|
||||||
|
return s.ticketStore.CountTicketByIP(ctx, IP)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
func (s *Service) UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
return s.ticketStore.UpdateTicketOutcomeStatus(ctx, id, status)
|
return s.ticketStore.UpdateTicketOutcomeStatus(ctx, id, status)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func (s *Service) GetCashiersByBranch(ctx context.Context, branchID int64) ([]do
|
||||||
return s.userStore.GetCashiersByBranch(ctx, branchID)
|
return s.userStore.GetCashiersByBranch(ctx, branchID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error) {
|
func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, int64, error){
|
||||||
return s.userStore.GetAllCashiers(ctx)
|
return s.userStore.GetAllCashiers(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ type UserStore interface {
|
||||||
CreateUserWithoutOtp(ctx context.Context, user domain.User, is_company bool) (domain.User, error)
|
CreateUserWithoutOtp(ctx context.Context, user domain.User, is_company bool) (domain.User, error)
|
||||||
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||||
GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, int64, error)
|
GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, int64, error)
|
||||||
GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error)
|
GetAllCashiers(ctx context.Context) ([]domain.GetCashier, int64, error)
|
||||||
GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error)
|
GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error)
|
||||||
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
|
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
|
||||||
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
|
@ -33,6 +34,7 @@ func (s *Service) ResetPassword(ctx context.Context, resetReq domain.ResetPasswo
|
||||||
} else {
|
} else {
|
||||||
sentTo = resetReq.PhoneNumber
|
sentTo = resetReq.PhoneNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
otp, err := s.otpStore.GetOtp(
|
otp, err := s.otpStore.GetOtp(
|
||||||
ctx, sentTo,
|
ctx, sentTo,
|
||||||
domain.OtpReset, resetReq.OtpMedium)
|
domain.OtpReset, resetReq.OtpMedium)
|
||||||
|
|
@ -55,6 +57,7 @@ func (s *Service) ResetPassword(ctx context.Context, resetReq domain.ResetPasswo
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// reset pass and mark otp as used
|
// reset pass and mark otp as used
|
||||||
|
|
||||||
err = s.userStore.UpdatePassword(ctx, sentTo, hashedPassword, otp.ID)
|
err = s.userStore.UpdatePassword(ctx, sentTo, hashedPassword, otp.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -39,26 +39,38 @@ func SetupReportCronJob(reportWorker *worker.ReportWorker) {
|
||||||
s.StartAsync()
|
s.StartAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.Service, resultService *resultsvc.Service) {
|
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.ServiceImpl, resultService *resultsvc.Service) {
|
||||||
c := cron.New(cron.WithSeconds())
|
c := cron.New(cron.WithSeconds())
|
||||||
|
|
||||||
schedule := []struct {
|
schedule := []struct {
|
||||||
spec string
|
spec string
|
||||||
task func()
|
task func()
|
||||||
}{
|
}{
|
||||||
|
// {
|
||||||
|
// spec: "0 0 * * * *", // Every 1 hour
|
||||||
|
// task: func() {
|
||||||
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
|
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// spec: "0 0 * * * *", // Every 15 minutes
|
||||||
|
// task: func() {
|
||||||
|
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
|
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
spec: "0 0 * * * *", // Every 1 hour
|
spec: "0 */5 * * * *", // Every 5 Minutes
|
||||||
task: func() {
|
task: func() {
|
||||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
log.Println("Updating expired events status...")
|
||||||
log.Printf("FetchUpcomingEvents error: %v", err)
|
|
||||||
}
|
if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil {
|
||||||
},
|
log.Printf("Failed to update events: %v", err)
|
||||||
},
|
} else {
|
||||||
{
|
log.Printf("Successfully updated expired events")
|
||||||
spec: "0 */15 * * * *", // Every 15 minutes
|
|
||||||
task: func() {
|
|
||||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
|
||||||
log.Printf("FetchNonLiveOdds error: %v", err)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -77,7 +89,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
// job.task()
|
job.task()
|
||||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ import (
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /bet [post]
|
// @Router /bet [post]
|
||||||
func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
||||||
|
fmt.Printf("Calling leagues")
|
||||||
// Get user_id from middleware
|
// Get user_id from middleware
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
role := c.Locals("role").(domain.Role)
|
role := c.Locals("role").(domain.Role)
|
||||||
|
|
@ -39,7 +40,8 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := h.betSvc.PlaceBet(c.Context(), req, userID, role)
|
res, err := h.betSvc.
|
||||||
|
PlaceBet(c.Context(), req, userID, role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("PlaceBet failed", "error", err)
|
h.logger.Error("PlaceBet failed", "error", err)
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ type BranchDetailRes struct {
|
||||||
IsSelfOwned bool `json:"is_self_owned" example:"false"`
|
IsSelfOwned bool `json:"is_self_owned" example:"false"`
|
||||||
ManagerName string `json:"manager_name" example:"John Smith"`
|
ManagerName string `json:"manager_name" example:"John Smith"`
|
||||||
ManagerPhoneNumber string `json:"manager_phone_number" example:"0911111111"`
|
ManagerPhoneNumber string `json:"manager_phone_number" example:"0911111111"`
|
||||||
|
Balance float32 `json:"balance" example:"100.5"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertBranch(branch domain.Branch) BranchRes {
|
func convertBranch(branch domain.Branch) BranchRes {
|
||||||
|
|
@ -92,6 +93,7 @@ func convertBranchDetail(branch domain.BranchDetail) BranchDetailRes {
|
||||||
IsSelfOwned: branch.IsSelfOwned,
|
IsSelfOwned: branch.IsSelfOwned,
|
||||||
ManagerName: branch.ManagerName,
|
ManagerName: branch.ManagerName,
|
||||||
ManagerPhoneNumber: branch.ManagerPhoneNumber,
|
ManagerPhoneNumber: branch.ManagerPhoneNumber,
|
||||||
|
Balance: branch.Balance.Float32(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -552,6 +554,50 @@ func (h *Handler) GetBranchCashiers(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Branch Cashiers retrieved successfully", result, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Cashiers retrieved successfully", result, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBranchForCashier godoc
|
||||||
|
// @Summary Gets branch for cahier
|
||||||
|
// @Description Gets branch for cahier
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Success 200 {object} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branchCashier [get]
|
||||||
|
func (h *Handler) GetBranchForCashier(c *fiber.Ctx) error {
|
||||||
|
cashierID, ok := c.Locals("user_id").(int64)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
h.logger.Error("Invalid cashier ID in context")
|
||||||
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid cashier identification", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
role, ok := c.Locals("role").(domain.Role)
|
||||||
|
|
||||||
|
if !ok || role != domain.RoleCashier {
|
||||||
|
h.logger.Error("Unauthorized access", "cashierID", cashierID, "role", role)
|
||||||
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branchID, ok := c.Locals("branch_id").(domain.ValidInt64)
|
||||||
|
if !ok || !branchID.Valid {
|
||||||
|
h.logger.Error("Invalid branch ID in context", "cashierID", cashierID)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := h.branchSvc.GetBranchByID(c.Context(), branchID.Value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to get branch by ID", "branchID", branchID.Value, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertBranchDetail(branch)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// GetBetByBranchID godoc
|
// GetBetByBranchID godoc
|
||||||
// @Summary Gets bets by its branch id
|
// @Summary Gets bets by its branch id
|
||||||
// @Description Gets bets by its branch id
|
// @Description Gets bets by its branch id
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@ type GetCashierRes struct {
|
||||||
Suspended bool `json:"suspended"`
|
Suspended bool `json:"suspended"`
|
||||||
LastLogin time.Time `json:"last_login"`
|
LastLogin time.Time `json:"last_login"`
|
||||||
BranchID int64 `json:"branch_id"`
|
BranchID int64 `json:"branch_id"`
|
||||||
|
BranchName string `json:"branch_name"`
|
||||||
|
BranchWallet int64 `json:"branch_wallet"`
|
||||||
|
BranchLocation string `json:"branch_location"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllCashiers godoc
|
// GetAllCashiers godoc
|
||||||
|
|
@ -139,7 +142,7 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
cashiers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
cashiers, total, err := h.userSvc.GetAllCashiers(c.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("GetAllCashiers failed", "error", err)
|
h.logger.Error("GetAllCashiers failed", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
|
||||||
|
|
@ -172,6 +175,10 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
|
||||||
SuspendedAt: cashier.SuspendedAt,
|
SuspendedAt: cashier.SuspendedAt,
|
||||||
Suspended: cashier.Suspended,
|
Suspended: cashier.Suspended,
|
||||||
LastLogin: *lastLogin,
|
LastLogin: *lastLogin,
|
||||||
|
BranchID: cashier.BranchID,
|
||||||
|
BranchName: cashier.BranchName,
|
||||||
|
BranchWallet: cashier.BranchWallet,
|
||||||
|
BranchLocation: cashier.BranchLocation,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,6 +222,7 @@ func (h *Handler) GetCashierByID(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.userSvc.GetCashierByID(c.Context(), cashierID)
|
user, err := h.userSvc.GetCashierByID(c.Context(), cashierID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Get User By ID failed", "error", err)
|
h.logger.Error("Get User By ID failed", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
|
||||||
|
|
@ -244,6 +252,9 @@ func (h *Handler) GetCashierByID(c *fiber.Ctx) error {
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
LastLogin: *lastLogin,
|
LastLogin: *lastLogin,
|
||||||
BranchID: user.BranchID,
|
BranchID: user.BranchID,
|
||||||
|
BranchName: user.BranchName,
|
||||||
|
BranchWallet: user.BranchWallet,
|
||||||
|
BranchLocation: user.BranchLocation,
|
||||||
}
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
|
||||||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||||
|
|
@ -48,6 +49,7 @@ type Handler struct {
|
||||||
veliVirtualGameSvc veli.VeliVirtualGameService
|
veliVirtualGameSvc veli.VeliVirtualGameService
|
||||||
recommendationSvc recommendation.RecommendationService
|
recommendationSvc recommendation.RecommendationService
|
||||||
authSvc *authentication.Service
|
authSvc *authentication.Service
|
||||||
|
resultSvc result.Service
|
||||||
jwtConfig jwtutil.JwtConfig
|
jwtConfig jwtutil.JwtConfig
|
||||||
validator *customvalidator.CustomValidator
|
validator *customvalidator.CustomValidator
|
||||||
Cfg *config.Config
|
Cfg *config.Config
|
||||||
|
|
@ -76,6 +78,7 @@ func New(
|
||||||
prematchSvc *odds.ServiceImpl,
|
prematchSvc *odds.ServiceImpl,
|
||||||
eventSvc event.Service,
|
eventSvc event.Service,
|
||||||
leagueSvc league.Service,
|
leagueSvc league.Service,
|
||||||
|
resultSvc result.Service,
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
) *Handler {
|
) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
|
|
@ -100,6 +103,7 @@ func New(
|
||||||
veliVirtualGameSvc: veliVirtualGameSvc,
|
veliVirtualGameSvc: veliVirtualGameSvc,
|
||||||
recommendationSvc: recommendationSvc,
|
recommendationSvc: recommendationSvc,
|
||||||
authSvc: authSvc,
|
authSvc: authSvc,
|
||||||
|
resultSvc: resultSvc,
|
||||||
jwtConfig: jwtConfig,
|
jwtConfig: jwtConfig,
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,85 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetAllLeagues godoc
|
||||||
|
// @Summary Gets all leagues
|
||||||
|
// @Description Gets all leagues
|
||||||
|
// @Tags leagues
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.League
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /leagues [get]
|
||||||
func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
|
func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
|
||||||
leagues, err := h.leagueSvc.GetAllLeagues(c.Context())
|
page := c.QueryInt("page", 1)
|
||||||
if err != nil {
|
pageSize := c.QueryInt("page_size", 10)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get leagues", err, nil)
|
|
||||||
|
limit := domain.ValidInt64{
|
||||||
|
Value: int64(pageSize),
|
||||||
|
Valid: pageSize == 0,
|
||||||
|
}
|
||||||
|
offset := domain.ValidInt64{
|
||||||
|
Value: int64(page - 1),
|
||||||
|
Valid: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "All leagues retrived", leagues, nil)
|
countryCodeQuery := c.Query("cc")
|
||||||
|
countryCode := domain.ValidString{
|
||||||
|
Value: countryCodeQuery,
|
||||||
|
Valid: countryCodeQuery != "",
|
||||||
|
}
|
||||||
|
isActiveQuery := c.QueryBool("is_active", false)
|
||||||
|
isActiveFilter := c.QueryBool("is_active_filter", false)
|
||||||
|
isActive := domain.ValidBool{
|
||||||
|
Value: isActiveQuery,
|
||||||
|
Valid: isActiveFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
sportIDQuery := c.Query("sport_id")
|
||||||
|
var sportID domain.ValidInt32
|
||||||
|
if sportIDQuery != "" {
|
||||||
|
sportIDint, err := strconv.Atoi(sportIDQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("invalid sport id", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil)
|
||||||
|
}
|
||||||
|
sportID = domain.ValidInt32{
|
||||||
|
Value: int32(sportIDint),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leagues, err := h.leagueSvc.GetAllLeagues(c.Context(), domain.LeagueFilter{
|
||||||
|
CountryCode: countryCode,
|
||||||
|
IsActive: isActive,
|
||||||
|
SportID: sportID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error fetching league %v \n", err)
|
||||||
|
h.logger.Error("Failed to get leagues", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get leagues", err, nil)
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", leagues, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetLeagueActiveReq struct {
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) SetLeagueActive(c *fiber.Ctx) error {
|
func (h *Handler) SetLeagueActive(c *fiber.Ctx) error {
|
||||||
|
fmt.Printf("Set Active Leagues")
|
||||||
leagueIdStr := c.Params("id")
|
leagueIdStr := c.Params("id")
|
||||||
if leagueIdStr == "" {
|
if leagueIdStr == "" {
|
||||||
response.WriteJSON(c, fiber.StatusBadRequest, "Missing league id", nil, nil)
|
response.WriteJSON(c, fiber.StatusBadRequest, "Missing league id", nil, nil)
|
||||||
|
|
@ -26,7 +89,18 @@ func (h *Handler) SetLeagueActive(c *fiber.Ctx) error {
|
||||||
response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.leagueSvc.SetLeagueActive(c.Context(), int64(leagueId)); err != nil {
|
var req SetLeagueActiveReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.logger.Error("SetLeagueReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to parse request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := h.validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.leagueSvc.SetLeagueActive(c.Context(), int64(leagueId), req.IsActive); err != nil {
|
||||||
response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update league", err, nil)
|
response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update league", err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,10 @@ func (h *Handler) ConnectSocket(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
h.notificationSvc.Hub.Register <- client
|
h.notificationSvc.Hub.Register <- client
|
||||||
h.logger.Info("WebSocket connection established", "userID", userID)
|
// h.logger.Info("WebSocket connection established", "userID", userID)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
h.notificationSvc.Hub.Unregister <- client
|
h.notificationSvc.Hub.Unregister <- client
|
||||||
h.logger.Info("WebSocket connection closed", "userID", userID)
|
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -9,33 +10,6 @@ import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetPrematchOdds godoc
|
|
||||||
// @Summary Retrieve prematch odds for an event
|
|
||||||
// @Description Retrieve prematch odds for a specific event by event ID
|
|
||||||
// @Tags prematch
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param event_id path string true "Event ID"
|
|
||||||
// @Success 200 {array} domain.Odd
|
|
||||||
// @Failure 400 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Router /prematch/odds/{event_id} [get]
|
|
||||||
func (h *Handler) GetPrematchOdds(c *fiber.Ctx) error {
|
|
||||||
|
|
||||||
eventID := c.Params("event_id")
|
|
||||||
if eventID == "" {
|
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing event_id", nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
odds, err := h.prematchSvc.GetPrematchOdds(c.Context(), eventID)
|
|
||||||
if err != nil {
|
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve odds", nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetALLPrematchOdds
|
// GetALLPrematchOdds
|
||||||
// @Summary Retrieve all prematch odds
|
// @Summary Retrieve all prematch odds
|
||||||
// @Description Retrieve all prematch odds from the database
|
// @Description Retrieve all prematch odds from the database
|
||||||
|
|
@ -44,7 +18,7 @@ func (h *Handler) GetPrematchOdds(c *fiber.Ctx) error {
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} domain.Odd
|
// @Success 200 {array} domain.Odd
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /prematch/odds [get]
|
// @Router /odds [get]
|
||||||
func (h *Handler) GetALLPrematchOdds(c *fiber.Ctx) error {
|
func (h *Handler) GetALLPrematchOdds(c *fiber.Ctx) error {
|
||||||
|
|
||||||
odds, err := h.prematchSvc.GetALLPrematchOdds(c.Context())
|
odds, err := h.prematchSvc.GetALLPrematchOdds(c.Context())
|
||||||
|
|
@ -67,7 +41,7 @@ func (h *Handler) GetALLPrematchOdds(c *fiber.Ctx) error {
|
||||||
// @Success 200 {array} domain.RawOddsByMarketID
|
// @Success 200 {array} domain.RawOddsByMarketID
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /prematch/odds/upcoming/{upcoming_id}/market/{market_id} [get]
|
// @Router /odds/upcoming/{upcoming_id}/market/{market_id} [get]
|
||||||
func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
marketID := c.Params("market_id")
|
marketID := c.Params("market_id")
|
||||||
|
|
@ -82,7 +56,8 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
|
rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// h.logger.Error("failed to fetch raw odds", "error", err)
|
fmt.Printf("Failed to fetch raw odds: %v market_id:%v upcomingID:%v\n", err, marketID, upcomingID)
|
||||||
|
h.logger.Error("failed to fetch raw odds", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,37 +74,51 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
||||||
// @Param page_size query int false "Page size"
|
// @Param page_size query int false "Page size"
|
||||||
// @Param league_id query string false "League ID Filter"
|
// @Param league_id query string false "League ID Filter"
|
||||||
// @Param sport_id query string false "Sport 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 first_start_time query string false "Start Time"
|
||||||
// @Param last_start_time query string false "End Time"
|
// @Param last_start_time query string false "End Time"
|
||||||
// @Success 200 {array} domain.UpcomingEvent
|
// @Success 200 {array} domain.UpcomingEvent
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /prematch/events [get]
|
// @Router /events [get]
|
||||||
func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
page := c.QueryInt("page", 1)
|
page := c.QueryInt("page", 1)
|
||||||
pageSize := c.QueryInt("page_size", 10)
|
pageSize := c.QueryInt("page_size", 10)
|
||||||
leagueIDQuery, err := strconv.Atoi(c.Query("league_id"))
|
limit := domain.ValidInt64{
|
||||||
|
Value: int64(pageSize),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
offset := domain.ValidInt64{
|
||||||
|
Value: int64(page - 1),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
leagueIDQuery := c.Query("league_id")
|
||||||
|
var leagueID domain.ValidInt32
|
||||||
|
if leagueIDQuery != "" {
|
||||||
|
leagueIDInt, err := strconv.Atoi(leagueIDQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("invalid league id", "error", err)
|
h.logger.Error("invalid league id", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
||||||
}
|
}
|
||||||
|
leagueID = domain.ValidInt32{
|
||||||
sportIDQuery, err := strconv.Atoi(c.Query("sport_id"))
|
Value: int32(leagueIDInt),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sportIDQuery := c.Query("sport_id")
|
||||||
|
var sportID domain.ValidInt32
|
||||||
|
if sportIDQuery != "" {
|
||||||
|
sportIDint, err := strconv.Atoi(sportIDQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("invalid sport id", "error", err)
|
h.logger.Error("invalid sport id", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil)
|
||||||
}
|
}
|
||||||
|
sportID = domain.ValidInt32{
|
||||||
|
Value: int32(sportIDint),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
firstStartTimeQuery := c.Query("first_start_time")
|
firstStartTimeQuery := c.Query("first_start_time")
|
||||||
lastStartTimeQuery := c.Query("last_start_time")
|
|
||||||
|
|
||||||
leagueID := domain.ValidInt32{
|
|
||||||
Value: int32(leagueIDQuery),
|
|
||||||
Valid: leagueIDQuery != 0,
|
|
||||||
}
|
|
||||||
sportID := domain.ValidInt32{
|
|
||||||
Value: int32(sportIDQuery),
|
|
||||||
Valid: sportIDQuery != 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstStartTime domain.ValidTime
|
var firstStartTime domain.ValidTime
|
||||||
if firstStartTimeQuery != "" {
|
if firstStartTimeQuery != "" {
|
||||||
firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
|
firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
|
||||||
|
|
@ -142,6 +131,8 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastStartTimeQuery := c.Query("last_start_time")
|
||||||
var lastStartTime domain.ValidTime
|
var lastStartTime domain.ValidTime
|
||||||
if lastStartTimeQuery != "" {
|
if lastStartTimeQuery != "" {
|
||||||
lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
|
lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
|
||||||
|
|
@ -155,17 +146,21 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
limit := domain.ValidInt64{
|
countryCodeQuery := c.Query("cc")
|
||||||
Value: int64(pageSize),
|
countryCode := domain.ValidString{
|
||||||
Valid: true,
|
Value: countryCodeQuery,
|
||||||
|
Valid: countryCodeQuery != "",
|
||||||
}
|
}
|
||||||
offset := domain.ValidInt64{
|
|
||||||
Value: int64(page - 1),
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
events, total, err := h.eventSvc.GetPaginatedUpcomingEvents(
|
events, total, err := h.eventSvc.GetPaginatedUpcomingEvents(
|
||||||
c.Context(), limit, offset, leagueID, sportID, firstStartTime, lastStartTime)
|
c.Context(), domain.EventFilter{
|
||||||
|
SportID: sportID,
|
||||||
|
LeagueID: leagueID,
|
||||||
|
FirstStartTime: firstStartTime,
|
||||||
|
LastStartTime: lastStartTime,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
CountryCode: countryCode,
|
||||||
|
})
|
||||||
|
|
||||||
// fmt.Printf("League ID: %v", leagueID)
|
// fmt.Printf("League ID: %v", leagueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -186,7 +181,7 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
// @Success 200 {object} domain.UpcomingEvent
|
// @Success 200 {object} domain.UpcomingEvent
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /prematch/events/{id} [get]
|
// @Router /events/{id} [get]
|
||||||
func (h *Handler) GetUpcomingEventByID(c *fiber.Ctx) error {
|
func (h *Handler) GetUpcomingEventByID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
id := c.Params("id")
|
id := c.Params("id")
|
||||||
|
|
@ -214,8 +209,8 @@ func (h *Handler) GetUpcomingEventByID(c *fiber.Ctx) error {
|
||||||
// @Success 200 {array} domain.Odd
|
// @Success 200 {array} domain.Odd
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /prematch/odds/upcoming/{upcoming_id} [get]
|
// @Router /odds/upcoming/{upcoming_id} [get]
|
||||||
func (h *Handler) GetPrematchOddsByUpcomingID(c *fiber.Ctx) error {
|
func (h *Handler) GetOddsByUpcomingID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
upcomingID := c.Params("upcoming_id")
|
upcomingID := c.Params("upcoming_id")
|
||||||
if upcomingID == "" {
|
if upcomingID == "" {
|
||||||
|
|
@ -240,3 +235,29 @@ func (h *Handler) GetPrematchOddsByUpcomingID(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateEventStatusReq struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEventStatusToRemoved godoc
|
||||||
|
// @Summary Set the event status to removed
|
||||||
|
// @Description Set the event status to removed
|
||||||
|
// @Tags event
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Event ID"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /events/{id} [delete]
|
||||||
|
func (h *Handler) SetEventStatusToRemoved(c *fiber.Ctx) error {
|
||||||
|
eventID := c.Params("id")
|
||||||
|
err := h.eventSvc.UpdateEventStatus(c.Context(), eventID, domain.STATUS_REMOVED)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to update event status", "eventID", eventID, "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
47
internal/web_server/handlers/result_handler.go
Normal file
47
internal/web_server/handlers/result_handler.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResultRes struct {
|
||||||
|
ResultData json.RawMessage `json:"result_data"`
|
||||||
|
Outcomes []domain.BetOutcome `json:"outcomes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will take an event ID and return the success results for
|
||||||
|
// all the odds for that event.
|
||||||
|
// @Summary Get results for an event
|
||||||
|
// @Description Get results for an event
|
||||||
|
// @Tags result
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Event ID"
|
||||||
|
// @Success 200 {array} ResultRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /result/{id} [get]
|
||||||
|
func (h *Handler) GetResultsByEventID(c *fiber.Ctx) error {
|
||||||
|
eventID := c.Params("id")
|
||||||
|
if eventID == "" {
|
||||||
|
h.logger.Error("Event ID is required")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Event ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
results, outcomes, err := h.resultSvc.GetResultsForEvent(c.Context(), eventID)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to get results by Event ID", "eventID", eventID, "error", err)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve results")
|
||||||
|
}
|
||||||
|
|
||||||
|
resultRes := ResultRes{
|
||||||
|
ResultData: results,
|
||||||
|
Outcomes: outcomes,
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Results retrieved successfully", resultRes, nil)
|
||||||
|
}
|
||||||
|
|
@ -65,6 +65,20 @@ func (h *Handler) CreateTicket(c *fiber.Ctx) error {
|
||||||
if len(req.Outcomes) > 30 {
|
if len(req.Outcomes) > 30 {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Amount > 100000 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Cannot create a ticket with an amount above 100,000 birr", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientIP := c.IP()
|
||||||
|
count, err := h.ticketSvc.CountTicketByIP(c.Context(), clientIP)
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Error fetching user info", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if count > 50 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Ticket Limit reached", nil, nil)
|
||||||
|
}
|
||||||
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
||||||
var totalOdds float32 = 1
|
var totalOdds float32 = 1
|
||||||
for _, outcome := range req.Outcomes {
|
for _, outcome := range req.Outcomes {
|
||||||
|
|
@ -129,10 +143,16 @@ func (h *Handler) CreateTicket(c *fiber.Ctx) error {
|
||||||
OddHandicap: selectedOdd.Handicap,
|
OddHandicap: selectedOdd.Handicap,
|
||||||
Expires: event.StartTime,
|
Expires: event.StartTime,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
totalWinnings := req.Amount * totalOdds
|
||||||
|
if totalWinnings > 1000000 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Cannot create a ticket with 1,000,000 winnings", nil, nil)
|
||||||
}
|
}
|
||||||
ticket, err := h.ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
ticket, err := h.ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
||||||
Amount: domain.ToCurrency(req.Amount),
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
TotalOdds: totalOdds,
|
TotalOdds: totalOdds,
|
||||||
|
IP: clientIP,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("CreateTicketReq failed", "error", err)
|
h.logger.Error("CreateTicketReq failed", "error", err)
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error {
|
||||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid company_id")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid company_id")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
h.logger.Info("Fetching customer wallet", "userID", userID)
|
// h.logger.Info("Fetching customer wallet", "userID", userID)
|
||||||
|
|
||||||
wallet, err := h.walletSvc.GetWalletsByUser(c.Context(), userID)
|
wallet, err := h.walletSvc.GetWalletsByUser(c.Context(), userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -265,3 +265,64 @@ func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWalletForCashier godoc
|
||||||
|
// @Summary Get wallet for cashier
|
||||||
|
// @Description Get wallet for cashier
|
||||||
|
// @Tags cashier
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {object} UserProfileRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /cashierWallet [get]
|
||||||
|
func (h *Handler) GetWalletForCashier(c *fiber.Ctx) error {
|
||||||
|
cashierID, ok := c.Locals("user_id").(int64)
|
||||||
|
|
||||||
|
if !ok || cashierID == 0 {
|
||||||
|
h.logger.Error("Invalid cashier ID in context")
|
||||||
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid cashier identification", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
role, ok := c.Locals("role").(domain.Role)
|
||||||
|
|
||||||
|
if !ok || role != domain.RoleCashier {
|
||||||
|
h.logger.Error("Unauthorized access", "cashierID", cashierID, "role", role)
|
||||||
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branchID, ok := c.Locals("branch_id").(domain.ValidInt64)
|
||||||
|
if !ok || !branchID.Valid {
|
||||||
|
h.logger.Error("Invalid branch ID in context", "cashierID", cashierID)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := h.branchSvc.GetBranchByID(c.Context(), branchID.Value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to get branch by ID", "branchID", branchID.Value, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := h.walletSvc.GetWalletByID(c.Context(), branch.WalletID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to get wallet for cashier", "cashierID", cashierID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallet", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := WalletRes{
|
||||||
|
ID: wallet.ID,
|
||||||
|
Balance: wallet.Balance.Float32(),
|
||||||
|
IsWithdraw: wallet.IsWithdraw,
|
||||||
|
IsBettable: wallet.IsBettable,
|
||||||
|
IsTransferable: wallet.IsTransferable,
|
||||||
|
IsActive: wallet.IsActive,
|
||||||
|
UserID: wallet.UserID,
|
||||||
|
UpdatedAt: wallet.UpdatedAt,
|
||||||
|
CreatedAt: wallet.CreatedAt,
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func (a *App) authMiddleware(c *fiber.Ctx) error {
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
authHeader := c.Get("Authorization")
|
||||||
if authHeader == "" {
|
if authHeader == "" {
|
||||||
fmt.Println("Auth Header Missing")
|
// fmt.Println("Auth Header Missing")
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, "Authorization header missing")
|
return fiber.NewError(fiber.StatusUnauthorized, "Authorization header missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,7 +39,6 @@ func (a *App) authMiddleware(c *fiber.Ctx) error {
|
||||||
if refreshToken == "" {
|
if refreshToken == "" {
|
||||||
|
|
||||||
// refreshToken = c.Cookies("refresh_token", "")
|
// refreshToken = c.Cookies("refresh_token", "")
|
||||||
|
|
||||||
// return fiber.NewError(fiber.StatusUnauthorized, "Refresh token missing")
|
// return fiber.NewError(fiber.StatusUnauthorized, "Refresh token missing")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.prematchSvc,
|
a.prematchSvc,
|
||||||
a.eventSvc,
|
a.eventSvc,
|
||||||
a.leagueSvc,
|
a.leagueSvc,
|
||||||
|
*a.resultSvc,
|
||||||
a.cfg,
|
a.cfg,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -121,17 +122,19 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Put("/managers/:id", a.authMiddleware, h.UpdateManagers)
|
a.fiber.Put("/managers/:id", a.authMiddleware, h.UpdateManagers)
|
||||||
a.fiber.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID)
|
a.fiber.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID)
|
||||||
|
|
||||||
a.fiber.Get("/events/odds/:event_id", h.GetPrematchOdds)
|
a.fiber.Get("/odds", h.GetALLPrematchOdds)
|
||||||
a.fiber.Get("/events/odds", h.GetALLPrematchOdds)
|
a.fiber.Get("/odds/upcoming/:upcoming_id", h.GetOddsByUpcomingID)
|
||||||
a.fiber.Get("/events/odds/upcoming/:upcoming_id/market/:market_id", h.GetRawOddsByMarketID)
|
a.fiber.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetRawOddsByMarketID)
|
||||||
|
|
||||||
a.fiber.Get("/events/:id", h.GetUpcomingEventByID)
|
|
||||||
a.fiber.Get("/events", h.GetAllUpcomingEvents)
|
a.fiber.Get("/events", h.GetAllUpcomingEvents)
|
||||||
a.fiber.Get("/events/odds/upcoming/:upcoming_id", h.GetPrematchOddsByUpcomingID)
|
a.fiber.Get("/events/:id", h.GetUpcomingEventByID)
|
||||||
|
a.fiber.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
|
||||||
|
|
||||||
// Leagues
|
// Leagues
|
||||||
a.fiber.Get("/leagues", h.GetAllLeagues)
|
a.fiber.Get("/leagues", h.GetAllLeagues)
|
||||||
a.fiber.Get("/leagues/:id/set-active", h.SetLeagueActive)
|
a.fiber.Put("/leagues/:id/set-active", h.SetLeagueActive)
|
||||||
|
|
||||||
|
a.fiber.Get("/result/:id", h.GetResultsByEventID)
|
||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
||||||
|
|
@ -147,6 +150,7 @@ func (a *App) initAppRoutes() {
|
||||||
// /branch/search
|
// /branch/search
|
||||||
// branch/wallet
|
// branch/wallet
|
||||||
a.fiber.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers)
|
a.fiber.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers)
|
||||||
|
a.fiber.Get("/branchCashier", a.authMiddleware, h.GetBranchForCashier)
|
||||||
|
|
||||||
// Branch Operation
|
// Branch Operation
|
||||||
a.fiber.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations)
|
a.fiber.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations)
|
||||||
|
|
@ -185,6 +189,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Get("/wallet/:id", h.GetWalletByID)
|
a.fiber.Get("/wallet/:id", h.GetWalletByID)
|
||||||
a.fiber.Put("/wallet/:id", h.UpdateWalletActive)
|
a.fiber.Put("/wallet/:id", h.UpdateWalletActive)
|
||||||
a.fiber.Get("/branchWallet", a.authMiddleware, h.GetAllBranchWallets)
|
a.fiber.Get("/branchWallet", a.authMiddleware, h.GetAllBranchWallets)
|
||||||
|
a.fiber.Get("/cashierWallet", a.authMiddleware, h.GetWalletForCashier)
|
||||||
|
|
||||||
// Transfer
|
// Transfer
|
||||||
// /transfer/wallet - transfer from one wallet to another wallet
|
// /transfer/wallet - transfer from one wallet to another wallet
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package ws
|
package ws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -37,7 +36,7 @@ func (h *NotificationHub) Run() {
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
h.Clients[client] = true
|
h.Clients[client] = true
|
||||||
h.mu.Unlock()
|
h.mu.Unlock()
|
||||||
log.Printf("Client registered: %d", client.RecipientID)
|
// log.Printf("Client registered: %d", client.RecipientID)
|
||||||
case client := <-h.Unregister:
|
case client := <-h.Unregister:
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
if _, ok := h.Clients[client]; ok {
|
if _, ok := h.Clients[client]; ok {
|
||||||
|
|
@ -45,7 +44,7 @@ func (h *NotificationHub) Run() {
|
||||||
client.Conn.Close()
|
client.Conn.Close()
|
||||||
}
|
}
|
||||||
h.mu.Unlock()
|
h.mu.Unlock()
|
||||||
log.Printf("Client unregistered: %d", client.RecipientID)
|
// log.Printf("Client unregistered: %d", client.RecipientID)
|
||||||
case message := <-h.Broadcast:
|
case message := <-h.Broadcast:
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
for client := range h.Clients {
|
for client := range h.Clients {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user