major fixes while integrating

This commit is contained in:
Samuel Tariku 2025-04-11 21:46:48 +03:00
parent a97cb32bba
commit 1b0a068a02
48 changed files with 2811 additions and 438 deletions

View File

@ -69,20 +69,26 @@ CREATE TABLE IF NOT EXISTS bet_outcomes (
id BIGSERIAL PRIMARY KEY,
bet_id BIGINT NOT NULL,
event_id bigint not null,
odd_id BIGINT NOT NULL,
odd_id BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS ticket_outcomes (
id BIGSERIAL PRIMARY KEY,
ticket_id BIGINT NOT NULL,
event_id bigint not null,
odd_id BIGINT NOT NULL,
odd_id BIGINT NOT NULL
);
ALTER TABLE bets
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE bets
ADD CONSTRAINT fk_bets_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
ALTER TABLE bet_outcomes
ADD CONSTRAINT fk_bet_outcomes_bet FOREIGN KEY (bet_id) REFERENCES bets(id);
CREATE VIEW bet_with_outcomes AS
SELECT bets.*,
JSON_AGG(bet_outcomes.*) AS outcomes
FROM bets
LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id
GROUP BY bets.id;
CREATE VIEW ticket_with_outcomes AS
SELECT tickets.*,
JSON_AGG(ticket_outcomes.*) AS outcomes
FROM tickets
LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id
GROUP BY tickets.id;
CREATE TABLE IF NOT EXISTS wallets (
id BIGSERIAL PRIMARY KEY,
balance BIGINT NOT NULL DEFAULT 0,
@ -164,6 +170,48 @@ CREATE TABLE IF NOT EXISTS branch_operations (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS branch_cashiers (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
branch_id BIGINT NOT NULL,
UNIQUE(user_id, branch_id)
);
ALTER TABLE refresh_tokens
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE bets
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id),
ADD CONSTRAINT fk_bets_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
ALTER TABLE bet_outcomes
ADD CONSTRAINT fk_bet_outcomes_bets FOREIGN KEY (bet_id) REFERENCES bets(id),
ADD CONSTRAINT fk_bet_outcomes_events FOREIGN KEY (event_id) REFERENCES supported_operations(id),
ADD CONSTRAINT fk_bet_outcomes_odds FOREIGN KEY (odd_id) REFERENCES supported_operations(id);
ALTER TABLE ticket_outcomes
ADD CONSTRAINT fk_ticket_outcomes_tickets FOREIGN KEY (ticket_id) REFERENCES tickets(id),
ADD CONSTRAINT fk_ticket_outcomes_events FOREIGN KEY (event_id) REFERENCES supported_operations(id),
ADD CONSTRAINT fk_ticket_outcomes_odds FOREIGN KEY (odd_id) REFERENCES supported_operations(id);
ALTER TABLE wallets
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE customer_wallets
ADD CONSTRAINT fk_customer_wallets_customers FOREIGN KEY (customer_id) REFERENCES users(id),
ADD CONSTRAINT fk_customer_wallets_regular_wallet FOREIGN KEY (regular_wallet_id) REFERENCES wallets(id),
ADD CONSTRAINT fk_customer_wallets_static_wallet FOREIGN KEY (static_wallet_id) REFERENCES wallets(id);
ALTER TABLE wallet_transfer
ADD CONSTRAINT fk_wallet_transfer_receiver_wallet FOREIGN KEY (receiver_wallet_id) REFERENCES wallets(id),
ADD CONSTRAINT fk_wallet_transfer_sender_wallet FOREIGN KEY (sender_wallet_id) REFERENCES wallets(id),
ADD CONSTRAINT fk_wallet_transfer_cashier FOREIGN KEY (cashier_id) REFERENCES users(id);
ALTER TABLE transactions
ADD CONSTRAINT fk_transactions_branches FOREIGN KEY (branch_id) REFERENCES branches(id),
ADD CONSTRAINT fk_transactions_cashiers FOREIGN KEY (cashier_id) REFERENCES users(id),
ADD CONSTRAINT fk_transactions_bets FOREIGN KEY (bet_id) REFERENCES bets(id);
ALTER TABLE branches
ADD CONSTRAINT fk_branches_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id),
ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id);
ALTER TABLE branch_operations
ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id),
ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
ALTER TABLE branch_cashiers
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id),
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
----------------------------------------------seed data-------------------------------------------------------------
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
CREATE EXTENSION IF NOT EXISTS pgcrypto;
@ -215,7 +263,7 @@ VALUES (
'cybersamt@gmail.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'cashier',
'super_admin',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
@ -227,3 +275,23 @@ INSERT INTO supported_operations (name, description)
VALUES ('SportBook', 'Sportbook operations'),
('Virtual', 'Virtual operations'),
('GameZone', 'GameZone operations');
INSERT INTO wallets (
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
is_active,
created_at,
updated_at
)
VALUES (
10000,
TRUE,
TRUE,
TRUE,
1,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);

View File

@ -1,16 +1,43 @@
-- name: CreateBet :one
INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet, cashout_id)
INSERT INTO bets (
amount,
total_odds,
status,
full_name,
phone_number,
branch_id,
user_id,
is_shop_bet,
cashout_id
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING *;
-- name: CreateBetOutcome :copyfrom
INSERT INTO bet_outcomes (bet_id, event_id, odd_id)
VALUES ($1, $2, $3);
-- name: GetAllBets :many
SELECT * FROM bets;
SELECT *
FROM bet_with_outcomes;
-- name: GetBetByID :one
SELECT * FROM bets WHERE id = $1;
SELECT *
FROM bet_with_outcomes
WHERE id = $1;
-- name: GetBetByCashoutID :many
SELECT
FROM bet_with_outcomes
WHERE cashout_id = $1;
-- name: GetBetByBranchID :many
SELECT *
FROM bet_with_outcomes
WHERE branch_id = $1;
-- name: UpdateCashOut :exec
UPDATE bets SET cashed_out = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1;
UPDATE bets
SET cashed_out = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1;
-- name: DeleteBet :exec
DELETE FROM bets WHERE id = $1;
DELETE FROM bets
WHERE id = $1;
-- name: DeleteBetOutcome :exec
DELETE FROM bet_outcomes
WHERE bet_id = $1;

View File

@ -1,42 +1,86 @@
-- name: CreateBranch :one
INSERT INTO branches (name, location, wallet_id, branch_manager_id, company_id, is_self_owned) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *;
INSERT INTO branches (
name,
location,
wallet_id,
branch_manager_id,
company_id,
is_self_owned
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *;
-- name: CreateSupportedOperation :one
INSERT INTO supported_operations (name, description) VALUES ($1, $2) RETURNING *;
INSERT INTO supported_operations (name, description)
VALUES ($1, $2)
RETURNING *;
-- name: CreateBranchOperation :one
INSERT INTO branch_operations (operation_id, branch_id) VALUES ($1, $2) RETURNING *;
INSERT INTO branch_operations (operation_id, branch_id)
VALUES ($1, $2)
RETURNING *;
-- name: CreateBranchCashier :one
INSERT INTO branch_cashiers (user_id, branch_id)
VALUES ($1, $2)
RETURNING *;
-- name: GetAllBranches :many
SELECT * FROM branch_details;
SELECT *
FROM branch_details;
-- name: GetBranchByID :one
SELECT * FROM branch_details WHERE id = $1;
SELECT *
FROM branch_details
WHERE id = $1;
-- name: GetBranchByCompanyID :many
SELECT * FROM branch_details WHERE company_id = $1;
SELECT *
FROM branch_details
WHERE company_id = $1;
-- name: GetBranchByManagerID :many
SELECT * FROM branch_details WHERE branch_manager_id = $1;
SELECT *
FROM branch_details
WHERE branch_manager_id = $1;
-- name: SearchBranchByName :many
SELECT * FROM branch_details WHERE name ILIKE '%' || $1 || '%';
SELECT *
FROM branch_details
WHERE name ILIKE '%' || $1 || '%';
-- name: GetAllSupportedOperations :many
SELECT * FROM supported_operations;
SELECT *
FROM supported_operations;
-- name: GetBranchOperations :many
SELECT branch_operations.*, supported_operations.name, supported_operations.description
SELECT branch_operations.*,
supported_operations.name,
supported_operations.description
FROM branch_operations
JOIN supported_operations ON branch_operations.operation_id = supported_operations.id
WHERE branch_operations.branch_id = $1;
-- name: GetBranchByCashier :one
SELECT branches.*
FROM branch_cashiers
JOIN branches ON branch_cashiers.branch_id = branches.id
WHERE branch_cashiers.user_id = $1;
-- name: GetCashiersByBranch :many
SELECT users.*
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
WHERE branch_cashiers.branch_id = $1;
-- name: GetAllCashiers :many
SELECT users.*
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id;
-- name: UpdateBranch :one
UPDATE branches SET name = $1, location = $2, branch_manager_id = $3, company_id = $4, is_self_owned = $5 WHERE id = $6 RETURNING *;
UPDATE branches
SET name = $1,
location = $2,
branch_manager_id = $3,
company_id = $4,
is_self_owned = $5
WHERE id = $6
RETURNING *;
-- name: DeleteBranch :exec
DELETE FROM branches WHERE id = $1;
DELETE FROM branches
WHERE id = $1;
-- name: DeleteBranchOperation :exec
DELETE FROM branch_operations WHERE operation_id = $1 AND branch_id = $2;
DELETE FROM branch_operations
WHERE operation_id = $1
AND branch_id = $2;
-- name: DeleteBranchCashier :exec
DELETE FROM branch_cashiers
WHERE user_id = $1;

View File

@ -2,15 +2,26 @@
INSERT INTO tickets (amount, total_odds)
VALUES ($1, $2)
RETURNING *;
-- name: CreateTicketOutcome :copyfrom
INSERT INTO ticket_outcomes (ticket_id, event_id, odd_id)
VALUES ($1, $2, $3);
-- name: GetAllTickets :many
SELECT * FROM tickets;
SELECT *
FROM ticket_with_outcomes;
-- name: GetTicketByID :one
SELECT * FROM tickets WHERE id = $1;
SELECT *
FROM ticket_with_outcomes
WHERE id = $1;
-- name: GetTicketOutcome :many
SELECT *
FROM ticket_outcomes
WHERE ticket_id = $1;
-- name: DeleteTicket :exec
DELETE FROM tickets WHERE id = $1;
DELETE FROM tickets
WHERE id = $1;
-- name: DeleteOldTickets :exec
Delete from tickets where created_at < now() - interval '1 day';
Delete from tickets
where created_at < now() - interval '1 day';
-- name: DeleteTicketOutcome :exec
Delete from ticket_outcomes
where ticket_id = $1;

View File

@ -1,49 +1,114 @@
-- name: CreateUser :one
INSERT INTO users (first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at)
INSERT INTO users (
first_name,
last_name,
email,
phone_number,
role,
password,
email_verified,
phone_verified,
created_at,
updated_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at;
RETURNING id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at;
-- name: GetUserByID :one
SELECT *
FROM users
WHERE id = $1;
-- name: GetAllUsers :many
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users;
-- name: SearchUserByNameOrPhone :many
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
WHERE first_name ILIKE '%' || $1 || '%'
OR last_name ILIKE '%' || $1 || '%'
OR phone_number LIKE '%' || $1 || '%';
-- name: UpdateUser :exec
UPDATE users
SET first_name = $1, last_name = $2, email = $3, phone_number = $4, role = $5, updated_at = $6
SET first_name = $1,
last_name = $2,
email = $3,
phone_number = $4,
role = $5,
updated_at = $6
WHERE id = $7;
-- name: DeleteUser :exec
DELETE FROM users
WHERE id = $1;
-- name: CheckPhoneEmailExist :one
SELECT
EXISTS (SELECT 1 FROM users WHERE users.phone_number = $1 AND users.phone_number IS NOT NULL) AS phone_exists,
EXISTS (SELECT 1 FROM users WHERE users.email = $2 AND users.email IS NOT NULL) AS email_exists;
SELECT EXISTS (
SELECT 1
FROM users
WHERE users.phone_number = $1
AND users.phone_number IS NOT NULL
) AS phone_exists,
EXISTS (
SELECT 1
FROM users
WHERE users.email = $2
AND users.email IS NOT NULL
) AS email_exists;
-- name: GetUserByEmail :one
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
WHERE email = $1;
-- name: GetUserByPhone :one
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
WHERE phone_number = $1;
-- name: UpdatePassword :exec
UPDATE users
SET password = $1, updated_at = $4
WHERE (email = $2 OR phone_number = $3);
SET password = $1,
updated_at = $4
WHERE (
email = $2
OR phone_number = $3
);

View File

@ -1,21 +1,34 @@
-- name: CreateWallet :one
INSERT INTO wallets (is_withdraw, is_bettable, is_transferable, user_id) VALUES ($1, $2, $3, $4) RETURNING *;
INSERT INTO wallets (
is_withdraw,
is_bettable,
is_transferable,
user_id
)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: CreateCustomerWallet :one
INSERT INTO customer_wallets (customer_id, company_id, regular_wallet_id, static_wallet_id) VALUES ($1, $2, $3, $4) RETURNING *;
INSERT INTO customer_wallets (
customer_id,
company_id,
regular_wallet_id,
static_wallet_id
)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetAllWallets :many
SELECT * FROM wallets;
SELECT *
FROM wallets;
-- name: GetWalletByID :one
SELECT * FROM wallets WHERE id = $1;
SELECT *
FROM wallets
WHERE id = $1;
-- name: GetWalletByUserID :many
SELECT * FROM wallets WHERE user_id = $1;
SELECT *
FROM wallets
WHERE user_id = $1;
-- name: GetCustomerWallet :one
SELECT
cw.id,
SELECT cw.id,
cw.customer_id,
cw.company_id,
rw.id AS regular_id,
@ -28,13 +41,28 @@ SELECT
FROM customer_wallets cw
JOIN wallets rw ON cw.regular_wallet_id = rw.id
JOIN wallets sw ON cw.static_wallet_id = sw.id
WHERE cw.customer_id = $1 AND cw.company_id = $2;
WHERE cw.customer_id = $1
AND cw.company_id = $2;
-- name: GetAllBranchWallets :many
SELECT wallets.id,
wallets.balance,
wallets.is_active,
wallets.updated_at,
wallets.created_at,
branches.name,
branches.location,
branches.branch_manager_id,
branches.company_id,
branches.is_self_owned
FROM branches
JOIN wallets ON branches.wallet_id = wallets.id;
-- name: UpdateBalance :exec
UPDATE wallets SET balance = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2;
UPDATE wallets
SET balance = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
-- name: UpdateWalletActive :exec
UPDATE wallets SET is_active = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2;
UPDATE wallets
SET is_active = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2;

View File

@ -618,6 +618,44 @@ const docTemplate = `{
}
}
},
"/branch/{id}/bets": {
"get": {
"description": "Gets bets by its branch id",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"branch"
],
"summary": "Gets bets by its branch id",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.BetRes"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/branch/{id}/operation": {
"get": {
"description": "Gets branch operations",
@ -716,6 +754,44 @@ const docTemplate = `{
}
}
},
"/branchWallet": {
"get": {
"description": "Retrieve all branch wallets",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"wallet"
],
"summary": "Get all branch wallets",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.WalletRes"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/cashiers": {
"get": {
"description": "Get all cashiers",
@ -1170,6 +1246,53 @@ const docTemplate = `{
}
}
},
"/search/branch": {
"get": {
"description": "Search branches by name or location",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"branch"
],
"summary": "Search branches",
"parameters": [
{
"type": "string",
"description": "Search query",
"name": "q",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.BranchDetailRes"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/supportedOperation": {
"get": {
"description": "Gets all supported operations",
@ -1555,7 +1678,53 @@ const docTemplate = `{
}
}
},
"/transfer/wallet": {
"/transfer/refill/:id": {
"post": {
"description": "Super Admin route to refill a wallet",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"transfer"
],
"summary": "Refill wallet",
"parameters": [
{
"description": "Create Transfer",
"name": "refillWallet",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.CreateTransferReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.TransferWalletRes"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/transfer/wallet/:id": {
"post": {
"description": "Create a transfer to wallet",
"consumes": [
@ -1583,7 +1752,53 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.TransferRes"
"$ref": "#/definitions/handlers.TransferWalletRes"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/transfer/wallet/{id}": {
"get": {
"description": "Get transfer by wallet",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"transfer"
],
"summary": "Get transfer by wallet",
"parameters": [
{
"description": "Create Transfer",
"name": "transferToWallet",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.CreateTransferReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.TransferWalletRes"
}
},
"400": {
@ -2101,6 +2316,23 @@ const docTemplate = `{
}
},
"definitions": {
"domain.BetOutcome": {
"type": "object",
"properties": {
"betID": {
"type": "integer"
},
"eventID": {
"type": "integer"
},
"id": {
"type": "integer"
},
"oddID": {
"type": "integer"
}
}
},
"domain.BetStatus": {
"type": "integer",
"enum": [
@ -2116,9 +2348,6 @@ const docTemplate = `{
"BET_STATUS_ERROR"
]
},
"domain.Outcome": {
"type": "object"
},
"domain.PaymentOption": {
"type": "integer",
"enum": [
@ -2151,6 +2380,36 @@ const docTemplate = `{
"RoleCashier"
]
},
"domain.TicketOutcome": {
"type": "object",
"properties": {
"eventID": {
"type": "integer"
},
"id": {
"type": "integer"
},
"oddID": {
"type": "integer"
},
"ticketID": {
"type": "integer"
}
}
},
"handlers.BetOutcome": {
"type": "object",
"properties": {
"event_id": {
"type": "integer",
"example": 1
},
"odd_id": {
"type": "integer",
"example": 1
}
}
},
"handlers.BetRes": {
"type": "object",
"properties": {
@ -2177,7 +2436,7 @@ const docTemplate = `{
"outcomes": {
"type": "array",
"items": {
"$ref": "#/definitions/domain.Outcome"
"$ref": "#/definitions/domain.BetOutcome"
}
},
"phone_number": {
@ -2213,6 +2472,10 @@ const docTemplate = `{
"type": "integer",
"example": 1
},
"id": {
"type": "integer",
"example": 1
},
"is_self_owned": {
"type": "boolean",
"example": false
@ -2263,6 +2526,10 @@ const docTemplate = `{
"type": "integer",
"example": 1
},
"id": {
"type": "integer",
"example": 1
},
"is_self_owned": {
"type": "boolean",
"example": false
@ -2306,43 +2573,7 @@ const docTemplate = `{
}
},
"handlers.CreateBetReq": {
"type": "object",
"properties": {
"amount": {
"type": "number",
"example": 100
},
"full_name": {
"type": "string",
"example": "John"
},
"is_shop_bet": {
"type": "boolean",
"example": false
},
"outcomes": {
"type": "array",
"items": {
"type": "integer"
}
},
"phone_number": {
"type": "string",
"example": "1234567890"
},
"status": {
"allOf": [
{
"$ref": "#/definitions/domain.BetStatus"
}
],
"example": 1
},
"total_odds": {
"type": "number",
"example": 4.22
}
}
"type": "object"
},
"handlers.CreateBranchOperationReq": {
"type": "object",
@ -2391,6 +2622,10 @@ const docTemplate = `{
"handlers.CreateCashierReq": {
"type": "object",
"properties": {
"branch_id": {
"type": "integer",
"example": 1
},
"email": {
"type": "string",
"example": "john.doe@example.com"
@ -2416,10 +2651,6 @@ const docTemplate = `{
"handlers.CreateManagerReq": {
"type": "object",
"properties": {
"branch_id": {
"type": "integer",
"example": 1
},
"email": {
"type": "string",
"example": "john.doe@example.com"
@ -2465,7 +2696,7 @@ const docTemplate = `{
"outcomes": {
"type": "array",
"items": {
"type": "integer"
"$ref": "#/definitions/handlers.TicketOutcome"
}
},
"total_odds": {
@ -2477,6 +2708,10 @@ const docTemplate = `{
"handlers.CreateTicketRes": {
"type": "object",
"properties": {
"created_number": {
"type": "integer",
"example": 3
},
"fast_code": {
"type": "integer",
"example": 1234
@ -2550,10 +2785,6 @@ const docTemplate = `{
"payment_method": {
"type": "string",
"example": "cash"
},
"receiver_id": {
"type": "integer",
"example": 1
}
}
},
@ -2599,6 +2830,17 @@ const docTemplate = `{
}
}
},
"handlers.NullableInt64": {
"type": "object",
"properties": {
"valid": {
"type": "boolean"
},
"value": {
"type": "integer"
}
}
},
"handlers.RegisterCodeReq": {
"type": "object",
"properties": {
@ -2701,6 +2943,19 @@ const docTemplate = `{
}
}
},
"handlers.TicketOutcome": {
"type": "object",
"properties": {
"event_id": {
"type": "integer",
"example": 1
},
"odd_id": {
"type": "integer",
"example": 1
}
}
},
"handlers.TicketRes": {
"type": "object",
"properties": {
@ -2715,7 +2970,7 @@ const docTemplate = `{
"outcomes": {
"type": "array",
"items": {
"$ref": "#/definitions/domain.Outcome"
"$ref": "#/definitions/domain.TicketOutcome"
}
},
"total_odds": {
@ -2788,7 +3043,7 @@ const docTemplate = `{
}
}
},
"handlers.TransferRes": {
"handlers.TransferWalletRes": {
"type": "object",
"properties": {
"amount": {

View File

@ -610,6 +610,44 @@
}
}
},
"/branch/{id}/bets": {
"get": {
"description": "Gets bets by its branch id",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"branch"
],
"summary": "Gets bets by its branch id",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.BetRes"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/branch/{id}/operation": {
"get": {
"description": "Gets branch operations",
@ -708,6 +746,44 @@
}
}
},
"/branchWallet": {
"get": {
"description": "Retrieve all branch wallets",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"wallet"
],
"summary": "Get all branch wallets",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.WalletRes"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/cashiers": {
"get": {
"description": "Get all cashiers",
@ -1162,6 +1238,53 @@
}
}
},
"/search/branch": {
"get": {
"description": "Search branches by name or location",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"branch"
],
"summary": "Search branches",
"parameters": [
{
"type": "string",
"description": "Search query",
"name": "q",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.BranchDetailRes"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/supportedOperation": {
"get": {
"description": "Gets all supported operations",
@ -1547,7 +1670,53 @@
}
}
},
"/transfer/wallet": {
"/transfer/refill/:id": {
"post": {
"description": "Super Admin route to refill a wallet",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"transfer"
],
"summary": "Refill wallet",
"parameters": [
{
"description": "Create Transfer",
"name": "refillWallet",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.CreateTransferReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.TransferWalletRes"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/transfer/wallet/:id": {
"post": {
"description": "Create a transfer to wallet",
"consumes": [
@ -1575,7 +1744,53 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.TransferRes"
"$ref": "#/definitions/handlers.TransferWalletRes"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.APIResponse"
}
}
}
}
},
"/transfer/wallet/{id}": {
"get": {
"description": "Get transfer by wallet",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"transfer"
],
"summary": "Get transfer by wallet",
"parameters": [
{
"description": "Create Transfer",
"name": "transferToWallet",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.CreateTransferReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.TransferWalletRes"
}
},
"400": {
@ -2093,6 +2308,23 @@
}
},
"definitions": {
"domain.BetOutcome": {
"type": "object",
"properties": {
"betID": {
"type": "integer"
},
"eventID": {
"type": "integer"
},
"id": {
"type": "integer"
},
"oddID": {
"type": "integer"
}
}
},
"domain.BetStatus": {
"type": "integer",
"enum": [
@ -2108,9 +2340,6 @@
"BET_STATUS_ERROR"
]
},
"domain.Outcome": {
"type": "object"
},
"domain.PaymentOption": {
"type": "integer",
"enum": [
@ -2143,6 +2372,36 @@
"RoleCashier"
]
},
"domain.TicketOutcome": {
"type": "object",
"properties": {
"eventID": {
"type": "integer"
},
"id": {
"type": "integer"
},
"oddID": {
"type": "integer"
},
"ticketID": {
"type": "integer"
}
}
},
"handlers.BetOutcome": {
"type": "object",
"properties": {
"event_id": {
"type": "integer",
"example": 1
},
"odd_id": {
"type": "integer",
"example": 1
}
}
},
"handlers.BetRes": {
"type": "object",
"properties": {
@ -2169,7 +2428,7 @@
"outcomes": {
"type": "array",
"items": {
"$ref": "#/definitions/domain.Outcome"
"$ref": "#/definitions/domain.BetOutcome"
}
},
"phone_number": {
@ -2205,6 +2464,10 @@
"type": "integer",
"example": 1
},
"id": {
"type": "integer",
"example": 1
},
"is_self_owned": {
"type": "boolean",
"example": false
@ -2255,6 +2518,10 @@
"type": "integer",
"example": 1
},
"id": {
"type": "integer",
"example": 1
},
"is_self_owned": {
"type": "boolean",
"example": false
@ -2298,43 +2565,7 @@
}
},
"handlers.CreateBetReq": {
"type": "object",
"properties": {
"amount": {
"type": "number",
"example": 100
},
"full_name": {
"type": "string",
"example": "John"
},
"is_shop_bet": {
"type": "boolean",
"example": false
},
"outcomes": {
"type": "array",
"items": {
"type": "integer"
}
},
"phone_number": {
"type": "string",
"example": "1234567890"
},
"status": {
"allOf": [
{
"$ref": "#/definitions/domain.BetStatus"
}
],
"example": 1
},
"total_odds": {
"type": "number",
"example": 4.22
}
}
"type": "object"
},
"handlers.CreateBranchOperationReq": {
"type": "object",
@ -2383,6 +2614,10 @@
"handlers.CreateCashierReq": {
"type": "object",
"properties": {
"branch_id": {
"type": "integer",
"example": 1
},
"email": {
"type": "string",
"example": "john.doe@example.com"
@ -2408,10 +2643,6 @@
"handlers.CreateManagerReq": {
"type": "object",
"properties": {
"branch_id": {
"type": "integer",
"example": 1
},
"email": {
"type": "string",
"example": "john.doe@example.com"
@ -2457,7 +2688,7 @@
"outcomes": {
"type": "array",
"items": {
"type": "integer"
"$ref": "#/definitions/handlers.TicketOutcome"
}
},
"total_odds": {
@ -2469,6 +2700,10 @@
"handlers.CreateTicketRes": {
"type": "object",
"properties": {
"created_number": {
"type": "integer",
"example": 3
},
"fast_code": {
"type": "integer",
"example": 1234
@ -2542,10 +2777,6 @@
"payment_method": {
"type": "string",
"example": "cash"
},
"receiver_id": {
"type": "integer",
"example": 1
}
}
},
@ -2591,6 +2822,17 @@
}
}
},
"handlers.NullableInt64": {
"type": "object",
"properties": {
"valid": {
"type": "boolean"
},
"value": {
"type": "integer"
}
}
},
"handlers.RegisterCodeReq": {
"type": "object",
"properties": {
@ -2693,6 +2935,19 @@
}
}
},
"handlers.TicketOutcome": {
"type": "object",
"properties": {
"event_id": {
"type": "integer",
"example": 1
},
"odd_id": {
"type": "integer",
"example": 1
}
}
},
"handlers.TicketRes": {
"type": "object",
"properties": {
@ -2707,7 +2962,7 @@
"outcomes": {
"type": "array",
"items": {
"$ref": "#/definitions/domain.Outcome"
"$ref": "#/definitions/domain.TicketOutcome"
}
},
"total_odds": {
@ -2780,7 +3035,7 @@
}
}
},
"handlers.TransferRes": {
"handlers.TransferWalletRes": {
"type": "object",
"properties": {
"amount": {

View File

@ -1,4 +1,15 @@
definitions:
domain.BetOutcome:
properties:
betID:
type: integer
eventID:
type: integer
id:
type: integer
oddID:
type: integer
type: object
domain.BetStatus:
enum:
- 0
@ -11,8 +22,6 @@ definitions:
- BET_STATUS_WIN
- BET_STATUS_LOSS
- BET_STATUS_ERROR
domain.Outcome:
type: object
domain.PaymentOption:
enum:
- 0
@ -39,6 +48,26 @@ definitions:
- RoleBranchManager
- RoleCustomer
- RoleCashier
domain.TicketOutcome:
properties:
eventID:
type: integer
id:
type: integer
oddID:
type: integer
ticketID:
type: integer
type: object
handlers.BetOutcome:
properties:
event_id:
example: 1
type: integer
odd_id:
example: 1
type: integer
type: object
handlers.BetRes:
properties:
amount:
@ -58,7 +87,7 @@ definitions:
type: boolean
outcomes:
items:
$ref: '#/definitions/domain.Outcome'
$ref: '#/definitions/domain.BetOutcome'
type: array
phone_number:
example: "1234567890"
@ -82,6 +111,9 @@ definitions:
company_id:
example: 1
type: integer
id:
example: 1
type: integer
is_self_owned:
example: false
type: boolean
@ -118,6 +150,9 @@ definitions:
company_id:
example: 1
type: integer
id:
example: 1
type: integer
is_self_owned:
example: false
type: boolean
@ -148,30 +183,6 @@ definitions:
type: boolean
type: object
handlers.CreateBetReq:
properties:
amount:
example: 100
type: number
full_name:
example: John
type: string
is_shop_bet:
example: false
type: boolean
outcomes:
items:
type: integer
type: array
phone_number:
example: "1234567890"
type: string
status:
allOf:
- $ref: '#/definitions/domain.BetStatus'
example: 1
total_odds:
example: 4.22
type: number
type: object
handlers.CreateBranchOperationReq:
properties:
@ -206,6 +217,9 @@ definitions:
type: object
handlers.CreateCashierReq:
properties:
branch_id:
example: 1
type: integer
email:
example: john.doe@example.com
type: string
@ -224,9 +238,6 @@ definitions:
type: object
handlers.CreateManagerReq:
properties:
branch_id:
example: 1
type: integer
email:
example: john.doe@example.com
type: string
@ -259,7 +270,7 @@ definitions:
type: number
outcomes:
items:
type: integer
$ref: '#/definitions/handlers.TicketOutcome'
type: array
total_odds:
example: 4.22
@ -267,6 +278,9 @@ definitions:
type: object
handlers.CreateTicketRes:
properties:
created_number:
example: 3
type: integer
fast_code:
example: 1234
type: integer
@ -318,9 +332,6 @@ definitions:
payment_method:
example: cash
type: string
receiver_id:
example: 1
type: integer
type: object
handlers.CustomerWalletRes:
properties:
@ -352,6 +363,13 @@ definitions:
static_updated_at:
type: string
type: object
handlers.NullableInt64:
properties:
valid:
type: boolean
value:
type: integer
type: object
handlers.RegisterCodeReq:
properties:
email:
@ -423,6 +441,15 @@ definitions:
example: SportsBook
type: string
type: object
handlers.TicketOutcome:
properties:
event_id:
example: 1
type: integer
odd_id:
example: 1
type: integer
type: object
handlers.TicketRes:
properties:
amount:
@ -433,7 +460,7 @@ definitions:
type: integer
outcomes:
items:
$ref: '#/definitions/domain.Outcome'
$ref: '#/definitions/domain.TicketOutcome'
type: array
total_odds:
example: 4.22
@ -483,7 +510,7 @@ definitions:
example: true
type: boolean
type: object
handlers.TransferRes:
handlers.TransferWalletRes:
properties:
amount:
example: 100
@ -1055,6 +1082,31 @@ paths:
summary: Updates a branch
tags:
- branch
/branch/{id}/bets:
get:
consumes:
- application/json
description: Gets bets by its branch id
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/handlers.BetRes'
type: array
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Gets bets by its branch id
tags:
- branch
/branch/{id}/operation:
get:
consumes:
@ -1120,6 +1172,31 @@ paths:
summary: Delete the branch operation
tags:
- branch
/branchWallet:
get:
consumes:
- application/json
description: Retrieve all branch wallets
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/handlers.WalletRes'
type: array
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get all branch wallets
tags:
- wallet
/cashiers:
get:
consumes:
@ -1418,6 +1495,37 @@ paths:
summary: Create a operation
tags:
- branch
/search/branch:
get:
consumes:
- application/json
description: Search branches by name or location
parameters:
- description: Search query
in: query
name: q
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/handlers.BranchDetailRes'
type: array
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Search branches
tags:
- branch
/supportedOperation:
get:
consumes:
@ -1672,7 +1780,37 @@ paths:
summary: Updates the cashed out field
tags:
- transaction
/transfer/wallet:
/transfer/refill/:id:
post:
consumes:
- application/json
description: Super Admin route to refill a wallet
parameters:
- description: Create Transfer
in: body
name: refillWallet
required: true
schema:
$ref: '#/definitions/handlers.CreateTransferReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.TransferWalletRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Refill wallet
tags:
- transfer
/transfer/wallet/:id:
post:
consumes:
- application/json
@ -1690,7 +1828,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.TransferRes'
$ref: '#/definitions/handlers.TransferWalletRes'
"400":
description: Bad Request
schema:
@ -1702,6 +1840,36 @@ paths:
summary: Create a transfer to wallet
tags:
- transfer
/transfer/wallet/{id}:
get:
consumes:
- application/json
description: Get transfer by wallet
parameters:
- description: Create Transfer
in: body
name: transferToWallet
required: true
schema:
$ref: '#/definitions/handlers.CreateTransferReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.TransferWalletRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get transfer by wallet
tags:
- transfer
/user/checkPhoneEmailExist:
post:
consumes:

View File

@ -12,7 +12,17 @@ import (
)
const CreateBet = `-- name: CreateBet :one
INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet, cashout_id)
INSERT INTO bets (
amount,
total_odds,
status,
full_name,
phone_number,
branch_id,
user_id,
is_shop_bet,
cashout_id
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet
`
@ -60,8 +70,15 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro
return i, err
}
type CreateBetOutcomeParams struct {
BetID int64
EventID int64
OddID int64
}
const DeleteBet = `-- name: DeleteBet :exec
DELETE FROM bets WHERE id = $1
DELETE FROM bets
WHERE id = $1
`
func (q *Queries) DeleteBet(ctx context.Context, id int64) error {
@ -69,19 +86,30 @@ func (q *Queries) DeleteBet(ctx context.Context, id int64) error {
return err
}
const GetAllBets = `-- name: GetAllBets :many
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet FROM bets
const DeleteBetOutcome = `-- name: DeleteBetOutcome :exec
DELETE FROM bet_outcomes
WHERE bet_id = $1
`
func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) {
func (q *Queries) DeleteBetOutcome(ctx context.Context, betID int64) error {
_, err := q.db.Exec(ctx, DeleteBetOutcome, betID)
return err
}
const GetAllBets = `-- name: GetAllBets :many
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
FROM bet_with_outcomes
`
func (q *Queries) GetAllBets(ctx context.Context) ([]BetWithOutcome, error) {
rows, err := q.db.Query(ctx, GetAllBets)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Bet
var items []BetWithOutcome
for rows.Next() {
var i Bet
var i BetWithOutcome
if err := rows.Scan(
&i.ID,
&i.Amount,
@ -96,6 +124,7 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) {
&i.CreatedAt,
&i.UpdatedAt,
&i.IsShopBet,
&i.Outcomes,
); err != nil {
return nil, err
}
@ -107,13 +136,85 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) {
return items, nil
}
const GetBetByID = `-- name: GetBetByID :one
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet FROM bets WHERE id = $1
const GetBetByBranchID = `-- name: GetBetByBranchID :many
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
FROM bet_with_outcomes
WHERE branch_id = $1
`
func (q *Queries) GetBetByID(ctx context.Context, id int64) (Bet, error) {
func (q *Queries) GetBetByBranchID(ctx context.Context, branchID pgtype.Int8) ([]BetWithOutcome, error) {
rows, err := q.db.Query(ctx, GetBetByBranchID, branchID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []BetWithOutcome
for rows.Next() {
var i BetWithOutcome
if err := rows.Scan(
&i.ID,
&i.Amount,
&i.TotalOdds,
&i.Status,
&i.FullName,
&i.PhoneNumber,
&i.BranchID,
&i.UserID,
&i.CashedOut,
&i.CashoutID,
&i.CreatedAt,
&i.UpdatedAt,
&i.IsShopBet,
&i.Outcomes,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetBetByCashoutID = `-- name: GetBetByCashoutID :many
SELECT
FROM bet_with_outcomes
WHERE cashout_id = $1
`
type GetBetByCashoutIDRow struct {
}
func (q *Queries) GetBetByCashoutID(ctx context.Context, cashoutID string) ([]GetBetByCashoutIDRow, error) {
rows, err := q.db.Query(ctx, GetBetByCashoutID, cashoutID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetBetByCashoutIDRow
for rows.Next() {
var i GetBetByCashoutIDRow
if err := rows.Scan(); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetBetByID = `-- name: GetBetByID :one
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
FROM bet_with_outcomes
WHERE id = $1
`
func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, error) {
row := q.db.QueryRow(ctx, GetBetByID, id)
var i Bet
var i BetWithOutcome
err := row.Scan(
&i.ID,
&i.Amount,
@ -128,12 +229,16 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (Bet, error) {
&i.CreatedAt,
&i.UpdatedAt,
&i.IsShopBet,
&i.Outcomes,
)
return i, err
}
const UpdateCashOut = `-- name: UpdateCashOut :exec
UPDATE bets SET cashed_out = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1
UPDATE bets
SET cashed_out = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
`
type UpdateCashOutParams struct {

View File

@ -12,7 +12,16 @@ import (
)
const CreateBranch = `-- name: CreateBranch :one
INSERT INTO branches (name, location, wallet_id, branch_manager_id, company_id, is_self_owned) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at
INSERT INTO branches (
name,
location,
wallet_id,
branch_manager_id,
company_id,
is_self_owned
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at
`
type CreateBranchParams struct {
@ -48,8 +57,28 @@ func (q *Queries) CreateBranch(ctx context.Context, arg CreateBranchParams) (Bra
return i, err
}
const CreateBranchCashier = `-- name: CreateBranchCashier :one
INSERT INTO branch_cashiers (user_id, branch_id)
VALUES ($1, $2)
RETURNING id, user_id, branch_id
`
type CreateBranchCashierParams struct {
UserID int64
BranchID int64
}
func (q *Queries) CreateBranchCashier(ctx context.Context, arg CreateBranchCashierParams) (BranchCashier, error) {
row := q.db.QueryRow(ctx, CreateBranchCashier, arg.UserID, arg.BranchID)
var i BranchCashier
err := row.Scan(&i.ID, &i.UserID, &i.BranchID)
return i, err
}
const CreateBranchOperation = `-- name: CreateBranchOperation :one
INSERT INTO branch_operations (operation_id, branch_id) VALUES ($1, $2) RETURNING id, operation_id, branch_id, created_at, updated_at
INSERT INTO branch_operations (operation_id, branch_id)
VALUES ($1, $2)
RETURNING id, operation_id, branch_id, created_at, updated_at
`
type CreateBranchOperationParams struct {
@ -71,7 +100,9 @@ func (q *Queries) CreateBranchOperation(ctx context.Context, arg CreateBranchOpe
}
const CreateSupportedOperation = `-- name: CreateSupportedOperation :one
INSERT INTO supported_operations (name, description) VALUES ($1, $2) RETURNING id, name, description
INSERT INTO supported_operations (name, description)
VALUES ($1, $2)
RETURNING id, name, description
`
type CreateSupportedOperationParams struct {
@ -87,7 +118,8 @@ func (q *Queries) CreateSupportedOperation(ctx context.Context, arg CreateSuppor
}
const DeleteBranch = `-- name: DeleteBranch :exec
DELETE FROM branches WHERE id = $1
DELETE FROM branches
WHERE id = $1
`
func (q *Queries) DeleteBranch(ctx context.Context, id int64) error {
@ -95,8 +127,20 @@ func (q *Queries) DeleteBranch(ctx context.Context, id int64) error {
return err
}
const DeleteBranchCashier = `-- name: DeleteBranchCashier :exec
DELETE FROM branch_cashiers
WHERE user_id = $1
`
func (q *Queries) DeleteBranchCashier(ctx context.Context, userID int64) error {
_, err := q.db.Exec(ctx, DeleteBranchCashier, userID)
return err
}
const DeleteBranchOperation = `-- name: DeleteBranchOperation :exec
DELETE FROM branch_operations WHERE operation_id = $1 AND branch_id = $2
DELETE FROM branch_operations
WHERE operation_id = $1
AND branch_id = $2
`
type DeleteBranchOperationParams struct {
@ -110,7 +154,8 @@ func (q *Queries) DeleteBranchOperation(ctx context.Context, arg DeleteBranchOpe
}
const GetAllBranches = `-- name: GetAllBranches :many
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number FROM branch_details
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
FROM branch_details
`
func (q *Queries) GetAllBranches(ctx context.Context) ([]BranchDetail, error) {
@ -145,8 +190,49 @@ func (q *Queries) GetAllBranches(ctx context.Context) ([]BranchDetail, error) {
return items, nil
}
const GetAllCashiers = `-- name: GetAllCashiers :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.suspended_at, users.suspended
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
`
func (q *Queries) GetAllCashiers(ctx context.Context) ([]User, error) {
rows, err := q.db.Query(ctx, GetAllCashiers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.SuspendedAt,
&i.Suspended,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllSupportedOperations = `-- name: GetAllSupportedOperations :many
SELECT id, name, description FROM supported_operations
SELECT id, name, description
FROM supported_operations
`
func (q *Queries) GetAllSupportedOperations(ctx context.Context) ([]SupportedOperation, error) {
@ -169,8 +255,34 @@ func (q *Queries) GetAllSupportedOperations(ctx context.Context) ([]SupportedOpe
return items, nil
}
const GetBranchByCashier = `-- name: GetBranchByCashier :one
SELECT branches.id, branches.name, branches.location, branches.wallet_id, branches.branch_manager_id, branches.company_id, branches.is_self_owned, branches.created_at, branches.updated_at
FROM branch_cashiers
JOIN branches ON branch_cashiers.branch_id = branches.id
WHERE branch_cashiers.user_id = $1
`
func (q *Queries) GetBranchByCashier(ctx context.Context, userID int64) (Branch, error) {
row := q.db.QueryRow(ctx, GetBranchByCashier, userID)
var i Branch
err := row.Scan(
&i.ID,
&i.Name,
&i.Location,
&i.WalletID,
&i.BranchManagerID,
&i.CompanyID,
&i.IsSelfOwned,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetBranchByCompanyID = `-- name: GetBranchByCompanyID :many
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number FROM branch_details WHERE company_id = $1
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
FROM branch_details
WHERE company_id = $1
`
func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]BranchDetail, error) {
@ -206,7 +318,9 @@ func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]
}
const GetBranchByID = `-- name: GetBranchByID :one
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number FROM branch_details WHERE id = $1
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
FROM branch_details
WHERE id = $1
`
func (q *Queries) GetBranchByID(ctx context.Context, id int64) (BranchDetail, error) {
@ -229,7 +343,9 @@ func (q *Queries) GetBranchByID(ctx context.Context, id int64) (BranchDetail, er
}
const GetBranchByManagerID = `-- name: GetBranchByManagerID :many
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number FROM branch_details WHERE branch_manager_id = $1
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
FROM branch_details
WHERE branch_manager_id = $1
`
func (q *Queries) GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]BranchDetail, error) {
@ -265,7 +381,9 @@ func (q *Queries) GetBranchByManagerID(ctx context.Context, branchManagerID int6
}
const GetBranchOperations = `-- name: GetBranchOperations :many
SELECT branch_operations.id, branch_operations.operation_id, branch_operations.branch_id, branch_operations.created_at, branch_operations.updated_at, supported_operations.name, supported_operations.description
SELECT branch_operations.id, branch_operations.operation_id, branch_operations.branch_id, branch_operations.created_at, branch_operations.updated_at,
supported_operations.name,
supported_operations.description
FROM branch_operations
JOIN supported_operations ON branch_operations.operation_id = supported_operations.id
WHERE branch_operations.branch_id = $1
@ -309,8 +427,51 @@ func (q *Queries) GetBranchOperations(ctx context.Context, branchID int64) ([]Ge
return items, nil
}
const GetCashiersByBranch = `-- name: GetCashiersByBranch :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.suspended_at, users.suspended
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
WHERE branch_cashiers.branch_id = $1
`
func (q *Queries) GetCashiersByBranch(ctx context.Context, branchID int64) ([]User, error) {
rows, err := q.db.Query(ctx, GetCashiersByBranch, branchID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.SuspendedAt,
&i.Suspended,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchBranchByName = `-- name: SearchBranchByName :many
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number FROM branch_details WHERE name ILIKE '%' || $1 || '%'
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
FROM branch_details
WHERE name ILIKE '%' || $1 || '%'
`
func (q *Queries) SearchBranchByName(ctx context.Context, dollar_1 pgtype.Text) ([]BranchDetail, error) {
@ -346,7 +507,14 @@ func (q *Queries) SearchBranchByName(ctx context.Context, dollar_1 pgtype.Text)
}
const UpdateBranch = `-- name: UpdateBranch :one
UPDATE branches SET name = $1, location = $2, branch_manager_id = $3, company_id = $4, is_self_owned = $5 WHERE id = $6 RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at
UPDATE branches
SET name = $1,
location = $2,
branch_manager_id = $3,
company_id = $4,
is_self_owned = $5
WHERE id = $6
RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at
`
type UpdateBranchParams struct {

78
gen/db/copyfrom.go Normal file
View File

@ -0,0 +1,78 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.28.0
// source: copyfrom.go
package dbgen
import (
"context"
)
// iteratorForCreateBetOutcome implements pgx.CopyFromSource.
type iteratorForCreateBetOutcome struct {
rows []CreateBetOutcomeParams
skippedFirstNextCall bool
}
func (r *iteratorForCreateBetOutcome) Next() bool {
if len(r.rows) == 0 {
return false
}
if !r.skippedFirstNextCall {
r.skippedFirstNextCall = true
return true
}
r.rows = r.rows[1:]
return len(r.rows) > 0
}
func (r iteratorForCreateBetOutcome) Values() ([]interface{}, error) {
return []interface{}{
r.rows[0].BetID,
r.rows[0].EventID,
r.rows[0].OddID,
}, nil
}
func (r iteratorForCreateBetOutcome) Err() error {
return nil
}
func (q *Queries) CreateBetOutcome(ctx context.Context, arg []CreateBetOutcomeParams) (int64, error) {
return q.db.CopyFrom(ctx, []string{"bet_outcomes"}, []string{"bet_id", "event_id", "odd_id"}, &iteratorForCreateBetOutcome{rows: arg})
}
// iteratorForCreateTicketOutcome implements pgx.CopyFromSource.
type iteratorForCreateTicketOutcome struct {
rows []CreateTicketOutcomeParams
skippedFirstNextCall bool
}
func (r *iteratorForCreateTicketOutcome) Next() bool {
if len(r.rows) == 0 {
return false
}
if !r.skippedFirstNextCall {
r.skippedFirstNextCall = true
return true
}
r.rows = r.rows[1:]
return len(r.rows) > 0
}
func (r iteratorForCreateTicketOutcome) Values() ([]interface{}, error) {
return []interface{}{
r.rows[0].TicketID,
r.rows[0].EventID,
r.rows[0].OddID,
}, nil
}
func (r iteratorForCreateTicketOutcome) Err() error {
return nil
}
func (q *Queries) CreateTicketOutcome(ctx context.Context, arg []CreateTicketOutcomeParams) (int64, error) {
return q.db.CopyFrom(ctx, []string{"ticket_outcomes"}, []string{"ticket_id", "event_id", "odd_id"}, &iteratorForCreateTicketOutcome{rows: arg})
}

View File

@ -15,6 +15,7 @@ type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error)
}
func New(db DBTX) *Queries {

View File

@ -24,6 +24,30 @@ type Bet struct {
IsShopBet bool
}
type BetOutcome struct {
ID int64
BetID int64
EventID int64
OddID int64
}
type BetWithOutcome struct {
ID int64
Amount int64
TotalOdds float32
Status int32
FullName string
PhoneNumber string
BranchID pgtype.Int8
UserID pgtype.Int8
CashedOut bool
CashoutID string
CreatedAt pgtype.Timestamp
UpdatedAt pgtype.Timestamp
IsShopBet bool
Outcomes []BetOutcome
}
type Branch struct {
ID int64
Name string
@ -36,6 +60,12 @@ type Branch struct {
UpdatedAt pgtype.Timestamp
}
type BranchCashier struct {
ID int64
UserID int64
BranchID int64
}
type BranchDetail struct {
ID int64
Name string
@ -120,6 +150,22 @@ type Ticket struct {
UpdatedAt pgtype.Timestamp
}
type TicketOutcome struct {
ID int64
TicketID int64
EventID int64
OddID int64
}
type TicketWithOutcome struct {
ID int64
Amount pgtype.Int8
TotalOdds float32
CreatedAt pgtype.Timestamp
UpdatedAt pgtype.Timestamp
Outcomes []TicketOutcome
}
type Transaction struct {
ID int64
Amount int64

View File

@ -35,8 +35,15 @@ func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Tic
return i, err
}
type CreateTicketOutcomeParams struct {
TicketID int64
EventID int64
OddID int64
}
const DeleteOldTickets = `-- name: DeleteOldTickets :exec
Delete from tickets where created_at < now() - interval '1 day'
Delete from tickets
where created_at < now() - interval '1 day'
`
func (q *Queries) DeleteOldTickets(ctx context.Context) error {
@ -45,7 +52,8 @@ func (q *Queries) DeleteOldTickets(ctx context.Context) error {
}
const DeleteTicket = `-- name: DeleteTicket :exec
DELETE FROM tickets WHERE id = $1
DELETE FROM tickets
WHERE id = $1
`
func (q *Queries) DeleteTicket(ctx context.Context, id int64) error {
@ -53,25 +61,37 @@ func (q *Queries) DeleteTicket(ctx context.Context, id int64) error {
return err
}
const GetAllTickets = `-- name: GetAllTickets :many
SELECT id, amount, total_odds, created_at, updated_at FROM tickets
const DeleteTicketOutcome = `-- name: DeleteTicketOutcome :exec
Delete from ticket_outcomes
where ticket_id = $1
`
func (q *Queries) GetAllTickets(ctx context.Context) ([]Ticket, error) {
func (q *Queries) DeleteTicketOutcome(ctx context.Context, ticketID int64) error {
_, err := q.db.Exec(ctx, DeleteTicketOutcome, ticketID)
return err
}
const GetAllTickets = `-- name: GetAllTickets :many
SELECT id, amount, total_odds, created_at, updated_at, outcomes
FROM ticket_with_outcomes
`
func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error) {
rows, err := q.db.Query(ctx, GetAllTickets)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Ticket
var items []TicketWithOutcome
for rows.Next() {
var i Ticket
var i TicketWithOutcome
if err := rows.Scan(
&i.ID,
&i.Amount,
&i.TotalOdds,
&i.CreatedAt,
&i.UpdatedAt,
&i.Outcomes,
); err != nil {
return nil, err
}
@ -84,18 +104,52 @@ func (q *Queries) GetAllTickets(ctx context.Context) ([]Ticket, error) {
}
const GetTicketByID = `-- name: GetTicketByID :one
SELECT id, amount, total_odds, created_at, updated_at FROM tickets WHERE id = $1
SELECT id, amount, total_odds, created_at, updated_at, outcomes
FROM ticket_with_outcomes
WHERE id = $1
`
func (q *Queries) GetTicketByID(ctx context.Context, id int64) (Ticket, error) {
func (q *Queries) GetTicketByID(ctx context.Context, id int64) (TicketWithOutcome, error) {
row := q.db.QueryRow(ctx, GetTicketByID, id)
var i Ticket
var i TicketWithOutcome
err := row.Scan(
&i.ID,
&i.Amount,
&i.TotalOdds,
&i.CreatedAt,
&i.UpdatedAt,
&i.Outcomes,
)
return i, err
}
const GetTicketOutcome = `-- name: GetTicketOutcome :many
SELECT id, ticket_id, event_id, odd_id
FROM ticket_outcomes
WHERE ticket_id = $1
`
func (q *Queries) GetTicketOutcome(ctx context.Context, ticketID int64) ([]TicketOutcome, error) {
rows, err := q.db.Query(ctx, GetTicketOutcome, ticketID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []TicketOutcome
for rows.Next() {
var i TicketOutcome
if err := rows.Scan(
&i.ID,
&i.TicketID,
&i.EventID,
&i.OddID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@ -12,9 +12,18 @@ import (
)
const CheckPhoneEmailExist = `-- name: CheckPhoneEmailExist :one
SELECT
EXISTS (SELECT 1 FROM users WHERE users.phone_number = $1 AND users.phone_number IS NOT NULL) AS phone_exists,
EXISTS (SELECT 1 FROM users WHERE users.email = $2 AND users.email IS NOT NULL) AS email_exists
SELECT EXISTS (
SELECT 1
FROM users
WHERE users.phone_number = $1
AND users.phone_number IS NOT NULL
) AS phone_exists,
EXISTS (
SELECT 1
FROM users
WHERE users.email = $2
AND users.email IS NOT NULL
) AS email_exists
`
type CheckPhoneEmailExistParams struct {
@ -35,10 +44,29 @@ func (q *Queries) CheckPhoneEmailExist(ctx context.Context, arg CheckPhoneEmailE
}
const CreateUser = `-- name: CreateUser :one
INSERT INTO users (first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at)
INSERT INTO users (
first_name,
last_name,
email,
phone_number,
role,
password,
email_verified,
phone_verified,
created_at,
updated_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
RETURNING id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
`
type CreateUserParams struct {
@ -107,7 +135,16 @@ func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
}
const GetAllUsers = `-- name: GetAllUsers :many
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
`
@ -156,7 +193,16 @@ func (q *Queries) GetAllUsers(ctx context.Context) ([]GetAllUsersRow, error) {
}
const GetUserByEmail = `-- name: GetUserByEmail :one
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
WHERE email = $1
`
@ -220,7 +266,16 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
}
const GetUserByPhone = `-- name: GetUserByPhone :one
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
WHERE phone_number = $1
`
@ -257,7 +312,16 @@ func (q *Queries) GetUserByPhone(ctx context.Context, phoneNumber pgtype.Text) (
}
const SearchUserByNameOrPhone = `-- name: SearchUserByNameOrPhone :many
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
SELECT id,
first_name,
last_name,
email,
phone_number,
role,
email_verified,
phone_verified,
created_at,
updated_at
FROM users
WHERE first_name ILIKE '%' || $1 || '%'
OR last_name ILIKE '%' || $1 || '%'
@ -310,8 +374,12 @@ func (q *Queries) SearchUserByNameOrPhone(ctx context.Context, dollar_1 pgtype.T
const UpdatePassword = `-- name: UpdatePassword :exec
UPDATE users
SET password = $1, updated_at = $4
WHERE (email = $2 OR phone_number = $3)
SET password = $1,
updated_at = $4
WHERE (
email = $2
OR phone_number = $3
)
`
type UpdatePasswordParams struct {
@ -333,7 +401,12 @@ func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams)
const UpdateUser = `-- name: UpdateUser :exec
UPDATE users
SET first_name = $1, last_name = $2, email = $3, phone_number = $4, role = $5, updated_at = $6
SET first_name = $1,
last_name = $2,
email = $3,
phone_number = $4,
role = $5,
updated_at = $6
WHERE id = $7
`

View File

@ -12,7 +12,14 @@ import (
)
const CreateCustomerWallet = `-- name: CreateCustomerWallet :one
INSERT INTO customer_wallets (customer_id, company_id, regular_wallet_id, static_wallet_id) VALUES ($1, $2, $3, $4) RETURNING id, customer_id, company_id, regular_wallet_id, static_wallet_id, created_at, updated_at
INSERT INTO customer_wallets (
customer_id,
company_id,
regular_wallet_id,
static_wallet_id
)
VALUES ($1, $2, $3, $4)
RETURNING id, customer_id, company_id, regular_wallet_id, static_wallet_id, created_at, updated_at
`
type CreateCustomerWalletParams struct {
@ -43,7 +50,14 @@ func (q *Queries) CreateCustomerWallet(ctx context.Context, arg CreateCustomerWa
}
const CreateWallet = `-- name: CreateWallet :one
INSERT INTO wallets (is_withdraw, is_bettable, is_transferable, user_id) VALUES ($1, $2, $3, $4) RETURNING id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at
INSERT INTO wallets (
is_withdraw,
is_bettable,
is_transferable,
user_id
)
VALUES ($1, $2, $3, $4)
RETURNING id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at
`
type CreateWalletParams struct {
@ -75,8 +89,68 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
return i, err
}
const GetAllBranchWallets = `-- name: GetAllBranchWallets :many
SELECT wallets.id,
wallets.balance,
wallets.is_active,
wallets.updated_at,
wallets.created_at,
branches.name,
branches.location,
branches.branch_manager_id,
branches.company_id,
branches.is_self_owned
FROM branches
JOIN wallets ON branches.wallet_id = wallets.id
`
type GetAllBranchWalletsRow struct {
ID int64
Balance int64
IsActive bool
UpdatedAt pgtype.Timestamp
CreatedAt pgtype.Timestamp
Name string
Location string
BranchManagerID int64
CompanyID int64
IsSelfOwned bool
}
func (q *Queries) GetAllBranchWallets(ctx context.Context) ([]GetAllBranchWalletsRow, error) {
rows, err := q.db.Query(ctx, GetAllBranchWallets)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetAllBranchWalletsRow
for rows.Next() {
var i GetAllBranchWalletsRow
if err := rows.Scan(
&i.ID,
&i.Balance,
&i.IsActive,
&i.UpdatedAt,
&i.CreatedAt,
&i.Name,
&i.Location,
&i.BranchManagerID,
&i.CompanyID,
&i.IsSelfOwned,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllWallets = `-- name: GetAllWallets :many
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at FROM wallets
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at
FROM wallets
`
func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
@ -110,8 +184,7 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
}
const GetCustomerWallet = `-- name: GetCustomerWallet :one
SELECT
cw.id,
SELECT cw.id,
cw.customer_id,
cw.company_id,
rw.id AS regular_id,
@ -124,7 +197,8 @@ SELECT
FROM customer_wallets cw
JOIN wallets rw ON cw.regular_wallet_id = rw.id
JOIN wallets sw ON cw.static_wallet_id = sw.id
WHERE cw.customer_id = $1 AND cw.company_id = $2
WHERE cw.customer_id = $1
AND cw.company_id = $2
`
type GetCustomerWalletParams struct {
@ -164,7 +238,9 @@ func (q *Queries) GetCustomerWallet(ctx context.Context, arg GetCustomerWalletPa
}
const GetWalletByID = `-- name: GetWalletByID :one
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at FROM wallets WHERE id = $1
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at
FROM wallets
WHERE id = $1
`
func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
@ -185,7 +261,9 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
}
const GetWalletByUserID = `-- name: GetWalletByUserID :many
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at FROM wallets WHERE user_id = $1
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at
FROM wallets
WHERE user_id = $1
`
func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet, error) {
@ -219,7 +297,10 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
}
const UpdateBalance = `-- name: UpdateBalance :exec
UPDATE wallets SET balance = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2
UPDATE wallets
SET balance = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2
`
type UpdateBalanceParams struct {
@ -233,7 +314,10 @@ func (q *Queries) UpdateBalance(ctx context.Context, arg UpdateBalanceParams) er
}
const UpdateWalletActive = `-- name: UpdateWalletActive :exec
UPDATE wallets SET is_active = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2
UPDATE wallets
SET is_active = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2
`
type UpdateWalletActiveParams struct {

View File

@ -1,5 +1,18 @@
package domain
type BetOutcome struct {
ID int64
BetID int64
EventID int64
OddID int64
}
type CreateBetOutcome struct {
BetID int64
EventID int64
OddID int64
}
type BetStatus int
const (
@ -13,7 +26,6 @@ const (
// If it is a DigitalBet then UserID will be the user and the branchID will be 0 or nil
type Bet struct {
ID int64
Outcomes []Outcome
Amount Currency
TotalOdds float32
Status BetStatus
@ -26,8 +38,22 @@ type Bet struct {
CashoutID string
}
type GetBet struct {
ID int64
Amount Currency
TotalOdds float32
Status BetStatus
FullName string
PhoneNumber string
BranchID ValidInt64 // Can Be Nullable
UserID ValidInt64 // Can Be Nullable
IsShopBet bool
CashedOut bool
CashoutID string
Outcomes []BetOutcome
}
type CreateBet struct {
Outcomes []int64
Amount Currency
TotalOdds float32
Status BetStatus

View File

@ -37,3 +37,5 @@ func (m Currency) String() string {
return fmt.Sprintf("$%.2f", x)
}

View File

@ -1,15 +1,33 @@
package domain
type TicketOutcome struct {
ID int64
TicketID int64
EventID int64
OddID int64
}
type CreateTicketOutcome struct {
TicketID int64
EventID int64
OddID int64
}
// ID will serve as the fast code since this doesn't need to be secure
type Ticket struct {
ID int64
Outcomes []Outcome
Amount Currency
TotalOdds float32
}
type GetTicket struct {
ID int64
Amount Currency
TotalOdds float32
Outcomes []TicketOutcome
}
type CreateTicket struct {
Outcomes []int64
Amount Currency
TotalOdds float32
}

View File

@ -42,7 +42,6 @@ type RegisterUserReq struct {
OtpMedium OtpMedium
}
type CreateUserReq struct {
BranchID int64
FirstName string
LastName string
Email string

View File

@ -34,6 +34,19 @@ type GetCustomerWallet struct {
CreatedAt time.Time
}
type BranchWallet struct {
ID int64
Balance Currency
IsActive bool
Name string
Location string
BranchManagerID int64
CompanyID int64
IsSelfOwned bool
UpdatedAt time.Time
CreatedAt time.Time
}
type CreateWallet struct {
IsWithdraw bool
IsBettable bool

View File

@ -30,6 +30,39 @@ func convertDBBet(bet dbgen.Bet) domain.Bet {
}
}
func convertDBBetOutcomes(bet dbgen.BetWithOutcome) domain.GetBet {
var outcomes []domain.BetOutcome = make([]domain.BetOutcome, len(bet.Outcomes))
for _, outcome := range bet.Outcomes {
outcomes = append(outcomes, domain.BetOutcome{
ID: outcome.ID,
BetID: outcome.BetID,
EventID: outcome.EventID,
OddID: outcome.OddID,
})
}
return domain.GetBet{
ID: bet.ID,
Amount: domain.Currency(bet.Amount),
TotalOdds: bet.TotalOdds,
Status: domain.BetStatus(bet.Status),
FullName: bet.FullName,
PhoneNumber: bet.PhoneNumber,
BranchID: domain.ValidInt64{
Value: bet.BranchID.Int64,
Valid: bet.BranchID.Valid,
},
UserID: domain.ValidInt64{
Value: bet.UserID.Int64,
Valid: bet.UserID.Valid,
},
IsShopBet: bet.IsShopBet,
CashedOut: bet.CashedOut,
CashoutID: bet.CashoutID,
Outcomes: outcomes,
}
}
func convertCreateBet(bet domain.CreateBet) dbgen.CreateBetParams {
return dbgen.CreateBetParams{
Amount: int64(bet.Amount),
@ -51,7 +84,6 @@ func convertCreateBet(bet domain.CreateBet) dbgen.CreateBetParams {
}
func (s *Store) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
newBet, err := s.queries.CreateBet(ctx, convertCreateBet(bet))
if err != nil {
return domain.Bet{}, err
@ -60,25 +92,62 @@ func (s *Store) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet
}
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.Bet, error) {
func (s *Store) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error) {
var dbParams []dbgen.CreateBetOutcomeParams = make([]dbgen.CreateBetOutcomeParams, 0, len(outcomes))
for _, outcome := range outcomes {
dbParams = append(dbParams, dbgen.CreateBetOutcomeParams{
BetID: outcome.BetID,
EventID: outcome.EventID,
OddID: outcome.OddID,
})
}
rows, err := s.queries.CreateBetOutcome(ctx, dbParams)
if err != nil {
return rows, err
}
return rows, nil
}
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
bet, err := s.queries.GetBetByID(ctx, id)
if err != nil {
return domain.Bet{}, err
return domain.GetBet{}, err
}
return convertDBBet(bet), nil
return convertDBBetOutcomes(bet), nil
}
func (s *Store) GetAllBets(ctx context.Context) ([]domain.Bet, error) {
func (s *Store) GetAllBets(ctx context.Context) ([]domain.GetBet, error) {
bets, err := s.queries.GetAllBets(ctx)
if err != nil {
return nil, err
}
var result []domain.Bet = make([]domain.Bet, 0, len(bets))
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets {
result = append(result, convertDBBet(bet))
result = append(result, convertDBBetOutcomes(bet))
}
return result, nil
}
func (s *Store) GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error) {
bets, err := s.queries.GetBetByBranchID(ctx, pgtype.Int8{
Int64: BranchID,
Valid: true,
})
if err != nil {
return nil, err
}
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
for _, bet := range bets {
result = append(result, convertDBBetOutcomes(bet))
}
return result, nil

View File

@ -154,6 +154,18 @@ func (s *Store) CreateSupportedOperation(ctx context.Context, supportedOperation
}, nil
}
func (s *Store) CreateBranchCashier(ctx context.Context, branchID int64, userID int64) error {
_, err := s.queries.CreateBranchCashier(ctx, dbgen.CreateBranchCashierParams{
UserID: userID,
BranchID: branchID,
})
if err != nil {
return err
}
return nil
}
func (s *Store) GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error) {
dbOperations, err := s.queries.GetAllSupportedOperations(ctx)
if err != nil {
@ -188,6 +200,16 @@ func (s *Store) GetBranchOperations(ctx context.Context, branchID int64) ([]doma
return branchOperations, nil
}
func (s *Store) GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error) {
branch, err := s.queries.GetBranchByCashier(ctx, userID)
if err != nil {
return domain.Branch{}, err
}
return convertDBBranch(branch), err
}
func (s *Store) DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error {
err := s.queries.DeleteBranchOperation(ctx, dbgen.DeleteBranchOperationParams{
BranchID: branchID,
@ -195,3 +217,8 @@ func (s *Store) DeleteBranchOperation(ctx context.Context, branchID int64, opera
})
return err
}
func (s *Store) DeleteBranchCashier(ctx context.Context, userID int64) error {
return s.queries.DeleteBranchCashier(ctx, userID)
}

View File

@ -14,6 +14,27 @@ func convertDBTicket(ticket dbgen.Ticket) domain.Ticket {
Amount: domain.Currency(ticket.Amount.Int64),
TotalOdds: ticket.TotalOdds,
}
}
func convertDBTicketOutcomes(ticket dbgen.TicketWithOutcome) domain.GetTicket {
var outcomes []domain.TicketOutcome = make([]domain.TicketOutcome, 0, len(ticket.Outcomes))
for _, outcome := range ticket.Outcomes {
outcomes = append(outcomes, domain.TicketOutcome{
ID: outcome.ID,
TicketID: outcome.TicketID,
EventID: outcome.EventID,
OddID: outcome.OddID,
})
}
return domain.GetTicket{
ID: ticket.ID,
Amount: domain.Currency(ticket.Amount.Int64),
TotalOdds: ticket.TotalOdds,
Outcomes: outcomes,
}
}
func convertCreateTicket(ticket domain.CreateTicket) dbgen.CreateTicketParams {
@ -35,25 +56,45 @@ func (s *Store) CreateTicket(ctx context.Context, ticket domain.CreateTicket) (d
}
func (s *Store) GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) {
func (s *Store) CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error) {
var dbParams []dbgen.CreateTicketOutcomeParams = make([]dbgen.CreateTicketOutcomeParams, 0, len(outcomes))
for _, outcome := range outcomes {
dbParams = append(dbParams, dbgen.CreateTicketOutcomeParams{
TicketID: outcome.TicketID,
EventID: outcome.EventID,
OddID: outcome.OddID,
})
}
rows, err := s.queries.CreateTicketOutcome(ctx, dbParams)
if err != nil {
return rows, err
}
return rows, nil
}
func (s *Store) GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error) {
ticket, err := s.queries.GetTicketByID(ctx, id)
if err != nil {
return domain.Ticket{}, err
return domain.GetTicket{}, err
}
return convertDBTicket(ticket), nil
return convertDBTicketOutcomes(ticket), nil
}
func (s *Store) GetAllTickets(ctx context.Context) ([]domain.Ticket, error) {
func (s *Store) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error) {
tickets, err := s.queries.GetAllTickets(ctx)
if err != nil {
return nil, err
}
var result []domain.Ticket = make([]domain.Ticket, 0, len(tickets))
var result []domain.GetTicket = make([]domain.GetTicket, 0, len(tickets))
for _, ticket := range tickets {
result = append(result, convertDBTicket(ticket))
result = append(result, convertDBTicketOutcomes(ticket))
}
return result, nil

View File

@ -102,6 +102,44 @@ func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.U
return userList, nil
}
func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.User, error) {
users, err := s.queries.GetAllCashiers(ctx)
if err != nil {
return nil, err
}
userList := make([]domain.User, len(users))
for i, user := range users {
userList[i] = domain.User{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email.String,
PhoneNumber: user.PhoneNumber.String,
Role: domain.Role(user.Role),
}
}
return userList, nil
}
func (s *Store) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) {
users, err := s.queries.GetCashiersByBranch(ctx, branchID)
if err != nil {
return nil, err
}
userList := make([]domain.User, len(users))
for i, user := range users {
userList[i] = domain.User{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email.String,
PhoneNumber: user.PhoneNumber.String,
Role: domain.Role(user.Role),
}
}
return userList, nil
}
func (s *Store) SearchUserByNameOrPhone(ctx context.Context, searchString string) ([]domain.User, error) {
users, err := s.queries.SearchUserByNameOrPhone(ctx, pgtype.Text{
String: searchString,
@ -234,6 +272,40 @@ func (s *Store) UpdatePassword(ctx context.Context, identifier string, password
}
return nil
}
func (s *Store) CreateUserWithoutOtp(ctx context.Context, user domain.CreateUserReq) (domain.User, error) {
return domain.User{}, nil
func (s *Store) CreateUserWithoutOtp(ctx context.Context, user domain.User) (domain.User, error) {
userRes, err := s.queries.CreateUser(ctx, dbgen.CreateUserParams{
FirstName: user.FirstName,
LastName: user.LastName,
Email: pgtype.Text{
String: user.Email,
Valid: user.Email != "",
},
PhoneNumber: pgtype.Text{
String: user.PhoneNumber,
Valid: user.PhoneNumber != "",
},
Password: user.Password,
Role: string(user.Role),
EmailVerified: user.EmailVerified,
PhoneVerified: user.PhoneVerified,
CreatedAt: pgtype.Timestamptz{
Time: time.Now(),
Valid: true,
},
UpdatedAt: pgtype.Timestamptz{
Time: time.Now(),
Valid: true,
},
})
if err != nil {
return domain.User{}, err
}
return domain.User{
ID: userRes.ID,
FirstName: userRes.FirstName,
LastName: userRes.LastName,
Email: userRes.Email.String,
PhoneNumber: userRes.PhoneNumber.String,
Role: domain.Role(userRes.Role),
}, nil
}

View File

@ -129,6 +129,31 @@ func (s *Store) GetCustomerWallet(ctx context.Context, customerID int64, company
return convertDBGetCustomerWallet(customerWallet), nil
}
func (s *Store) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error) {
wallets, err := s.queries.GetAllBranchWallets(ctx)
if err != nil {
return nil, err
}
var result []domain.BranchWallet = make([]domain.BranchWallet, 0, len(wallets))
for _, wallet := range wallets {
result = append(result, domain.BranchWallet{
ID: wallet.ID,
Balance: domain.Currency(wallet.Balance),
IsActive: wallet.IsActive,
UpdatedAt: wallet.UpdatedAt.Time,
CreatedAt: wallet.CreatedAt.Time,
Name: wallet.Name,
Location: wallet.Location,
BranchManagerID: wallet.BranchManagerID,
CompanyID: wallet.CompanyID,
IsSelfOwned: wallet.IsSelfOwned,
})
}
return result, nil
}
func (s *Store) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
err := s.queries.UpdateBalance(ctx, dbgen.UpdateBalanceParams{
ID: id,

View File

@ -8,8 +8,10 @@ import (
type BetStore interface {
CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error)
GetBetByID(ctx context.Context, id int64) (domain.Bet, error)
GetAllBets(ctx context.Context) ([]domain.Bet, error)
CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error)
GetBetByID(ctx context.Context, id int64) (domain.GetBet, error)
GetAllBets(ctx context.Context) ([]domain.GetBet, error)
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
DeleteBet(ctx context.Context, id int64) error
}

View File

@ -19,13 +19,22 @@ func NewService(betStore BetStore) *Service {
func (s *Service) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
return s.betStore.CreateBet(ctx, bet)
}
func (s *Service) GetBetByID(ctx context.Context, id int64) (domain.Bet, error) {
func (s *Service) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error) {
return s.betStore.CreateBetOutcome(ctx, outcomes)
}
func (s *Service) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
return s.betStore.GetBetByID(ctx, id)
}
func (s *Service) GetAllBets(ctx context.Context) ([]domain.Bet, error) {
func (s *Service) GetAllBets(ctx context.Context) ([]domain.GetBet, error) {
return s.betStore.GetAllBets(ctx)
}
func (s *Service) GetBetByBranchID(ctx context.Context, branchID int64) ([]domain.GetBet, error) {
return s.betStore.GetBetByBranchID(ctx, branchID)
}
func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error {
return s.betStore.UpdateCashOut(ctx, id, cashedOut)
}

View File

@ -8,16 +8,19 @@ import (
type BranchStore interface {
CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error)
CreateSupportedOperation(ctx context.Context, supportedOperation domain.CreateSupportedOperation) (domain.SupportedOperation, error)
CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error
GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error)
GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]domain.BranchDetail, error)
GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error)
GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error)
GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error)
GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error)
SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error)
UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error)
DeleteBranch(ctx context.Context, id int64) error
CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error
CreateSupportedOperation(ctx context.Context, supportedOperation domain.CreateSupportedOperation) (domain.SupportedOperation, error)
GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error)
GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error)
DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error
CreateBranchCashier(ctx context.Context, branchID int64, userID int64) error
GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error)
DeleteBranchCashier(ctx context.Context, userID int64) error
}

View File

@ -25,6 +25,11 @@ func (s *Service) CreateSupportedOperation(ctx context.Context, supportedOperati
func (s *Service) CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error {
return s.branchStore.CreateBranchOperation(ctx, branchOperation)
}
func (s *Service) CreateBranchCashier(ctx context.Context, branchID int64, userID int64) error {
return s.branchStore.CreateBranchCashier(ctx, branchID, userID)
}
func (s *Service) GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error) {
return s.branchStore.GetBranchByID(ctx, id)
}
@ -41,6 +46,10 @@ func (s *Service) GetAllBranches(ctx context.Context) ([]domain.BranchDetail, er
return s.branchStore.GetAllBranches(ctx)
}
func (s *Service) GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error) {
return s.branchStore.GetBranchByCashier(ctx, userID)
}
func (s *Service) GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error) {
return s.branchStore.GetAllSupportedOperations(ctx)
}
@ -57,3 +66,7 @@ func (s *Service) DeleteBranch(ctx context.Context, id int64) error {
func (s *Service) DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error {
return s.branchStore.DeleteBranchOperation(ctx, branchID, operationID)
}
func (s *Service) DeleteBranchCashier(ctx context.Context, userID int64) error {
return s.branchStore.DeleteBranchCashier(ctx, userID)
}

View File

@ -8,8 +8,9 @@ import (
type TicketStore interface {
CreateTicket(ctx context.Context, ticket domain.CreateTicket) (domain.Ticket, error)
GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error)
GetAllTickets(ctx context.Context) ([]domain.Ticket, error)
CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error)
GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error)
GetAllTickets(ctx context.Context) ([]domain.GetTicket, error)
DeleteOldTickets(ctx context.Context) error
DeleteTicket(ctx context.Context, id int64) error
}

View File

@ -19,10 +19,15 @@ func NewService(ticketStore TicketStore) *Service {
func (s *Service) CreateTicket(ctx context.Context, ticket domain.CreateTicket) (domain.Ticket, error) {
return s.ticketStore.CreateTicket(ctx, ticket)
}
func (s *Service) GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) {
func (s *Service) CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error) {
return s.ticketStore.CreateTicketOutcome(ctx, outcomes)
}
func (s *Service) GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error) {
return s.ticketStore.GetTicketByID(ctx, id)
}
func (s *Service) GetAllTickets(ctx context.Context) ([]domain.Ticket, error) {
func (s *Service) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error) {
return s.ticketStore.GetAllTickets(ctx)
}
func (s *Service) DeleteTicket(ctx context.Context, id int64) error {

View File

@ -19,8 +19,21 @@ func (s *Service) CreateUser(ctx context.Context, User domain.CreateUserReq) (do
// User.BranchID = branchId
// User.Role = string(domain.RoleBranchManager)
// }
hashedPassword, err := hashPassword(User.Password)
if err != nil {
return domain.User{}, err
}
return s.userStore.CreateUserWithoutOtp(ctx, User)
return s.userStore.CreateUserWithoutOtp(ctx, domain.User{
FirstName: User.FirstName,
LastName: User.LastName,
Email: User.Email,
PhoneNumber: User.PhoneNumber,
Password: hashedPassword,
Role: domain.Role(User.Role),
EmailVerified: true,
PhoneVerified: true,
})
}
func (s *Service) DeleteUser(ctx context.Context, id int64) error {
@ -51,3 +64,11 @@ func (s *Service) GetUserById(ctx context.Context, id int64) (domain.User, error
return s.userStore.GetUserByID(ctx, id)
}
func (s *Service) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) {
return s.userStore.GetCashiersByBranch(ctx, branchID)
}
func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.User, error) {
return s.userStore.GetAllCashiers(ctx)
}

View File

@ -8,9 +8,11 @@ import (
type UserStore interface {
CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error)
CreateUserWithoutOtp(ctx context.Context, user domain.CreateUserReq) (domain.User, error)
CreateUserWithoutOtp(ctx context.Context, user domain.User) (domain.User, error)
GetUserByID(ctx context.Context, id int64) (domain.User, error)
GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, error)
GetAllCashiers(ctx context.Context) ([]domain.User, error)
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
DeleteUser(ctx context.Context, id int64) error
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error)

View File

@ -13,6 +13,7 @@ type WalletStore interface {
GetAllWallets(ctx context.Context) ([]domain.Wallet, error)
GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error)
GetCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.GetCustomerWallet, error)
GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error)
UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error
UpdateWalletActive(ctx context.Context, id int64, isActive bool) error
}
@ -24,4 +25,3 @@ type TransferStore interface {
GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error)
UpdateTransferVerification(ctx context.Context, id int64, verified bool) error
}

View File

@ -23,10 +23,43 @@ func (s *Service) GetTransferByID(ctx context.Context, id int64) (domain.Transfe
return s.transferStore.GetTransferByID(ctx, id)
}
func (s *Service) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error) {
return s.transferStore.GetTransfersByWallet(ctx, walletID)
}
func (s *Service) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error {
return s.transferStore.UpdateTransferVerification(ctx, id, verified)
}
func (s *Service) RefillWallet(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
receiverWallet, err := s.GetWalletByID(ctx, transfer.ReceiverWalletID)
if err != nil {
return domain.Transfer{}, err
}
// Add to receiver
err = s.walletStore.UpdateBalance(ctx, receiverWallet.ID, receiverWallet.Balance+transfer.Amount)
if err != nil {
return domain.Transfer{}, err
}
// Log the transfer so that if there is a mistake, it can be reverted
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
CashierID: transfer.CashierID,
ReceiverWalletID: receiverWallet.ID,
Amount: transfer.Amount,
Type: domain.DEPOSIT,
PaymentMethod: transfer.PaymentMethod,
Verified: true,
})
if err != nil {
return domain.Transfer{}, err
}
return newTransfer, nil
}
func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiverID int64, amount domain.Currency, paymentMethod domain.PaymentMethod, cashierID domain.ValidInt64) (domain.Transfer, error) {
senderWallet, err := s.GetWalletByID(ctx, senderID)

View File

@ -7,7 +7,6 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
var (
ErrBalanceInsufficient = errors.New("wallet balance is insufficient")
)
@ -62,6 +61,10 @@ func (s *Service) GetCustomerWallet(ctx context.Context, customerID int64, compa
return s.walletStore.GetCustomerWallet(ctx, customerID, companyID)
}
func (s *Service) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error) {
return s.walletStore.GetAllBranchWallets(ctx)
}
func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
return s.walletStore.UpdateBalance(ctx, id, balance)
}

View File

@ -1,30 +1,79 @@
package handlers
import (
"encoding/json"
"log/slog"
"strconv"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
)
type BetOutcome struct {
EventID int64 `json:"event_id" example:"1"`
OddID int64 `json:"odd_id" example:"1"`
}
type NullableInt64 struct {
Value int64
Valid bool
}
func (n *NullableInt64) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
n.Valid = false
return nil
}
var value int64
if err := json.Unmarshal(data, &value); err != nil {
return err
}
n.Value = value
n.Valid = true
return nil
}
func (n NullableInt64) MarshalJSON() ([]byte, error) {
if !n.Valid {
return []byte("null"), nil
}
return json.Marshal(n.Value)
}
type CreateBetReq struct {
Outcomes []int64 `json:"outcomes"`
Outcomes []BetOutcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
Status domain.BetStatus `json:"status" example:"1"`
FullName string `json:"full_name" example:"John"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
BranchID NullableInt64 `json:"branch_id" example:"1"`
}
type CreateBetRes struct {
ID int64 `json:"id" example:"1"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
Status domain.BetStatus `json:"status" example:"1"`
FullName string `json:"full_name" example:"John"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
BranchID int64 `json:"branch_id" example:"2"`
UserID int64 `json:"user_id" example:"2"`
IsShopBet bool `json:"is_shop_bet" example:"false"`
CreatedNumber int64 `json:"created_number" example:"2"`
}
type BetRes struct {
ID int64 `json:"id" example:"1"`
Outcomes []domain.Outcome `json:"outcomes"`
Outcomes []domain.BetOutcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
Status domain.BetStatus `json:"status" example:"1"`
@ -35,10 +84,23 @@ type BetRes struct {
IsShopBet bool `json:"is_shop_bet" example:"false"`
}
func convertBet(bet domain.Bet) BetRes {
func convertCreateBet(bet domain.Bet, createdNumber int64) CreateBetRes {
return CreateBetRes{
ID: bet.ID,
Amount: bet.Amount.Float64(),
TotalOdds: bet.TotalOdds,
Status: bet.Status,
FullName: bet.FullName,
PhoneNumber: bet.PhoneNumber,
BranchID: bet.BranchID.Value,
UserID: bet.UserID.Value,
CreatedNumber: createdNumber,
}
}
func convertBet(bet domain.GetBet) BetRes {
return BetRes{
ID: bet.ID,
Outcomes: bet.Outcomes,
Amount: bet.Amount.Float64(),
TotalOdds: bet.TotalOdds,
Status: bet.Status,
@ -60,15 +122,12 @@ func convertBet(bet domain.Bet) BetRes {
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /bet [post]
func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
func CreateBet(logger *slog.Logger, betSvc *bet.Service, userSvc *user.Service, branchSvc *branch.Service, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
// TODO if user is customer, get id from the token then get the wallet id from there
// TODO: If user is a cashier, check the token, and find the role and get the branch id from there. Reduce amount from the branch wallet
var isShopBet bool = true
var branchID int64 = 1
var userID int64
// Get user_id from middleware
userID := c.Locals("user_id").(int64)
var isShopBet bool
var req CreateBetReq
@ -85,12 +144,46 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalida
return nil
}
user, err := userSvc.GetUserByID(c.Context(), userID)
if user.Role != domain.RoleCustomer {
isShopBet = true
if !req.BranchID.Valid {
logger.Error("CreateBetReq failed, branch id necessary")
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Branch ID necessary",
})
}
// Get the branch from the branch ID
branch, err := branchSvc.GetBranchByID(c.Context(), req.BranchID.Value)
if err != nil {
logger.Error("CreateBetReq failed, branch id invalid")
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Branch ID invalid",
})
}
// Deduct a percentage of the amount
var deductedAmount = req.Amount / 10
err = walletSvc.DeductFromWallet(c.Context(), branch.WalletID, domain.Currency(deductedAmount))
if err != nil {
logger.Error("CreateBetReq failed, unable to deduct from WalletID", branch.WalletID)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Unable to deduct from branch wallet",
})
}
} else {
isShopBet = false
// TODO if user is customer, get id from the token then get the wallet id from there and reduce the amount
}
// TODO Validate Outcomes Here and make sure they didn't expire
cashoutUUID := uuid.New()
bet, err := betSvc.CreateBet(c.Context(), domain.CreateBet{
Outcomes: req.Outcomes,
Amount: domain.Currency(req.Amount),
TotalOdds: req.TotalOdds,
Status: req.Status,
@ -98,7 +191,7 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalida
PhoneNumber: req.PhoneNumber,
BranchID: domain.ValidInt64{
Value: branchID,
Value: req.BranchID.Value,
Valid: isShopBet,
},
UserID: domain.ValidInt64{
@ -113,8 +206,25 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalida
logger.Error("CreateBetReq failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
}
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
res := convertBet(bet)
for _, outcome := range req.Outcomes {
outcomes = append(outcomes, domain.CreateBetOutcome{
BetID: bet.ID,
EventID: outcome.EventID,
OddID: outcome.OddID,
})
}
rows, err := betSvc.CreateBetOutcome(c.Context(), outcomes)
if err != nil {
logger.Error("CreateBetReq failed to create outcomes", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Internal server error",
})
}
res := convertCreateBet(bet, rows)
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
}

View File

@ -5,6 +5,7 @@ import (
"strconv"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
@ -43,6 +44,7 @@ type BranchOperationRes struct {
}
type BranchRes struct {
ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"4-kilo Branch"`
Location string `json:"location" example:"Addis Ababa"`
WalletID int64 `json:"wallet_id" example:"1"`
@ -52,6 +54,7 @@ type BranchRes struct {
}
type BranchDetailRes struct {
ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"4-kilo Branch"`
Location string `json:"location" example:"Addis Ababa"`
WalletID int64 `json:"wallet_id" example:"1"`
@ -64,6 +67,7 @@ type BranchDetailRes struct {
func convertBranch(branch domain.Branch) BranchRes {
return BranchRes{
ID: branch.ID,
Name: branch.Name,
Location: branch.Location,
WalletID: branch.WalletID,
@ -75,6 +79,7 @@ func convertBranch(branch domain.Branch) BranchRes {
func convertBranchDetail(branch domain.BranchDetail) BranchDetailRes {
return BranchDetailRes{
ID: branch.ID,
Name: branch.Name,
Location: branch.Location,
WalletID: branch.WalletID,
@ -393,6 +398,42 @@ func GetAllBranches(logger *slog.Logger, branchSvc *branch.Service, validator *c
}
}
// SearchBranch godoc
// @Summary Search branches
// @Description Search branches by name or location
// @Tags branch
// @Accept json
// @Produce json
// @Param q query string true "Search query"
// @Success 200 {array} BranchDetailRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /search/branch [get]
func SearchBranch(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
// Get search query from request
searchQuery := c.Query("q")
if searchQuery == "" {
return response.WriteJSON(c, fiber.StatusBadRequest, "Search query is required", nil, nil)
}
// Call the service to search for branches
branches, err := branchSvc.SearchBranchByName(c.Context(), searchQuery)
if err != nil {
logger.Error("Failed to search branches", "query", searchQuery, "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to search branches", err, nil)
}
// Convert branches to response format
var result []BranchDetailRes
for _, branch := range branches {
result = append(result, convertBranchDetail(branch))
}
return response.WriteJSON(c, fiber.StatusOK, "Branches retrieved successfully", result, nil)
}
}
// GetAllSupportedOperations godoc
// @Summary Gets all supported operations
// @Description Gets all supported operations
@ -465,6 +506,41 @@ func GetBranchOperations(logger *slog.Logger, branchSvc *branch.Service, validat
}
}
// GetBetByBranchID godoc
// @Summary Gets bets by its branch id
// @Description Gets bets by its branch id
// @Tags branch
// @Accept json
// @Produce json
// @Success 200 {array} BetRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /branch/{id}/bets [get]
func GetBetByBranchID(logger *slog.Logger, betSvc *bet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
branchID := c.Params("id")
id, err := strconv.ParseInt(branchID, 10, 64)
if err != nil {
logger.Error("Invalid branch ID", "branchID", branchID, "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil)
}
bets, err := betSvc.GetBetByBranchID(c.Context(), id)
if err != nil {
logger.Error("Failed to get bets", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bets", err, nil)
}
var res []BetRes = make([]BetRes, 0, len(bets))
for _, bet := range bets {
res = append(res, convertBet(bet))
}
return response.WriteJSON(c, fiber.StatusOK, "Branch Bets Retrieved", res, nil)
}
}
// UpdateBranch godoc
// @Summary Updates a branch
// @Description Updates a branch

View File

@ -3,8 +3,10 @@ package handlers
import (
"log/slog"
"strconv"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
@ -17,6 +19,7 @@ type CreateCashierReq struct {
Email string `json:"email" example:"john.doe@example.com"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
Password string `json:"password" example:"password123"`
BranchID int64 `json:"branch_id" example:"1"`
}
// CreateCashier godoc
@ -31,10 +34,9 @@ type CreateCashierReq struct {
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /cashiers [post]
func CreateCashier(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
func CreateCashier(logger *slog.Logger, userSvc *user.Service, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
creatorBranch := c.Locals("branch_id").(int64)
var req CreateCashierReq
if err := c.BodyParser(&req); err != nil {
logger.Error("RegisterUser failed", "error", err)
@ -47,27 +49,49 @@ func CreateCashier(logger *slog.Logger, userSvc *user.Service, validator *custom
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return nil
}
user := domain.CreateUserReq{
userRequest := domain.CreateUserReq{
FirstName: req.FirstName,
LastName: req.LastName,
Email: req.Email,
PhoneNumber: req.PhoneNumber,
Password: req.Password,
Role: string(domain.RoleCashier),
BranchID: creatorBranch,
}
_, err := userSvc.CreateUser(c.Context(), user)
newUser, err := userSvc.CreateUser(c.Context(), userRequest)
if err != nil {
logger.Error("CreateCashier failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil)
return nil
}
err = branchSvc.CreateBranchCashier(c.Context(), req.BranchID, newUser.ID)
if err != nil {
logger.Error("CreateCashier failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil)
return nil
}
response.WriteJSON(c, fiber.StatusOK, "Cashier created successfully", nil, nil)
return nil
}
}
type GetCashierRes struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
PhoneNumber string `json:"phone_number"`
Role domain.Role `json:"role"`
EmailVerified bool `json:"email_verified"`
PhoneVerified bool `json:"phone_verified"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
SuspendedAt time.Time `json:"suspended_at"`
Suspended bool `json:"suspended"`
}
// GetAllCashiers godoc
// @Summary Get all cashiers
// @Description Get all cashiers
@ -83,28 +107,48 @@ func CreateCashier(logger *slog.Logger, userSvc *user.Service, validator *custom
// @Router /cashiers [get]
func GetAllCashiers(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
branchId := int64(12) //c.Locals("branch_id").(int64)
filter := user.Filter{
Role: string(domain.RoleCashier),
BranchId: user.ValidBranchId{
Value: branchId,
Valid: true,
},
Page: c.QueryInt("page", 1),
PageSize: c.QueryInt("page_size", 10),
}
valErrs, ok := validator.Validate(c, filter)
if !ok {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return nil
}
cashiers, err := userSvc.GetAllUsers(c.Context(), filter)
// branchId := int64(12) //c.Locals("branch_id").(int64)
// filter := user.Filter{
// Role: string(domain.RoleCashier),
// BranchId: user.ValidBranchId{
// Value: branchId,
// Valid: true,
// },
// Page: c.QueryInt("page", 1),
// PageSize: c.QueryInt("page_size", 10),
// }
// valErrs, ok := validator.Validate(c, filter)
// if !ok {
// response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
// return nil
// }
cashiers, err := userSvc.GetAllCashiers(c.Context())
if err != nil {
logger.Error("GetAllCashiers failed", "error", err)
response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
return nil
}
response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", cashiers, nil)
var result []GetCashierRes
for _, cashier := range cashiers {
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,
})
}
response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", result, nil)
return nil
}

View File

@ -17,7 +17,6 @@ type CreateManagerReq struct {
Email string `json:"email" example:"john.doe@example.com"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
Password string `json:"password" example:"password123"`
BranchId int64 `json:"branch_id" example:"1"`
}
// CreateManagers godoc
@ -53,7 +52,6 @@ func CreateManager(logger *slog.Logger, userSvc *user.Service, validator *custom
PhoneNumber: req.PhoneNumber,
Password: req.Password,
Role: string(domain.RoleBranchManager),
BranchID: req.BranchId,
}
_, err := userSvc.CreateUser(c.Context(), user)
if err != nil {

View File

@ -11,13 +11,19 @@ import (
"github.com/gofiber/fiber/v2"
)
type TicketOutcome struct {
EventID int64 `json:"event_id" example:"1"`
OddID int64 `json:"odd_id" example:"1"`
}
type CreateTicketReq struct {
Outcomes []int64 `json:"outcomes"`
Outcomes []TicketOutcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
}
type CreateTicketRes struct {
FastCode int64 `json:"fast_code" example:"1234"`
CreatedNumber int64 `json:"created_number" example:"3"`
}
// CreateTicket godoc
@ -51,7 +57,6 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
// TODO Validate Outcomes Here and make sure they didn't expire
ticket, err := ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
Outcomes: req.Outcomes,
Amount: domain.Currency(req.Amount),
TotalOdds: req.TotalOdds,
})
@ -61,8 +66,27 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
"error": "Internal server error",
})
}
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
for _, outcome := range req.Outcomes {
outcomes = append(outcomes, domain.CreateTicketOutcome{
TicketID: ticket.ID,
EventID: outcome.EventID,
OddID: outcome.OddID,
})
}
rows, err := ticketSvc.CreateTicketOutcome(c.Context(), outcomes)
if err != nil {
logger.Error("CreateTicketReq failed to create outcomes", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Internal server error",
})
}
res := CreateTicketRes{
FastCode: ticket.ID,
CreatedNumber: rows,
}
return response.WriteJSON(c, fiber.StatusOK, "Ticket Created", res, nil)
}
@ -70,7 +94,7 @@ func CreateTicket(logger *slog.Logger, ticketSvc *ticket.Service,
type TicketRes struct {
ID int64 `json:"id" example:"1"`
Outcomes []domain.Outcome `json:"outcomes"`
Outcomes []domain.TicketOutcome `json:"outcomes"`
Amount float32 `json:"amount" example:"100.0"`
TotalOdds float32 `json:"total_odds" example:"4.22"`
}

View File

@ -153,6 +153,9 @@ func GetAllTransactions(
// Check user role and fetch transactions accordingly
switch user.Role {
case domain.RoleSuperAdmin:
// Admin can fetch all transactions
transactions, err = transactionSvc.GetAllTransactions(c.Context())
case domain.RoleAdmin:
// Admin can fetch all transactions
transactions, err = transactionSvc.GetAllTransactions(c.Context())

View File

@ -2,6 +2,7 @@ package handlers
import (
"log/slog"
"strconv"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -12,7 +13,19 @@ import (
"github.com/gofiber/fiber/v2"
)
type TransferRes struct {
type TransferWalletRes struct {
ID int64 `json:"id" example:"1"`
Amount float32 `json:"amount" example:"100.0"`
Verified bool `json:"verified" example:"true"`
Type string `json:"type" example:"transfer"`
PaymentMethod string `json:"payment_method" example:"bank"`
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
CashierID *int64 `json:"cashier_id" example:"789"`
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:30:00Z"`
}
type RefillRes struct {
ID int64 `json:"id" example:"1"`
Amount float32 `json:"amount" example:"100.0"`
Verified bool `json:"verified" example:"true"`
@ -25,7 +38,7 @@ type TransferRes struct {
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:30:00Z"`
}
func convertTransfer(transfer domain.Transfer) TransferRes {
func convertTransfer(transfer domain.Transfer) TransferWalletRes {
var senderWalletID *int64
if transfer.SenderWalletID.Valid {
senderWalletID = &transfer.SenderWalletID.Value
@ -36,7 +49,7 @@ func convertTransfer(transfer domain.Transfer) TransferRes {
cashierID = &transfer.CashierID.Value
}
return TransferRes{
return TransferWalletRes{
ID: transfer.ID,
Amount: transfer.Amount.Float64(),
Verified: transfer.Verified,
@ -51,11 +64,47 @@ func convertTransfer(transfer domain.Transfer) TransferRes {
}
type CreateTransferReq struct {
ReceiverID int64 `json:"receiver_id" example:"1"`
Amount float64 `json:"amount" example:"100.0"`
PaymentMethod string `json:"payment_method" example:"cash"`
}
// GetTransfersByWallet godoc
// @Summary Get transfer by wallet
// @Description Get transfer by wallet
// @Tags transfer
// @Accept json
// @Produce json
// @Param transferToWallet body CreateTransferReq true "Create Transfer"
// @Success 200 {object} TransferWalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /transfer/wallet/{id} [get]
func GetTransfersByWallet(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
walletID := c.Params("id")
id, err := strconv.ParseInt(walletID, 10, 64)
if err != nil {
logger.Error("Invalid wallet ID", "walletID", walletID, "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
}
transfers, err := walletSvc.GetTransfersByWallet(c.Context(), int64(id))
if err != nil {
logger.Error("Failed to get transfers by wallet", "walletID", walletID, "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transfers", err, nil)
}
var transferResponses []TransferWalletRes
for _, transfer := range transfers {
transferResponses = append(transferResponses, convertTransfer(transfer))
}
return response.WriteJSON(c, fiber.StatusOK, "Transfers retrieved successfully", transferResponses, nil)
}
}
// TransferToWallet godoc
// @Summary Create a transfer to wallet
// @Description Create a transfer to wallet
@ -63,26 +112,42 @@ type CreateTransferReq struct {
// @Accept json
// @Produce json
// @Param transferToWallet body CreateTransferReq true "Create Transfer"
// @Success 200 {object} TransferRes
// @Success 200 {object} TransferWalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /transfer/wallet [post]
// @Router /transfer/wallet/:id [post]
func TransferToWallet(logger *slog.Logger, walletSvc *wallet.Service, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
receiverIDString := c.Params("id")
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
if err != nil {
logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
}
// Get sender ID from the cashier
userID := c.Locals("user_id").(int64)
role := string(c.Locals("role").(domain.Role))
branchID := c.Locals("branch_id").(int64)
var senderID int64
if role == string(domain.RoleCustomer) {
logger.Error("Unauthorized access", "userID", userID, "role", role)
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
}
branchWallet, err := branchSvc.GetBranchByID(c.Context(), branchID)
} else if role == string(domain.RoleBranchManager) || role == string(domain.RoleAdmin) || role == string(domain.RoleSuperAdmin) {
// TODO Add a way for admins to reference branch wallet
senderID = 0
logger.Error("Will", "userID", userID, "role", role)
return response.WriteJSON(c, fiber.StatusBadRequest, "Unauthorized access", nil, nil)
} else {
cashierBranch, err := branchSvc.GetBranchByCashier(c.Context(), userID)
if err != nil {
logger.Error("Failed to get branch wallet", "branch ID", branchID, "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch wallet", err, nil)
logger.Error("Failed to get branch", "user ID", userID, "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier branch", err, nil)
}
senderID = cashierBranch.WalletID
}
var req CreateTransferReq
@ -100,7 +165,7 @@ func TransferToWallet(logger *slog.Logger, walletSvc *wallet.Service, branchSvc
return nil
}
transfer, err := walletSvc.TransferToWallet(c.Context(), branchWallet.ID, req.ReceiverID, domain.Currency(req.Amount), domain.PaymentMethod(req.PaymentMethod), domain.ValidInt64{Value: userID, Valid: true})
transfer, err := walletSvc.TransferToWallet(c.Context(), senderID, receiverID, domain.Currency(req.Amount), domain.PaymentMethod(req.PaymentMethod), domain.ValidInt64{Value: userID, Valid: true})
if !ok {
response.WriteJSON(c, fiber.StatusInternalServerError, "Transfer Failed", err, nil)
@ -113,3 +178,72 @@ func TransferToWallet(logger *slog.Logger, walletSvc *wallet.Service, branchSvc
}
}
// RefillWallet godoc
// @Summary Refill wallet
// @Description Super Admin route to refill a wallet
// @Tags transfer
// @Accept json
// @Produce json
// @Param refillWallet body CreateTransferReq true "Create Transfer"
// @Success 200 {object} TransferWalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /transfer/refill/:id [post]
func RefillWallet(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
receiverIDString := c.Params("id")
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
if err != nil {
logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
}
// Get sender ID from the cashier
userID := c.Locals("user_id").(int64)
role := string(c.Locals("role").(domain.Role))
if role != string(domain.RoleSuperAdmin) {
logger.Error("Unauthorized access", "userID", userID, "role", role)
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
}
var req CreateTransferReq
if err := c.BodyParser(&req); err != nil {
logger.Error("CreateTransferReq failed", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid request",
})
}
valErrs, ok := validator.Validate(c, req)
if !ok {
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
return nil
}
transfer, err := walletSvc.RefillWallet(c.Context(), domain.CreateTransfer{
Amount: domain.Currency(req.Amount),
PaymentMethod: domain.PaymentMethod(req.PaymentMethod),
ReceiverWalletID: receiverID,
CashierID: domain.ValidInt64{
Value: userID,
Valid: true,
},
Type: domain.TransferType("deposit"),
})
if !ok {
response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil)
return nil
}
res := convertTransfer(transfer)
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
}
}

View File

@ -66,6 +66,19 @@ func convertCustomerWallet(wallet domain.GetCustomerWallet) CustomerWalletRes {
}
}
type BranchWalletRes struct {
ID int64 `json:"id" example:"1"`
Balance float32 `json:"balance" example:"100.0"`
IsActive bool `json:"is_active" example:"true"`
Name string `json:"name" example:"true"`
Location string `json:"location" example:"somewhere"`
BranchManagerID int64 `json:"branch_manager_id" example:"1"`
CompanyID int64 `json:"company_id" example:"1"`
IsSelfOwned bool `json:"is_self_owned" example:"false"`
UpdatedAt time.Time `json:"updated_at"`
CreatedAt time.Time `json:"created_at"`
}
// GetWalletByID godoc
// @Summary Get wallet by ID
// @Description Retrieve wallet details by wallet ID
@ -112,10 +125,12 @@ func GetWalletByID(logger *slog.Logger, walletSvc *wallet.Service, validator *cu
// @Router /wallet [get]
func GetAllWallets(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
wallets, err := walletSvc.GetAllWallets(c.Context())
if err != nil {
logger.Error("Failed to get wallets", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil)
}
var res []WalletRes = make([]WalletRes, 0, len(wallets))
@ -128,6 +143,47 @@ func GetAllWallets(logger *slog.Logger, walletSvc *wallet.Service, validator *cu
}
}
// GetAllBranchWallets godoc
// @Summary Get all branch wallets
// @Description Retrieve all branch wallets
// @Tags wallet
// @Accept json
// @Produce json
// @Success 200 {array} WalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /branchWallet [get]
func GetAllBranchWallets(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
return func(c *fiber.Ctx) error {
wallets, err := walletSvc.GetAllBranchWallets(c.Context())
if err != nil {
logger.Error("Failed to get wallets", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil)
}
var res []BranchWalletRes = make([]BranchWalletRes, 0, len(wallets))
for _, wallet := range wallets {
res = append(res, BranchWalletRes{
ID: wallet.ID,
Balance: wallet.Balance.Float64(),
IsActive: wallet.IsActive,
Name: wallet.Name,
Location: wallet.Location,
BranchManagerID: wallet.BranchManagerID,
CompanyID: wallet.CompanyID,
IsSelfOwned: wallet.IsSelfOwned,
UpdatedAt: wallet.UpdatedAt,
CreatedAt: wallet.CreatedAt,
})
}
return response.WriteJSON(c, fiber.StatusOK, "All Wallets retrieved", res, nil)
}
}
type UpdateWalletActiveReq struct {
IsActive bool
}

View File

@ -42,7 +42,7 @@ func (a *App) initAppRoutes() {
//
//, a.authMiddleware
a.fiber.Get("/cashiers", handlers.GetAllCashiers(a.logger, a.userSvc, a.validator))
a.fiber.Post("/cashiers", handlers.CreateCashier(a.logger, a.userSvc, a.validator))
a.fiber.Post("/cashiers", handlers.CreateCashier(a.logger, a.userSvc, a.branchSvc, a.validator))
a.fiber.Put("/cashiers/:id", handlers.UpdateCashier(a.logger, a.userSvc, a.validator))
//
@ -64,8 +64,11 @@ func (a *App) initAppRoutes() {
a.fiber.Post("/branch", handlers.CreateBranch(a.logger, a.branchSvc, a.walletSvc, a.validator))
a.fiber.Get("/branch", handlers.GetAllBranches(a.logger, a.branchSvc, a.validator))
a.fiber.Get("/branch/:id", handlers.GetBranchByID(a.logger, a.branchSvc, a.validator))
a.fiber.Get("/branch/:id/bets", handlers.GetBetByBranchID(a.logger, a.betSvc, a.validator))
a.fiber.Put("/branch/:id", handlers.UpdateBranch(a.logger, a.branchSvc, a.validator))
a.fiber.Delete("/branch/:id", handlers.DeleteBranch(a.logger, a.branchSvc, a.validator))
a.fiber.Get("/search/branch", a.authMiddleware, handlers.SearchBranch(a.logger, a.branchSvc, a.validator))
// /branch/search
// branch/wallet
// Branch Operation
@ -81,7 +84,7 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/ticket/:id", handlers.GetTicketByID(a.logger, a.ticketSvc, a.validator))
// Bet
a.fiber.Post("/bet", handlers.CreateBet(a.logger, a.betSvc, a.validator))
a.fiber.Post("/bet", handlers.CreateBet(a.logger, a.betSvc, a.userSvc, a.branchSvc, a.walletSvc, a.validator))
a.fiber.Get("/bet", handlers.GetAllBet(a.logger, a.betSvc, a.validator))
a.fiber.Get("/bet/:id", handlers.GetBetByID(a.logger, a.betSvc, a.validator))
a.fiber.Patch("/bet/:id", handlers.UpdateCashOut(a.logger, a.betSvc, a.validator))
@ -91,10 +94,13 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/wallet", handlers.GetAllWallets(a.logger, a.walletSvc, a.validator))
a.fiber.Get("/wallet/:id", handlers.GetWalletByID(a.logger, a.walletSvc, a.validator))
a.fiber.Put("/wallet/:id", handlers.UpdateWalletActive(a.logger, a.walletSvc, a.validator))
a.fiber.Get("/branchWallet", handlers.GetAllBranchWallets(a.logger, a.walletSvc, a.validator))
// Transfer
// /transfer/wallet - transfer from one wallet to another wallet
a.fiber.Post("/transfer/wallet", a.authMiddleware, handlers.TransferToWallet(a.logger, a.walletSvc, a.branchSvc, a.validator))
a.fiber.Post("/transfer/wallet/:id", a.authMiddleware, handlers.TransferToWallet(a.logger, a.walletSvc, a.branchSvc, a.validator))
a.fiber.Get("/transfer/wallet/:id", a.authMiddleware, handlers.GetTransfersByWallet(a.logger, a.walletSvc, a.validator))
a.fiber.Get("/transfer/refill/:id", a.authMiddleware, handlers.RefillWallet(a.logger, a.walletSvc, a.validator))
// Transactions
a.fiber.Post("/transaction", a.authMiddleware, handlers.CreateTransaction(a.logger, a.transactionSvc, a.validator))

View File

@ -16,4 +16,12 @@ sql:
- db_type: "uuid"
go_type: "github.com/google/uuid.NullUUID"
nullable: true
- column: "bet_with_outcomes.outcomes"
go_type:
type: "BetOutcome"
slice: true
- column: "ticket_with_outcomes.outcomes"
go_type:
type: "TicketOutcome"
slice: true