events pagination + ticket and bet validation
This commit is contained in:
parent
cab7dbe2fa
commit
991199c3dc
|
|
@ -76,6 +76,8 @@ CREATE TABLE IF NOT EXISTS bet_outcomes (
|
|||
market_name VARCHAR(255) NOT NULL,
|
||||
odd REAL NOT NULL,
|
||||
odd_name VARCHAR(255) NOT NULL,
|
||||
odd_header VARCHAR(255) NOT NULL,
|
||||
odd_handicap VARCHAR(255) NOT NULL,
|
||||
expires TIMESTAMP NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
||||
|
|
@ -89,6 +91,8 @@ CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
|||
market_name VARCHAR(255) NOT NULL,
|
||||
odd REAL NOT NULL,
|
||||
odd_name VARCHAR(255) NOT NULL,
|
||||
odd_header VARCHAR(255) NOT NULL,
|
||||
odd_handicap VARCHAR(255) NOT NULL,
|
||||
expires TIMESTAMP NOT NULL
|
||||
);
|
||||
CREATE VIEW bet_with_outcomes AS
|
||||
|
|
@ -321,6 +325,34 @@ VALUES (
|
|||
NULL,
|
||||
FALSE
|
||||
);
|
||||
INSERT INTO users (
|
||||
first_name,
|
||||
last_name,
|
||||
email,
|
||||
phone_number,
|
||||
password,
|
||||
role,
|
||||
email_verified,
|
||||
phone_verified,
|
||||
created_at,
|
||||
updated_at,
|
||||
suspended_at,
|
||||
suspended
|
||||
)
|
||||
VALUES (
|
||||
'Kirubel',
|
||||
'Kibru',
|
||||
'kirubeljkl679 @gmail.com',
|
||||
NULL,
|
||||
crypt('password@123', gen_salt('bf'))::bytea,
|
||||
'super_admin',
|
||||
TRUE,
|
||||
FALSE,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
INSERT INTO supported_operations (name, description)
|
||||
VALUES ('SportBook', 'Sportbook operations'),
|
||||
('Virtual', 'Virtual operations'),
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ INSERT INTO bet_outcomes (
|
|||
market_name,
|
||||
odd,
|
||||
odd_name,
|
||||
odd_header,
|
||||
odd_handicap,
|
||||
expires
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
|
||||
-- name: GetAllBets :many
|
||||
SELECT *
|
||||
FROM bet_with_outcomes;
|
||||
|
|
@ -46,6 +48,11 @@ UPDATE bets
|
|||
SET cashed_out = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
-- name: UpdateStatus :exec
|
||||
UPDATE bets
|
||||
SET status = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
-- name: DeleteBet :exec
|
||||
DELETE FROM bets
|
||||
WHERE id = $1;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,50 @@
|
|||
-- name: InsertEvent :exec
|
||||
INSERT INTO events (
|
||||
id, sport_id, match_name, home_team, away_team,
|
||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
||||
league_id, league_name, league_cc, start_time, score,
|
||||
match_minute, timer_status, added_time, match_period,
|
||||
is_live, status
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12, $13, $14,
|
||||
$15, $16, $17, $18,
|
||||
$19, $20
|
||||
id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
away_team,
|
||||
home_team_id,
|
||||
away_team_id,
|
||||
home_kit_image,
|
||||
away_kit_image,
|
||||
league_id,
|
||||
league_name,
|
||||
league_cc,
|
||||
start_time,
|
||||
score,
|
||||
match_minute,
|
||||
timer_status,
|
||||
added_time,
|
||||
match_period,
|
||||
is_live,
|
||||
status
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
sport_id = EXCLUDED.sport_id,
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13,
|
||||
$14,
|
||||
$15,
|
||||
$16,
|
||||
$17,
|
||||
$18,
|
||||
$19,
|
||||
$20
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
match_name = EXCLUDED.match_name,
|
||||
home_team = EXCLUDED.home_team,
|
||||
away_team = EXCLUDED.away_team,
|
||||
|
|
@ -35,18 +66,41 @@ ON CONFLICT (id) DO UPDATE SET
|
|||
fetched_at = now();
|
||||
-- name: InsertUpcomingEvent :exec
|
||||
INSERT INTO events (
|
||||
id, sport_id, match_name, home_team, away_team,
|
||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
||||
league_id, league_name, league_cc, start_time,
|
||||
is_live, status
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12, $13,
|
||||
false, 'upcoming'
|
||||
id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
away_team,
|
||||
home_team_id,
|
||||
away_team_id,
|
||||
home_kit_image,
|
||||
away_kit_image,
|
||||
league_id,
|
||||
league_name,
|
||||
league_cc,
|
||||
start_time,
|
||||
is_live,
|
||||
status
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
sport_id = EXCLUDED.sport_id,
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13,
|
||||
false,
|
||||
'upcoming'
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
match_name = EXCLUDED.match_name,
|
||||
home_team = EXCLUDED.home_team,
|
||||
away_team = EXCLUDED.away_team,
|
||||
|
|
@ -61,14 +115,12 @@ ON CONFLICT (id) DO UPDATE SET
|
|||
is_live = false,
|
||||
status = 'upcoming',
|
||||
fetched_at = now();
|
||||
|
||||
|
||||
-- name: ListLiveEvents :many
|
||||
SELECT id FROM events WHERE is_live = true;
|
||||
|
||||
SELECT id
|
||||
FROM events
|
||||
WHERE is_live = true;
|
||||
-- name: GetAllUpcomingEvents :many
|
||||
SELECT
|
||||
id,
|
||||
SELECT id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
|
|
@ -88,9 +140,35 @@ FROM events
|
|||
WHERE is_live = false
|
||||
AND status = 'upcoming'
|
||||
ORDER BY start_time ASC;
|
||||
-- name: GetTotalEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
AND status = 'upcoming';
|
||||
-- name: GetPaginatedUpcomingEvents :many
|
||||
SELECT id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
away_team,
|
||||
home_team_id,
|
||||
away_team_id,
|
||||
home_kit_image,
|
||||
away_kit_image,
|
||||
league_id,
|
||||
league_name,
|
||||
league_cc,
|
||||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
AND status = 'upcoming'
|
||||
ORDER BY start_time ASC
|
||||
LIMIT $1 OFFSET $2;
|
||||
-- name: GetUpcomingByID :one
|
||||
SELECT
|
||||
id,
|
||||
SELECT id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
|
|
|
|||
|
|
@ -83,16 +83,18 @@ SELECT event_id,
|
|||
FROM odds
|
||||
WHERE is_active = true
|
||||
AND source = 'b365api';
|
||||
-- name: GetRawOddsByMarketID :many
|
||||
-- name: GetRawOddsByMarketID :one
|
||||
SELECT id,
|
||||
market_name,
|
||||
handicap,
|
||||
raw_odds,
|
||||
fetched_at
|
||||
FROM odds
|
||||
WHERE market_id = $1
|
||||
AND fi = $2
|
||||
AND is_active = true
|
||||
AND source = 'b365api'
|
||||
LIMIT $3 OFFSET $4;
|
||||
AND source = 'b365api';
|
||||
|
||||
-- name: GetPrematchOddsByUpcomingID :many
|
||||
SELECT o.event_id,
|
||||
o.fi,
|
||||
|
|
|
|||
|
|
@ -13,9 +13,24 @@ INSERT INTO ticket_outcomes (
|
|||
market_name,
|
||||
odd,
|
||||
odd_name,
|
||||
odd_header,
|
||||
odd_handicap,
|
||||
expires
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12
|
||||
);
|
||||
-- name: GetAllTickets :many
|
||||
SELECT *
|
||||
FROM ticket_with_outcomes;
|
||||
|
|
|
|||
100
docs/docs.go
100
docs/docs.go
|
|
@ -1303,6 +1303,20 @@ const docTemplate = `{
|
|||
"prematch"
|
||||
],
|
||||
"summary": "Retrieve all upcoming events",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
|
|
@ -2667,6 +2681,14 @@ const docTemplate = `{
|
|||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_handicap": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_header": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
|
|
@ -2764,9 +2786,15 @@ const docTemplate = `{
|
|||
"fetched_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"handicap": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"market_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"raw_odds": {
|
||||
"type": "array",
|
||||
"items": {}
|
||||
|
|
@ -2825,6 +2853,14 @@ const docTemplate = `{
|
|||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_handicap": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_header": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
|
|
@ -3069,45 +3105,18 @@ const docTemplate = `{
|
|||
"handlers.CreateBetOutcomeReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"away_team_name": {
|
||||
"type": "string",
|
||||
"example": "Liverpool"
|
||||
},
|
||||
"bet_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"event_id": {
|
||||
"description": "BetID int64 ` + "`" + `json:\"bet_id\" example:\"1\"` + "`" + `",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"expires": {
|
||||
"type": "string",
|
||||
"example": "2025-04-08T12:00:00Z"
|
||||
},
|
||||
"home_team_name": {
|
||||
"type": "string",
|
||||
"example": "Manchester"
|
||||
},
|
||||
"market_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"market_name": {
|
||||
"type": "string",
|
||||
"example": "Fulltime Result"
|
||||
},
|
||||
"odd": {
|
||||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"odd_name": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -3264,45 +3273,18 @@ const docTemplate = `{
|
|||
"handlers.CreateTicketOutcomeReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"away_team_name": {
|
||||
"type": "string",
|
||||
"example": "Liverpool"
|
||||
},
|
||||
"event_id": {
|
||||
"description": "TicketID int64 ` + "`" + `json:\"ticket_id\" example:\"1\"` + "`" + `",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"expires": {
|
||||
"type": "string",
|
||||
"example": "2025-04-08T12:00:00Z"
|
||||
},
|
||||
"home_team_name": {
|
||||
"type": "string",
|
||||
"example": "Manchester"
|
||||
},
|
||||
"market_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"market_name": {
|
||||
"type": "string",
|
||||
"example": "Fulltime Result"
|
||||
},
|
||||
"odd": {
|
||||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"odd_name": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"ticket_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -3858,11 +3840,17 @@ const docTemplate = `{
|
|||
"type": "string"
|
||||
},
|
||||
"metadata": {},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/response.Status"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1295,6 +1295,20 @@
|
|||
"prematch"
|
||||
],
|
||||
"summary": "Retrieve all upcoming events",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
|
|
@ -2659,6 +2673,14 @@
|
|||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_handicap": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_header": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
|
|
@ -2756,9 +2778,15 @@
|
|||
"fetched_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"handicap": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"market_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"raw_odds": {
|
||||
"type": "array",
|
||||
"items": {}
|
||||
|
|
@ -2817,6 +2845,14 @@
|
|||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_handicap": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_header": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
|
|
@ -3061,45 +3097,18 @@
|
|||
"handlers.CreateBetOutcomeReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"away_team_name": {
|
||||
"type": "string",
|
||||
"example": "Liverpool"
|
||||
},
|
||||
"bet_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"event_id": {
|
||||
"description": "BetID int64 `json:\"bet_id\" example:\"1\"`",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"expires": {
|
||||
"type": "string",
|
||||
"example": "2025-04-08T12:00:00Z"
|
||||
},
|
||||
"home_team_name": {
|
||||
"type": "string",
|
||||
"example": "Manchester"
|
||||
},
|
||||
"market_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"market_name": {
|
||||
"type": "string",
|
||||
"example": "Fulltime Result"
|
||||
},
|
||||
"odd": {
|
||||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"odd_name": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -3256,45 +3265,18 @@
|
|||
"handlers.CreateTicketOutcomeReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"away_team_name": {
|
||||
"type": "string",
|
||||
"example": "Liverpool"
|
||||
},
|
||||
"event_id": {
|
||||
"description": "TicketID int64 `json:\"ticket_id\" example:\"1\"`",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"expires": {
|
||||
"type": "string",
|
||||
"example": "2025-04-08T12:00:00Z"
|
||||
},
|
||||
"home_team_name": {
|
||||
"type": "string",
|
||||
"example": "Manchester"
|
||||
},
|
||||
"market_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"market_name": {
|
||||
"type": "string",
|
||||
"example": "Fulltime Result"
|
||||
},
|
||||
"odd": {
|
||||
"type": "number",
|
||||
"example": 1.5
|
||||
},
|
||||
"odd_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"odd_name": {
|
||||
"type": "string",
|
||||
"example": "1"
|
||||
},
|
||||
"ticket_id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -3850,11 +3832,17 @@
|
|||
"type": "string"
|
||||
},
|
||||
"metadata": {},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/response.Status"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@ definitions:
|
|||
odd:
|
||||
example: 1.5
|
||||
type: number
|
||||
odd_handicap:
|
||||
example: "1"
|
||||
type: string
|
||||
odd_header:
|
||||
example: "1"
|
||||
type: string
|
||||
odd_id:
|
||||
example: 1
|
||||
type: integer
|
||||
|
|
@ -97,8 +103,12 @@ definitions:
|
|||
properties:
|
||||
fetched_at:
|
||||
type: string
|
||||
handicap:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
market_name:
|
||||
type: string
|
||||
raw_odds:
|
||||
items: {}
|
||||
type: array
|
||||
|
|
@ -143,6 +153,12 @@ definitions:
|
|||
odd:
|
||||
example: 1.5
|
||||
type: number
|
||||
odd_handicap:
|
||||
example: "1"
|
||||
type: string
|
||||
odd_header:
|
||||
example: "1"
|
||||
type: string
|
||||
odd_id:
|
||||
example: 1
|
||||
type: integer
|
||||
|
|
@ -317,36 +333,16 @@ definitions:
|
|||
type: object
|
||||
handlers.CreateBetOutcomeReq:
|
||||
properties:
|
||||
away_team_name:
|
||||
example: Liverpool
|
||||
type: string
|
||||
bet_id:
|
||||
example: 1
|
||||
type: integer
|
||||
event_id:
|
||||
description: BetID int64 `json:"bet_id" example:"1"`
|
||||
example: 1
|
||||
type: integer
|
||||
expires:
|
||||
example: "2025-04-08T12:00:00Z"
|
||||
type: string
|
||||
home_team_name:
|
||||
example: Manchester
|
||||
type: string
|
||||
market_id:
|
||||
example: 1
|
||||
type: integer
|
||||
market_name:
|
||||
example: Fulltime Result
|
||||
type: string
|
||||
odd:
|
||||
example: 1.5
|
||||
type: number
|
||||
odd_id:
|
||||
example: 1
|
||||
type: integer
|
||||
odd_name:
|
||||
example: "1"
|
||||
type: string
|
||||
type: object
|
||||
handlers.CreateBetReq:
|
||||
properties:
|
||||
|
|
@ -455,36 +451,16 @@ definitions:
|
|||
type: object
|
||||
handlers.CreateTicketOutcomeReq:
|
||||
properties:
|
||||
away_team_name:
|
||||
example: Liverpool
|
||||
type: string
|
||||
event_id:
|
||||
description: TicketID int64 `json:"ticket_id" example:"1"`
|
||||
example: 1
|
||||
type: integer
|
||||
expires:
|
||||
example: "2025-04-08T12:00:00Z"
|
||||
type: string
|
||||
home_team_name:
|
||||
example: Manchester
|
||||
type: string
|
||||
market_id:
|
||||
example: 1
|
||||
type: integer
|
||||
market_name:
|
||||
example: Fulltime Result
|
||||
type: string
|
||||
odd:
|
||||
example: 1.5
|
||||
type: number
|
||||
odd_id:
|
||||
example: 1
|
||||
type: integer
|
||||
odd_name:
|
||||
example: "1"
|
||||
type: string
|
||||
ticket_id:
|
||||
example: 1
|
||||
type: integer
|
||||
type: object
|
||||
handlers.CreateTicketReq:
|
||||
properties:
|
||||
|
|
@ -867,10 +843,14 @@ definitions:
|
|||
message:
|
||||
type: string
|
||||
metadata: {}
|
||||
page:
|
||||
type: integer
|
||||
status:
|
||||
$ref: '#/definitions/response.Status'
|
||||
timestamp:
|
||||
type: string
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
response.Status:
|
||||
enum:
|
||||
|
|
@ -1732,6 +1712,15 @@ paths:
|
|||
consumes:
|
||||
- application/json
|
||||
description: Retrieve all upcoming events from the database
|
||||
parameters:
|
||||
- description: Page number
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: Page size
|
||||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ type CreateBetOutcomeParams struct {
|
|||
MarketName string `json:"market_name"`
|
||||
Odd float32 `json:"odd"`
|
||||
OddName string `json:"odd_name"`
|
||||
OddHeader string `json:"odd_header"`
|
||||
OddHandicap string `json:"odd_handicap"`
|
||||
Expires pgtype.Timestamp `json:"expires"`
|
||||
}
|
||||
|
||||
|
|
@ -256,3 +258,20 @@ func (q *Queries) UpdateCashOut(ctx context.Context, arg UpdateCashOutParams) er
|
|||
_, err := q.db.Exec(ctx, UpdateCashOut, arg.ID, arg.CashedOut)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateStatus = `-- name: UpdateStatus :exec
|
||||
UPDATE bets
|
||||
SET status = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateStatusParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Status int32 `json:"status"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateStatus(ctx context.Context, arg UpdateStatusParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateStatus, arg.ID, arg.Status)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ func (r iteratorForCreateBetOutcome) Values() ([]interface{}, error) {
|
|||
r.rows[0].MarketName,
|
||||
r.rows[0].Odd,
|
||||
r.rows[0].OddName,
|
||||
r.rows[0].OddHeader,
|
||||
r.rows[0].OddHandicap,
|
||||
r.rows[0].Expires,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -47,7 +49,7 @@ func (r iteratorForCreateBetOutcome) Err() error {
|
|||
}
|
||||
|
||||
func (q *Queries) CreateBetOutcome(ctx context.Context, arg []CreateBetOutcomeParams) (int64, error) {
|
||||
return q.db.CopyFrom(ctx, []string{"bet_outcomes"}, []string{"bet_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "expires"}, &iteratorForCreateBetOutcome{rows: arg})
|
||||
return q.db.CopyFrom(ctx, []string{"bet_outcomes"}, []string{"bet_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "odd_header", "odd_handicap", "expires"}, &iteratorForCreateBetOutcome{rows: arg})
|
||||
}
|
||||
|
||||
// iteratorForCreateTicketOutcome implements pgx.CopyFromSource.
|
||||
|
|
@ -79,6 +81,8 @@ func (r iteratorForCreateTicketOutcome) Values() ([]interface{}, error) {
|
|||
r.rows[0].MarketName,
|
||||
r.rows[0].Odd,
|
||||
r.rows[0].OddName,
|
||||
r.rows[0].OddHeader,
|
||||
r.rows[0].OddHandicap,
|
||||
r.rows[0].Expires,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -88,5 +92,5 @@ func (r iteratorForCreateTicketOutcome) Err() error {
|
|||
}
|
||||
|
||||
func (q *Queries) CreateTicketOutcome(ctx context.Context, arg []CreateTicketOutcomeParams) (int64, error) {
|
||||
return q.db.CopyFrom(ctx, []string{"ticket_outcomes"}, []string{"ticket_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "expires"}, &iteratorForCreateTicketOutcome{rows: arg})
|
||||
return q.db.CopyFrom(ctx, []string{"ticket_outcomes"}, []string{"ticket_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "odd_header", "odd_handicap", "expires"}, &iteratorForCreateTicketOutcome{rows: arg})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import (
|
|||
)
|
||||
|
||||
const GetAllUpcomingEvents = `-- name: GetAllUpcomingEvents :many
|
||||
SELECT
|
||||
id,
|
||||
SELECT id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
|
|
@ -91,9 +90,107 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]GetAllUpcomingEve
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const GetPaginatedUpcomingEvents = `-- name: GetPaginatedUpcomingEvents :many
|
||||
SELECT id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
away_team,
|
||||
home_team_id,
|
||||
away_team_id,
|
||||
home_kit_image,
|
||||
away_kit_image,
|
||||
league_id,
|
||||
league_name,
|
||||
league_cc,
|
||||
start_time,
|
||||
is_live,
|
||||
status,
|
||||
fetched_at
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
AND status = 'upcoming'
|
||||
ORDER BY start_time ASC
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type GetPaginatedUpcomingEventsParams struct {
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
type GetPaginatedUpcomingEventsRow struct {
|
||||
ID string `json:"id"`
|
||||
SportID pgtype.Text `json:"sport_id"`
|
||||
MatchName pgtype.Text `json:"match_name"`
|
||||
HomeTeam pgtype.Text `json:"home_team"`
|
||||
AwayTeam pgtype.Text `json:"away_team"`
|
||||
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||
LeagueID pgtype.Text `json:"league_id"`
|
||||
LeagueName pgtype.Text `json:"league_name"`
|
||||
LeagueCc pgtype.Text `json:"league_cc"`
|
||||
StartTime pgtype.Timestamp `json:"start_time"`
|
||||
IsLive pgtype.Bool `json:"is_live"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginatedUpcomingEventsParams) ([]GetPaginatedUpcomingEventsRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetPaginatedUpcomingEvents, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetPaginatedUpcomingEventsRow
|
||||
for rows.Next() {
|
||||
var i GetPaginatedUpcomingEventsRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.SportID,
|
||||
&i.MatchName,
|
||||
&i.HomeTeam,
|
||||
&i.AwayTeam,
|
||||
&i.HomeTeamID,
|
||||
&i.AwayTeamID,
|
||||
&i.HomeKitImage,
|
||||
&i.AwayKitImage,
|
||||
&i.LeagueID,
|
||||
&i.LeagueName,
|
||||
&i.LeagueCc,
|
||||
&i.StartTime,
|
||||
&i.IsLive,
|
||||
&i.Status,
|
||||
&i.FetchedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetTotalEvents = `-- name: GetTotalEvents :one
|
||||
SELECT COUNT(*)
|
||||
FROM events
|
||||
WHERE is_live = false
|
||||
AND status = 'upcoming'
|
||||
`
|
||||
|
||||
func (q *Queries) GetTotalEvents(ctx context.Context) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, GetTotalEvents)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const GetUpcomingByID = `-- name: GetUpcomingByID :one
|
||||
SELECT
|
||||
id,
|
||||
SELECT id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
|
|
@ -161,20 +258,51 @@ func (q *Queries) GetUpcomingByID(ctx context.Context, id string) (GetUpcomingBy
|
|||
|
||||
const InsertEvent = `-- name: InsertEvent :exec
|
||||
INSERT INTO events (
|
||||
id, sport_id, match_name, home_team, away_team,
|
||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
||||
league_id, league_name, league_cc, start_time, score,
|
||||
match_minute, timer_status, added_time, match_period,
|
||||
is_live, status
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12, $13, $14,
|
||||
$15, $16, $17, $18,
|
||||
$19, $20
|
||||
id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
away_team,
|
||||
home_team_id,
|
||||
away_team_id,
|
||||
home_kit_image,
|
||||
away_kit_image,
|
||||
league_id,
|
||||
league_name,
|
||||
league_cc,
|
||||
start_time,
|
||||
score,
|
||||
match_minute,
|
||||
timer_status,
|
||||
added_time,
|
||||
match_period,
|
||||
is_live,
|
||||
status
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
sport_id = EXCLUDED.sport_id,
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13,
|
||||
$14,
|
||||
$15,
|
||||
$16,
|
||||
$17,
|
||||
$18,
|
||||
$19,
|
||||
$20
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
match_name = EXCLUDED.match_name,
|
||||
home_team = EXCLUDED.home_team,
|
||||
away_team = EXCLUDED.away_team,
|
||||
|
|
@ -247,18 +375,41 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error
|
|||
|
||||
const InsertUpcomingEvent = `-- name: InsertUpcomingEvent :exec
|
||||
INSERT INTO events (
|
||||
id, sport_id, match_name, home_team, away_team,
|
||||
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
||||
league_id, league_name, league_cc, start_time,
|
||||
is_live, status
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12, $13,
|
||||
false, 'upcoming'
|
||||
id,
|
||||
sport_id,
|
||||
match_name,
|
||||
home_team,
|
||||
away_team,
|
||||
home_team_id,
|
||||
away_team_id,
|
||||
home_kit_image,
|
||||
away_kit_image,
|
||||
league_id,
|
||||
league_name,
|
||||
league_cc,
|
||||
start_time,
|
||||
is_live,
|
||||
status
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
sport_id = EXCLUDED.sport_id,
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13,
|
||||
false,
|
||||
'upcoming'
|
||||
) ON CONFLICT (id) DO
|
||||
UPDATE
|
||||
SET sport_id = EXCLUDED.sport_id,
|
||||
match_name = EXCLUDED.match_name,
|
||||
home_team = EXCLUDED.home_team,
|
||||
away_team = EXCLUDED.away_team,
|
||||
|
|
@ -311,7 +462,9 @@ func (q *Queries) InsertUpcomingEvent(ctx context.Context, arg InsertUpcomingEve
|
|||
}
|
||||
|
||||
const ListLiveEvents = `-- name: ListLiveEvents :many
|
||||
SELECT id FROM events WHERE is_live = true
|
||||
SELECT id
|
||||
FROM events
|
||||
WHERE is_live = true
|
||||
`
|
||||
|
||||
func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ type BetOutcome struct {
|
|||
MarketName string `json:"market_name"`
|
||||
Odd float32 `json:"odd"`
|
||||
OddName string `json:"odd_name"`
|
||||
OddHeader string `json:"odd_header"`
|
||||
OddHandicap string `json:"odd_handicap"`
|
||||
Expires pgtype.Timestamp `json:"expires"`
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +213,8 @@ type TicketOutcome struct {
|
|||
MarketName string `json:"market_name"`
|
||||
Odd float32 `json:"odd"`
|
||||
OddName string `json:"odd_name"`
|
||||
OddHeader string `json:"odd_header"`
|
||||
OddHandicap string `json:"odd_handicap"`
|
||||
Expires pgtype.Timestamp `json:"expires"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -247,8 +247,10 @@ func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, arg GetPremat
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :many
|
||||
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :one
|
||||
SELECT id,
|
||||
market_name,
|
||||
handicap,
|
||||
raw_odds,
|
||||
fetched_at
|
||||
FROM odds
|
||||
|
|
@ -256,45 +258,32 @@ WHERE market_id = $1
|
|||
AND fi = $2
|
||||
AND is_active = true
|
||||
AND source = 'b365api'
|
||||
LIMIT $3 OFFSET $4
|
||||
`
|
||||
|
||||
type GetRawOddsByMarketIDParams struct {
|
||||
MarketID pgtype.Text `json:"market_id"`
|
||||
Fi pgtype.Text `json:"fi"`
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
type GetRawOddsByMarketIDRow struct {
|
||||
ID int32 `json:"id"`
|
||||
MarketName pgtype.Text `json:"market_name"`
|
||||
Handicap pgtype.Text `json:"handicap"`
|
||||
RawOdds []byte `json:"raw_odds"`
|
||||
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) ([]GetRawOddsByMarketIDRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetRawOddsByMarketID,
|
||||
arg.MarketID,
|
||||
arg.Fi,
|
||||
arg.Limit,
|
||||
arg.Offset,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetRawOddsByMarketIDRow
|
||||
for rows.Next() {
|
||||
func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) (GetRawOddsByMarketIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetRawOddsByMarketID, arg.MarketID, arg.Fi)
|
||||
var i GetRawOddsByMarketIDRow
|
||||
if err := rows.Scan(&i.ID, &i.RawOdds, &i.FetchedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.MarketName,
|
||||
&i.Handicap,
|
||||
&i.RawOdds,
|
||||
&i.FetchedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ type CreateTicketOutcomeParams struct {
|
|||
MarketName string `json:"market_name"`
|
||||
Odd float32 `json:"odd"`
|
||||
OddName string `json:"odd_name"`
|
||||
OddHeader string `json:"odd_header"`
|
||||
OddHandicap string `json:"odd_handicap"`
|
||||
Expires pgtype.Timestamp `json:"expires"`
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +133,7 @@ func (q *Queries) GetTicketByID(ctx context.Context, id int64) (TicketWithOutcom
|
|||
}
|
||||
|
||||
const GetTicketOutcome = `-- name: GetTicketOutcome :many
|
||||
SELECT id, ticket_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, expires
|
||||
SELECT id, ticket_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, expires
|
||||
FROM ticket_outcomes
|
||||
WHERE ticket_id = $1
|
||||
`
|
||||
|
|
@ -156,6 +158,8 @@ func (q *Queries) GetTicketOutcome(ctx context.Context, ticketID int64) ([]Ticke
|
|||
&i.MarketName,
|
||||
&i.Odd,
|
||||
&i.OddName,
|
||||
&i.OddHeader,
|
||||
&i.OddHandicap,
|
||||
&i.Expires,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ type BetOutcome struct {
|
|||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
Odd float32 `json:"odd" example:"1.5"`
|
||||
OddName string `json:"odd_name" example:"1"`
|
||||
OddHeader string `json:"odd_header" example:"1"`
|
||||
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||
|
||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
|
|
@ -26,6 +29,8 @@ type CreateBetOutcome struct {
|
|||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
Odd float32 `json:"odd" example:"1.5"`
|
||||
OddName string `json:"odd_name" example:"1"`
|
||||
OddHeader string `json:"odd_header" example:"1"`
|
||||
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package domain
|
|||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
)
|
||||
|
||||
type RawMessage interface{}
|
||||
|
||||
type Market struct {
|
||||
|
|
@ -40,6 +40,8 @@ type Odd struct {
|
|||
}
|
||||
type RawOddsByMarketID struct {
|
||||
ID int64 `json:"id"`
|
||||
MarketName string `json:"market_name"`
|
||||
Handicap string `json:"handicap"`
|
||||
RawOdds []RawMessage `json:"raw_odds"`
|
||||
FetchedAt time.Time `json:"fetched_at"`
|
||||
}
|
||||
|
|
@ -6,13 +6,15 @@ type TicketOutcome struct {
|
|||
ID int64 `json:"id" example:"1"`
|
||||
TicketID int64 `json:"ticket_id" example:"1"`
|
||||
EventID int64 `json:"event_id" example:"1"`
|
||||
OddID int64 `json:"odd_id" example:"1"`
|
||||
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||
MarketID int64 `json:"market_id" example:"1"`
|
||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
OddID int64 `json:"odd_id" example:"1"`
|
||||
Odd float32 `json:"odd" example:"1.5"`
|
||||
OddName string `json:"odd_name" example:"1"`
|
||||
OddHeader string `json:"odd_header" example:"1"`
|
||||
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
|
|
@ -26,6 +28,8 @@ type CreateTicketOutcome struct {
|
|||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
Odd float32 `json:"odd" example:"1.5"`
|
||||
OddName string `json:"odd_name" example:"1"`
|
||||
OddHeader string `json:"odd_header" example:"1"`
|
||||
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ func convertDBBetOutcomes(bet dbgen.BetWithOutcome) domain.GetBet {
|
|||
MarketName: outcome.MarketName,
|
||||
Odd: outcome.Odd,
|
||||
OddName: outcome.OddName,
|
||||
OddHeader: outcome.OddHeader,
|
||||
OddHandicap: outcome.OddHandicap,
|
||||
Expires: outcome.Expires.Time,
|
||||
})
|
||||
}
|
||||
|
|
@ -82,6 +84,8 @@ func convertDBCreateBetOutcome(betOutcome domain.CreateBetOutcome) dbgen.CreateB
|
|||
MarketName: betOutcome.MarketName,
|
||||
Odd: betOutcome.Odd,
|
||||
OddName: betOutcome.OddName,
|
||||
OddHeader: betOutcome.OddHeader,
|
||||
OddHandicap: betOutcome.OddHandicap,
|
||||
Expires: pgtype.Timestamp{
|
||||
Time: betOutcome.Expires,
|
||||
Valid: true,
|
||||
|
|
@ -193,6 +197,14 @@ func (s *Store) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) err
|
|||
return err
|
||||
}
|
||||
|
||||
func (s *Store) UpdateStatus(ctx context.Context, id int64, status domain.BetStatus) error {
|
||||
err := s.queries.UpdateStatus(ctx, dbgen.UpdateStatusParams{
|
||||
ID: id,
|
||||
Status: int32(status),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
||||
return s.queries.DeleteBet(ctx, id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
|
||||
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
|
@ -86,6 +87,42 @@ func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEven
|
|||
}
|
||||
return upcomingEvents, nil
|
||||
}
|
||||
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32) ([]domain.UpcomingEvent, int64, error) {
|
||||
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
|
||||
Limit: limit,
|
||||
Offset: offset * limit,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
upcomingEvents := make([]domain.UpcomingEvent, len(events))
|
||||
for i, e := range events {
|
||||
upcomingEvents[i] = domain.UpcomingEvent{
|
||||
ID: e.ID,
|
||||
SportID: e.SportID.String,
|
||||
MatchName: e.MatchName.String,
|
||||
HomeTeam: e.HomeTeam.String,
|
||||
AwayTeam: e.AwayTeam.String,
|
||||
HomeTeamID: e.HomeTeamID.String,
|
||||
AwayTeamID: e.AwayTeamID.String,
|
||||
HomeKitImage: e.HomeKitImage.String,
|
||||
AwayKitImage: e.AwayKitImage.String,
|
||||
LeagueID: e.LeagueID.String,
|
||||
LeagueName: e.LeagueName.String,
|
||||
LeagueCC: e.LeagueCc.String,
|
||||
StartTime: e.StartTime.Time.UTC(),
|
||||
}
|
||||
}
|
||||
totalCount, err := s.queries.GetTotalEvents(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
numberOfPages := (totalCount) / int64(limit)
|
||||
return upcomingEvents, numberOfPages, nil
|
||||
}
|
||||
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||
event, err := s.queries.GetUpcomingByID(ctx, ID)
|
||||
if err != nil {
|
||||
|
|
@ -108,4 +145,3 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
|||
StartTime: event.StartTime.Time.UTC(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package repository
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
|
@ -180,28 +179,22 @@ func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upco
|
|||
params := dbgen.GetRawOddsByMarketIDParams{
|
||||
MarketID: pgtype.Text{String: rawOddsID, Valid: true},
|
||||
Fi: pgtype.Text{String: upcomingID, Valid: true},
|
||||
Limit: 1,
|
||||
Offset: 0,
|
||||
}
|
||||
|
||||
rows, err := s.queries.GetRawOddsByMarketID(ctx, params)
|
||||
odds, err := s.queries.GetRawOddsByMarketID(ctx, params)
|
||||
if err != nil {
|
||||
return domain.RawOddsByMarketID{}, err
|
||||
}
|
||||
|
||||
if len(rows) == 0 {
|
||||
return domain.RawOddsByMarketID{}, fmt.Errorf("no raw odds found for market_id: %s", rawOddsID)
|
||||
}
|
||||
|
||||
row := rows[0]
|
||||
|
||||
var rawOdds []json.RawMessage
|
||||
if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil {
|
||||
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
|
||||
return domain.RawOddsByMarketID{}, err
|
||||
}
|
||||
|
||||
return domain.RawOddsByMarketID{
|
||||
ID: int64(row.ID),
|
||||
ID: int64(odds.ID),
|
||||
MarketName: odds.MarketName.String,
|
||||
Handicap: odds.Handicap.String,
|
||||
RawOdds: func() []domain.RawMessage {
|
||||
converted := make([]domain.RawMessage, len(rawOdds))
|
||||
for i, r := range rawOdds {
|
||||
|
|
@ -209,7 +202,7 @@ func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upco
|
|||
}
|
||||
return converted
|
||||
}(),
|
||||
FetchedAt: row.FetchedAt.Time,
|
||||
FetchedAt: odds.FetchedAt.Time,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ func convertDBTicketOutcomes(ticket dbgen.TicketWithOutcome) domain.GetTicket {
|
|||
MarketName: outcome.MarketName,
|
||||
Odd: outcome.Odd,
|
||||
OddName: outcome.OddName,
|
||||
OddHeader: outcome.OddHeader,
|
||||
OddHandicap: outcome.OddHandicap,
|
||||
Expires: outcome.Expires.Time,
|
||||
})
|
||||
}
|
||||
|
|
@ -54,6 +56,8 @@ func convertDBCreateTicketOutcome(ticketOutcome domain.CreateTicketOutcome) dbge
|
|||
MarketName: ticketOutcome.MarketName,
|
||||
Odd: ticketOutcome.Odd,
|
||||
OddName: ticketOutcome.OddName,
|
||||
OddHeader: ticketOutcome.OddHeader,
|
||||
OddHandicap: ticketOutcome.OddHandicap,
|
||||
Expires: pgtype.Timestamp{
|
||||
Time: ticketOutcome.Expires,
|
||||
Valid: true,
|
||||
|
|
|
|||
|
|
@ -14,5 +14,6 @@ type BetStore interface {
|
|||
GetAllBets(ctx context.Context) ([]domain.GetBet, error)
|
||||
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
|
||||
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
|
||||
UpdateStatus(ctx context.Context, id int64, status domain.BetStatus) error
|
||||
DeleteBet(ctx context.Context, id int64) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) e
|
|||
return s.betStore.UpdateCashOut(ctx, id, cashedOut)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.BetStatus) error {
|
||||
return s.betStore.UpdateStatus(ctx, id, status)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
|
||||
return s.betStore.DeleteBet(ctx, id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ type Service interface {
|
|||
FetchLiveEvents(ctx context.Context) error
|
||||
FetchUpcomingEvents(ctx context.Context) error
|
||||
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||
GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32) ([]domain.UpcomingEvent, int64, error)
|
||||
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,6 +178,10 @@ func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEv
|
|||
return s.store.GetAllUpcomingEvents(ctx)
|
||||
}
|
||||
|
||||
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32) ([]domain.UpcomingEvent, int64, error) {
|
||||
return s.store.GetPaginatedUpcomingEvents(ctx, limit, offset)
|
||||
}
|
||||
|
||||
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||
return s.store.GetUpcomingEventByID(ctx, ID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ type Service interface {
|
|||
FetchNonLiveOdds(ctx context.Context) error
|
||||
GetPrematchOdds(ctx context.Context, eventID string) ([]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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,13 +119,13 @@ func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, err
|
|||
return s.store.GetALLPrematchOdds(ctx)
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) ([]domain.RawOddsByMarketID, error) {
|
||||
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error) {
|
||||
rows, err := s.store.GetRawOddsByMarketID(ctx, marketID, upcomingID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return domain.RawOddsByMarketID{}, err
|
||||
}
|
||||
|
||||
return []domain.RawOddsByMarketID{rows}, nil
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
package httpserver
|
||||
|
||||
import (
|
||||
// "context"
|
||||
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
|
|
@ -19,7 +18,6 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
}{
|
||||
|
||||
// {
|
||||
|
||||
// spec: "0 0 * * * *", // Every hour
|
||||
// task: func() {
|
||||
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||
|
|
@ -48,6 +46,8 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
}
|
||||
|
||||
for _, job := range schedule {
|
||||
job.task()
|
||||
fmt.Printf("here at")
|
||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package handlers
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"time"
|
||||
|
|
@ -9,6 +10,8 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||
|
|
@ -18,16 +21,16 @@ import (
|
|||
)
|
||||
|
||||
type CreateBetOutcomeReq struct {
|
||||
BetID int64 `json:"bet_id" example:"1"`
|
||||
// BetID int64 `json:"bet_id" example:"1"`
|
||||
EventID int64 `json:"event_id" example:"1"`
|
||||
OddID int64 `json:"odd_id" example:"1"`
|
||||
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||
MarketID int64 `json:"market_id" example:"1"`
|
||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
Odd float32 `json:"odd" example:"1.5"`
|
||||
OddName string `json:"odd_name" example:"1"`
|
||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
// HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||
// AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||
// MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
// Odd float32 `json:"odd" example:"1.5"`
|
||||
// OddName string `json:"odd_name" example:"1"`
|
||||
// Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
type NullableInt64 struct {
|
||||
|
|
@ -139,7 +142,7 @@ func convertBet(bet domain.GetBet) BetRes {
|
|||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /bet [post]
|
||||
func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service, branchSvc *branch.Service, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||
func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service, branchSvc *branch.Service, walletSvc *wallet.Service, eventSvc event.Service, oddSvc odds.ServiceImpl, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
|
||||
// Get user_id from middleware
|
||||
|
|
@ -160,6 +163,8 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service,
|
|||
return nil
|
||||
}
|
||||
|
||||
// Validating user by role
|
||||
// Differentiating between offline and online bets
|
||||
user, err := userSvc.GetUserByID(c.Context(), userID)
|
||||
cashoutUUID := uuid.New()
|
||||
var bet domain.Bet
|
||||
|
|
@ -226,28 +231,88 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service,
|
|||
})
|
||||
}
|
||||
|
||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||
|
||||
if err != nil {
|
||||
logger.Error("CreateBetReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||
}
|
||||
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
||||
|
||||
//
|
||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||
// Validation for creating tickets
|
||||
if len(req.Outcomes) > 30 {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||
return nil
|
||||
}
|
||||
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
||||
for _, outcome := range req.Outcomes {
|
||||
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||
event, err := eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||
if err != nil {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checking to make sure the event hasn't already started
|
||||
currentTime := time.Now()
|
||||
if event.StartTime.Before(currentTime) {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
odds, err := oddSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||
|
||||
if err != nil {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||
return nil
|
||||
}
|
||||
type rawOddType struct {
|
||||
ID string
|
||||
Name string
|
||||
Odds string
|
||||
Header string
|
||||
Handicap string
|
||||
}
|
||||
var selectedOdd rawOddType
|
||||
var isOddFound bool = false
|
||||
for _, raw := range odds.RawOdds {
|
||||
var rawOdd rawOddType
|
||||
rawBytes, err := json.Marshal(raw)
|
||||
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to unmarshal raw odd:", err)
|
||||
continue
|
||||
}
|
||||
if rawOdd.ID == oddIDStr {
|
||||
selectedOdd = rawOdd
|
||||
isOddFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isOddFound {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||
|
||||
outcomes = append(outcomes, domain.CreateBetOutcome{
|
||||
BetID: bet.ID,
|
||||
EventID: outcome.EventID,
|
||||
OddID: outcome.OddID,
|
||||
HomeTeamName: outcome.HomeTeamName,
|
||||
AwayTeamName: outcome.AwayTeamName,
|
||||
MarketID: outcome.MarketID,
|
||||
MarketName: outcome.MarketName,
|
||||
Odd: outcome.Odd,
|
||||
OddName: outcome.OddName,
|
||||
Expires: outcome.Expires,
|
||||
HomeTeamName: event.HomeTeam,
|
||||
AwayTeamName: event.AwayTeam,
|
||||
MarketName: odds.MarketName,
|
||||
Odd: float32(parsedOdd),
|
||||
OddName: selectedOdd.Name,
|
||||
OddHeader: selectedOdd.Header,
|
||||
OddHandicap: selectedOdd.Handicap,
|
||||
Expires: event.StartTime,
|
||||
})
|
||||
}
|
||||
|
||||
rows, err := betSvc.CreateBetOutcome(c.Context(), outcomes)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -96,17 +96,22 @@ func GetRawOddsByMarketID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fi
|
|||
// @Tags prematch
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number"
|
||||
// @Param page_size query int false "Page size"
|
||||
// @Success 200 {array} domain.UpcomingEvent
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /prematch/events [get]
|
||||
func GetAllUpcomingEvents(logger *slog.Logger, eventSvc event.Service) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
events, err := eventSvc.GetAllUpcomingEvents(c.Context())
|
||||
page := c.QueryInt("page", 1)
|
||||
pageSize := c.QueryInt("page_size", 10)
|
||||
|
||||
events, total, err := eventSvc.GetPaginatedUpcomingEvents(c.Context(), int32(pageSize), int32(page) - 1)
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all upcoming events", nil, nil)
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil)
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil, page, int(total))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||
|
|
@ -13,16 +17,16 @@ import (
|
|||
)
|
||||
|
||||
type CreateTicketOutcomeReq struct {
|
||||
TicketID int64 `json:"ticket_id" example:"1"`
|
||||
// TicketID int64 `json:"ticket_id" example:"1"`
|
||||
EventID int64 `json:"event_id" example:"1"`
|
||||
OddID int64 `json:"odd_id" example:"1"`
|
||||
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||
MarketID int64 `json:"market_id" example:"1"`
|
||||
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
Odd float32 `json:"odd" example:"1.5"`
|
||||
OddName string `json:"odd_name" example:"1"`
|
||||
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
// HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||
// AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||
// MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||
// Odd float32 `json:"odd" example:"1.5"`
|
||||
// OddName string `json:"odd_name" example:"1"`
|
||||
// Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
type CreateTicketReq struct {
|
||||
|
|
@ -46,8 +50,7 @@ type CreateTicketRes struct {
|
|||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /ticket [post]
|
||||
func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
|
||||
validator *customvalidator.CustomValidator) fiber.Handler {
|
||||
func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service, eventSvc event.Service, oddSvc odds.ServiceImpl, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
var req CreateTicketReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
|
|
@ -64,6 +67,79 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
|
|||
}
|
||||
|
||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||
// Validation for creating tickets
|
||||
if len(req.Outcomes) > 30 {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||
return nil
|
||||
}
|
||||
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
||||
for _, outcome := range req.Outcomes {
|
||||
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||
event, err := eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||
if err != nil {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checking to make sure the event hasn't already started
|
||||
currentTime := time.Now()
|
||||
if event.StartTime.Before(currentTime) {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
odds, err := oddSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||
|
||||
if err != nil {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||
return nil
|
||||
}
|
||||
type rawOddType struct {
|
||||
ID string
|
||||
Name string
|
||||
Odds string
|
||||
Header string
|
||||
Handicap string
|
||||
}
|
||||
var selectedOdd rawOddType
|
||||
var isOddFound bool = false
|
||||
for _, raw := range odds.RawOdds {
|
||||
var rawOdd rawOddType
|
||||
rawBytes, err := json.Marshal(raw)
|
||||
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to unmarshal raw odd:", err)
|
||||
continue
|
||||
}
|
||||
if rawOdd.ID == oddIDStr {
|
||||
selectedOdd = rawOdd
|
||||
isOddFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isOddFound {
|
||||
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||
|
||||
outcomes = append(outcomes, domain.CreateTicketOutcome{
|
||||
EventID: outcome.EventID,
|
||||
OddID: outcome.OddID,
|
||||
MarketID: outcome.MarketID,
|
||||
HomeTeamName: event.HomeTeam,
|
||||
AwayTeamName: event.AwayTeam,
|
||||
MarketName: odds.MarketName,
|
||||
Odd: float32(parsedOdd),
|
||||
OddName: selectedOdd.Name,
|
||||
OddHeader: selectedOdd.Header,
|
||||
OddHandicap: selectedOdd.Handicap,
|
||||
Expires: event.StartTime,
|
||||
})
|
||||
}
|
||||
|
||||
ticket, err := ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
|
|
@ -76,22 +152,11 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
|
|||
})
|
||||
}
|
||||
|
||||
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
||||
|
||||
for _, outcome := range req.Outcomes {
|
||||
outcomes = append(outcomes, domain.CreateTicketOutcome{
|
||||
TicketID: ticket.ID,
|
||||
EventID: outcome.EventID,
|
||||
OddID: outcome.OddID,
|
||||
HomeTeamName: outcome.HomeTeamName,
|
||||
AwayTeamName: outcome.AwayTeamName,
|
||||
MarketID: outcome.MarketID,
|
||||
MarketName: outcome.MarketName,
|
||||
Odd: outcome.Odd,
|
||||
OddName: outcome.OddName,
|
||||
Expires: outcome.Expires,
|
||||
})
|
||||
// Add the ticket id now that it has fetched from the database
|
||||
for index := range outcomes {
|
||||
outcomes[index].TicketID = ticket.ID
|
||||
}
|
||||
|
||||
rows, err := ticketSvc.CreateTicketOutcome(c.Context(), outcomes)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -18,12 +18,15 @@ type APIResponse struct {
|
|||
Message string `json:"message"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
Metadata interface{} `json:"metadata,omitempty"`
|
||||
Page *int `json:"page,omitempty"`
|
||||
Total *int `json:"total,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
func NewAPIResponse(
|
||||
status Status, message string,
|
||||
data interface{}, metadata interface{},
|
||||
page *int, total *int,
|
||||
) APIResponse {
|
||||
|
||||
return APIResponse{
|
||||
|
|
@ -32,6 +35,8 @@ func NewAPIResponse(
|
|||
Data: data,
|
||||
Metadata: metadata,
|
||||
Timestamp: time.Now(),
|
||||
Page: page,
|
||||
Total: total,
|
||||
}
|
||||
}
|
||||
func WriteJSON(c *fiber.Ctx, status int, message string, data, metadata interface{}) error {
|
||||
|
|
@ -41,7 +46,18 @@ func WriteJSON(c *fiber.Ctx, status int, message string, data, metadata interfac
|
|||
} else {
|
||||
apiStatus = Error
|
||||
}
|
||||
apiRes := NewAPIResponse(apiStatus, message, data, metadata)
|
||||
apiRes := NewAPIResponse(apiStatus, message, data, metadata, nil, nil)
|
||||
|
||||
return c.Status(status).JSON(apiRes)
|
||||
}
|
||||
func WritePaginatedJSON(c *fiber.Ctx, status int, message string, data, metadata interface{}, page int, total int) error {
|
||||
var apiStatus Status
|
||||
if status >= 200 && status <= 299 {
|
||||
apiStatus = Success
|
||||
} else {
|
||||
apiStatus = Error
|
||||
}
|
||||
apiRes := NewAPIResponse(apiStatus, message, data, metadata, &page, &total)
|
||||
|
||||
return c.Status(status).JSON(apiRes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,12 +86,12 @@ func (a *App) initAppRoutes() {
|
|||
a.fiber.Delete("/branch/:id/operation/:opID", a.authMiddleware, handlers.DeleteBranchOperation(a.logger, a.branchSvc, a.validator))
|
||||
|
||||
// Ticket
|
||||
a.fiber.Post("/ticket", handlers.CreateTicket(a.logger, a.ticketSvc, a.validator))
|
||||
a.fiber.Post("/ticket", handlers.CreateTicket(a.logger, a.ticketSvc, a.eventSvc, *a.prematchSvc, a.validator))
|
||||
a.fiber.Get("/ticket", handlers.GetAllTickets(a.logger, a.ticketSvc, a.validator))
|
||||
a.fiber.Get("/ticket/:id", handlers.GetTicketByID(a.logger, a.ticketSvc, a.validator))
|
||||
|
||||
// Bet
|
||||
a.fiber.Post("/bet", a.authMiddleware, handlers.CreateBet(a.logger, a.betSvc, a.userSvc, a.branchSvc, a.walletSvc, a.validator))
|
||||
a.fiber.Post("/bet", a.authMiddleware, handlers.CreateBet(a.logger, a.betSvc, a.userSvc, a.branchSvc, a.walletSvc, a.eventSvc, *a.prematchSvc, a.validator))
|
||||
a.fiber.Get("/bet", a.authMiddleware, handlers.GetAllBet(a.logger, a.betSvc, a.validator))
|
||||
a.fiber.Get("/bet/:id", a.authMiddleware, handlers.GetBetByID(a.logger, a.betSvc, a.validator))
|
||||
a.fiber.Get("/bet/cashout/:id", a.authMiddleware, handlers.GetBetByCashoutID(a.logger, a.betSvc, a.validator))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user