integration issues
This commit is contained in:
parent
95fb33c9d4
commit
4c6fb73342
|
|
@ -234,12 +234,17 @@ CREATE TABLE companies (
|
||||||
wallet_id BIGINT NOT NULL
|
wallet_id BIGINT NOT NULL
|
||||||
);
|
);
|
||||||
-- Views
|
-- Views
|
||||||
CREATE VIEW companies_with_wallets AS
|
CREATE VIEW companies_details AS
|
||||||
SELECT companies.*,
|
SELECT companies.*,
|
||||||
wallets.balance,
|
wallets.balance,
|
||||||
wallets.is_active
|
wallets.is_active,
|
||||||
|
users.first_name AS admin_first_name,
|
||||||
|
users.last_name AS admin_last_name,
|
||||||
|
users.phone_number AS admin_phone_number
|
||||||
FROM companies
|
FROM companies
|
||||||
JOIN wallets ON wallets.id = companies.wallet_id;
|
JOIN wallets ON wallets.id = companies.wallet_id
|
||||||
|
JOIN users ON users.id = companies.admin_id;
|
||||||
|
;
|
||||||
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,
|
||||||
|
|
@ -290,11 +295,11 @@ ALTER TABLE branch_operations
|
||||||
ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id) ON DELETE CASCADE,
|
ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id) ON DELETE CASCADE,
|
||||||
ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
||||||
ALTER TABLE branch_cashiers
|
ALTER TABLE branch_cashiers
|
||||||
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id),
|
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
|
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
||||||
ALTER TABLE companies
|
ALTER TABLE companies
|
||||||
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
|
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
|
||||||
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id);
|
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE;
|
||||||
----------------------------------------------seed data-------------------------------------------------------------
|
----------------------------------------------seed data-------------------------------------------------------------
|
||||||
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
|
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
|
@ -344,7 +349,7 @@ VALUES (
|
||||||
'Test',
|
'Test',
|
||||||
'Admin',
|
'Admin',
|
||||||
'test.admin@gmail.com',
|
'test.admin@gmail.com',
|
||||||
'0911111111',
|
'0988554466',
|
||||||
crypt('password123', gen_salt('bf'))::bytea,
|
crypt('password123', gen_salt('bf'))::bytea,
|
||||||
'admin',
|
'admin',
|
||||||
TRUE,
|
TRUE,
|
||||||
|
|
@ -400,7 +405,7 @@ VALUES (
|
||||||
'Kirubel',
|
'Kirubel',
|
||||||
'Kibru',
|
'Kibru',
|
||||||
'kirubeljkl679 @gmail.com',
|
'kirubeljkl679 @gmail.com',
|
||||||
'0911111111',
|
'0911554486',
|
||||||
crypt('password@123', gen_salt('bf'))::bytea,
|
crypt('password@123', gen_salt('bf'))::bytea,
|
||||||
'super_admin',
|
'super_admin',
|
||||||
TRUE,
|
TRUE,
|
||||||
|
|
@ -412,8 +417,7 @@ VALUES (
|
||||||
);
|
);
|
||||||
INSERT INTO supported_operations (name, description)
|
INSERT INTO supported_operations (name, description)
|
||||||
VALUES ('SportBook', 'Sportbook operations'),
|
VALUES ('SportBook', 'Sportbook operations'),
|
||||||
('Virtual', 'Virtual operations'),
|
('Virtual', 'Virtual operations');
|
||||||
('GameZone', 'GameZone operations');
|
|
||||||
INSERT INTO wallets (
|
INSERT INTO wallets (
|
||||||
balance,
|
balance,
|
||||||
is_withdraw,
|
is_withdraw,
|
||||||
|
|
@ -434,3 +438,53 @@ VALUES (
|
||||||
CURRENT_TIMESTAMP,
|
CURRENT_TIMESTAMP,
|
||||||
CURRENT_TIMESTAMP
|
CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
INSERT INTO companies (
|
||||||
|
name,
|
||||||
|
admin_id,
|
||||||
|
wallet_id
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
'Test Company',
|
||||||
|
2,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
INSERT INTO wallets (
|
||||||
|
balance,
|
||||||
|
is_withdraw,
|
||||||
|
is_bettable,
|
||||||
|
is_transferable,
|
||||||
|
user_id,
|
||||||
|
is_active,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
10000,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
2,
|
||||||
|
TRUE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
INSERT INTO branches (
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
wallet_id,
|
||||||
|
branch_manager_id,
|
||||||
|
company_id,
|
||||||
|
is_self_owned,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
'Test Branch',
|
||||||
|
'Addis Ababa',
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
TRUE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
@ -8,14 +8,14 @@ VALUES ($1, $2, $3)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
-- name: GetAllCompanies :many
|
-- name: GetAllCompanies :many
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM companies_with_wallets;
|
FROM companies_details;
|
||||||
-- name: GetCompanyByID :one
|
-- name: GetCompanyByID :one
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM companies_with_wallets
|
FROM companies_details
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
-- name: SearchCompanyByName :many
|
-- name: SearchCompanyByName :many
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM companies_with_wallets
|
FROM companies_details
|
||||||
WHERE name ILIKE '%' || $1 || '%';
|
WHERE name ILIKE '%' || $1 || '%';
|
||||||
-- name: UpdateCompany :one
|
-- name: UpdateCompany :one
|
||||||
UPDATE companies
|
UPDATE companies
|
||||||
|
|
|
||||||
226
docs/docs.go
226
docs/docs.go
|
|
@ -805,6 +805,53 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/branch/{id}/cashier": {
|
||||||
|
"get": {
|
||||||
|
"description": "Gets branch cashiers",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"branch"
|
||||||
|
],
|
||||||
|
"summary": "Gets branch cashiers",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Branch ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/handlers.GetCashierRes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/branch/{id}/operation": {
|
"/branch/{id}/operation": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Gets branch operations",
|
"description": "Gets branch operations",
|
||||||
|
|
@ -2756,6 +2803,50 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/delete/{id}": {
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete a user by their ID",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Delete user by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user/profile": {
|
"/user/profile": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -3052,7 +3143,7 @@ const docTemplate = `{
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/response.APIResponse"
|
"$ref": "#/definitions/handlers.UserProfileRes"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
|
|
@ -3076,6 +3167,52 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/suspend": {
|
||||||
|
"post": {
|
||||||
|
"description": "Suspend or unsuspend a user",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Suspend or unsuspend a user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Suspend or unsuspend a user",
|
||||||
|
"name": "updateUserSuspend",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.UpdateUserSuspendReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.UpdateUserSuspendRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user/wallet": {
|
"/user/wallet": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -3601,9 +3738,11 @@ const docTemplate = `{
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4
|
4,
|
||||||
|
5
|
||||||
],
|
],
|
||||||
"x-enum-comments": {
|
"x-enum-comments": {
|
||||||
|
"OUTCOME_STATUS_ERROR": "Half Win and Half Given Back",
|
||||||
"OUTCOME_STATUS_HALF": "Half Win and Half Given Back",
|
"OUTCOME_STATUS_HALF": "Half Win and Half Given Back",
|
||||||
"OUTCOME_STATUS_VOID": "Give Back"
|
"OUTCOME_STATUS_VOID": "Give Back"
|
||||||
},
|
},
|
||||||
|
|
@ -3612,7 +3751,8 @@ const docTemplate = `{
|
||||||
"OUTCOME_STATUS_WIN",
|
"OUTCOME_STATUS_WIN",
|
||||||
"OUTCOME_STATUS_LOSS",
|
"OUTCOME_STATUS_LOSS",
|
||||||
"OUTCOME_STATUS_VOID",
|
"OUTCOME_STATUS_VOID",
|
||||||
"OUTCOME_STATUS_HALF"
|
"OUTCOME_STATUS_HALF",
|
||||||
|
"OUTCOME_STATUS_ERROR"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"domain.PaymentOption": {
|
"domain.PaymentOption": {
|
||||||
|
|
@ -3660,10 +3800,18 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"domain.RandomBetReq": {
|
"domain.RandomBetReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"branch_id",
|
||||||
|
"number_of_bets"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"branch_id": {
|
"branch_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
|
},
|
||||||
|
"number_of_bets": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4383,6 +4531,50 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.GetCashierRes": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"created_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email_verified": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"last_login": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone_verified": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"$ref": "#/definitions/domain.Role"
|
||||||
|
},
|
||||||
|
"suspended": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"suspended_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.ManagersRes": {
|
"handlers.ManagersRes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -4733,6 +4925,34 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.UpdateUserSuspendReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"suspended",
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"suspended": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handlers.UpdateUserSuspendRes": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"suspended": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.UpdateWalletActiveReq": {
|
"handlers.UpdateWalletActiveReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -797,6 +797,53 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/branch/{id}/cashier": {
|
||||||
|
"get": {
|
||||||
|
"description": "Gets branch cashiers",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"branch"
|
||||||
|
],
|
||||||
|
"summary": "Gets branch cashiers",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Branch ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/handlers.GetCashierRes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/branch/{id}/operation": {
|
"/branch/{id}/operation": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Gets branch operations",
|
"description": "Gets branch operations",
|
||||||
|
|
@ -2748,6 +2795,50 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/delete/{id}": {
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete a user by their ID",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Delete user by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user/profile": {
|
"/user/profile": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -3044,7 +3135,7 @@
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/response.APIResponse"
|
"$ref": "#/definitions/handlers.UserProfileRes"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
|
|
@ -3068,6 +3159,52 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/suspend": {
|
||||||
|
"post": {
|
||||||
|
"description": "Suspend or unsuspend a user",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Suspend or unsuspend a user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Suspend or unsuspend a user",
|
||||||
|
"name": "updateUserSuspend",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.UpdateUserSuspendReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.UpdateUserSuspendRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user/wallet": {
|
"/user/wallet": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -3593,9 +3730,11 @@
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4
|
4,
|
||||||
|
5
|
||||||
],
|
],
|
||||||
"x-enum-comments": {
|
"x-enum-comments": {
|
||||||
|
"OUTCOME_STATUS_ERROR": "Half Win and Half Given Back",
|
||||||
"OUTCOME_STATUS_HALF": "Half Win and Half Given Back",
|
"OUTCOME_STATUS_HALF": "Half Win and Half Given Back",
|
||||||
"OUTCOME_STATUS_VOID": "Give Back"
|
"OUTCOME_STATUS_VOID": "Give Back"
|
||||||
},
|
},
|
||||||
|
|
@ -3604,7 +3743,8 @@
|
||||||
"OUTCOME_STATUS_WIN",
|
"OUTCOME_STATUS_WIN",
|
||||||
"OUTCOME_STATUS_LOSS",
|
"OUTCOME_STATUS_LOSS",
|
||||||
"OUTCOME_STATUS_VOID",
|
"OUTCOME_STATUS_VOID",
|
||||||
"OUTCOME_STATUS_HALF"
|
"OUTCOME_STATUS_HALF",
|
||||||
|
"OUTCOME_STATUS_ERROR"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"domain.PaymentOption": {
|
"domain.PaymentOption": {
|
||||||
|
|
@ -3652,10 +3792,18 @@
|
||||||
},
|
},
|
||||||
"domain.RandomBetReq": {
|
"domain.RandomBetReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"branch_id",
|
||||||
|
"number_of_bets"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"branch_id": {
|
"branch_id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
|
},
|
||||||
|
"number_of_bets": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4375,6 +4523,50 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.GetCashierRes": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"created_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email_verified": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"last_login": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone_number": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone_verified": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"$ref": "#/definitions/domain.Role"
|
||||||
|
},
|
||||||
|
"suspended": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"suspended_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.ManagersRes": {
|
"handlers.ManagersRes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -4725,6 +4917,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.UpdateUserSuspendReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"suspended",
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"suspended": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handlers.UpdateUserSuspendRes": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"suspended": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.UpdateWalletActiveReq": {
|
"handlers.UpdateWalletActiveReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -165,8 +165,10 @@ definitions:
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
- 4
|
- 4
|
||||||
|
- 5
|
||||||
type: integer
|
type: integer
|
||||||
x-enum-comments:
|
x-enum-comments:
|
||||||
|
OUTCOME_STATUS_ERROR: Half Win and Half Given Back
|
||||||
OUTCOME_STATUS_HALF: Half Win and Half Given Back
|
OUTCOME_STATUS_HALF: Half Win and Half Given Back
|
||||||
OUTCOME_STATUS_VOID: Give Back
|
OUTCOME_STATUS_VOID: Give Back
|
||||||
x-enum-varnames:
|
x-enum-varnames:
|
||||||
|
|
@ -175,6 +177,7 @@ definitions:
|
||||||
- OUTCOME_STATUS_LOSS
|
- OUTCOME_STATUS_LOSS
|
||||||
- OUTCOME_STATUS_VOID
|
- OUTCOME_STATUS_VOID
|
||||||
- OUTCOME_STATUS_HALF
|
- OUTCOME_STATUS_HALF
|
||||||
|
- OUTCOME_STATUS_ERROR
|
||||||
domain.PaymentOption:
|
domain.PaymentOption:
|
||||||
enum:
|
enum:
|
||||||
- 0
|
- 0
|
||||||
|
|
@ -211,6 +214,12 @@ definitions:
|
||||||
branch_id:
|
branch_id:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
|
number_of_bets:
|
||||||
|
example: 1
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- branch_id
|
||||||
|
- number_of_bets
|
||||||
type: object
|
type: object
|
||||||
domain.RawOddsByMarketID:
|
domain.RawOddsByMarketID:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -718,6 +727,35 @@ definitions:
|
||||||
static_updated_at:
|
static_updated_at:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
handlers.GetCashierRes:
|
||||||
|
properties:
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
email_verified:
|
||||||
|
type: boolean
|
||||||
|
first_name:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
last_login:
|
||||||
|
type: string
|
||||||
|
last_name:
|
||||||
|
type: string
|
||||||
|
phone_number:
|
||||||
|
type: string
|
||||||
|
phone_verified:
|
||||||
|
type: boolean
|
||||||
|
role:
|
||||||
|
$ref: '#/definitions/domain.Role'
|
||||||
|
suspended:
|
||||||
|
type: boolean
|
||||||
|
suspended_at:
|
||||||
|
type: string
|
||||||
|
updated_at:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
handlers.ManagersRes:
|
handlers.ManagersRes:
|
||||||
properties:
|
properties:
|
||||||
created_at:
|
created_at:
|
||||||
|
|
@ -963,6 +1001,25 @@ definitions:
|
||||||
example: true
|
example: true
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
|
handlers.UpdateUserSuspendReq:
|
||||||
|
properties:
|
||||||
|
suspended:
|
||||||
|
example: true
|
||||||
|
type: boolean
|
||||||
|
user_id:
|
||||||
|
example: 123
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- suspended
|
||||||
|
- user_id
|
||||||
|
type: object
|
||||||
|
handlers.UpdateUserSuspendRes:
|
||||||
|
properties:
|
||||||
|
suspended:
|
||||||
|
type: boolean
|
||||||
|
user_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
handlers.UpdateWalletActiveReq:
|
handlers.UpdateWalletActiveReq:
|
||||||
properties:
|
properties:
|
||||||
is_active:
|
is_active:
|
||||||
|
|
@ -1658,6 +1715,37 @@ paths:
|
||||||
summary: Gets bets by its branch id
|
summary: Gets bets by its branch id
|
||||||
tags:
|
tags:
|
||||||
- branch
|
- branch
|
||||||
|
/branch/{id}/cashier:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Gets branch cashiers
|
||||||
|
parameters:
|
||||||
|
- description: Branch ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/handlers.GetCashierRes'
|
||||||
|
type: array
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Gets branch cashiers
|
||||||
|
tags:
|
||||||
|
- branch
|
||||||
/branch/{id}/operation:
|
/branch/{id}/operation:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -2940,6 +3028,35 @@ paths:
|
||||||
summary: Check if phone number or email exist
|
summary: Check if phone number or email exist
|
||||||
tags:
|
tags:
|
||||||
- user
|
- user
|
||||||
|
/user/delete/{id}:
|
||||||
|
delete:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Delete a user by their ID
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Delete user by ID
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
/user/profile:
|
/user/profile:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -3132,7 +3249,7 @@ paths:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.APIResponse'
|
$ref: '#/definitions/handlers.UserProfileRes'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -3148,6 +3265,36 @@ paths:
|
||||||
summary: Get user by id
|
summary: Get user by id
|
||||||
tags:
|
tags:
|
||||||
- user
|
- user
|
||||||
|
/user/suspend:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Suspend or unsuspend a user
|
||||||
|
parameters:
|
||||||
|
- description: Suspend or unsuspend a user
|
||||||
|
in: body
|
||||||
|
name: updateUserSuspend
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handlers.UpdateUserSuspendReq'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handlers.UpdateUserSuspendRes'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Suspend or unsuspend a user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
/user/wallet:
|
/user/wallet:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
|
|
@ -50,19 +50,19 @@ func (q *Queries) DeleteCompany(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllCompanies = `-- name: GetAllCompanies :many
|
const GetAllCompanies = `-- name: GetAllCompanies :many
|
||||||
SELECT id, name, admin_id, wallet_id, balance, is_active
|
SELECT id, name, admin_id, wallet_id, balance, is_active, admin_first_name, admin_last_name, admin_phone_number
|
||||||
FROM companies_with_wallets
|
FROM companies_details
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllCompanies(ctx context.Context) ([]CompaniesWithWallet, error) {
|
func (q *Queries) GetAllCompanies(ctx context.Context) ([]CompaniesDetail, error) {
|
||||||
rows, err := q.db.Query(ctx, GetAllCompanies)
|
rows, err := q.db.Query(ctx, GetAllCompanies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []CompaniesWithWallet
|
var items []CompaniesDetail
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i CompaniesWithWallet
|
var i CompaniesDetail
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
|
@ -70,6 +70,9 @@ func (q *Queries) GetAllCompanies(ctx context.Context) ([]CompaniesWithWallet, e
|
||||||
&i.WalletID,
|
&i.WalletID,
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
|
&i.AdminFirstName,
|
||||||
|
&i.AdminLastName,
|
||||||
|
&i.AdminPhoneNumber,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -82,14 +85,14 @@ func (q *Queries) GetAllCompanies(ctx context.Context) ([]CompaniesWithWallet, e
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetCompanyByID = `-- name: GetCompanyByID :one
|
const GetCompanyByID = `-- name: GetCompanyByID :one
|
||||||
SELECT id, name, admin_id, wallet_id, balance, is_active
|
SELECT id, name, admin_id, wallet_id, balance, is_active, admin_first_name, admin_last_name, admin_phone_number
|
||||||
FROM companies_with_wallets
|
FROM companies_details
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesWithWallet, error) {
|
func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail, error) {
|
||||||
row := q.db.QueryRow(ctx, GetCompanyByID, id)
|
row := q.db.QueryRow(ctx, GetCompanyByID, id)
|
||||||
var i CompaniesWithWallet
|
var i CompaniesDetail
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
|
@ -97,25 +100,28 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesWithWa
|
||||||
&i.WalletID,
|
&i.WalletID,
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
|
&i.AdminFirstName,
|
||||||
|
&i.AdminLastName,
|
||||||
|
&i.AdminPhoneNumber,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchCompanyByName = `-- name: SearchCompanyByName :many
|
const SearchCompanyByName = `-- name: SearchCompanyByName :many
|
||||||
SELECT id, name, admin_id, wallet_id, balance, is_active
|
SELECT id, name, admin_id, wallet_id, balance, is_active, admin_first_name, admin_last_name, admin_phone_number
|
||||||
FROM companies_with_wallets
|
FROM companies_details
|
||||||
WHERE name ILIKE '%' || $1 || '%'
|
WHERE name ILIKE '%' || $1 || '%'
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text) ([]CompaniesWithWallet, error) {
|
func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text) ([]CompaniesDetail, error) {
|
||||||
rows, err := q.db.Query(ctx, SearchCompanyByName, dollar_1)
|
rows, err := q.db.Query(ctx, SearchCompanyByName, dollar_1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []CompaniesWithWallet
|
var items []CompaniesDetail
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i CompaniesWithWallet
|
var i CompaniesDetail
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
|
@ -123,6 +129,9 @@ func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text)
|
||||||
&i.WalletID,
|
&i.WalletID,
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
|
&i.AdminFirstName,
|
||||||
|
&i.AdminLastName,
|
||||||
|
&i.AdminPhoneNumber,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,13 +146,16 @@ type BranchOperation struct {
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompaniesWithWallet struct {
|
type CompaniesDetail struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
AdminID int64 `json:"admin_id"`
|
AdminID int64 `json:"admin_id"`
|
||||||
WalletID int64 `json:"wallet_id"`
|
WalletID int64 `json:"wallet_id"`
|
||||||
Balance int64 `json:"balance"`
|
Balance int64 `json:"balance"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
AdminFirstName string `json:"admin_first_name"`
|
||||||
|
AdminLastName string `json:"admin_last_name"`
|
||||||
|
AdminPhoneNumber pgtype.Text `json:"admin_phone_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Company struct {
|
type Company struct {
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ type CreateBetReq struct {
|
||||||
|
|
||||||
type RandomBetReq struct {
|
type RandomBetReq struct {
|
||||||
BranchID int64 `json:"branch_id" validate:"required" example:"1"`
|
BranchID int64 `json:"branch_id" validate:"required" example:"1"`
|
||||||
|
NumberOfBets int64 `json:"number_of_bets" validate:"required" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateBetRes struct {
|
type CreateBetRes struct {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ type GetCompany struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string
|
Name string
|
||||||
AdminID int64
|
AdminID int64
|
||||||
|
AdminFirstName string
|
||||||
|
AdminLastName string
|
||||||
|
AdminPhoneNumber string
|
||||||
WalletID int64
|
WalletID int64
|
||||||
WalletBalance Currency
|
WalletBalance Currency
|
||||||
IsWalletActive bool
|
IsWalletActive bool
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,14 @@ var SupportedLeagues = []int64{
|
||||||
// Basketball
|
// Basketball
|
||||||
173998768, //NBA
|
173998768, //NBA
|
||||||
10041830, //NBA
|
10041830, //NBA
|
||||||
|
10049984, //WNBA
|
||||||
|
10037165, //German Bundesliga
|
||||||
|
10036608, //Italian Lega 1
|
||||||
|
10040795, //EuroLeague
|
||||||
|
|
||||||
// Ice Hockey
|
// Ice Hockey
|
||||||
10037477, //NHL
|
10037477, //NHL
|
||||||
10037447, //AHL
|
10037447, //AHL
|
||||||
10069385, //IIHF World Championship
|
10069385, //IIHF World Championship
|
||||||
10040795, //EuroLeague
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,3 +64,21 @@ func (o *OutcomeStatus) String() string {
|
||||||
return "UNKNOWN"
|
return "UNKNOWN"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TimeStatus int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
TIME_STATUS_NOT_STARTED TimeStatus = 0
|
||||||
|
TIME_STATUS_IN_PLAY TimeStatus = 1
|
||||||
|
TIME_STATUS_TO_BE_FIXED TimeStatus = 2
|
||||||
|
TIME_STATUS_ENDED TimeStatus = 3
|
||||||
|
TIME_STATUS_POSTPONED TimeStatus = 4
|
||||||
|
TIME_STATUS_CANCELLED TimeStatus = 5
|
||||||
|
TIME_STATUS_WALKOVER TimeStatus = 6
|
||||||
|
TIME_STATUS_INTERRUPTED TimeStatus = 7
|
||||||
|
TIME_STATUS_ABANDONED TimeStatus = 8
|
||||||
|
TIME_STATUS_RETIRED TimeStatus = 9
|
||||||
|
TIME_STATUS_SUSPENDED TimeStatus = 10
|
||||||
|
TIME_STATUS_DECIDED_BY_FA TimeStatus = 11
|
||||||
|
TIME_STATUS_REMOVED TimeStatus = 99
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ type FootballResultResponse struct {
|
||||||
Stats struct {
|
Stats struct {
|
||||||
Attacks []string `json:"attacks"`
|
Attacks []string `json:"attacks"`
|
||||||
Corners []string `json:"corners"`
|
Corners []string `json:"corners"`
|
||||||
|
HalfTimeCorners []string `json:"corner_h"`
|
||||||
DangerousAttacks []string `json:"dangerous_attacks"`
|
DangerousAttacks []string `json:"dangerous_attacks"`
|
||||||
Goals []string `json:"goals"`
|
Goals []string `json:"goals"`
|
||||||
OffTarget []string `json:"off_target"`
|
OffTarget []string `json:"off_target"`
|
||||||
|
|
@ -94,7 +95,7 @@ type BasketballResultResponse struct {
|
||||||
Possession []string `json:"possession"`
|
Possession []string `json:"possession"`
|
||||||
SuccessAttempts []string `json:"success_attempts"`
|
SuccessAttempts []string `json:"success_attempts"`
|
||||||
TimeSpendInLead []string `json:"timespent_inlead"`
|
TimeSpendInLead []string `json:"timespent_inlead"`
|
||||||
Timeuts []string `json:"time_outs"`
|
TimeOuts []string `json:"time_outs"`
|
||||||
} `json:"stats"`
|
} `json:"stats"`
|
||||||
Extra struct {
|
Extra struct {
|
||||||
HomePos string `json:"home_pos"`
|
HomePos string `json:"home_pos"`
|
||||||
|
|
@ -104,7 +105,7 @@ type BasketballResultResponse struct {
|
||||||
NumberOfPeriods string `json:"numberofperiods"`
|
NumberOfPeriods string `json:"numberofperiods"`
|
||||||
PeriodLength string `json:"periodlength"`
|
PeriodLength string `json:"periodlength"`
|
||||||
StadiumData map[string]string `json:"stadium_data"`
|
StadiumData map[string]string `json:"stadium_data"`
|
||||||
Length string `json:"length"`
|
Length int `json:"length"`
|
||||||
Round string `json:"round"`
|
Round string `json:"round"`
|
||||||
} `json:"extra"`
|
} `json:"extra"`
|
||||||
Events []map[string]string `json:"events"`
|
Events []map[string]string `json:"events"`
|
||||||
|
|
@ -142,7 +143,7 @@ type IceHockeyResultResponse struct {
|
||||||
NumberOfPeriods string `json:"numberofperiods"`
|
NumberOfPeriods string `json:"numberofperiods"`
|
||||||
PeriodLength string `json:"periodlength"`
|
PeriodLength string `json:"periodlength"`
|
||||||
StadiumData map[string]string `json:"stadium_data"`
|
StadiumData map[string]string `json:"stadium_data"`
|
||||||
Length string `json:"length"`
|
Length int `json:"length"`
|
||||||
Round string `json:"round"`
|
Round string `json:"round"`
|
||||||
} `json:"extra"`
|
} `json:"extra"`
|
||||||
Events []map[string]string `json:"events"`
|
Events []map[string]string `json:"events"`
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,13 @@ const (
|
||||||
FOOTBALL_GOALS_ODD_EVEN FootballMarket = 10111 //"goals_odd_even"
|
FOOTBALL_GOALS_ODD_EVEN FootballMarket = 10111 //"goals_odd_even"
|
||||||
FOOTBALL_DRAW_NO_BET FootballMarket = 10544 //"draw_no_bet"
|
FOOTBALL_DRAW_NO_BET FootballMarket = 10544 //"draw_no_bet"
|
||||||
|
|
||||||
|
FOOTBALL_CORNERS FootballMarket = 760 //"corners"
|
||||||
|
FOOTBALL_CORNERS_TWO_WAY FootballMarket = 10235 //"corners_2_way"
|
||||||
|
FOOTBALL_FIRST_HALF_CORNERS FootballMarket = 10539 //"first_half_corners"
|
||||||
|
FOOTBALL_ASIAN_TOTAL_CORNERS FootballMarket = 10164 //"asian_total_corners"
|
||||||
|
FOOTBALL_FIRST_HALF_ASIAN_CORNERS FootballMarket = 10233 //"1st_half_asian_corners"
|
||||||
|
FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN FootballMarket = 10206 //"1st_half_goals_odd_even"
|
||||||
|
FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN FootballMarket = 50433 //"2nd_half_goals_odd_even"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -111,6 +118,13 @@ var SupportedMarkets = map[int64]bool{
|
||||||
int64(FOOTBALL_FIRST_TEAM_TO_SCORE): true, //"first_team_to_score"
|
int64(FOOTBALL_FIRST_TEAM_TO_SCORE): true, //"first_team_to_score"
|
||||||
int64(FOOTBALL_GOALS_ODD_EVEN): true, //"goals_odd_even"
|
int64(FOOTBALL_GOALS_ODD_EVEN): true, //"goals_odd_even"
|
||||||
int64(FOOTBALL_DRAW_NO_BET): true, //"draw_no_bet"
|
int64(FOOTBALL_DRAW_NO_BET): true, //"draw_no_bet"
|
||||||
|
int64(FOOTBALL_CORNERS): true,
|
||||||
|
int64(FOOTBALL_CORNERS_TWO_WAY): true,
|
||||||
|
int64(FOOTBALL_FIRST_HALF_CORNERS): true,
|
||||||
|
int64(FOOTBALL_ASIAN_TOTAL_CORNERS): true,
|
||||||
|
int64(FOOTBALL_FIRST_HALF_ASIAN_CORNERS): true,
|
||||||
|
int64(FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN): true,
|
||||||
|
int64(FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN): true,
|
||||||
|
|
||||||
// Basketball Markets
|
// Basketball Markets
|
||||||
int64(BASKETBALL_GAME_LINES): true,
|
int64(BASKETBALL_GAME_LINES): true,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ func convertDBCompany(dbCompany dbgen.Company) domain.Company {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertDBCompanyWithWallet(dbCompany dbgen.CompaniesWithWallet) domain.GetCompany {
|
func convertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) domain.GetCompany {
|
||||||
return domain.GetCompany{
|
return domain.GetCompany{
|
||||||
ID: dbCompany.ID,
|
ID: dbCompany.ID,
|
||||||
Name: dbCompany.Name,
|
Name: dbCompany.Name,
|
||||||
|
|
@ -33,6 +33,9 @@ func convertDBCompanyWithWallet(dbCompany dbgen.CompaniesWithWallet) domain.GetC
|
||||||
WalletID: dbCompany.WalletID,
|
WalletID: dbCompany.WalletID,
|
||||||
WalletBalance: domain.Currency(dbCompany.Balance),
|
WalletBalance: domain.Currency(dbCompany.Balance),
|
||||||
IsWalletActive: dbCompany.IsActive,
|
IsWalletActive: dbCompany.IsActive,
|
||||||
|
AdminFirstName: dbCompany.AdminFirstName,
|
||||||
|
AdminLastName: dbCompany.AdminLastName,
|
||||||
|
AdminPhoneNumber: dbCompany.AdminPhoneNumber.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,7 +77,7 @@ func (s *Store) GetAllCompanies(ctx context.Context) ([]domain.GetCompany, error
|
||||||
|
|
||||||
var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies))
|
var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies))
|
||||||
for _, dbCompany := range dbCompanies {
|
for _, dbCompany := range dbCompanies {
|
||||||
companies = append(companies, convertDBCompanyWithWallet(dbCompany))
|
companies = append(companies, convertDBCompanyDetails(dbCompany))
|
||||||
}
|
}
|
||||||
|
|
||||||
return companies, nil
|
return companies, nil
|
||||||
|
|
@ -92,7 +95,7 @@ func (s *Store) SearchCompanyByName(ctx context.Context, name string) ([]domain.
|
||||||
var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies))
|
var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies))
|
||||||
|
|
||||||
for _, dbCompany := range dbCompanies {
|
for _, dbCompany := range dbCompanies {
|
||||||
companies = append(companies, convertDBCompanyWithWallet(dbCompany))
|
companies = append(companies, convertDBCompanyDetails(dbCompany))
|
||||||
}
|
}
|
||||||
return companies, nil
|
return companies, nil
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +106,7 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.GetCompany{}, err
|
return domain.GetCompany{}, err
|
||||||
}
|
}
|
||||||
return convertDBCompanyWithWallet(dbCompany), nil
|
return convertDBCompanyDetails(dbCompany), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
|
func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,22 @@ func (s *Store) UpdateUserCompany(ctx context.Context, id int64, companyID int64
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateUserSuspend(ctx context.Context, id int64, status bool) error {
|
||||||
|
err := s.queries.SuspendUser(ctx, dbgen.SuspendUserParams{
|
||||||
|
ID: id,
|
||||||
|
Suspended: status,
|
||||||
|
SuspendedAt: pgtype.Timestamptz{
|
||||||
|
Time: time.Now(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) DeleteUser(ctx context.Context, id int64) error {
|
func (s *Store) DeleteUser(ctx context.Context, id int64) error {
|
||||||
err := s.queries.DeleteUser(ctx, id)
|
err := s.queries.DeleteUser(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -362,7 +362,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
|
|
||||||
// TODO: Add the option of passing number of created events
|
// TODO: Add the option of passing number of created events
|
||||||
var selectedUpcomingEvents []domain.UpcomingEvent
|
var selectedUpcomingEvents []domain.UpcomingEvent
|
||||||
numEventsPerBet := random.Intn(4) + 1 //Eliminate the option of 0
|
numEventsPerBet := min(random.Intn(4)+1, len(events)) //Eliminate the option of 0
|
||||||
|
|
||||||
for i := 0; i < int(numEventsPerBet); i++ {
|
for i := 0; i < int(numEventsPerBet); i++ {
|
||||||
randomIndex := random.Intn(len(events))
|
randomIndex := random.Intn(len(events))
|
||||||
|
|
@ -371,7 +371,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Info("Generating random bet events", "selectedUpcomingEvents", len(selectedUpcomingEvents))
|
// s.logger.Info("Generating random bet events", "selectedUpcomingEvents", len(selectedUpcomingEvents))
|
||||||
|
|
||||||
// Get market and odds for that
|
// Get market and odds for that
|
||||||
var randomOdds []domain.CreateBetOutcome
|
var randomOdds []domain.CreateBetOutcome
|
||||||
|
|
@ -395,7 +395,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le
|
||||||
return domain.CreateBetRes{}, ErrGenerateRandomOutcome
|
return domain.CreateBetRes{}, ErrGenerateRandomOutcome
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Info("Generated Random bet Outcome", "randomOdds", len(randomOdds))
|
// s.logger.Info("Generated Random bet Outcome", "randomOdds", len(randomOdds))
|
||||||
|
|
||||||
var cashoutID string
|
var cashoutID string
|
||||||
|
|
||||||
|
|
@ -491,9 +491,9 @@ func (s *Service) CheckBetOutcomeForBet(ctx context.Context, betID int64) (domai
|
||||||
status = betOutcome.Status
|
status = betOutcome.Status
|
||||||
case domain.OUTCOME_STATUS_WIN:
|
case domain.OUTCOME_STATUS_WIN:
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
||||||
status = domain.OUTCOME_STATUS_HALF
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
} else if betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
||||||
status = domain.OUTCOME_STATUS_VOID
|
status = domain.OUTCOME_STATUS_HALF
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
} else if betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
||||||
status = domain.OUTCOME_STATUS_WIN
|
status = domain.OUTCOME_STATUS_WIN
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
||||||
|
|
@ -509,16 +509,18 @@ func (s *Service) CheckBetOutcomeForBet(ctx context.Context, betID int64) (domai
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
} else if betOutcome.Status == domain.OUTCOME_STATUS_WIN {
|
||||||
status = domain.OUTCOME_STATUS_LOSS
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
} else if betOutcome.Status == domain.OUTCOME_STATUS_VOID {
|
||||||
status = domain.OUTCOME_STATUS_VOID
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
} else {
|
} else {
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
status = domain.OUTCOME_STATUS_ERROR
|
||||||
}
|
}
|
||||||
case domain.OUTCOME_STATUS_VOID:
|
case domain.OUTCOME_STATUS_VOID:
|
||||||
if betOutcome.Status == domain.OUTCOME_STATUS_VOID ||
|
if betOutcome.Status == domain.OUTCOME_STATUS_VOID ||
|
||||||
betOutcome.Status == domain.OUTCOME_STATUS_WIN ||
|
betOutcome.Status == domain.OUTCOME_STATUS_WIN ||
|
||||||
betOutcome.Status == domain.OUTCOME_STATUS_LOSS ||
|
|
||||||
betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
betOutcome.Status == domain.OUTCOME_STATUS_HALF {
|
||||||
status = domain.OUTCOME_STATUS_VOID
|
status = domain.OUTCOME_STATUS_VOID
|
||||||
|
} else if betOutcome.Status == domain.OUTCOME_STATUS_LOSS {
|
||||||
|
status = domain.OUTCOME_STATUS_LOSS
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
status = domain.OUTCOME_STATUS_ERROR
|
status = domain.OUTCOME_STATUS_ERROR
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
||||||
|
|
||||||
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
// sportIDs := []int{1, 18, 17}
|
// sportIDs := []int{1, 18, 17}
|
||||||
sportIDs := []int{18}
|
sportIDs := []int{18, 17}
|
||||||
|
|
||||||
for _, sportID := range sportIDs {
|
for _, sportID := range sportIDs {
|
||||||
var totalPages int = 1
|
var totalPages int = 1
|
||||||
|
|
@ -142,6 +142,7 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
} `json:"away"`
|
} `json:"away"`
|
||||||
|
|
||||||
} `json:"results"`
|
} `json:"results"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||||
|
|
@ -164,7 +165,7 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slices.Contains(domain.SupportedLeagues, leagueID) {
|
if !slices.Contains(domain.SupportedLeagues, leagueID) {
|
||||||
|
fmt.Printf("⚠️ Skipping league %s (%d) as it is not supported\n", ev.League.Name, leagueID)
|
||||||
skippedLeague = append(skippedLeague, ev.League.Name)
|
skippedLeague = append(skippedLeague, ev.League.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +173,7 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
event := domain.UpcomingEvent{
|
event := domain.UpcomingEvent{
|
||||||
ID: ev.ID,
|
ID: ev.ID,
|
||||||
SportID: ev.SportID,
|
SportID: ev.SportID,
|
||||||
MatchName: ev.Home.Name,
|
MatchName: "",
|
||||||
HomeTeam: ev.Home.Name,
|
HomeTeam: ev.Home.Name,
|
||||||
AwayTeam: "", // handle nil safely
|
AwayTeam: "", // handle nil safely
|
||||||
HomeTeamID: ev.Home.ID,
|
HomeTeamID: ev.Home.ID,
|
||||||
|
|
@ -188,6 +189,7 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
if ev.Away != nil {
|
if ev.Away != nil {
|
||||||
event.AwayTeam = ev.Away.Name
|
event.AwayTeam = ev.Away.Name
|
||||||
event.AwayTeamID = ev.Away.ID
|
event.AwayTeamID = ev.Away.ID
|
||||||
|
event.MatchName = ev.Home.Name + " vs " + ev.Away.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.store.SaveUpcomingEvent(ctx, event)
|
err = s.store.SaveUpcomingEvent(ctx, event)
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
||||||
var marketIDint 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")
|
s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,8 @@ func checkMultiOutcome(outcome domain.OutcomeStatus, secondOutcome domain.Outcom
|
||||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("❌ mutli outcome: %v -> %v \n", outcome.String(), secondOutcome.String())
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("❌ mutli outcome: %v -> %v \n", outcome.String(), secondOutcome.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("| Multi Outcome | %v -> %v \n", outcome.String(), secondOutcome.String())
|
||||||
|
|
||||||
switch outcome {
|
switch outcome {
|
||||||
case domain.OUTCOME_STATUS_PENDING:
|
case domain.OUTCOME_STATUS_PENDING:
|
||||||
return secondOutcome, nil
|
return secondOutcome, nil
|
||||||
|
|
@ -94,7 +96,7 @@ func checkMultiOutcome(outcome domain.OutcomeStatus, secondOutcome domain.Outcom
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_LOSS {
|
} else if secondOutcome == domain.OUTCOME_STATUS_LOSS {
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_HALF {
|
} else if secondOutcome == domain.OUTCOME_STATUS_HALF {
|
||||||
return domain.OUTCOME_STATUS_HALF, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_VOID {
|
} else if secondOutcome == domain.OUTCOME_STATUS_VOID {
|
||||||
return domain.OUTCOME_STATUS_HALF, nil
|
return domain.OUTCOME_STATUS_HALF, nil
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -107,14 +109,14 @@ func checkMultiOutcome(outcome domain.OutcomeStatus, secondOutcome domain.Outcom
|
||||||
secondOutcome == domain.OUTCOME_STATUS_HALF {
|
secondOutcome == domain.OUTCOME_STATUS_HALF {
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_VOID {
|
} else if secondOutcome == domain.OUTCOME_STATUS_VOID {
|
||||||
return domain.OUTCOME_STATUS_HALF, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("❌ multi outcome: %v -> %v \n", outcome.String(), secondOutcome.String())
|
fmt.Printf("❌ multi outcome: %v -> %v \n", outcome.String(), secondOutcome.String())
|
||||||
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid multi outcome")
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid multi outcome")
|
||||||
}
|
}
|
||||||
case domain.OUTCOME_STATUS_VOID:
|
case domain.OUTCOME_STATUS_VOID:
|
||||||
if secondOutcome == domain.OUTCOME_STATUS_WIN || secondOutcome == domain.OUTCOME_STATUS_LOSS {
|
if secondOutcome == domain.OUTCOME_STATUS_WIN || secondOutcome == domain.OUTCOME_STATUS_LOSS {
|
||||||
return domain.OUTCOME_STATUS_HALF, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_VOID || secondOutcome == domain.OUTCOME_STATUS_HALF {
|
} else if secondOutcome == domain.OUTCOME_STATUS_VOID || secondOutcome == domain.OUTCOME_STATUS_HALF {
|
||||||
return domain.OUTCOME_STATUS_VOID, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -123,7 +125,7 @@ func checkMultiOutcome(outcome domain.OutcomeStatus, secondOutcome domain.Outcom
|
||||||
}
|
}
|
||||||
case domain.OUTCOME_STATUS_HALF:
|
case domain.OUTCOME_STATUS_HALF:
|
||||||
if secondOutcome == domain.OUTCOME_STATUS_WIN || secondOutcome == domain.OUTCOME_STATUS_HALF {
|
if secondOutcome == domain.OUTCOME_STATUS_WIN || secondOutcome == domain.OUTCOME_STATUS_HALF {
|
||||||
return domain.OUTCOME_STATUS_HALF, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_LOSS {
|
} else if secondOutcome == domain.OUTCOME_STATUS_LOSS {
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
} else if secondOutcome == domain.OUTCOME_STATUS_VOID {
|
} else if secondOutcome == domain.OUTCOME_STATUS_VOID {
|
||||||
|
|
@ -139,6 +141,8 @@ func checkMultiOutcome(outcome domain.OutcomeStatus, secondOutcome domain.Outcom
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asian Handicap betting is a type of betting that eliminates the possibility of a draw by giving one team a virtual advantage or disadvantage.
|
// Asian Handicap betting is a type of betting that eliminates the possibility of a draw by giving one team a virtual advantage or disadvantage.
|
||||||
|
// When the handicap has two values like "+0.5, +1.0" or "-0.5, -1.0", then it a multi outcome bet
|
||||||
|
// .
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
// "id": "548319135",
|
// "id": "548319135",
|
||||||
|
|
@ -178,27 +182,33 @@ func evaluateAsianHandicap(outcome domain.BetOutcome, score struct{ Home, Away i
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_ERROR, err
|
return domain.OUTCOME_STATUS_ERROR, err
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_ERROR, err
|
return domain.OUTCOME_STATUS_ERROR, err
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
} else if adjustedHomeScore < adjustedAwayScore {
|
} else if adjustedHomeScore < adjustedAwayScore {
|
||||||
if outcome.OddHeader == "2" {
|
if outcome.OddHeader == "2" {
|
||||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_WIN)
|
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_WIN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_ERROR, err
|
return domain.OUTCOME_STATUS_ERROR, err
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_LOSS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_ERROR, err
|
return domain.OUTCOME_STATUS_ERROR, err
|
||||||
}
|
}
|
||||||
}
|
continue
|
||||||
|
} else if adjustedHomeScore == adjustedAwayScore {
|
||||||
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_VOID)
|
newOutcome, err = checkMultiOutcome(newOutcome, domain.OUTCOME_STATUS_VOID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_ERROR, err
|
return domain.OUTCOME_STATUS_ERROR, err
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return newOutcome, nil
|
return newOutcome, nil
|
||||||
}
|
}
|
||||||
|
|
@ -306,24 +316,60 @@ func evaluateGoalsOddEven(outcome domain.BetOutcome, score struct{ Home, Away in
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func evaluateTeamOddEven(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
|
|
||||||
|
switch outcome.OddHeader {
|
||||||
|
case "1":
|
||||||
|
if outcome.OddHandicap == "Odd" {
|
||||||
|
if score.Home%2 == 1 {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
} else if outcome.OddHandicap == "Even" {
|
||||||
|
if score.Home%2 == 0 {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
} else {
|
||||||
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd handicap: %s", outcome.OddHandicap)
|
||||||
|
}
|
||||||
|
case "2":
|
||||||
|
if outcome.OddHandicap == "Odd" {
|
||||||
|
if score.Away%2 == 1 {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
} else if outcome.OddHandicap == "Even" {
|
||||||
|
if score.Away%2 == 0 {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
} else {
|
||||||
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd handicap: %s", outcome.OddHandicap)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Double Chance betting is a type of bet where the bettor predicts two of the three possible outcomes of a match.
|
// Double Chance betting is a type of bet where the bettor predicts two of the three possible outcomes of a match.
|
||||||
func evaluateDoubleChance(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func evaluateDoubleChance(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
isHomeWin := score.Home > score.Away
|
isHomeWin := score.Home > score.Away
|
||||||
isDraw := score.Home == score.Away
|
isDraw := score.Home == score.Away
|
||||||
isAwayWin := score.Away > score.Home
|
isAwayWin := score.Away > score.Home
|
||||||
|
|
||||||
switch outcome.OddName {
|
switch outcome.OddName {
|
||||||
case "1 or Draw", (outcome.HomeTeamName + " or " + "Draw"):
|
case "1 or Draw", (outcome.HomeTeamName + " or " + "Draw"), ("Draw" + " or " + outcome.HomeTeamName):
|
||||||
if isHomeWin || isDraw {
|
if isHomeWin || isDraw {
|
||||||
return domain.OUTCOME_STATUS_WIN, nil
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
}
|
}
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
case "Draw or 2", ("Draw" + " or " + outcome.AwayTeamName):
|
case "Draw or 2", ("Draw" + " or " + outcome.AwayTeamName), (outcome.AwayTeamName + " or " + "Draw"):
|
||||||
if isDraw || isAwayWin {
|
if isDraw || isAwayWin {
|
||||||
return domain.OUTCOME_STATUS_WIN, nil
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
}
|
}
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
case "1 or 2", (outcome.HomeTeamName + " or " + outcome.AwayTeamName):
|
case "1 or 2", (outcome.HomeTeamName + " or " + outcome.AwayTeamName), (outcome.AwayTeamName + " or " + outcome.HomeTeamName):
|
||||||
if isHomeWin || isAwayWin {
|
if isHomeWin || isAwayWin {
|
||||||
return domain.OUTCOME_STATUS_WIN, nil
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
}
|
}
|
||||||
|
|
@ -346,6 +392,34 @@ func evaluateDrawNoBet(outcome domain.BetOutcome, score struct{ Home, Away int }
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func evaluateCorners(outcome domain.BetOutcome, corners struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
|
|
||||||
|
totalCorners := corners.Home + corners.Away
|
||||||
|
threshold, err := strconv.ParseFloat(outcome.OddName, 10)
|
||||||
|
if err != nil {
|
||||||
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid threshold: %s", outcome.OddName)
|
||||||
|
}
|
||||||
|
switch outcome.OddHeader {
|
||||||
|
case "Over":
|
||||||
|
if totalCorners > int(threshold) {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
case "Under":
|
||||||
|
if totalCorners < int(threshold) {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
case "Exactly":
|
||||||
|
if totalCorners == int(threshold) {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
default:
|
||||||
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Basketball evaluations
|
// Basketball evaluations
|
||||||
|
|
||||||
// Game Lines is an aggregate of money line, spread and total betting markets in one
|
// Game Lines is an aggregate of money line, spread and total betting markets in one
|
||||||
|
|
@ -715,6 +789,30 @@ func evaluateHighestScoringQuarter(outcome domain.BetOutcome, firstScore struct{
|
||||||
return domain.OUTCOME_STATUS_LOSS, nil
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Team With Highest Scoring Quarter betting is a type of bet where the bettor predicts which team will have the highest score in a specific quarter.
|
||||||
|
func evaluateTeamWithHighestScoringQuarter(outcome domain.BetOutcome, firstScore struct{ Home, Away int }, secondScore struct{ Home, Away int }, thirdScore struct{ Home, Away int }, fourthScore struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
|
homeTeamHighestQuarter := max(firstScore.Home, secondScore.Home, thirdScore.Home, fourthScore.Home)
|
||||||
|
awayTeamHighestQuarter := max(firstScore.Away, secondScore.Away, thirdScore.Away, fourthScore.Away)
|
||||||
|
|
||||||
|
switch outcome.OddName {
|
||||||
|
case "1":
|
||||||
|
if homeTeamHighestQuarter > awayTeamHighestQuarter {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
case "2":
|
||||||
|
if awayTeamHighestQuarter > homeTeamHighestQuarter {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
case "Tie":
|
||||||
|
if homeTeamHighestQuarter == awayTeamHighestQuarter {
|
||||||
|
return domain.OUTCOME_STATUS_WIN, nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid oddname: %s", outcome.OddName)
|
||||||
|
}
|
||||||
|
return domain.OUTCOME_STATUS_LOSS, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Handicap and Total betting is a combination of spread betting and total points betting
|
// Handicap and Total betting is a combination of spread betting and total points betting
|
||||||
// where the bettor predicts the outcome of a match with a point spread and the total number of points scored is over or under a specified number.
|
// where the bettor predicts the outcome of a match with a point spread and the total number of points scored is over or under a specified number.
|
||||||
func evaluateHandicapAndTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func evaluateHandicapAndTotal(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResultCheck struct {
|
var (
|
||||||
}
|
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
|
||||||
|
|
@ -72,7 +73,7 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
|
|
||||||
if outcome.Expires.After(time.Now()) {
|
if outcome.Expires.After(time.Now()) {
|
||||||
isDeleted = false
|
isDeleted = false
|
||||||
s.logger.Info("Outcome is not expired yet", "event_id", event.ID, "outcome_id", outcome.ID)
|
s.logger.Warn("Outcome is not expired yet", "event_id", event.ID, "outcome_id", outcome.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,6 +86,10 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
// TODO: optimize this because the result is being fetched for each outcome which will have the same event id but different market id
|
// TODO: optimize this because the result is being fetched for each outcome which will have the same event id but different market id
|
||||||
result, err := s.fetchResult(ctx, outcome.EventID, outcome.OddID, outcome.MarketID, sportID, outcome)
|
result, err := s.fetchResult(ctx, outcome.EventID, outcome.OddID, outcome.MarketID, 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",
|
fmt.Printf("❌ failed to parse 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
||||||
outcome.MarketName,
|
outcome.MarketName,
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
||||||
|
|
@ -123,13 +128,14 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("🧾 Updating bet status for event %v (%d/%d) to %v\n", event.ID, j+1, len(outcomes), status.String())
|
fmt.Printf("🧾 Updating bet %v - event %v (%d/%d) to %v\n", outcome.BetID, event.ID, j+1, len(outcomes), status.String())
|
||||||
err = s.betSvc.UpdateStatus(ctx, outcome.BetID, status)
|
err = s.betSvc.UpdateStatus(ctx, outcome.BetID, status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
|
s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("✅ Successfully updated 🎫 Bet for event %v(%v) (%d/%d) \n",
|
fmt.Printf("✅ Successfully updated 🎫 Bet %v - event %v(%v) (%d/%d) \n",
|
||||||
|
outcome.BetID,
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
||||||
j+1, len(outcomes))
|
j+1, len(outcomes))
|
||||||
|
|
||||||
|
|
@ -273,6 +279,34 @@ func (s *Service) fetchResult(ctx context.Context, eventID, oddID, marketID, spo
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) parseTimeStatus(timeStatusStr string) (bool, 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) {
|
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 {
|
||||||
|
|
@ -280,16 +314,24 @@ func (s *Service) parseFootball(resultRes json.RawMessage, eventID, oddID, marke
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
}
|
}
|
||||||
result := fbResp
|
result := fbResp
|
||||||
if result.TimeStatus != "3" {
|
|
||||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
isEventActive, err := s.parseTimeStatus(result.TimeStatus)
|
||||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
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 := parseSS(fmt.Sprintf("%s-%s", 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)
|
||||||
|
|
||||||
corners := parseStats(result.Stats.Corners)
|
corners := parseStats(result.Stats.Corners)
|
||||||
status, err := s.evaluateFootballOutcome(outcome, finalScore, firstHalfScore, corners, result.Events)
|
halfTimeCorners := parseStats(result.Stats.HalfTimeCorners)
|
||||||
|
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", eventID, "market_id", marketID, "error", err)
|
||||||
return domain.CreateResult{}, err
|
return domain.CreateResult{}, err
|
||||||
|
|
@ -309,12 +351,17 @@ func (s *Service) parseFootball(resultRes json.RawMessage, eventID, oddID, marke
|
||||||
func (s *Service) parseBasketball(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
func (s *Service) parseBasketball(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||||
var basketBallRes domain.BasketballResultResponse
|
var basketBallRes domain.BasketballResultResponse
|
||||||
if err := json.Unmarshal(response, &basketBallRes); err != nil {
|
if err := json.Unmarshal(response, &basketBallRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal football 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
|
||||||
}
|
}
|
||||||
if basketBallRes.TimeStatus != "3" {
|
isEventActive, err := s.parseTimeStatus(basketBallRes.TimeStatus)
|
||||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
if err != nil {
|
||||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
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)
|
||||||
|
|
@ -337,12 +384,17 @@ func (s *Service) parseBasketball(response json.RawMessage, eventID, oddID, mark
|
||||||
func (s *Service) parseIceHockey(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
func (s *Service) parseIceHockey(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
|
||||||
var iceHockeyRes domain.IceHockeyResultResponse
|
var iceHockeyRes domain.IceHockeyResultResponse
|
||||||
if err := json.Unmarshal(response, &iceHockeyRes); err != nil {
|
if err := json.Unmarshal(response, &iceHockeyRes); err != nil {
|
||||||
s.logger.Error("Failed to unmarshal football 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
|
||||||
}
|
}
|
||||||
if iceHockeyRes.TimeStatus != "3" {
|
isEventActive, err := s.parseTimeStatus(iceHockeyRes.TimeStatus)
|
||||||
s.logger.Warn("Match not yet completed", "event_id", eventID)
|
if err != nil {
|
||||||
return domain.CreateResult{}, fmt.Errorf("match not yet completed")
|
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)
|
||||||
|
|
@ -388,7 +440,10 @@ func parseStats(stats []string) struct{ Home, Away int } {
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateOutcome determines the outcome status based on market type and odd
|
// evaluateOutcome determines the outcome status based on market type and odd
|
||||||
func (s *Service) evaluateFootballOutcome(outcome domain.BetOutcome, finalScore, firstHalfScore struct{ Home, Away int }, corners struct{ Home, Away int }, events []map[string]string) (domain.OutcomeStatus, error) {
|
func (s *Service) evaluateFootballOutcome(outcome domain.BetOutcome, finalScore,
|
||||||
|
firstHalfScore struct{ Home, Away int }, secondHalfScore struct{ Home, Away int },
|
||||||
|
corners struct{ Home, Away int }, halfTimeCorners struct{ Home, Away int },
|
||||||
|
events []map[string]string) (domain.OutcomeStatus, error) {
|
||||||
|
|
||||||
if !domain.SupportedMarkets[outcome.MarketID] {
|
if !domain.SupportedMarkets[outcome.MarketID] {
|
||||||
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
|
||||||
|
|
@ -420,6 +475,21 @@ func (s *Service) evaluateFootballOutcome(outcome domain.BetOutcome, finalScore,
|
||||||
return evaluateDoubleChance(outcome, finalScore)
|
return evaluateDoubleChance(outcome, finalScore)
|
||||||
case int64(domain.FOOTBALL_DRAW_NO_BET):
|
case int64(domain.FOOTBALL_DRAW_NO_BET):
|
||||||
return evaluateDrawNoBet(outcome, finalScore)
|
return evaluateDrawNoBet(outcome, finalScore)
|
||||||
|
case int64(domain.FOOTBALL_CORNERS):
|
||||||
|
return evaluateCorners(outcome, corners)
|
||||||
|
case int64(domain.FOOTBALL_CORNERS_TWO_WAY):
|
||||||
|
return evaluateCorners(outcome, corners)
|
||||||
|
case int64(domain.FOOTBALL_FIRST_HALF_CORNERS):
|
||||||
|
return evaluateCorners(outcome, halfTimeCorners)
|
||||||
|
case int64(domain.FOOTBALL_ASIAN_TOTAL_CORNERS):
|
||||||
|
return evaluateCorners(outcome, corners)
|
||||||
|
case int64(domain.FOOTBALL_FIRST_HALF_ASIAN_CORNERS):
|
||||||
|
return evaluateCorners(outcome, halfTimeCorners)
|
||||||
|
case int64(domain.FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN):
|
||||||
|
return evaluateGoalsOddEven(outcome, firstHalfScore)
|
||||||
|
case int64(domain.FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN):
|
||||||
|
return evaluateGoalsOddEven(outcome, secondHalfScore)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
|
s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("market type not implemented: %s", outcome.MarketName)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("market type not implemented: %s", outcome.MarketName)
|
||||||
|
|
@ -456,7 +526,9 @@ func (s *Service) evaluateBasketballOutcome(outcome domain.BetOutcome, res domai
|
||||||
case int64(domain.BASKETBALL_GAME_TOTAL_ODD_EVEN):
|
case int64(domain.BASKETBALL_GAME_TOTAL_ODD_EVEN):
|
||||||
return evaluateGoalsOddEven(outcome, finalScore)
|
return evaluateGoalsOddEven(outcome, finalScore)
|
||||||
case int64(domain.BASKETBALL_TEAM_TOTALS):
|
case int64(domain.BASKETBALL_TEAM_TOTALS):
|
||||||
return evaluateGoalsOddEven(outcome, finalScore)
|
return evaluateTeamTotal(outcome, finalScore)
|
||||||
|
case int64(domain.BASKETBALL_TEAM_TOTAL_ODD_EVEN):
|
||||||
|
return evaluateTeamOddEven(outcome, finalScore)
|
||||||
|
|
||||||
case int64(domain.BASKETBALL_FIRST_HALF):
|
case int64(domain.BASKETBALL_FIRST_HALF):
|
||||||
return evaluateGameLines(outcome, firstHalfScore)
|
return evaluateGameLines(outcome, firstHalfScore)
|
||||||
|
|
@ -487,6 +559,11 @@ func (s *Service) evaluateBasketballOutcome(outcome domain.BetOutcome, res domai
|
||||||
return evaluateDoubleChance(outcome, firstQuarter)
|
return evaluateDoubleChance(outcome, firstQuarter)
|
||||||
case int64(domain.BASKETBALL_HIGHEST_SCORING_QUARTER):
|
case int64(domain.BASKETBALL_HIGHEST_SCORING_QUARTER):
|
||||||
return evaluateHighestScoringQuarter(outcome, firstQuarter, secondQuarter, thirdQuarter, fourthQuarter)
|
return evaluateHighestScoringQuarter(outcome, firstQuarter, secondQuarter, thirdQuarter, fourthQuarter)
|
||||||
|
case int64(domain.BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL):
|
||||||
|
return evaluateResultAndTotal(outcome, firstQuarter)
|
||||||
|
|
||||||
|
case int64(domain.BASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTER):
|
||||||
|
return evaluateTeamWithHighestScoringQuarter(outcome, firstQuarter, secondQuarter, thirdQuarter, fourthQuarter)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
|
s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ type UserStore interface {
|
||||||
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
|
||||||
UpdateUserCompany(ctx context.Context, id int64, companyID int64) error
|
UpdateUserCompany(ctx context.Context, id int64, companyID int64) error
|
||||||
|
UpdateUserSuspend(ctx context.Context, id int64, status bool) error
|
||||||
DeleteUser(ctx context.Context, id int64) error
|
DeleteUser(ctx context.Context, id int64) error
|
||||||
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error)
|
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error)
|
||||||
GetUserByEmail(ctx context.Context, email string) (domain.User, error)
|
GetUserByEmail(ctx context.Context, email string) (domain.User, error)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,11 @@ func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) err
|
||||||
func (s *Service) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error {
|
func (s *Service) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error {
|
||||||
// update user
|
// update user
|
||||||
return s.userStore.UpdateUserCompany(ctx, id, companyID)
|
return s.userStore.UpdateUserCompany(ctx, id, companyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateUserSuspend(ctx context.Context, id int64, status bool) error {
|
||||||
|
// update user
|
||||||
|
return s.userStore.UpdateUserSuspend(ctx, id, status)
|
||||||
}
|
}
|
||||||
func (s *Service) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
|
func (s *Service) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
|
||||||
return s.userStore.GetUserByID(ctx, id)
|
return s.userStore.GetUserByID(ctx, id)
|
||||||
|
|
|
||||||
|
|
@ -21,53 +21,24 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
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: "*/5 * * * * *", // Every 5 seconds
|
|
||||||
// task: func() {
|
|
||||||
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
|
||||||
// log.Printf("FetchLiveEvents error: %v", err)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// spec: "0 */15 * * * *", // Every 15 minutes
|
|
||||||
// task: func() {
|
|
||||||
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
|
||||||
// log.Printf("FetchNonLiveOdds error: %v", err)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// spec: "0 */15 * * * *",
|
|
||||||
// task: func() {
|
|
||||||
// log.Println("Fetching results for upcoming events...")
|
|
||||||
|
|
||||||
// upcomingEvents, err := eventService.GetAllUpcomingEvents(context.Background())
|
|
||||||
// if err != nil {
|
|
||||||
// log.Printf("Failed to fetch upcoming events: %v", err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, event := range upcomingEvents {
|
|
||||||
// if err := resultService.FetchAndStoreResult(context.Background(), event.ID); err != nil {
|
|
||||||
// log.Printf(" Failed to fetch/store result for event %s: %v", event.ID, err)
|
|
||||||
// } else {
|
|
||||||
// log.Printf(" Successfully stored result for event %s", event.ID)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
spec: "0 */15 * * * *",
|
spec: "0 0 * * * *", // Every 1 hour
|
||||||
|
task: func() {
|
||||||
|
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
|
log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spec: "0 */15 * * * *", // Every 15 minutes
|
||||||
|
task: func() {
|
||||||
|
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
|
log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spec: "0 */15 * * * *", // Every 15 Minutes
|
||||||
task: func() {
|
task: func() {
|
||||||
log.Println("Fetching results for upcoming events...")
|
log.Println("Fetching results for upcoming events...")
|
||||||
|
|
||||||
|
|
@ -81,7 +52,6 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,10 @@ func (h *Handler) RandomBet(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.PlaceRandomBet(c.Context(), userID, req.BranchID, leagueID, sportID, firstStartTime, lastStartTime)
|
var res domain.CreateBetRes
|
||||||
|
var err error
|
||||||
|
for i := 0; i < int(req.NumberOfBets); i++ {
|
||||||
|
res, err = h.betSvc.PlaceRandomBet(c.Context(), userID, req.BranchID, leagueID, sportID, firstStartTime, lastStartTime)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Random Bet failed", "error", err)
|
h.logger.Error("Random Bet failed", "error", err)
|
||||||
|
|
@ -126,7 +129,7 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Unable to create random bet")
|
return fiber.NewError(fiber.StatusInternalServerError, "Unable to create random bet")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -177,8 +180,9 @@ func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
bet, err := h.betSvc.GetBetByID(c.Context(), id)
|
bet, err := h.betSvc.GetBetByID(c.Context(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// TODO: handle all the errors types
|
||||||
h.logger.Error("Failed to get bet by ID", "betID", id, "error", err)
|
h.logger.Error("Failed to get bet by ID", "betID", id, "error", err)
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bet")
|
return fiber.NewError(fiber.StatusNotFound, "Failed to retrieve bet")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := domain.ConvertBet(bet)
|
res := domain.ConvertBet(bet)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
@ -492,6 +493,64 @@ func (h *Handler) GetBranchOperations(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Branch Operations retrieved successfully", result, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Operations retrieved successfully", result, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBranchCashiers godoc
|
||||||
|
// @Summary Gets branch cashiers
|
||||||
|
// @Description Gets branch cashiers
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Success 200 {array} GetCashierRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id}/cashier [get]
|
||||||
|
func (h *Handler) GetBranchCashiers(c *fiber.Ctx) error {
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
cashiers, err := h.userSvc.GetCashiersByBranch(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to get cashier by branch ID", "branchID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []GetCashierRes = make([]GetCashierRes, 0, len(cashiers))
|
||||||
|
|
||||||
|
for _, cashier := range cashiers {
|
||||||
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), cashier.ID)
|
||||||
|
if err != nil {
|
||||||
|
if err == authentication.ErrRefreshTokenNotFound {
|
||||||
|
lastLogin = &cashier.CreatedAt
|
||||||
|
} else {
|
||||||
|
h.logger.Error("Failed to get user last login", "userID", cashier.ID, "error", err)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = append(result, GetCashierRes{
|
||||||
|
ID: cashier.ID,
|
||||||
|
FirstName: cashier.FirstName,
|
||||||
|
LastName: cashier.LastName,
|
||||||
|
Email: cashier.Email,
|
||||||
|
PhoneNumber: cashier.PhoneNumber,
|
||||||
|
Role: cashier.Role,
|
||||||
|
EmailVerified: cashier.EmailVerified,
|
||||||
|
PhoneVerified: cashier.PhoneVerified,
|
||||||
|
CreatedAt: cashier.CreatedAt,
|
||||||
|
UpdatedAt: cashier.UpdatedAt,
|
||||||
|
SuspendedAt: cashier.SuspendedAt,
|
||||||
|
Suspended: cashier.Suspended,
|
||||||
|
LastLogin: *lastLogin,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Cashiers retrieved successfully", result, 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
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ type GetCompanyRes struct {
|
||||||
WalletID int64 `json:"wallet_id" example:"1"`
|
WalletID int64 `json:"wallet_id" example:"1"`
|
||||||
WalletBalance float32 `json:"balance" example:"1"`
|
WalletBalance float32 `json:"balance" example:"1"`
|
||||||
IsActive bool `json:"is_active" example:"false"`
|
IsActive bool `json:"is_active" example:"false"`
|
||||||
|
AdminFirstName string `json:"admin_first_name" example:"John"`
|
||||||
|
AdminLastName string `json:"admin_last_name" example:"Doe"`
|
||||||
|
AdminPhoneNumber string `json:"admin_phone_number" example:"1234567890"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertCompany(company domain.Company) CompanyRes {
|
func convertCompany(company domain.Company) CompanyRes {
|
||||||
|
|
@ -50,6 +53,9 @@ func convertGetCompany(company domain.GetCompany) GetCompanyRes {
|
||||||
WalletID: company.WalletID,
|
WalletID: company.WalletID,
|
||||||
WalletBalance: company.WalletBalance.Float32(),
|
WalletBalance: company.WalletBalance.Float32(),
|
||||||
IsActive: company.IsWalletActive,
|
IsActive: company.IsWalletActive,
|
||||||
|
AdminFirstName: company.AdminFirstName,
|
||||||
|
AdminLastName: company.AdminLastName,
|
||||||
|
AdminPhoneNumber: company.AdminPhoneNumber,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ func (h *Handler) GetTicketByID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
ticket, err := h.ticketSvc.GetTicketByID(c.Context(), id)
|
ticket, err := h.ticketSvc.GetTicketByID(c.Context(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// h.logger.Error("Failed to get ticket by ID", "ticketID", id, "error", err)
|
h.logger.Error("Failed to get ticket by ID", "ticketID", id, "error", err)
|
||||||
return fiber.NewError(fiber.StatusNotFound, "Failed to retrieve ticket")
|
return fiber.NewError(fiber.StatusNotFound, "Failed to retrieve ticket")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -450,7 +450,7 @@ func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "User ID"
|
// @Param id path int true "User ID"
|
||||||
// @Success 200 {object} response.APIResponse
|
// @Success 200 {object} UserProfileRes
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
|
@ -513,3 +513,75 @@ func (h *Handler) GetUserByID(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", res, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteUser godoc
|
||||||
|
// @Summary Delete user by ID
|
||||||
|
// @Description Delete a user by their ID
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /user/delete/{id} [delete]
|
||||||
|
func (h *Handler) DeleteUser(c *fiber.Ctx) error {
|
||||||
|
userIDstr := c.Params("id")
|
||||||
|
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("DeleteUser failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid user ID", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.userSvc.DeleteUser(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to delete user", "userID", userID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to delete user", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "User deleted successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateUserSuspendReq struct {
|
||||||
|
UserID int64 `json:"user_id" validate:"required" example:"123"`
|
||||||
|
Suspended bool `json:"suspended" validate:"required" example:"true"`
|
||||||
|
}
|
||||||
|
type UpdateUserSuspendRes struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Suspended bool `json:"suspended"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserSuspend godoc
|
||||||
|
// @Summary Suspend or unsuspend a user
|
||||||
|
// @Description Suspend or unsuspend a user
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param updateUserSuspend body UpdateUserSuspendReq true "Suspend or unsuspend a user"
|
||||||
|
// @Success 200 {object} UpdateUserSuspendRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /user/suspend [post]
|
||||||
|
func (h *Handler) UpdateUserSuspend(c *fiber.Ctx) error {
|
||||||
|
var req UpdateUserSuspendReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.logger.Error("Failed to parse UpdateUserSuspend request", "error", err)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
|
}
|
||||||
|
|
||||||
|
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := h.userSvc.UpdateUserSuspend(c.Context(), req.UserID, req.Suspended)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to update user suspend status", "error", err)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update user suspend status")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := UpdateUserSuspendRes{
|
||||||
|
UserID: req.UserID,
|
||||||
|
Suspended: req.Suspended,
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "User suspend status updated successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Get("/", func(c *fiber.Ctx) error {
|
a.fiber.Get("/", func(c *fiber.Ctx) error {
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"message": "Welcome to the FortuneBet API",
|
"message": "Welcome to the FortuneBet API",
|
||||||
"version": "1.0.1",
|
"version": "1.0dev2",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -77,6 +77,8 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
a.fiber.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
||||||
a.fiber.Get("/user/profile", a.authMiddleware, h.UserProfile)
|
a.fiber.Get("/user/profile", a.authMiddleware, h.UserProfile)
|
||||||
a.fiber.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
a.fiber.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
||||||
|
a.fiber.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
||||||
|
a.fiber.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
||||||
|
|
||||||
a.fiber.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet)
|
a.fiber.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet)
|
||||||
a.fiber.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
|
a.fiber.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
|
||||||
|
|
@ -120,12 +122,14 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Get("/search/branch", a.authMiddleware, h.SearchBranch)
|
a.fiber.Get("/search/branch", a.authMiddleware, h.SearchBranch)
|
||||||
// /branch/search
|
// /branch/search
|
||||||
// branch/wallet
|
// branch/wallet
|
||||||
|
a.fiber.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers)
|
||||||
|
|
||||||
// Branch Operation
|
// Branch Operation
|
||||||
a.fiber.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations)
|
a.fiber.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations)
|
||||||
a.fiber.Post("/supportedOperation", a.authMiddleware, h.CreateSupportedOperation)
|
a.fiber.Post("/supportedOperation", a.authMiddleware, h.CreateSupportedOperation)
|
||||||
a.fiber.Post("/operation", a.authMiddleware, h.CreateBranchOperation)
|
a.fiber.Post("/operation", a.authMiddleware, h.CreateBranchOperation)
|
||||||
a.fiber.Get("/branch/:id/operation", a.authMiddleware, h.GetBranchOperations)
|
a.fiber.Get("/branch/:id/operation", a.authMiddleware, h.GetBranchOperations)
|
||||||
|
|
||||||
a.fiber.Delete("/branch/:id/operation/:opID", a.authMiddleware, h.DeleteBranchOperation)
|
a.fiber.Delete("/branch/:id/operation/:opID", a.authMiddleware, h.DeleteBranchOperation)
|
||||||
|
|
||||||
// Company
|
// Company
|
||||||
|
|
@ -145,7 +149,7 @@ func (a *App) initAppRoutes() {
|
||||||
// Bet Routes
|
// Bet Routes
|
||||||
a.fiber.Post("/bet", a.authMiddleware, h.CreateBet)
|
a.fiber.Post("/bet", a.authMiddleware, h.CreateBet)
|
||||||
a.fiber.Get("/bet", a.authMiddleware, h.GetAllBet)
|
a.fiber.Get("/bet", a.authMiddleware, h.GetAllBet)
|
||||||
a.fiber.Get("/bet/:id", a.authMiddleware, h.GetBetByID)
|
a.fiber.Get("/bet/:id", h.GetBetByID)
|
||||||
a.fiber.Get("/bet/cashout/:id", a.authMiddleware, h.GetBetByCashoutID)
|
a.fiber.Get("/bet/cashout/:id", a.authMiddleware, h.GetBetByCashoutID)
|
||||||
a.fiber.Patch("/bet/:id", a.authMiddleware, h.UpdateCashOut)
|
a.fiber.Patch("/bet/:id", a.authMiddleware, h.UpdateCashOut)
|
||||||
a.fiber.Delete("/bet/:id", a.authMiddleware, h.DeleteBet)
|
a.fiber.Delete("/bet/:id", a.authMiddleware, h.DeleteBet)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user