diff --git a/cmd/main.go b/cmd/main.go index d09e049..99718fe 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -123,7 +123,7 @@ func main() { companySvc := company.NewService(store) leagueSvc := league.New(store) ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger, *settingSvc, notificationSvc) - betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, *settingSvc, notificationSvc, logger, domain.MongoDBLogger) + betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, *companySvc, *settingSvc, notificationSvc, logger, domain.MongoDBLogger) resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc) bonusSvc := bonus.NewService(store) referalRepo := repository.NewReferralRepository(store) diff --git a/db/data/seed_data.sql b/db/data/seed_data.sql new file mode 100644 index 0000000..83b21aa --- /dev/null +++ b/db/data/seed_data.sql @@ -0,0 +1,259 @@ +BEGIN; +CREATE EXTENSION IF NOT EXISTS pgcrypto; +INSERT INTO users ( + id, + first_name, + last_name, + email, + phone_number, + password, + role, + email_verified, + phone_verified, + created_at, + updated_at, + suspended_at, + suspended + ) +VALUES ( + 1, + 'John', + 'Doe', + 'john.doe@example.com', + NULL, + crypt('password123', gen_salt('bf'))::bytea, + 'customer', + TRUE, + FALSE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP, + NULL, + FALSE + ); +INSERT INTO wallets ( + id, + balance, + is_withdraw, + is_bettable, + is_transferable, + user_id, + is_active, + created_at, + updated_at + ) +VALUES ( + 1, + 10000, + TRUE, + TRUE, + TRUE, + 1, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ); +INSERT INTO wallets ( + id, + balance, + is_withdraw, + is_bettable, + is_transferable, + user_id, + is_active, + created_at, + updated_at + ) +VALUES ( + 2, + 10000, + FALSE, + TRUE, + TRUE, + 1, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ); +INSERT INTO customer_wallets ( + id, + customer_id, + regular_wallet_id, + static_wallet_id + ) +VALUES (1, 1, 1, 2); +INSERT INTO users ( + id, + first_name, + last_name, + email, + phone_number, + password, + role, + email_verified, + phone_verified, + created_at, + updated_at, + suspended_at, + suspended, + company_id + ) +VALUES ( + 2, + 'Test', + 'Admin', + 'test.admin@gmail.com', + '0988554466', + crypt('password123', gen_salt('bf'))::bytea, + 'admin', + TRUE, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP, + NULL, + FALSE, + 1 + ); +INSERT INTO users ( + id, + first_name, + last_name, + email, + phone_number, + password, + role, + email_verified, + phone_verified, + created_at, + updated_at, + suspended_at, + suspended + ) +VALUES ( + 3, + 'Samuel', + 'Tariku', + 'cybersamt@gmail.com', + '0911111111', + crypt('password@123', gen_salt('bf'))::bytea, + 'super_admin', + TRUE, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP, + NULL, + FALSE + ); +INSERT INTO users ( + id, + first_name, + last_name, + email, + phone_number, + password, + role, + email_verified, + phone_verified, + created_at, + updated_at, + suspended_at, + suspended + ) +VALUES ( + 4, + 'Kirubel', + 'Kibru', + 'kirubeljkl679 @gmail.com', + '0911554486', + crypt('password@123', gen_salt('bf'))::bytea, + 'super_admin', + TRUE, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP, + NULL, + FALSE + ); +INSERT INTO supported_operations (id, name, description) +VALUES (1, 'SportBook', 'Sportbook operations'), + (2, 'Virtual', 'Virtual operations'); +INSERT INTO wallets ( + id, + balance, + is_withdraw, + is_bettable, + is_transferable, + user_id, + is_active, + created_at, + updated_at + ) +VALUES ( + 3, + 10000, + TRUE, + TRUE, + TRUE, + 2, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ); +INSERT INTO companies ( + id, + name, + admin_id, + wallet_id, + deducted_percentage + ) +values ( + 1, + 'Test Company', + 2, + 3, + 0.1 + ); +INSERT INTO wallets ( + id, + balance, + is_withdraw, + is_bettable, + is_transferable, + user_id, + is_active, + created_at, + updated_at + ) +VALUES ( + 4, + 10000, + TRUE, + TRUE, + TRUE, + 2, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ); +INSERT INTO branches ( + id, + name, + location, + wallet_id, + branch_manager_id, + company_id, + is_self_owned, + created_at, + updated_at + ) +values ( + 1, + 'Test Branch', + 'Addis Ababa', + 4, + 2, + 1, + TRUE, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + ); +COMMIT; \ No newline at end of file diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index 6640c6e..7864c40 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -206,14 +206,16 @@ CREATE TABLE IF NOT EXISTS shop_deposits ( CREATE TABLE IF NOT EXISTS branches ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, - location VARCHAR(255) NOT NULL, + location TEXT NOT NULL, + profit_percent REAL NOt NULL, is_active BOOLEAN NOT NULL DEFAULT false, wallet_id BIGINT NOT NULL, branch_manager_id BIGINT NOT NULL, company_id BIGINT NOT NULL, is_self_owned BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(wallet_id) ); CREATE TABLE IF NOT EXISTS branch_operations ( id BIGSERIAL PRIMARY KEY, @@ -228,6 +230,10 @@ CREATE TABLE IF NOT EXISTS branch_cashiers ( branch_id BIGINT NOT NULL, UNIQUE(user_id, branch_id) ); +CREATE TABLE IF NOT EXISTS branch_locations ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL +); CREATE TABLE events ( id TEXT PRIMARY KEY, sport_id INT, @@ -279,6 +285,8 @@ CREATE TABLE companies ( name TEXT NOT NULL, admin_id BIGINT NOT NULL, wallet_id BIGINT NOT NULL, + deducted_percentage REAL NOT NULL, + is_active BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); @@ -314,7 +322,7 @@ CREATE TABLE bonus ( CREATE VIEW companies_details AS SELECT companies.*, wallets.balance, - wallets.is_active, + wallets.is_active as wallet_is_active, users.first_name AS admin_first_name, users.last_name AS admin_last_name, users.phone_number AS admin_phone_number @@ -458,7 +466,8 @@ ADD CONSTRAINT fk_shop_deposit_transactions FOREIGN KEY (shop_transaction_id) RE ADD CONSTRAINT fk_shop_deposit_customers FOREIGN KEY (customer_id) REFERENCES users(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); + ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id), + ADD CONSTRAINT fk_branches_location FOREIGN KEY (location) REFERENCES branch_locations(key); ALTER TABLE branch_operations ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id) ON DELETE CASCADE, ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE; @@ -467,4 +476,4 @@ ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(i ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE; ALTER TABLE companies ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id), - ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE; + ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE; \ No newline at end of file diff --git a/db/migrations/000007_setting_data.up.sql b/db/migrations/000007_setting_data.up.sql index f4cdfd6..db01982 100644 --- a/db/migrations/000007_setting_data.up.sql +++ b/db/migrations/000007_setting_data.up.sql @@ -1,17 +1,9 @@ -- Settings Initial Data INSERT INTO settings (key, value) -VALUES ('max_number_of_outcomes', '30') ON CONFLICT (key) DO -UPDATE -SET value = EXCLUDED.value; -INSERT INTO settings (key, value) -VALUES ('bet_amount_limit', '100000') ON CONFLICT (key) DO -UPDATE -SET value = EXCLUDED.value; -INSERT INTO settings (key, value) -VALUES ('daily_ticket_limit', '50') ON CONFLICT (key) DO -UPDATE -SET value = EXCLUDED.value; -INSERT INTO settings (key, value) -VALUES ('total_winnings_limit', '1000000') ON CONFLICT (key) DO +VALUES ('max_number_of_outcomes', '30'), + ('bet_amount_limit', '100000'), + ('daily_ticket_limit', '50'), + ('total_winnings_limit', '1000000'), + ('amount_for_bet_referral', '1000000') ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; \ No newline at end of file diff --git a/db/migrations/000009_location_data.up.sql b/db/migrations/000009_location_data.up.sql new file mode 100644 index 0000000..3d9c67d --- /dev/null +++ b/db/migrations/000009_location_data.up.sql @@ -0,0 +1,76 @@ +-- Locations Initial Data +INSERT INTO branch_locations (key, value) +VALUES ('addis_ababa', 'Addis Ababa'), + ('dire_dawa', 'Dire Dawa'), + ('mekelle', 'Mekelle'), + ('adama', 'Adama'), + ('awassa', 'Awassa'), + ('bahir_dar', 'Bahir Dar'), + ('gonder', 'Gonder'), + ('dessie', 'Dessie'), + ('jimma', 'Jimma'), + ('jijiga', 'Jijiga'), + ('shashamane', 'Shashamane'), + ('bishoftu', 'Bishoftu'), + ('sodo', 'Sodo'), + ('arba_minch', 'Arba Minch'), + ('hosaena', 'Hosaena'), + ('harar', 'Harar'), + ('dilla', 'Dilla'), + ('nekemte', 'Nekemte'), + ('debre_birhan', 'Debre Birhan'), + ('asella', 'Asella'), + ('debre_markos', 'Debre Markos'), + ('kombolcha', 'Kombolcha'), + ('debre_tabor', 'Debre Tabor'), + ('adigrat', 'Adigrat'), + ('areka', 'Areka'), + ('weldiya', 'Weldiya'), + ('sebeta', 'Sebeta'), + ('burayu', 'Burayu'), + ('shire', 'Shire'), + ('ambo', 'Ambo'), + ('arsi_negele', 'Arsi Negele'), + ('aksum', 'Aksum'), + ('gambela', 'Gambela'), + ('bale_robe', 'Bale Robe'), + ('butajira', 'Butajira'), + ('batu', 'Batu'), + ('boditi', 'Boditi'), + ('adwa', 'Adwa'), + ('yirgalem', 'Yirgalem'), + ('waliso', 'Waliso'), + ('welkite', 'Welkite'), + ('gode', 'Gode'), + ('meki', 'Meki'), + ('negele_borana', 'Negele Borana'), + ('alaba_kulito', 'Alaba Kulito'), + ('alamata 14,', 'Alamata 14,'), + ('030', '030'), + ('chiro', 'Chiro'), + ('tepi', 'Tepi'), + ('durame', 'Durame'), + ('goba', 'Goba'), + ('assosa', 'Assosa'), + ('gimbi', 'Gimbi'), + ('wukro', 'Wukro'), + ('haramaya', 'Haramaya'), + ('mizan_teferi', 'Mizan Teferi'), + ('sawla', 'Sawla'), + ('mojo', 'Mojo'), + ('dembi_dolo', 'Dembi Dolo'), + ('aleta_wendo', 'Aleta Wendo'), + ('metu', 'Metu'), + ('mota', 'Mota'), + ('fiche', 'Fiche'), + ('finote_selam', 'Finote Selam'), + ('bule_hora_town', 'Bule Hora Town'), + ('bonga', 'Bonga'), + ('kobo', 'Kobo'), + ('jinka', 'Jinka'), + ('dangila', 'Dangila'), + ('degehabur', 'Degehabur'), + ('bedessa', 'Bedessa'), + ('agaro', 'Agaro') ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; \ No newline at end of file diff --git a/db/query/bet.sql b/db/query/bet.sql index 8f23a9c..eae60d5 100644 --- a/db/query/bet.sql +++ b/db/query/bet.sql @@ -131,4 +131,4 @@ DELETE FROM bets WHERE id = $1; -- name: DeleteBetOutcome :exec DELETE FROM bet_outcomes -WHERE bet_id = $1; \ No newline at end of file +WHERE bet_id = $1; diff --git a/db/query/bet_stat.sql b/db/query/bet_stat.sql new file mode 100644 index 0000000..76d8129 --- /dev/null +++ b/db/query/bet_stat.sql @@ -0,0 +1,134 @@ +-- name: GetBetSummary :one +SELECT SUM(amount) as total_stakes, + COUNT(*) as total_bets, + SUM( + CASE + WHEN status = 0 THEN 1 + ELSE 0 + END + ) as active_bets, + SUM( + CASE + WHEN status = 1 THEN 1 + ELSE 0 + END + ) as total_wins, + SUM( + CASE + WHEN status = 2 THEN 1 + ELSE 0 + END + ) as total_losses, + SUM( + CASE + WHEN status = 1 THEN amount * total_odds + ELSE 0 + END + ) as win_balance +FROM bets +wHERE ( + user_id = sqlc.narg('user_id') + OR sqlc.narg('user_id') IS NULL + ) + AND ( + created_at > sqlc.narg('created_before') + OR sqlc.narg('created_before') IS NULL + ) + AND ( + created_at < sqlc.narg('created_after') + OR sqlc.narg('created_after') IS NULL + ); +-- name: GetBetStats :many +SELECT DATE(created_at) as date, + COUNT(*) as total_bets, + SUM(amount) as total_stakes, + SUM( + CASE + WHEN status = 1 THEN 1 + ELSE 0 + END + ) as total_wins, + SUM( + CASE + WHEN status = 1 THEN amount * total_odds + ELSE 0 + END + ) as total_payouts, + AVG(total_odds) as average_odds +FROM bets +wHERE ( + user_id = sqlc.narg('user_id') + OR sqlc.narg('user_id') IS NULL + ) + AND ( + is_shop_bet = sqlc.narg('is_shop_bet') + OR sqlc.narg('is_shop_bet') IS NULL + ) + AND ( + cashed_out = sqlc.narg('cashed_out') + OR sqlc.narg('cashed_out') IS NULL + ) + AND ( + full_name ILIKE '%' || sqlc.narg('query') || '%' + OR phone_number ILIKE '%' || sqlc.narg('query') || '%' + OR sqlc.narg('query') IS NULL + ) + AND ( + created_at > sqlc.narg('created_before') + OR sqlc.narg('created_before') IS NULL + ) + AND ( + created_at < sqlc.narg('created_after') + OR sqlc.narg('created_after') IS NULL + ) +GROUP BY DATE(created_at) +ORDER BY DATE(created_at); +-- name: GetTotalBetsMadeInRange :one +SELECT COUNT(*) AS total_bets +FROM bets +WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to'); +-- name: GetTotalCashMadeInRange :one +SELECT COALESCE(SUM(amount), 0) AS total_cash_made +FROM bets +WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to'); +-- name: GetTotalCashOutInRange :one +SELECT COALESCE(SUM(amount), 0) AS total_cash_out +FROM bets +WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to') + AND cashed_out = true; +-- name: GetTotalCashBacksInRange :one +SELECT COALESCE(SUM(amount), 0) AS total_cash_backs +FROM bets +WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to') + AND status = 5; +-- name: GetMarketPopularity :one +WITH market_counts AS ( + SELECT DATE(b.created_at) as date, + bo.market_name, + COUNT(*) as bet_count, + ROW_NUMBER() OVER ( + PARTITION BY DATE(b.created_at) + ORDER BY COUNT(*) DESC + ) as rank + FROM bets b + JOIN bet_outcomes bo ON b.id = bo.bet_id + WHERE bo.market_name IS NOT NULL + AND ( + user_id = sqlc.narg('user_id') + OR sqlc.narg('user_id') IS NULL + ) + AND ( + created_at > sqlc.narg('created_before') + OR sqlc.narg('created_before') IS NULL + ) + AND ( + created_at < sqlc.narg('created_after') + OR sqlc.narg('created_after') IS NULL + ) + GROUP BY DATE(b.created_at), + bo.market_name +) +SELECT date, + market_name +FROM market_counts +WHERE rank = 1; \ No newline at end of file diff --git a/db/query/company.sql b/db/query/company.sql index 78779a8..32c7b2f 100644 --- a/db/query/company.sql +++ b/db/query/company.sql @@ -2,9 +2,10 @@ INSERT INTO companies ( name, admin_id, - wallet_id + wallet_id, + deducted_percentage ) -VALUES ($1, $2, $3) +VALUES ($1, $2, $3, $4) RETURNING *; -- name: GetAllCompanies :many SELECT * @@ -36,6 +37,11 @@ WHERE name ILIKE '%' || $1 || '%'; UPDATE companies SET name = COALESCE(sqlc.narg(name), name), admin_id = COALESCE(sqlc.narg(admin_id), admin_id), + is_active = COALESCE(sqlc.narg(is_active), is_active), + deducted_percentage = COALESCE( + sqlc.narg(deducted_percentage), + deducted_percentage + ), updated_at = CURRENT_TIMESTAMP WHERE id = $1 RETURNING *; diff --git a/db/query/events.sql b/db/query/events.sql index 42cc85e..14750c8 100644 --- a/db/query/events.sql +++ b/db/query/events.sql @@ -168,6 +168,10 @@ WHERE is_live = false AND ( leagues.country_code = sqlc.narg('country_code') OR sqlc.narg('country_code') IS NULL + ) + AND ( + flagged = sqlc.narg('flagged') + OR sqlc.narg('flagged') IS NULL ); -- name: GetPaginatedUpcomingEvents :many SELECT events.*, @@ -197,6 +201,10 @@ WHERE start_time > now() leagues.country_code = sqlc.narg('country_code') OR sqlc.narg('country_code') IS NULL ) + AND ( + flagged = sqlc.narg('flagged') + OR sqlc.narg('flagged') IS NULL + ) ORDER BY start_time ASC LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); -- name: GetUpcomingByID :one diff --git a/db/query/report.sql b/db/query/report.sql index dee35de..5f72931 100644 --- a/db/query/report.sql +++ b/db/query/report.sql @@ -1,21 +1,4 @@ --- name: GetTotalBetsMadeInRange :one -SELECT COUNT(*) AS total_bets -FROM bets -WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to'); --- name: GetTotalCashMadeInRange :one -SELECT COALESCE(SUM(amount), 0) AS total_cash_made -FROM bets -WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to'); --- name: GetTotalCashOutInRange :one -SELECT COALESCE(SUM(amount), 0) AS total_cash_out -FROM bets -WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to') - AND cashed_out = true; --- name: GetTotalCashBacksInRange :one -SELECT COALESCE(SUM(amount), 0) AS total_cash_backs -FROM bets -WHERE created_at BETWEEN sqlc.arg('from') AND sqlc.arg('to') - AND status = 5; + -- name: GetCompanyWiseReport :many SELECT b.company_id, c.name AS company_name, diff --git a/db/query/settings.sql b/db/query/settings.sql index d0f4482..6400096 100644 --- a/db/query/settings.sql +++ b/db/query/settings.sql @@ -10,4 +10,26 @@ INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, CURRENT_TIMESTAMP) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value -RETURNING *; \ No newline at end of file +RETURNING *; + +-- name: SetInitialData :exec +INSERT INTO settings (key, value) +VALUES ('max_number_of_outcomes', '30') ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; +INSERT INTO settings (key, value) +VALUES ('bet_amount_limit', '100000') ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; +INSERT INTO settings (key, value) +VALUES ('daily_ticket_limit', '50') ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; +INSERT INTO settings (key, value) +VALUES ('total_winnings_limit', '1000000') ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; +INSERT INTO settings (key, value) +VALUES ('amount_for_bet_referral', '1000000') ON CONFLICT (key) DO +UPDATE +SET value = EXCLUDED.value; \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index 5b797dd..0fe7846 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -24,7 +24,7 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/admin": { + "/api/v1/admin": { "get": { "description": "Get all Admins", "consumes": [ @@ -129,7 +129,42 @@ const docTemplate = `{ } } }, - "/admin/{id}": { + "/api/v1/admin-company": { + "get": { + "description": "Gets a single company by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets company by id", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetCompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/admin/{id}": { "get": { "description": "Get a single admin by id", "consumes": [ @@ -304,6 +339,162 @@ const docTemplate = `{ } } }, + "/api/v1/auth/login": { + "post": { + "description": "Login customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Login customer", + "parameters": [ + { + "description": "Login customer", + "name": "login", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.loginCustomerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginCustomerRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/auth/logout": { + "post": { + "description": "Logout customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Logout customer", + "parameters": [ + { + "description": "Logout customer", + "name": "logout", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.logoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/auth/refresh": { + "post": { + "description": "Refresh token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Refresh token", + "parameters": [ + { + "description": "tokens", + "name": "refresh", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.refreshToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginCustomerRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/banks": { "get": { "produces": [ @@ -515,6 +706,757 @@ const docTemplate = `{ } } }, + "/api/v1/branch": { + "get": { + "description": "Gets all branches", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets all branches", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Create a branch", + "parameters": [ + { + "description": "Creates branch", + "name": "createBranch", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBranchReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}": { + "get": { + "description": "Gets a single branch by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch by id", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Updates a branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Updates a branch", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update Branch", + "name": "updateBranch", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBranchReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Delete the branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Delete the branch", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}/cashier": { + "get": { + "description": "Gets branch cashiers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch cashiers", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.GetCashierRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}/operation": { + "get": { + "description": "Gets branch operations", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch operations", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchOperationRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}/operation/{opID}": { + "delete": { + "description": "Delete the branch operation", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Delete the branch operation", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Branch Operation ID", + "name": "opID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branchCashier": { + "get": { + "description": "Gets branch for cahier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch for cahier", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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" + } + } + } + } + }, + "/api/v1/cashier/{id}": { + "get": { + "description": "Get a single cashier by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Get cashier by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/cashierWallet": { + "get": { + "description": "Get wallet for cashier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Get wallet for cashier", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/cashiers": { + "get": { + "description": "Get all cashiers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Get all cashiers", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.GetCashierRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Create cashier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Create cashier", + "parameters": [ + { + "description": "Create cashier", + "name": "cashier", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CreateCashierReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/cashiers/{id}": { + "put": { + "description": "Update cashier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Update cashier", + "parameters": [ + { + "type": "integer", + "description": "Cashier ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update cashier", + "name": "cashier", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.updateCashierReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/chapa/banks": { "get": { "description": "Get list of banks supported by Chapa", @@ -749,6 +1691,272 @@ const docTemplate = `{ } } }, + "/api/v1/company": { + "get": { + "description": "Gets all companies", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets all companies", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.GetCompanyRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a company", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Create a company", + "parameters": [ + { + "description": "Creates company", + "name": "createCompany", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateCompanyReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/company/{id}": { + "get": { + "description": "Gets a single company by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets company by id", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetCompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Updates a company", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Updates a company", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update Company", + "name": "updateCompany", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateCompanyReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Delete the company", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Delete the company", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/company/{id}/branch": { + "get": { + "description": "Gets branches by company id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branches by company id", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/currencies": { "get": { "description": "Returns list of supported currencies", @@ -845,6 +2053,405 @@ const docTemplate = `{ } } }, + "/api/v1/customer": { + "get": { + "description": "Get all Customers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "customer" + ], + "summary": "Get all Customers", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/customer/{id}": { + "get": { + "description": "Get a single customer by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "customer" + ], + "summary": "Get customer by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Update Customers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "customer" + ], + "summary": "Update Customers", + "parameters": [ + { + "description": "Update Customers", + "name": "Customers", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.updateCustomerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/customerWallet": { + "get": { + "description": "Retrieve all customer wallets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get all customer wallets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.CustomerWalletRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/events": { + "get": { + "description": "Retrieve all upcoming events from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all upcoming events", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "League ID Filter", + "name": "league_id", + "in": "query" + }, + { + "type": "string", + "description": "Sport ID Filter", + "name": "sport_id", + "in": "query" + }, + { + "type": "string", + "description": "Country Code Filter", + "name": "cc", + "in": "query" + }, + { + "type": "string", + "description": "Start Time", + "name": "first_start_time", + "in": "query" + }, + { + "type": "string", + "description": "End Time", + "name": "last_start_time", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.UpcomingEvent" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/events/{id}": { + "get": { + "description": "Retrieve an upcoming event by ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve an upcoming by ID", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.UpcomingEvent" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Set the event status to removed", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "event" + ], + "summary": "Set the event status to removed", + "parameters": [ + { + "type": "integer", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/events/{id}/flag": { + "put": { + "description": "Update the event flagged", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "event" + ], + "summary": "update the event flagged", + "parameters": [ + { + "type": "integer", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/issues": { "get": { "description": "Admin endpoint to list all reported issues with pagination", @@ -932,21 +2539,21 @@ const docTemplate = `{ } } }, - "/api/v1/issues/customer/{customer_id}": { + "/api/v1/issues/user/{user_id}": { "get": { - "description": "Returns all issues reported by a specific customer", + "description": "Returns all issues reported by a specific user", "produces": [ "application/json" ], "tags": [ "Issues" ], - "summary": "Get reported issues by a customer", + "summary": "Get reported issues by a user", "parameters": [ { "type": "integer", - "description": "Customer ID", - "name": "customer_id", + "description": "User ID", + "name": "user_id", "in": "path", "required": true }, @@ -1069,6 +2676,97 @@ const docTemplate = `{ } } }, + "/api/v1/leagues": { + "get": { + "description": "Gets all leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Gets all leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.League" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/leagues/{id}/set-active": { + "put": { + "description": "Set the league to active", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Set the league to active", + "parameters": [ + { + "type": "integer", + "description": "League ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "League Active Request", + "name": "active", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SetLeagueActiveReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/logs": { "get": { "description": "Fetches the 100 most recent application logs from MongoDB", @@ -1098,6 +2796,590 @@ const docTemplate = `{ } } }, + "/api/v1/manager/{id}/branch": { + "get": { + "description": "Gets a branches by manager id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branches by manager id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/managers": { + "get": { + "description": "Get all Managers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Get all Managers", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.ManagersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Create Manager", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Create Manager", + "parameters": [ + { + "description": "Create manager", + "name": "manger", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CreateManagerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/managers/{id}": { + "get": { + "description": "Get a single manager by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Get manager by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.ManagersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Update Managers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Update Managers", + "parameters": [ + { + "description": "Update Managers", + "name": "Managers", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.updateManagerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/odds": { + "get": { + "description": "Retrieve all prematch odds from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all prematch odds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.Odd" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/odds/upcoming/{upcoming_id}": { + "get": { + "description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve prematch odds by upcoming ID (FI)", + "parameters": [ + { + "type": "string", + "description": "Upcoming Event ID (FI)", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Number of results to return (default: 10)", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Number of results to skip (default: 0)", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.Odd" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/odds/upcoming/{upcoming_id}/market/{market_id}": { + "get": { + "description": "Retrieve raw odds records using a Market ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve raw odds by Market ID", + "parameters": [ + { + "type": "string", + "description": "Upcoming ID", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Market ID", + "name": "market_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.RawOddsByMarketID" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/operation": { + "post": { + "description": "Creates a operation", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Create a operation", + "parameters": [ + { + "description": "Creates operation", + "name": "createBranchOperation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBranchOperationReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchOperationRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/referral/settings": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieves current referral settings (admin only)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "referral" + ], + "summary": "Get referral settings", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ReferralSettings" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Updates referral settings (admin only)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "referral" + ], + "summary": "Update referral settings", + "parameters": [ + { + "description": "Referral settings", + "name": "settings", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.ReferralSettings" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/referral/stats": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieves referral statistics for the authenticated user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "referral" + ], + "summary": "Get referral statistics", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ReferralStats" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/report-files/download/{filename}": { "get": { "description": "Downloads a generated report CSV file from the server", @@ -1276,6 +3558,1823 @@ const docTemplate = `{ } } }, + "/api/v1/result/{id}": { + "get": { + "description": "Get results for an event", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "result" + ], + "summary": "Get results for an event", + "parameters": [ + { + "type": "string", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.ResultRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/search/company": { + "get": { + "description": "Gets all companies", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets all companies", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.CompanyRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/bet": { + "post": { + "description": "Create bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Create bet at branch", + "parameters": [ + { + "description": "create bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.ShopBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/bet/{id}": { + "get": { + "description": "Cashout bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet at branch", + "parameters": [ + { + "description": "cashout bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/bet/{id}/cashout": { + "post": { + "description": "Cashout bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet at branch", + "parameters": [ + { + "description": "cashout bet", + "name": "cashoutBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/cashout": { + "post": { + "description": "Cashout bet by cashoutID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet by cashoutID", + "parameters": [ + { + "description": "cashout bet", + "name": "cashoutBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/cashout/{id}": { + "get": { + "description": "Cashout bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet at branch", + "parameters": [ + { + "description": "cashout bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/deposit": { + "post": { + "description": "Transfers money from branch wallet to customer wallet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Shop deposit into customer wallet", + "parameters": [ + { + "description": "ShopDepositReq", + "name": "transferToWallet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.ShopDepositReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopDepositRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/transaction": { + "get": { + "description": "Gets all the transactions", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Gets all transactions", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/transaction/{id}": { + "get": { + "description": "Gets a single transaction by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Gets transaction by id", + "parameters": [ + { + "type": "integer", + "description": "Transaction ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Updates the verified status of a transaction", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Updates the verified field of a transaction", + "parameters": [ + { + "type": "integer", + "description": "Transaction ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updates Transaction Verification", + "name": "updateVerified", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateTransactionVerifiedReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/transaction/{id}/bet": { + "get": { + "description": "Gets a single shop bet by transaction id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Gets shop bet by transaction id", + "parameters": [ + { + "type": "integer", + "description": "Transaction ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/bet": { + "get": { + "description": "Gets all the bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets all bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet", + "parameters": [ + { + "description": "Creates bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/bet/fastcode": { + "post": { + "description": "Creates a bet with fast code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet with fast code", + "parameters": [ + { + "description": "Creates bet", + "name": "createBetWithFastCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/bet/{id}": { + "get": { + "description": "Gets a single bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Deletes bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Deletes bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "patch": { + "description": "Updates the cashed out field", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Updates the cashed out field", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updates Cashed Out", + "name": "updateCashOut", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateCashOutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/random/bet": { + "post": { + "description": "Generate a random bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Generate a random bet", + "parameters": [ + { + "description": "Create Random bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RandomBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/supportedOperation": { + "get": { + "description": "Gets all supported operations", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets all supported operations", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a supported operation", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Create a supported operation", + "parameters": [ + { + "description": "Creates supported operation", + "name": "createSupportedOperation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateSupportedOperationReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.SupportedOperationRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/ticket": { + "get": { + "description": "Retrieve all tickets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get all tickets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.TicketRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a temporary ticket", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Create a temporary ticket", + "parameters": [ + { + "description": "Creates ticket", + "name": "createTicket", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateTicketReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CreateTicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/ticket/{id}": { + "get": { + "description": "Retrieve ticket details by ticket ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get ticket by ID", + "parameters": [ + { + "type": "integer", + "description": "Ticket ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.TicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/top-leagues": { + "get": { + "description": "Retrieve all top leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all top leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.TopLeague" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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" + } + } + } + } + }, + "/api/v1/transfer/wallet/:id": { + "post": { + "description": "Create a transfer to wallet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transfer" + ], + "summary": "Create a transfer to 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": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/bets": { + "get": { + "description": "Gets user bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Gets user bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/checkPhoneEmailExist": { + "post": { + "description": "Check if phone number or email exist", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Check if phone number or email exist", + "parameters": [ + { + "description": "Check phone number or email exist", + "name": "checkPhoneEmailExist", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/delete/{id}": { + "delete": { + "description": "Delete a user by their ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Delete user by ID", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get user profile", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user profile", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/register": { + "post": { + "description": "Register user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Register user", + "parameters": [ + { + "description": "Register user", + "name": "registerUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterUserReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/resetPassword": { + "post": { + "description": "Reset password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Reset password", + "parameters": [ + { + "description": "Reset password", + "name": "resetPassword", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetPasswordReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/search": { + "post": { + "description": "Search for user using name or phone", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Search for user using name or phone", + "parameters": [ + { + "description": "Search for using his name or phone", + "name": "searchUserByNameOrPhone", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/sendRegisterCode": { + "post": { + "description": "Send register code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send register code", + "parameters": [ + { + "description": "Send register code", + "name": "registerCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/sendResetCode": { + "post": { + "description": "Send reset code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send reset code", + "parameters": [ + { + "description": "Send reset code", + "name": "resetCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/single/{id}": { + "get": { + "description": "Get a single user by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/suspend": { + "post": { + "description": "Suspend or unsuspend a user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Suspend or unsuspend a user", + "parameters": [ + { + "description": "Suspend or unsuspend a user", + "name": "updateUserSuspend", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateUserSuspendReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UpdateUserSuspendRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/wallet": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieve customer wallet details", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get customer wallet", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "company_id", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomerWalletRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/veli/games-list": { "post": { "description": "Retrieves games for the specified provider", @@ -1677,6 +5776,139 @@ const docTemplate = `{ } } }, + "/api/v1/wallet": { + "get": { + "description": "Retrieve all wallets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get all 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" + } + } + } + } + }, + "/api/v1/wallet/{id}": { + "get": { + "description": "Retrieve wallet details by wallet ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get wallet by ID", + "parameters": [ + { + "type": "integer", + "description": "Wallet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.WalletRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "patch": { + "description": "Can activate and deactivate wallet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Activate and Deactivate Wallet", + "parameters": [ + { + "type": "integer", + "description": "Wallet ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update Wallet Active", + "name": "updateCashOut", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateWalletActiveReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/webhooks/alea": { "post": { "description": "Handles webhook callbacks from Alea Play virtual games for bet settlement", @@ -1726,1819 +5958,6 @@ const docTemplate = `{ } } }, - "/auth/login": { - "post": { - "description": "Login customer", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Login customer", - "parameters": [ - { - "description": "Login customer", - "name": "login", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.loginCustomerReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.loginCustomerRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/auth/logout": { - "post": { - "description": "Logout customer", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Logout customer", - "parameters": [ - { - "description": "Logout customer", - "name": "logout", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.logoutReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/auth/refresh": { - "post": { - "description": "Refresh token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Refresh token", - "parameters": [ - { - "description": "tokens", - "name": "refresh", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.refreshToken" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.loginCustomerRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch": { - "get": { - "description": "Gets all branches", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets all branches", - "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" - } - } - } - }, - "post": { - "description": "Creates a branch", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Create a branch", - "parameters": [ - { - "description": "Creates branch", - "name": "createBranch", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateBranchReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}": { - "get": { - "description": "Gets a single branch by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch by id", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchDetailRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Updates a branch", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Updates a branch", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update Branch", - "name": "updateBranch", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateBranchReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Delete the branch", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Delete the branch", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}/cashier": { - "get": { - "description": "Gets branch cashiers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch cashiers", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.GetCashierRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}/operation": { - "get": { - "description": "Gets branch operations", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch operations", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.BranchOperationRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}/operation/{opID}": { - "delete": { - "description": "Delete the branch operation", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Delete the branch operation", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Branch Operation ID", - "name": "opID", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branchCashier": { - "get": { - "description": "Gets branch for cahier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch for cahier", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchDetailRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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" - } - } - } - } - }, - "/cashier/{id}": { - "get": { - "description": "Get a single cashier by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Get cashier by id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/cashierWallet": { - "get": { - "description": "Get wallet for cashier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Get wallet for cashier", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/cashiers": { - "get": { - "description": "Get all cashiers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Get all cashiers", - "parameters": [ - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Page size", - "name": "page_size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Create cashier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Create cashier", - "parameters": [ - { - "description": "Create cashier", - "name": "cashier", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateCashierReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/cashiers/{id}": { - "put": { - "description": "Update cashier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Update cashier", - "parameters": [ - { - "type": "integer", - "description": "Cashier ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update cashier", - "name": "cashier", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateCashierReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/company": { - "get": { - "description": "Gets all companies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Gets all companies", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.CompanyRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a company", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Create a company", - "parameters": [ - { - "description": "Creates company", - "name": "createCompany", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateCompanyReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CompanyRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/company/{id}": { - "get": { - "description": "Gets a single company by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Gets company by id", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CompanyRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Updates a company", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Updates a company", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update Company", - "name": "updateCompany", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateCompanyReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CompanyRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Delete the company", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Delete the company", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/company/{id}/branch": { - "get": { - "description": "Gets branches by company id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branches by company id", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "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" - } - } - } - } - }, - "/events": { - "get": { - "description": "Retrieve all upcoming events from the database", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all upcoming events", - "parameters": [ - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Page size", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "League ID Filter", - "name": "league_id", - "in": "query" - }, - { - "type": "string", - "description": "Sport ID Filter", - "name": "sport_id", - "in": "query" - }, - { - "type": "string", - "description": "Country Code Filter", - "name": "cc", - "in": "query" - }, - { - "type": "string", - "description": "Start Time", - "name": "first_start_time", - "in": "query" - }, - { - "type": "string", - "description": "End Time", - "name": "last_start_time", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.UpcomingEvent" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/events/{id}": { - "get": { - "description": "Retrieve an upcoming event by ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve an upcoming by ID", - "parameters": [ - { - "type": "string", - "description": "ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.UpcomingEvent" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Set the event status to removed", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "event" - ], - "summary": "Set the event status to removed", - "parameters": [ - { - "type": "integer", - "description": "Event ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/leagues": { - "get": { - "description": "Gets all leagues", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leagues" - ], - "summary": "Gets all leagues", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.League" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/manager/{id}/branch": { - "get": { - "description": "Gets a branches by manager id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branches by manager id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "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" - } - } - } - } - }, - "/managers": { - "get": { - "description": "Get all Managers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Get all Managers", - "parameters": [ - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Page size", - "name": "page_size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.ManagersRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Create Manager", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Create Manager", - "parameters": [ - { - "description": "Create manager", - "name": "manger", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateManagerReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/managers/{id}": { - "get": { - "description": "Get a single manager by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Get manager by id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.ManagersRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Update Managers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Update Managers", - "parameters": [ - { - "description": "Update Managers", - "name": "Managers", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateManagerReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/odds": { - "get": { - "description": "Retrieve all prematch odds from the database", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all prematch odds", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.Odd" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/odds/upcoming/{upcoming_id}": { - "get": { - "description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve prematch odds by upcoming ID (FI)", - "parameters": [ - { - "type": "string", - "description": "Upcoming Event ID (FI)", - "name": "upcoming_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Number of results to return (default: 10)", - "name": "limit", - "in": "query" - }, - { - "type": "integer", - "description": "Number of results to skip (default: 0)", - "name": "offset", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.Odd" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/odds/upcoming/{upcoming_id}/market/{market_id}": { - "get": { - "description": "Retrieve raw odds records using a Market ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve raw odds by Market ID", - "parameters": [ - { - "type": "string", - "description": "Upcoming ID", - "name": "upcoming_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Market ID", - "name": "market_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.RawOddsByMarketID" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/operation": { - "post": { - "description": "Creates a operation", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Create a operation", - "parameters": [ - { - "description": "Creates operation", - "name": "createBranchOperation", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateBranchOperationReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchOperationRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/popok/games": { "get": { "description": "Retrieves the list of available PopOK slot games", @@ -3618,1686 +6037,6 @@ const docTemplate = `{ } } }, - "/referral/settings": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieves current referral settings (admin only)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "referral" - ], - "summary": "Get referral settings", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.ReferralSettings" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Updates referral settings (admin only)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "referral" - ], - "summary": "Update referral settings", - "parameters": [ - { - "description": "Referral settings", - "name": "settings", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.ReferralSettings" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/referral/stats": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieves referral statistics for the authenticated user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "referral" - ], - "summary": "Get referral statistics", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.ReferralStats" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/result/{id}": { - "get": { - "description": "Get results for an event", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "result" - ], - "summary": "Get results for an event", - "parameters": [ - { - "type": "string", - "description": "Event ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.ResultRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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" - } - } - } - } - }, - "/search/company": { - "get": { - "description": "Gets all companies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Gets all companies", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.CompanyRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/bet": { - "get": { - "description": "Gets all the bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets all bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a bet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Create a bet", - "parameters": [ - { - "description": "Creates bet", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateBetReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/bet/cashout/{id}": { - "get": { - "description": "Gets a single bet by cashout id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by cashout id", - "parameters": [ - { - "type": "string", - "description": "cashout ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/bet/{id}": { - "get": { - "description": "Gets a single bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Deletes bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Deletes bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "patch": { - "description": "Updates the cashed out field", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Updates the cashed out field", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Updates Cashed Out", - "name": "updateCashOut", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateCashOutReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/random/bet": { - "post": { - "description": "Generate a random bet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Generate a random bet", - "parameters": [ - { - "description": "Create Random bet", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.RandomBetReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "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", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets all supported operations", - "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" - } - } - } - }, - "post": { - "description": "Creates a supported operation", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Create a supported operation", - "parameters": [ - { - "description": "Creates supported operation", - "name": "createSupportedOperation", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateSupportedOperationReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.SupportedOperationRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/ticket": { - "get": { - "description": "Retrieve all tickets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get all tickets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.TicketRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a temporary ticket", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Create a temporary ticket", - "parameters": [ - { - "description": "Creates ticket", - "name": "createTicket", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateTicketReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.CreateTicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/ticket/{id}": { - "get": { - "description": "Retrieve ticket details by ticket ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get ticket by ID", - "parameters": [ - { - "type": "integer", - "description": "Ticket ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.TicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/top-leagues": { - "get": { - "description": "Retrieve all top leagues", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all top leagues", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.UpcomingEvent" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/transaction": { - "get": { - "description": "Gets all the transactions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Gets all transactions", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.TransactionRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a transaction", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Create a transaction", - "parameters": [ - { - "description": "Creates transaction", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateTransactionReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.TransactionRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/transaction/{id}": { - "get": { - "description": "Gets a single transaction by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Gets transaction by id", - "parameters": [ - { - "type": "integer", - "description": "Transaction ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.TransactionRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Updates the verified status of a transaction", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Updates the verified field of a transaction", - "parameters": [ - { - "type": "integer", - "description": "Transaction ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Updates Transaction Verification", - "name": "updateVerified", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateTransactionVerifiedReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transfer" - ], - "summary": "Create a transfer to 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": { - "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": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/bets": { - "get": { - "description": "Gets user bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Gets user bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/checkPhoneEmailExist": { - "post": { - "description": "Check if phone number or email exist", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Check if phone number or email exist", - "parameters": [ - { - "description": "Check phone number or email exist", - "name": "checkPhoneEmailExist", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/delete/{id}": { - "delete": { - "description": "Delete a user by their ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Delete user by ID", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/profile": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get user profile", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user profile", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/register": { - "post": { - "description": "Register user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Register user", - "parameters": [ - { - "description": "Register user", - "name": "registerUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterUserReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/resetPassword": { - "post": { - "description": "Reset password", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Reset password", - "parameters": [ - { - "description": "Reset password", - "name": "resetPassword", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetPasswordReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/search": { - "post": { - "description": "Search for user using name or phone", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Search for user using name or phone", - "parameters": [ - { - "description": "Search for using his name or phone", - "name": "searchUserByNameOrPhone", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/sendRegisterCode": { - "post": { - "description": "Send register code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send register code", - "parameters": [ - { - "description": "Send register code", - "name": "registerCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/sendResetCode": { - "post": { - "description": "Send reset code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send reset code", - "parameters": [ - { - "description": "Send reset code", - "name": "resetCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/single/{id}": { - "get": { - "description": "Get a single user by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user by id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/suspend": { - "post": { - "description": "Suspend or unsuspend a user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Suspend or unsuspend a user", - "parameters": [ - { - "description": "Suspend or unsuspend a user", - "name": "updateUserSuspend", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateUserSuspendReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UpdateUserSuspendRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/wallet": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieve customer wallet details", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Get customer wallet", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "company_id", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CustomerWalletRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/virtual-game/callback": { "post": { "description": "Processes callbacks from PopOK for game events", @@ -5400,139 +6139,6 @@ const docTemplate = `{ } } } - }, - "/wallet": { - "get": { - "description": "Retrieve all wallets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Get all 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" - } - } - } - } - }, - "/wallet/{id}": { - "get": { - "description": "Retrieve wallet details by wallet ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Get wallet by ID", - "parameters": [ - { - "type": "integer", - "description": "Wallet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.WalletRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "patch": { - "description": "Can activate and deactivate wallet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Activate and Deactivate Wallet", - "parameters": [ - { - "type": "integer", - "description": "Wallet ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update Wallet Active", - "name": "updateCashOut", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateWalletActiveReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } } }, "definitions": { @@ -5713,14 +6319,6 @@ const docTemplate = `{ "type": "number", "example": 100 }, - "branch_id": { - "type": "integer", - "example": 2 - }, - "cashed_id": { - "type": "string", - "example": "21234" - }, "cashed_out": { "type": "boolean", "example": false @@ -5729,9 +6327,12 @@ const docTemplate = `{ "type": "string", "example": "2025-04-08T12:00:00Z" }, + "fast_code": { + "type": "string" + }, "full_name": { "type": "string", - "example": "John" + "example": "John Smith" }, "id": { "type": "integer", @@ -5747,10 +6348,6 @@ const docTemplate = `{ "$ref": "#/definitions/domain.BetOutcome" } }, - "phone_number": { - "type": "string", - "example": "1234567890" - }, "status": { "allOf": [ { @@ -5769,6 +6366,145 @@ const docTemplate = `{ } } }, + "domain.BranchDetailRes": { + "type": "object", + "properties": { + "balance": { + "type": "number", + "example": 100.5 + }, + "branch_manager_id": { + "type": "integer", + "example": 1 + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_self_owned": { + "type": "boolean", + "example": false + }, + "is_wallet_active": { + "type": "boolean", + "example": false + }, + "location": { + "type": "string", + "example": "Addis Ababa" + }, + "manager_name": { + "type": "string", + "example": "John Smith" + }, + "manager_phone_number": { + "type": "string", + "example": "0911111111" + }, + "name": { + "type": "string", + "example": "4-kilo Branch" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, + "domain.BranchOperationRes": { + "type": "object", + "properties": { + "description": { + "type": "string", + "example": "Betting on sport events" + }, + "name": { + "type": "string", + "example": "SportsBook" + } + } + }, + "domain.BranchRes": { + "type": "object", + "properties": { + "branch_manager_id": { + "type": "integer", + "example": 1 + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_self_owned": { + "type": "boolean", + "example": false + }, + "location": { + "type": "string", + "example": "Addis Ababa" + }, + "name": { + "type": "string", + "example": "4-kilo Branch" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, + "domain.CashoutReq": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "bank_code": { + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "cashout_id": { + "type": "string", + "example": "1234" + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "reference_number": { + "type": "string" + } + } + }, "domain.ChapaDepositRequestPayload": { "type": "object", "required": [ @@ -5849,6 +6585,35 @@ const docTemplate = `{ } } }, + "domain.CompanyRes": { + "type": "object", + "properties": { + "admin_id": { + "type": "integer", + "example": 1 + }, + "deducted_percentage": { + "type": "number", + "example": 0.1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "name": { + "type": "string", + "example": "CompanyName" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, "domain.CreateBetOutcomeReq": { "type": "object", "properties": { @@ -5877,27 +6642,91 @@ const docTemplate = `{ "type": "integer", "example": 1 }, - "full_name": { - "type": "string", - "example": "John" - }, "outcomes": { "type": "array", "items": { "$ref": "#/definitions/domain.CreateBetOutcomeReq" } - }, - "phone_number": { - "type": "string", - "example": "1234567890" - }, - "status": { - "allOf": [ - { - "$ref": "#/definitions/domain.OutcomeStatus" - } - ], + } + } + }, + "domain.CreateBranchOperationReq": { + "type": "object", + "properties": { + "branch_id": { + "type": "integer", "example": 1 + }, + "operation_id": { + "type": "integer", + "example": 1 + } + } + }, + "domain.CreateBranchReq": { + "type": "object", + "required": [ + "branch_manager_id", + "location", + "name", + "operations" + ], + "properties": { + "branch_manager_id": { + "type": "integer", + "example": 1 + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "is_self_owned": { + "type": "boolean", + "example": false + }, + "location": { + "type": "string", + "maxLength": 100, + "minLength": 3, + "example": "Addis Ababa" + }, + "name": { + "type": "string", + "maxLength": 100, + "minLength": 3, + "example": "4-kilo Branch" + }, + "operations": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "domain.CreateCompanyReq": { + "type": "object", + "properties": { + "admin_id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "CompanyName" + } + } + }, + "domain.CreateSupportedOperationReq": { + "type": "object", + "properties": { + "description": { + "type": "string", + "example": "Betting on sport events" + }, + "name": { + "type": "string", + "example": "SportsBook" } } }, @@ -6364,6 +7193,55 @@ const docTemplate = `{ } } }, + "domain.GetCompanyRes": { + "type": "object", + "properties": { + "admin_first_name": { + "type": "string", + "example": "John" + }, + "admin_id": { + "type": "integer", + "example": 1 + }, + "admin_last_name": { + "type": "string", + "example": "Doe" + }, + "admin_phone_number": { + "type": "string", + "example": "1234567890" + }, + "balance": { + "type": "number", + "example": 1 + }, + "deducted_percentage": { + "type": "number", + "example": 0.1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_wallet_active": { + "type": "boolean", + "example": false + }, + "name": { + "type": "string", + "example": "CompanyName" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, "domain.League": { "type": "object", "properties": { @@ -6478,17 +7356,6 @@ const docTemplate = `{ } } }, - "domain.OtpProvider": { - "type": "string", - "enum": [ - "twilio", - "aformessage" - ], - "x-enum-varnames": [ - "TwilioSms", - "AfroMessage" - ] - }, "domain.OutcomeStatus": { "type": "integer", "enum": [ @@ -6752,9 +7619,6 @@ const docTemplate = `{ "created_at": { "type": "string" }, - "customer_id": { - "type": "integer" - }, "description": { "type": "string" }, @@ -6776,6 +7640,12 @@ const docTemplate = `{ }, "updated_at": { "type": "string" + }, + "user_id": { + "type": "integer" + }, + "user_role": { + "$ref": "#/definitions/domain.Role" } } }, @@ -6811,6 +7681,245 @@ const docTemplate = `{ "RoleCashier" ] }, + "domain.ShopBetReq": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "amount": { + "type": "number", + "example": 100 + }, + "bank_code": { + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "bet_id": { + "type": "integer", + "example": 1 + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "full_name": { + "type": "string", + "example": "John Smith" + }, + "outcomes": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.CreateBetOutcomeReq" + } + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "phone_number": { + "type": "string", + "example": "0911111111" + }, + "reference_number": { + "type": "string" + } + } + }, + "domain.ShopDepositReq": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "amount": { + "type": "number", + "example": 100 + }, + "bank_code": { + "description": "FullName string ` + "`" + `json:\"full_name\" example:\"John Smith\"` + "`" + `\nPhoneNumber string ` + "`" + `json:\"phone_number\" example:\"0911111111\"` + "`" + `", + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "customer_id": { + "type": "integer", + "example": 1 + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "reference_number": { + "type": "string" + } + } + }, + "domain.ShopDepositRes": { + "type": "object", + "properties": { + "customer_id": { + "type": "integer" + }, + "id": { + "type": "integer" + }, + "shop_transaction_id": { + "type": "integer" + }, + "wallet_transfer_id": { + "type": "integer" + } + } + }, + "domain.ShopTransactionRes": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "amount": { + "type": "number", + "example": 100 + }, + "approved_by": { + "type": "integer", + "example": 1 + }, + "approver_first_name": { + "type": "string", + "example": "John" + }, + "approver_last_name": { + "type": "string", + "example": "Smith" + }, + "approver_phone_number": { + "type": "string", + "example": "0911111111" + }, + "bank_code": { + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "branch_location": { + "type": "string", + "example": "Branch Location" + }, + "branch_name": { + "type": "string", + "example": "Branch Name" + }, + "cashier_name": { + "type": "string", + "example": "John Smith" + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "created_at": { + "type": "string" + }, + "creator_first_name": { + "type": "string", + "example": "John" + }, + "creator_last_name": { + "type": "string", + "example": "Smith" + }, + "creator_phone_number": { + "type": "string", + "example": "0911111111" + }, + "full_name": { + "type": "string", + "example": "John Smith" + }, + "id": { + "type": "integer", + "example": 1 + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "phone_number": { + "type": "string", + "example": "0911111111" + }, + "reference_number": { + "type": "string" + }, + "type": { + "type": "integer", + "example": 1 + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": "integer", + "example": 1 + }, + "verified": { + "type": "boolean", + "example": true + } + } + }, + "domain.SupportedOperationRes": { + "type": "object", + "properties": { + "description": { + "type": "string", + "example": "Betting on sport events" + }, + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "SportsBook" + } + } + }, "domain.TicketOutcome": { "type": "object", "properties": { @@ -6914,6 +8023,10 @@ const docTemplate = `{ "description": "Away team ID (can be empty/null)", "type": "integer" }, + "flagged": { + "description": "Whether the event is flagged or not", + "type": "boolean" + }, "home_kit_image": { "description": "Kit or image for home team (optional)", "type": "string" @@ -6968,6 +8081,36 @@ const docTemplate = `{ } } }, + "domain.UpdateCompanyReq": { + "type": "object", + "properties": { + "admin_id": { + "type": "integer", + "example": 1 + }, + "deducted_percentage": { + "type": "number", + "example": 0.1 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "name": { + "type": "string", + "example": "CompanyName" + } + } + }, + "domain.UpdateTransactionVerifiedReq": { + "type": "object", + "properties": { + "verified": { + "type": "boolean", + "example": true + } + } + }, "handlers.AdminRes": { "type": "object", "properties": { @@ -7012,97 +8155,6 @@ const docTemplate = `{ } } }, - "handlers.BranchDetailRes": { - "type": "object", - "properties": { - "balance": { - "type": "number", - "example": 100.5 - }, - "branch_manager_id": { - "type": "integer", - "example": 1 - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "id": { - "type": "integer", - "example": 1 - }, - "is_self_owned": { - "type": "boolean", - "example": false - }, - "location": { - "type": "string", - "example": "Addis Ababa" - }, - "manager_name": { - "type": "string", - "example": "John Smith" - }, - "manager_phone_number": { - "type": "string", - "example": "0911111111" - }, - "name": { - "type": "string", - "example": "4-kilo Branch" - }, - "wallet_id": { - "type": "integer", - "example": 1 - } - } - }, - "handlers.BranchOperationRes": { - "type": "object", - "properties": { - "description": { - "type": "string", - "example": "Betting on sport events" - }, - "name": { - "type": "string", - "example": "SportsBook" - } - } - }, - "handlers.BranchRes": { - "type": "object", - "properties": { - "branch_manager_id": { - "type": "integer", - "example": 1 - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "id": { - "type": "integer", - "example": 1 - }, - "is_self_owned": { - "type": "boolean", - "example": false - }, - "location": { - "type": "string", - "example": "Addis Ababa" - }, - "name": { - "type": "string", - "example": "4-kilo Branch" - }, - "wallet_id": { - "type": "integer", - "example": 1 - } - } - }, "handlers.CheckPhoneEmailExistReq": { "type": "object", "properties": { @@ -7127,27 +8179,6 @@ const docTemplate = `{ } } }, - "handlers.CompanyRes": { - "type": "object", - "properties": { - "admin_id": { - "type": "integer", - "example": 1 - }, - "id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "CompanyName" - }, - "wallet_id": { - "type": "integer", - "example": 1 - } - } - }, "handlers.CreateAdminReq": { "type": "object", "properties": { @@ -7177,60 +8208,6 @@ const docTemplate = `{ } } }, - "handlers.CreateBranchOperationReq": { - "type": "object", - "properties": { - "branch_id": { - "type": "integer", - "example": 1 - }, - "operation_id": { - "type": "integer", - "example": 1 - } - } - }, - "handlers.CreateBranchReq": { - "type": "object", - "required": [ - "branch_manager_id", - "location", - "name", - "operations" - ], - "properties": { - "branch_manager_id": { - "type": "integer", - "example": 1 - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "is_self_owned": { - "type": "boolean", - "example": false - }, - "location": { - "type": "string", - "maxLength": 100, - "minLength": 3, - "example": "Addis Ababa" - }, - "name": { - "type": "string", - "maxLength": 100, - "minLength": 3, - "example": "4-kilo Branch" - }, - "operations": { - "type": "array", - "items": { - "type": "integer" - } - } - } - }, "handlers.CreateCashierReq": { "type": "object", "properties": { @@ -7264,19 +8241,6 @@ const docTemplate = `{ } } }, - "handlers.CreateCompanyReq": { - "type": "object", - "properties": { - "admin_id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "CompanyName" - } - } - }, "handlers.CreateManagerReq": { "type": "object", "properties": { @@ -7306,75 +8270,6 @@ const docTemplate = `{ } } }, - "handlers.CreateSupportedOperationReq": { - "type": "object", - "properties": { - "description": { - "type": "string", - "example": "Betting on sport events" - }, - "name": { - "type": "string", - "example": "SportsBook" - } - } - }, - "handlers.CreateTransactionReq": { - "type": "object", - "properties": { - "account_name": { - "type": "string" - }, - "account_number": { - "type": "string" - }, - "amount": { - "type": "number", - "example": 100 - }, - "bank_code": { - "type": "string" - }, - "beneficiary_name": { - "type": "string" - }, - "bet_id": { - "type": "integer", - "example": 1 - }, - "branch_id": { - "type": "integer", - "example": 1 - }, - "cashout_id": { - "type": "string", - "example": "191212" - }, - "full_name": { - "type": "string", - "example": "John Smith" - }, - "payment_option": { - "allOf": [ - { - "$ref": "#/definitions/domain.PaymentOption" - } - ], - "example": 1 - }, - "phone_number": { - "type": "string", - "example": "0911111111" - }, - "reference_number": { - "type": "string" - }, - "type": { - "type": "integer", - "example": 1 - } - } - }, "handlers.CreateTransferReq": { "type": "object", "properties": { @@ -7398,10 +8293,22 @@ const docTemplate = `{ "type": "integer", "example": 1 }, + "first_name": { + "type": "string", + "example": "John" + }, "id": { "type": "integer", "example": 1 }, + "last_name": { + "type": "string", + "example": "Smith" + }, + "phone_number": { + "type": "string", + "example": "0911111111" + }, "regular_balance": { "type": "number", "example": 100 @@ -7410,6 +8317,10 @@ const docTemplate = `{ "type": "integer", "example": 1 }, + "regular_is_active": { + "type": "boolean", + "example": true + }, "regular_updated_at": { "type": "string" }, @@ -7421,11 +8332,59 @@ const docTemplate = `{ "type": "integer", "example": 1 }, + "static_is_active": { + "type": "boolean", + "example": true + }, "static_updated_at": { "type": "string" } } }, + "handlers.CustomersRes": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "email": { + "type": "string" + }, + "email_verified": { + "type": "boolean" + }, + "first_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_login": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "phone_number": { + "type": "string" + }, + "phone_verified": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/domain.Role" + }, + "suspended": { + "type": "boolean" + }, + "suspended_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "handlers.GetCashierRes": { "type": "object", "properties": { @@ -7528,9 +8487,6 @@ const docTemplate = `{ }, "handlers.RegisterCodeReq": { "type": "object", - "required": [ - "provider" - ], "properties": { "email": { "type": "string", @@ -7539,22 +8495,11 @@ const docTemplate = `{ "phone_number": { "type": "string", "example": "1234567890" - }, - "provider": { - "allOf": [ - { - "$ref": "#/definitions/domain.OtpProvider" - } - ], - "example": "twilio" } } }, "handlers.RegisterUserReq": { "type": "object", - "required": [ - "provider" - ], "properties": { "email": { "type": "string", @@ -7580,14 +8525,6 @@ const docTemplate = `{ "type": "string", "example": "1234567890" }, - "provider": { - "allOf": [ - { - "$ref": "#/definitions/domain.OtpProvider" - } - ], - "example": "twilio" - }, "referal_code": { "type": "string", "example": "ABC123" @@ -7596,9 +8533,6 @@ const docTemplate = `{ }, "handlers.ResetCodeReq": { "type": "object", - "required": [ - "provider" - ], "properties": { "email": { "type": "string", @@ -7607,14 +8541,6 @@ const docTemplate = `{ "phone_number": { "type": "string", "example": "1234567890" - }, - "provider": { - "allOf": [ - { - "$ref": "#/definitions/domain.OtpProvider" - } - ], - "example": "twilio" } } }, @@ -7666,118 +8592,34 @@ const docTemplate = `{ } } }, - "handlers.SupportedOperationRes": { + "handlers.SetLeagueActiveReq": { "type": "object", "properties": { - "description": { - "type": "string", - "example": "Betting on sport events" - }, - "id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "SportsBook" + "is_active": { + "type": "boolean" } } }, - "handlers.TransactionRes": { + "handlers.TopLeague": { "type": "object", "properties": { - "account_name": { + "events": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.UpcomingEvent" + } + }, + "league_cc": { "type": "string" }, - "account_number": { + "league_id": { + "type": "integer" + }, + "league_name": { "type": "string" }, - "amount": { - "type": "number", - "example": 100 - }, - "approved_by": { - "type": "integer", - "example": 1 - }, - "approver_name": { - "type": "string", - "example": "John Smith" - }, - "bank_code": { - "type": "string" - }, - "beneficiary_name": { - "type": "string" - }, - "bet_id": { - "type": "integer", - "example": 1 - }, - "branch_id": { - "type": "integer", - "example": 1 - }, - "branch_location": { - "type": "string", - "example": "Branch Location" - }, - "branch_name": { - "type": "string", - "example": "Branch Name" - }, - "cashier_id": { - "type": "integer", - "example": 1 - }, - "cashier_name": { - "type": "string", - "example": "John Smith" - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "created_at": { - "type": "string" - }, - "full_name": { - "type": "string", - "example": "John Smith" - }, - "id": { - "type": "integer", - "example": 1 - }, - "number_of_outcomes": { - "type": "integer", - "example": 1 - }, - "payment_option": { - "allOf": [ - { - "$ref": "#/definitions/domain.PaymentOption" - } - ], - "example": 1 - }, - "phone_number": { - "type": "string", - "example": "0911111111" - }, - "reference_number": { - "type": "string" - }, - "type": { - "type": "integer", - "example": 1 - }, - "updated_at": { - "type": "string" - }, - "verified": { - "type": "boolean", - "example": true + "league_sport_id": { + "type": "integer" } } }, @@ -7787,15 +8629,27 @@ const docTemplate = `{ "amount": { "type": "number" }, - "cashier_id": { + "created_at": { + "type": "string" + }, + "depositor_first_name": { + "type": "string" + }, + "depositor_id": { "type": "integer" }, - "created_at": { + "depositor_last_name": { + "type": "string" + }, + "depositor_phone_number": { "type": "string" }, "id": { "type": "integer" }, + "message": { + "type": "string" + }, "payment_method": { "type": "string" }, @@ -7828,32 +8682,9 @@ const docTemplate = `{ } } }, - "handlers.UpdateCompanyReq": { - "type": "object", - "properties": { - "admin_id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "CompanyName" - } - } - }, - "handlers.UpdateTransactionVerifiedReq": { - "type": "object", - "properties": { - "verified": { - "type": "boolean", - "example": true - } - } - }, "handlers.UpdateUserSuspendReq": { "type": "object", "required": [ - "suspended", "user_id" ], "properties": { @@ -7987,7 +8818,7 @@ const docTemplate = `{ }, "game_id": { "type": "string", - "example": "crash_001" + "example": "1" }, "mode": { "type": "string", @@ -8108,6 +8939,27 @@ const docTemplate = `{ } } }, + "handlers.updateCustomerReq": { + "type": "object", + "properties": { + "company_id": { + "type": "integer", + "example": 1 + }, + "first_name": { + "type": "string", + "example": "John" + }, + "last_name": { + "type": "string", + "example": "Doe" + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, "handlers.updateManagerReq": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 6bc23d6..b85270f 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -16,7 +16,7 @@ "version": "1.0.1" }, "paths": { - "/admin": { + "/api/v1/admin": { "get": { "description": "Get all Admins", "consumes": [ @@ -121,7 +121,42 @@ } } }, - "/admin/{id}": { + "/api/v1/admin-company": { + "get": { + "description": "Gets a single company by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets company by id", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetCompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/admin/{id}": { "get": { "description": "Get a single admin by id", "consumes": [ @@ -296,6 +331,162 @@ } } }, + "/api/v1/auth/login": { + "post": { + "description": "Login customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Login customer", + "parameters": [ + { + "description": "Login customer", + "name": "login", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.loginCustomerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginCustomerRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/auth/logout": { + "post": { + "description": "Logout customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Logout customer", + "parameters": [ + { + "description": "Logout customer", + "name": "logout", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.logoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/auth/refresh": { + "post": { + "description": "Refresh token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Refresh token", + "parameters": [ + { + "description": "tokens", + "name": "refresh", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.refreshToken" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginCustomerRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/banks": { "get": { "produces": [ @@ -507,6 +698,757 @@ } } }, + "/api/v1/branch": { + "get": { + "description": "Gets all branches", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets all branches", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Create a branch", + "parameters": [ + { + "description": "Creates branch", + "name": "createBranch", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBranchReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}": { + "get": { + "description": "Gets a single branch by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch by id", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Updates a branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Updates a branch", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update Branch", + "name": "updateBranch", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBranchReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Delete the branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Delete the branch", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}/cashier": { + "get": { + "description": "Gets branch cashiers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch cashiers", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.GetCashierRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}/operation": { + "get": { + "description": "Gets branch operations", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch operations", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchOperationRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branch/{id}/operation/{opID}": { + "delete": { + "description": "Delete the branch operation", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Delete the branch operation", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Branch Operation ID", + "name": "opID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/branchCashier": { + "get": { + "description": "Gets branch for cahier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branch for cahier", + "parameters": [ + { + "type": "integer", + "description": "Branch ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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" + } + } + } + } + }, + "/api/v1/cashier/{id}": { + "get": { + "description": "Get a single cashier by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Get cashier by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/cashierWallet": { + "get": { + "description": "Get wallet for cashier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Get wallet for cashier", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/cashiers": { + "get": { + "description": "Get all cashiers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Get all cashiers", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.GetCashierRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Create cashier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Create cashier", + "parameters": [ + { + "description": "Create cashier", + "name": "cashier", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CreateCashierReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/cashiers/{id}": { + "put": { + "description": "Update cashier", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "cashier" + ], + "summary": "Update cashier", + "parameters": [ + { + "type": "integer", + "description": "Cashier ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update cashier", + "name": "cashier", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.updateCashierReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/chapa/banks": { "get": { "description": "Get list of banks supported by Chapa", @@ -741,6 +1683,272 @@ } } }, + "/api/v1/company": { + "get": { + "description": "Gets all companies", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets all companies", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.GetCompanyRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a company", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Create a company", + "parameters": [ + { + "description": "Creates company", + "name": "createCompany", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateCompanyReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/company/{id}": { + "get": { + "description": "Gets a single company by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets company by id", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetCompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Updates a company", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Updates a company", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update Company", + "name": "updateCompany", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateCompanyReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CompanyRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Delete the company", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Delete the company", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/company/{id}/branch": { + "get": { + "description": "Gets branches by company id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branches by company id", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/currencies": { "get": { "description": "Returns list of supported currencies", @@ -837,6 +2045,405 @@ } } }, + "/api/v1/customer": { + "get": { + "description": "Get all Customers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "customer" + ], + "summary": "Get all Customers", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/customer/{id}": { + "get": { + "description": "Get a single customer by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "customer" + ], + "summary": "Get customer by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Update Customers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "customer" + ], + "summary": "Update Customers", + "parameters": [ + { + "description": "Update Customers", + "name": "Customers", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.updateCustomerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/customerWallet": { + "get": { + "description": "Retrieve all customer wallets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get all customer wallets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.CustomerWalletRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/events": { + "get": { + "description": "Retrieve all upcoming events from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all upcoming events", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "League ID Filter", + "name": "league_id", + "in": "query" + }, + { + "type": "string", + "description": "Sport ID Filter", + "name": "sport_id", + "in": "query" + }, + { + "type": "string", + "description": "Country Code Filter", + "name": "cc", + "in": "query" + }, + { + "type": "string", + "description": "Start Time", + "name": "first_start_time", + "in": "query" + }, + { + "type": "string", + "description": "End Time", + "name": "last_start_time", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.UpcomingEvent" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/events/{id}": { + "get": { + "description": "Retrieve an upcoming event by ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve an upcoming by ID", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.UpcomingEvent" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Set the event status to removed", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "event" + ], + "summary": "Set the event status to removed", + "parameters": [ + { + "type": "integer", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/events/{id}/flag": { + "put": { + "description": "Update the event flagged", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "event" + ], + "summary": "update the event flagged", + "parameters": [ + { + "type": "integer", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/issues": { "get": { "description": "Admin endpoint to list all reported issues with pagination", @@ -924,21 +2531,21 @@ } } }, - "/api/v1/issues/customer/{customer_id}": { + "/api/v1/issues/user/{user_id}": { "get": { - "description": "Returns all issues reported by a specific customer", + "description": "Returns all issues reported by a specific user", "produces": [ "application/json" ], "tags": [ "Issues" ], - "summary": "Get reported issues by a customer", + "summary": "Get reported issues by a user", "parameters": [ { "type": "integer", - "description": "Customer ID", - "name": "customer_id", + "description": "User ID", + "name": "user_id", "in": "path", "required": true }, @@ -1061,6 +2668,97 @@ } } }, + "/api/v1/leagues": { + "get": { + "description": "Gets all leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Gets all leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.League" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/leagues/{id}/set-active": { + "put": { + "description": "Set the league to active", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Set the league to active", + "parameters": [ + { + "type": "integer", + "description": "League ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "League Active Request", + "name": "active", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SetLeagueActiveReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/logs": { "get": { "description": "Fetches the 100 most recent application logs from MongoDB", @@ -1090,6 +2788,590 @@ } } }, + "/api/v1/manager/{id}/branch": { + "get": { + "description": "Gets a branches by manager id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets branches by manager id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/managers": { + "get": { + "description": "Get all Managers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Get all Managers", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.ManagersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Create Manager", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Create Manager", + "parameters": [ + { + "description": "Create manager", + "name": "manger", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CreateManagerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/managers/{id}": { + "get": { + "description": "Get a single manager by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Get manager by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.ManagersRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Update Managers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manager" + ], + "summary": "Update Managers", + "parameters": [ + { + "description": "Update Managers", + "name": "Managers", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.updateManagerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/odds": { + "get": { + "description": "Retrieve all prematch odds from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all prematch odds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.Odd" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/odds/upcoming/{upcoming_id}": { + "get": { + "description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve prematch odds by upcoming ID (FI)", + "parameters": [ + { + "type": "string", + "description": "Upcoming Event ID (FI)", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Number of results to return (default: 10)", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Number of results to skip (default: 0)", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.Odd" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/odds/upcoming/{upcoming_id}/market/{market_id}": { + "get": { + "description": "Retrieve raw odds records using a Market ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve raw odds by Market ID", + "parameters": [ + { + "type": "string", + "description": "Upcoming ID", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Market ID", + "name": "market_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.RawOddsByMarketID" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/operation": { + "post": { + "description": "Creates a operation", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Create a operation", + "parameters": [ + { + "description": "Creates operation", + "name": "createBranchOperation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBranchOperationReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BranchOperationRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/referral/settings": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieves current referral settings (admin only)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "referral" + ], + "summary": "Get referral settings", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ReferralSettings" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Updates referral settings (admin only)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "referral" + ], + "summary": "Update referral settings", + "parameters": [ + { + "description": "Referral settings", + "name": "settings", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.ReferralSettings" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/referral/stats": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieves referral statistics for the authenticated user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "referral" + ], + "summary": "Get referral statistics", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ReferralStats" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/report-files/download/{filename}": { "get": { "description": "Downloads a generated report CSV file from the server", @@ -1268,6 +3550,1823 @@ } } }, + "/api/v1/result/{id}": { + "get": { + "description": "Get results for an event", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "result" + ], + "summary": "Get results for an event", + "parameters": [ + { + "type": "string", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.ResultRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/search/company": { + "get": { + "description": "Gets all companies", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "company" + ], + "summary": "Gets all companies", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.CompanyRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/bet": { + "post": { + "description": "Create bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Create bet at branch", + "parameters": [ + { + "description": "create bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.ShopBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/bet/{id}": { + "get": { + "description": "Cashout bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet at branch", + "parameters": [ + { + "description": "cashout bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/bet/{id}/cashout": { + "post": { + "description": "Cashout bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet at branch", + "parameters": [ + { + "description": "cashout bet", + "name": "cashoutBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/cashout": { + "post": { + "description": "Cashout bet by cashoutID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet by cashoutID", + "parameters": [ + { + "description": "cashout bet", + "name": "cashoutBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/cashout/{id}": { + "get": { + "description": "Cashout bet at branch", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Cashout bet at branch", + "parameters": [ + { + "description": "cashout bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CashoutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/deposit": { + "post": { + "description": "Transfers money from branch wallet to customer wallet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Shop deposit into customer wallet", + "parameters": [ + { + "description": "ShopDepositReq", + "name": "transferToWallet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.ShopDepositReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopDepositRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/transaction": { + "get": { + "description": "Gets all the transactions", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Gets all transactions", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/transaction/{id}": { + "get": { + "description": "Gets a single transaction by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Gets transaction by id", + "parameters": [ + { + "type": "integer", + "description": "Transaction ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "put": { + "description": "Updates the verified status of a transaction", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Updates the verified field of a transaction", + "parameters": [ + { + "type": "integer", + "description": "Transaction ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updates Transaction Verification", + "name": "updateVerified", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.UpdateTransactionVerifiedReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/shop/transaction/{id}/bet": { + "get": { + "description": "Gets a single shop bet by transaction id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transaction" + ], + "summary": "Gets shop bet by transaction id", + "parameters": [ + { + "type": "integer", + "description": "Transaction ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.ShopTransactionRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/bet": { + "get": { + "description": "Gets all the bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets all bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet", + "parameters": [ + { + "description": "Creates bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/bet/fastcode": { + "post": { + "description": "Creates a bet with fast code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet with fast code", + "parameters": [ + { + "description": "Creates bet", + "name": "createBetWithFastCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/bet/{id}": { + "get": { + "description": "Gets a single bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Deletes bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Deletes bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "patch": { + "description": "Updates the cashed out field", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Updates the cashed out field", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updates Cashed Out", + "name": "updateCashOut", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateCashOutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/sport/random/bet": { + "post": { + "description": "Generate a random bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Generate a random bet", + "parameters": [ + { + "description": "Create Random bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RandomBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/supportedOperation": { + "get": { + "description": "Gets all supported operations", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Gets all supported operations", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BranchDetailRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a supported operation", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "branch" + ], + "summary": "Create a supported operation", + "parameters": [ + { + "description": "Creates supported operation", + "name": "createSupportedOperation", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateSupportedOperationReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.SupportedOperationRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/ticket": { + "get": { + "description": "Retrieve all tickets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get all tickets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.TicketRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a temporary ticket", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Create a temporary ticket", + "parameters": [ + { + "description": "Creates ticket", + "name": "createTicket", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateTicketReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CreateTicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/ticket/{id}": { + "get": { + "description": "Retrieve ticket details by ticket ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get ticket by ID", + "parameters": [ + { + "type": "integer", + "description": "Ticket ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.TicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/top-leagues": { + "get": { + "description": "Retrieve all top leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all top leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.TopLeague" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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" + } + } + } + } + }, + "/api/v1/transfer/wallet/:id": { + "post": { + "description": "Create a transfer to wallet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "transfer" + ], + "summary": "Create a transfer to 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": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/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": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/bets": { + "get": { + "description": "Gets user bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Gets user bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/checkPhoneEmailExist": { + "post": { + "description": "Check if phone number or email exist", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Check if phone number or email exist", + "parameters": [ + { + "description": "Check phone number or email exist", + "name": "checkPhoneEmailExist", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/delete/{id}": { + "delete": { + "description": "Delete a user by their ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Delete user by ID", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get user profile", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user profile", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/register": { + "post": { + "description": "Register user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Register user", + "parameters": [ + { + "description": "Register user", + "name": "registerUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterUserReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/resetPassword": { + "post": { + "description": "Reset password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Reset password", + "parameters": [ + { + "description": "Reset password", + "name": "resetPassword", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetPasswordReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/search": { + "post": { + "description": "Search for user using name or phone", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Search for user using name or phone", + "parameters": [ + { + "description": "Search for using his name or phone", + "name": "searchUserByNameOrPhone", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/sendRegisterCode": { + "post": { + "description": "Send register code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send register code", + "parameters": [ + { + "description": "Send register code", + "name": "registerCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/sendResetCode": { + "post": { + "description": "Send reset code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send reset code", + "parameters": [ + { + "description": "Send reset code", + "name": "resetCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/single/{id}": { + "get": { + "description": "Get a single user by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user by id", + "parameters": [ + { + "type": "integer", + "description": "User ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/suspend": { + "post": { + "description": "Suspend or unsuspend a user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Suspend or unsuspend a user", + "parameters": [ + { + "description": "Suspend or unsuspend a user", + "name": "updateUserSuspend", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateUserSuspendReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UpdateUserSuspendRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/user/wallet": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieve customer wallet details", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get customer wallet", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "company_id", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomerWalletRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/veli/games-list": { "post": { "description": "Retrieves games for the specified provider", @@ -1669,6 +5768,139 @@ } } }, + "/api/v1/wallet": { + "get": { + "description": "Retrieve all wallets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get all 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" + } + } + } + } + }, + "/api/v1/wallet/{id}": { + "get": { + "description": "Retrieve wallet details by wallet ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get wallet by ID", + "parameters": [ + { + "type": "integer", + "description": "Wallet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.WalletRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "patch": { + "description": "Can activate and deactivate wallet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Activate and Deactivate Wallet", + "parameters": [ + { + "type": "integer", + "description": "Wallet ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update Wallet Active", + "name": "updateCashOut", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateWalletActiveReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, "/api/v1/webhooks/alea": { "post": { "description": "Handles webhook callbacks from Alea Play virtual games for bet settlement", @@ -1718,1819 +5950,6 @@ } } }, - "/auth/login": { - "post": { - "description": "Login customer", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Login customer", - "parameters": [ - { - "description": "Login customer", - "name": "login", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.loginCustomerReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.loginCustomerRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/auth/logout": { - "post": { - "description": "Logout customer", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Logout customer", - "parameters": [ - { - "description": "Logout customer", - "name": "logout", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.logoutReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/auth/refresh": { - "post": { - "description": "Refresh token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Refresh token", - "parameters": [ - { - "description": "tokens", - "name": "refresh", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.refreshToken" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.loginCustomerRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch": { - "get": { - "description": "Gets all branches", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets all branches", - "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" - } - } - } - }, - "post": { - "description": "Creates a branch", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Create a branch", - "parameters": [ - { - "description": "Creates branch", - "name": "createBranch", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateBranchReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}": { - "get": { - "description": "Gets a single branch by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch by id", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchDetailRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Updates a branch", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Updates a branch", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update Branch", - "name": "updateBranch", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateBranchReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Delete the branch", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Delete the branch", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}/cashier": { - "get": { - "description": "Gets branch cashiers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch cashiers", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.GetCashierRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}/operation": { - "get": { - "description": "Gets branch operations", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch operations", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.BranchOperationRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branch/{id}/operation/{opID}": { - "delete": { - "description": "Delete the branch operation", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Delete the branch operation", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Branch Operation ID", - "name": "opID", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/branchCashier": { - "get": { - "description": "Gets branch for cahier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branch for cahier", - "parameters": [ - { - "type": "integer", - "description": "Branch ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchDetailRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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" - } - } - } - } - }, - "/cashier/{id}": { - "get": { - "description": "Get a single cashier by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Get cashier by id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/cashierWallet": { - "get": { - "description": "Get wallet for cashier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Get wallet for cashier", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/cashiers": { - "get": { - "description": "Get all cashiers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Get all cashiers", - "parameters": [ - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Page size", - "name": "page_size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Create cashier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Create cashier", - "parameters": [ - { - "description": "Create cashier", - "name": "cashier", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateCashierReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/cashiers/{id}": { - "put": { - "description": "Update cashier", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "cashier" - ], - "summary": "Update cashier", - "parameters": [ - { - "type": "integer", - "description": "Cashier ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update cashier", - "name": "cashier", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateCashierReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/company": { - "get": { - "description": "Gets all companies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Gets all companies", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.CompanyRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a company", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Create a company", - "parameters": [ - { - "description": "Creates company", - "name": "createCompany", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateCompanyReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CompanyRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/company/{id}": { - "get": { - "description": "Gets a single company by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Gets company by id", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CompanyRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Updates a company", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Updates a company", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update Company", - "name": "updateCompany", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateCompanyReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CompanyRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Delete the company", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Delete the company", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/company/{id}/branch": { - "get": { - "description": "Gets branches by company id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branches by company id", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "id", - "in": "path", - "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" - } - } - } - } - }, - "/events": { - "get": { - "description": "Retrieve all upcoming events from the database", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all upcoming events", - "parameters": [ - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Page size", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "League ID Filter", - "name": "league_id", - "in": "query" - }, - { - "type": "string", - "description": "Sport ID Filter", - "name": "sport_id", - "in": "query" - }, - { - "type": "string", - "description": "Country Code Filter", - "name": "cc", - "in": "query" - }, - { - "type": "string", - "description": "Start Time", - "name": "first_start_time", - "in": "query" - }, - { - "type": "string", - "description": "End Time", - "name": "last_start_time", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.UpcomingEvent" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/events/{id}": { - "get": { - "description": "Retrieve an upcoming event by ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve an upcoming by ID", - "parameters": [ - { - "type": "string", - "description": "ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.UpcomingEvent" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Set the event status to removed", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "event" - ], - "summary": "Set the event status to removed", - "parameters": [ - { - "type": "integer", - "description": "Event ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/leagues": { - "get": { - "description": "Gets all leagues", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leagues" - ], - "summary": "Gets all leagues", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.League" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/manager/{id}/branch": { - "get": { - "description": "Gets a branches by manager id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets branches by manager id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "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" - } - } - } - } - }, - "/managers": { - "get": { - "description": "Get all Managers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Get all Managers", - "parameters": [ - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Page size", - "name": "page_size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.ManagersRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Create Manager", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Create Manager", - "parameters": [ - { - "description": "Create manager", - "name": "manger", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateManagerReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/managers/{id}": { - "get": { - "description": "Get a single manager by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Get manager by id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.ManagersRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Update Managers", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "manager" - ], - "summary": "Update Managers", - "parameters": [ - { - "description": "Update Managers", - "name": "Managers", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.updateManagerReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/odds": { - "get": { - "description": "Retrieve all prematch odds from the database", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all prematch odds", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.Odd" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/odds/upcoming/{upcoming_id}": { - "get": { - "description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve prematch odds by upcoming ID (FI)", - "parameters": [ - { - "type": "string", - "description": "Upcoming Event ID (FI)", - "name": "upcoming_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "Number of results to return (default: 10)", - "name": "limit", - "in": "query" - }, - { - "type": "integer", - "description": "Number of results to skip (default: 0)", - "name": "offset", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.Odd" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/odds/upcoming/{upcoming_id}/market/{market_id}": { - "get": { - "description": "Retrieve raw odds records using a Market ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve raw odds by Market ID", - "parameters": [ - { - "type": "string", - "description": "Upcoming ID", - "name": "upcoming_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Market ID", - "name": "market_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.RawOddsByMarketID" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/operation": { - "post": { - "description": "Creates a operation", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Create a operation", - "parameters": [ - { - "description": "Creates operation", - "name": "createBranchOperation", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateBranchOperationReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.BranchOperationRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/popok/games": { "get": { "description": "Retrieves the list of available PopOK slot games", @@ -3610,1686 +6029,6 @@ } } }, - "/referral/settings": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieves current referral settings (admin only)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "referral" - ], - "summary": "Get referral settings", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.ReferralSettings" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Updates referral settings (admin only)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "referral" - ], - "summary": "Update referral settings", - "parameters": [ - { - "description": "Referral settings", - "name": "settings", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.ReferralSettings" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/referral/stats": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieves referral statistics for the authenticated user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "referral" - ], - "summary": "Get referral statistics", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.ReferralStats" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/result/{id}": { - "get": { - "description": "Get results for an event", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "result" - ], - "summary": "Get results for an event", - "parameters": [ - { - "type": "string", - "description": "Event ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.ResultRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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" - } - } - } - } - }, - "/search/company": { - "get": { - "description": "Gets all companies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "company" - ], - "summary": "Gets all companies", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.CompanyRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/bet": { - "get": { - "description": "Gets all the bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets all bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a bet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Create a bet", - "parameters": [ - { - "description": "Creates bet", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateBetReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/bet/cashout/{id}": { - "get": { - "description": "Gets a single bet by cashout id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by cashout id", - "parameters": [ - { - "type": "string", - "description": "cashout ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/bet/{id}": { - "get": { - "description": "Gets a single bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Deletes bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Deletes bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "patch": { - "description": "Updates the cashed out field", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Updates the cashed out field", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Updates Cashed Out", - "name": "updateCashOut", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateCashOutReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/sport/random/bet": { - "post": { - "description": "Generate a random bet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Generate a random bet", - "parameters": [ - { - "description": "Create Random bet", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.RandomBetReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "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", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Gets all supported operations", - "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" - } - } - } - }, - "post": { - "description": "Creates a supported operation", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "branch" - ], - "summary": "Create a supported operation", - "parameters": [ - { - "description": "Creates supported operation", - "name": "createSupportedOperation", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateSupportedOperationReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.SupportedOperationRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/ticket": { - "get": { - "description": "Retrieve all tickets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get all tickets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.TicketRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a temporary ticket", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Create a temporary ticket", - "parameters": [ - { - "description": "Creates ticket", - "name": "createTicket", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateTicketReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.CreateTicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/ticket/{id}": { - "get": { - "description": "Retrieve ticket details by ticket ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get ticket by ID", - "parameters": [ - { - "type": "integer", - "description": "Ticket ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.TicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/top-leagues": { - "get": { - "description": "Retrieve all top leagues", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all top leagues", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.UpcomingEvent" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/transaction": { - "get": { - "description": "Gets all the transactions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Gets all transactions", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.TransactionRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a transaction", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Create a transaction", - "parameters": [ - { - "description": "Creates transaction", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CreateTransactionReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.TransactionRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/transaction/{id}": { - "get": { - "description": "Gets a single transaction by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Gets transaction by id", - "parameters": [ - { - "type": "integer", - "description": "Transaction ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.TransactionRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "put": { - "description": "Updates the verified status of a transaction", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transaction" - ], - "summary": "Updates the verified field of a transaction", - "parameters": [ - { - "type": "integer", - "description": "Transaction ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Updates Transaction Verification", - "name": "updateVerified", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateTransactionVerifiedReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/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": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "transfer" - ], - "summary": "Create a transfer to 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": { - "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": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/bets": { - "get": { - "description": "Gets user bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Gets user bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/checkPhoneEmailExist": { - "post": { - "description": "Check if phone number or email exist", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Check if phone number or email exist", - "parameters": [ - { - "description": "Check phone number or email exist", - "name": "checkPhoneEmailExist", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/delete/{id}": { - "delete": { - "description": "Delete a user by their ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Delete user by ID", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/profile": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get user profile", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user profile", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/register": { - "post": { - "description": "Register user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Register user", - "parameters": [ - { - "description": "Register user", - "name": "registerUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterUserReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/resetPassword": { - "post": { - "description": "Reset password", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Reset password", - "parameters": [ - { - "description": "Reset password", - "name": "resetPassword", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetPasswordReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/search": { - "post": { - "description": "Search for user using name or phone", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Search for user using name or phone", - "parameters": [ - { - "description": "Search for using his name or phone", - "name": "searchUserByNameOrPhone", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/sendRegisterCode": { - "post": { - "description": "Send register code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send register code", - "parameters": [ - { - "description": "Send register code", - "name": "registerCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/sendResetCode": { - "post": { - "description": "Send reset code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send reset code", - "parameters": [ - { - "description": "Send reset code", - "name": "resetCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/single/{id}": { - "get": { - "description": "Get a single user by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user by id", - "parameters": [ - { - "type": "integer", - "description": "User ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/suspend": { - "post": { - "description": "Suspend or unsuspend a user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Suspend or unsuspend a user", - "parameters": [ - { - "description": "Suspend or unsuspend a user", - "name": "updateUserSuspend", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateUserSuspendReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UpdateUserSuspendRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/user/wallet": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieve customer wallet details", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Get customer wallet", - "parameters": [ - { - "type": "integer", - "description": "Company ID", - "name": "company_id", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CustomerWalletRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/virtual-game/callback": { "post": { "description": "Processes callbacks from PopOK for game events", @@ -5392,139 +6131,6 @@ } } } - }, - "/wallet": { - "get": { - "description": "Retrieve all wallets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Get all 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" - } - } - } - } - }, - "/wallet/{id}": { - "get": { - "description": "Retrieve wallet details by wallet ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Get wallet by ID", - "parameters": [ - { - "type": "integer", - "description": "Wallet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.WalletRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "patch": { - "description": "Can activate and deactivate wallet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "wallet" - ], - "summary": "Activate and Deactivate Wallet", - "parameters": [ - { - "type": "integer", - "description": "Wallet ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Update Wallet Active", - "name": "updateCashOut", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateWalletActiveReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } } }, "definitions": { @@ -5705,14 +6311,6 @@ "type": "number", "example": 100 }, - "branch_id": { - "type": "integer", - "example": 2 - }, - "cashed_id": { - "type": "string", - "example": "21234" - }, "cashed_out": { "type": "boolean", "example": false @@ -5721,9 +6319,12 @@ "type": "string", "example": "2025-04-08T12:00:00Z" }, + "fast_code": { + "type": "string" + }, "full_name": { "type": "string", - "example": "John" + "example": "John Smith" }, "id": { "type": "integer", @@ -5739,10 +6340,6 @@ "$ref": "#/definitions/domain.BetOutcome" } }, - "phone_number": { - "type": "string", - "example": "1234567890" - }, "status": { "allOf": [ { @@ -5761,6 +6358,145 @@ } } }, + "domain.BranchDetailRes": { + "type": "object", + "properties": { + "balance": { + "type": "number", + "example": 100.5 + }, + "branch_manager_id": { + "type": "integer", + "example": 1 + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_self_owned": { + "type": "boolean", + "example": false + }, + "is_wallet_active": { + "type": "boolean", + "example": false + }, + "location": { + "type": "string", + "example": "Addis Ababa" + }, + "manager_name": { + "type": "string", + "example": "John Smith" + }, + "manager_phone_number": { + "type": "string", + "example": "0911111111" + }, + "name": { + "type": "string", + "example": "4-kilo Branch" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, + "domain.BranchOperationRes": { + "type": "object", + "properties": { + "description": { + "type": "string", + "example": "Betting on sport events" + }, + "name": { + "type": "string", + "example": "SportsBook" + } + } + }, + "domain.BranchRes": { + "type": "object", + "properties": { + "branch_manager_id": { + "type": "integer", + "example": 1 + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_self_owned": { + "type": "boolean", + "example": false + }, + "location": { + "type": "string", + "example": "Addis Ababa" + }, + "name": { + "type": "string", + "example": "4-kilo Branch" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, + "domain.CashoutReq": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "bank_code": { + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "cashout_id": { + "type": "string", + "example": "1234" + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "reference_number": { + "type": "string" + } + } + }, "domain.ChapaDepositRequestPayload": { "type": "object", "required": [ @@ -5841,6 +6577,35 @@ } } }, + "domain.CompanyRes": { + "type": "object", + "properties": { + "admin_id": { + "type": "integer", + "example": 1 + }, + "deducted_percentage": { + "type": "number", + "example": 0.1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "name": { + "type": "string", + "example": "CompanyName" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, "domain.CreateBetOutcomeReq": { "type": "object", "properties": { @@ -5869,27 +6634,91 @@ "type": "integer", "example": 1 }, - "full_name": { - "type": "string", - "example": "John" - }, "outcomes": { "type": "array", "items": { "$ref": "#/definitions/domain.CreateBetOutcomeReq" } - }, - "phone_number": { - "type": "string", - "example": "1234567890" - }, - "status": { - "allOf": [ - { - "$ref": "#/definitions/domain.OutcomeStatus" - } - ], + } + } + }, + "domain.CreateBranchOperationReq": { + "type": "object", + "properties": { + "branch_id": { + "type": "integer", "example": 1 + }, + "operation_id": { + "type": "integer", + "example": 1 + } + } + }, + "domain.CreateBranchReq": { + "type": "object", + "required": [ + "branch_manager_id", + "location", + "name", + "operations" + ], + "properties": { + "branch_manager_id": { + "type": "integer", + "example": 1 + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "is_self_owned": { + "type": "boolean", + "example": false + }, + "location": { + "type": "string", + "maxLength": 100, + "minLength": 3, + "example": "Addis Ababa" + }, + "name": { + "type": "string", + "maxLength": 100, + "minLength": 3, + "example": "4-kilo Branch" + }, + "operations": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "domain.CreateCompanyReq": { + "type": "object", + "properties": { + "admin_id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "CompanyName" + } + } + }, + "domain.CreateSupportedOperationReq": { + "type": "object", + "properties": { + "description": { + "type": "string", + "example": "Betting on sport events" + }, + "name": { + "type": "string", + "example": "SportsBook" } } }, @@ -6356,6 +7185,55 @@ } } }, + "domain.GetCompanyRes": { + "type": "object", + "properties": { + "admin_first_name": { + "type": "string", + "example": "John" + }, + "admin_id": { + "type": "integer", + "example": 1 + }, + "admin_last_name": { + "type": "string", + "example": "Doe" + }, + "admin_phone_number": { + "type": "string", + "example": "1234567890" + }, + "balance": { + "type": "number", + "example": 1 + }, + "deducted_percentage": { + "type": "number", + "example": 0.1 + }, + "id": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": false + }, + "is_wallet_active": { + "type": "boolean", + "example": false + }, + "name": { + "type": "string", + "example": "CompanyName" + }, + "wallet_id": { + "type": "integer", + "example": 1 + } + } + }, "domain.League": { "type": "object", "properties": { @@ -6470,17 +7348,6 @@ } } }, - "domain.OtpProvider": { - "type": "string", - "enum": [ - "twilio", - "aformessage" - ], - "x-enum-varnames": [ - "TwilioSms", - "AfroMessage" - ] - }, "domain.OutcomeStatus": { "type": "integer", "enum": [ @@ -6744,9 +7611,6 @@ "created_at": { "type": "string" }, - "customer_id": { - "type": "integer" - }, "description": { "type": "string" }, @@ -6768,6 +7632,12 @@ }, "updated_at": { "type": "string" + }, + "user_id": { + "type": "integer" + }, + "user_role": { + "$ref": "#/definitions/domain.Role" } } }, @@ -6803,6 +7673,245 @@ "RoleCashier" ] }, + "domain.ShopBetReq": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "amount": { + "type": "number", + "example": 100 + }, + "bank_code": { + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "bet_id": { + "type": "integer", + "example": 1 + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "full_name": { + "type": "string", + "example": "John Smith" + }, + "outcomes": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.CreateBetOutcomeReq" + } + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "phone_number": { + "type": "string", + "example": "0911111111" + }, + "reference_number": { + "type": "string" + } + } + }, + "domain.ShopDepositReq": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "amount": { + "type": "number", + "example": 100 + }, + "bank_code": { + "description": "FullName string `json:\"full_name\" example:\"John Smith\"`\nPhoneNumber string `json:\"phone_number\" example:\"0911111111\"`", + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "customer_id": { + "type": "integer", + "example": 1 + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "reference_number": { + "type": "string" + } + } + }, + "domain.ShopDepositRes": { + "type": "object", + "properties": { + "customer_id": { + "type": "integer" + }, + "id": { + "type": "integer" + }, + "shop_transaction_id": { + "type": "integer" + }, + "wallet_transfer_id": { + "type": "integer" + } + } + }, + "domain.ShopTransactionRes": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "account_number": { + "type": "string" + }, + "amount": { + "type": "number", + "example": 100 + }, + "approved_by": { + "type": "integer", + "example": 1 + }, + "approver_first_name": { + "type": "string", + "example": "John" + }, + "approver_last_name": { + "type": "string", + "example": "Smith" + }, + "approver_phone_number": { + "type": "string", + "example": "0911111111" + }, + "bank_code": { + "type": "string" + }, + "beneficiary_name": { + "type": "string" + }, + "branch_id": { + "type": "integer", + "example": 1 + }, + "branch_location": { + "type": "string", + "example": "Branch Location" + }, + "branch_name": { + "type": "string", + "example": "Branch Name" + }, + "cashier_name": { + "type": "string", + "example": "John Smith" + }, + "company_id": { + "type": "integer", + "example": 1 + }, + "created_at": { + "type": "string" + }, + "creator_first_name": { + "type": "string", + "example": "John" + }, + "creator_last_name": { + "type": "string", + "example": "Smith" + }, + "creator_phone_number": { + "type": "string", + "example": "0911111111" + }, + "full_name": { + "type": "string", + "example": "John Smith" + }, + "id": { + "type": "integer", + "example": 1 + }, + "payment_option": { + "allOf": [ + { + "$ref": "#/definitions/domain.PaymentOption" + } + ], + "example": 1 + }, + "phone_number": { + "type": "string", + "example": "0911111111" + }, + "reference_number": { + "type": "string" + }, + "type": { + "type": "integer", + "example": 1 + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": "integer", + "example": 1 + }, + "verified": { + "type": "boolean", + "example": true + } + } + }, + "domain.SupportedOperationRes": { + "type": "object", + "properties": { + "description": { + "type": "string", + "example": "Betting on sport events" + }, + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "SportsBook" + } + } + }, "domain.TicketOutcome": { "type": "object", "properties": { @@ -6906,6 +8015,10 @@ "description": "Away team ID (can be empty/null)", "type": "integer" }, + "flagged": { + "description": "Whether the event is flagged or not", + "type": "boolean" + }, "home_kit_image": { "description": "Kit or image for home team (optional)", "type": "string" @@ -6960,6 +8073,36 @@ } } }, + "domain.UpdateCompanyReq": { + "type": "object", + "properties": { + "admin_id": { + "type": "integer", + "example": 1 + }, + "deducted_percentage": { + "type": "number", + "example": 0.1 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "name": { + "type": "string", + "example": "CompanyName" + } + } + }, + "domain.UpdateTransactionVerifiedReq": { + "type": "object", + "properties": { + "verified": { + "type": "boolean", + "example": true + } + } + }, "handlers.AdminRes": { "type": "object", "properties": { @@ -7004,97 +8147,6 @@ } } }, - "handlers.BranchDetailRes": { - "type": "object", - "properties": { - "balance": { - "type": "number", - "example": 100.5 - }, - "branch_manager_id": { - "type": "integer", - "example": 1 - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "id": { - "type": "integer", - "example": 1 - }, - "is_self_owned": { - "type": "boolean", - "example": false - }, - "location": { - "type": "string", - "example": "Addis Ababa" - }, - "manager_name": { - "type": "string", - "example": "John Smith" - }, - "manager_phone_number": { - "type": "string", - "example": "0911111111" - }, - "name": { - "type": "string", - "example": "4-kilo Branch" - }, - "wallet_id": { - "type": "integer", - "example": 1 - } - } - }, - "handlers.BranchOperationRes": { - "type": "object", - "properties": { - "description": { - "type": "string", - "example": "Betting on sport events" - }, - "name": { - "type": "string", - "example": "SportsBook" - } - } - }, - "handlers.BranchRes": { - "type": "object", - "properties": { - "branch_manager_id": { - "type": "integer", - "example": 1 - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "id": { - "type": "integer", - "example": 1 - }, - "is_self_owned": { - "type": "boolean", - "example": false - }, - "location": { - "type": "string", - "example": "Addis Ababa" - }, - "name": { - "type": "string", - "example": "4-kilo Branch" - }, - "wallet_id": { - "type": "integer", - "example": 1 - } - } - }, "handlers.CheckPhoneEmailExistReq": { "type": "object", "properties": { @@ -7119,27 +8171,6 @@ } } }, - "handlers.CompanyRes": { - "type": "object", - "properties": { - "admin_id": { - "type": "integer", - "example": 1 - }, - "id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "CompanyName" - }, - "wallet_id": { - "type": "integer", - "example": 1 - } - } - }, "handlers.CreateAdminReq": { "type": "object", "properties": { @@ -7169,60 +8200,6 @@ } } }, - "handlers.CreateBranchOperationReq": { - "type": "object", - "properties": { - "branch_id": { - "type": "integer", - "example": 1 - }, - "operation_id": { - "type": "integer", - "example": 1 - } - } - }, - "handlers.CreateBranchReq": { - "type": "object", - "required": [ - "branch_manager_id", - "location", - "name", - "operations" - ], - "properties": { - "branch_manager_id": { - "type": "integer", - "example": 1 - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "is_self_owned": { - "type": "boolean", - "example": false - }, - "location": { - "type": "string", - "maxLength": 100, - "minLength": 3, - "example": "Addis Ababa" - }, - "name": { - "type": "string", - "maxLength": 100, - "minLength": 3, - "example": "4-kilo Branch" - }, - "operations": { - "type": "array", - "items": { - "type": "integer" - } - } - } - }, "handlers.CreateCashierReq": { "type": "object", "properties": { @@ -7256,19 +8233,6 @@ } } }, - "handlers.CreateCompanyReq": { - "type": "object", - "properties": { - "admin_id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "CompanyName" - } - } - }, "handlers.CreateManagerReq": { "type": "object", "properties": { @@ -7298,75 +8262,6 @@ } } }, - "handlers.CreateSupportedOperationReq": { - "type": "object", - "properties": { - "description": { - "type": "string", - "example": "Betting on sport events" - }, - "name": { - "type": "string", - "example": "SportsBook" - } - } - }, - "handlers.CreateTransactionReq": { - "type": "object", - "properties": { - "account_name": { - "type": "string" - }, - "account_number": { - "type": "string" - }, - "amount": { - "type": "number", - "example": 100 - }, - "bank_code": { - "type": "string" - }, - "beneficiary_name": { - "type": "string" - }, - "bet_id": { - "type": "integer", - "example": 1 - }, - "branch_id": { - "type": "integer", - "example": 1 - }, - "cashout_id": { - "type": "string", - "example": "191212" - }, - "full_name": { - "type": "string", - "example": "John Smith" - }, - "payment_option": { - "allOf": [ - { - "$ref": "#/definitions/domain.PaymentOption" - } - ], - "example": 1 - }, - "phone_number": { - "type": "string", - "example": "0911111111" - }, - "reference_number": { - "type": "string" - }, - "type": { - "type": "integer", - "example": 1 - } - } - }, "handlers.CreateTransferReq": { "type": "object", "properties": { @@ -7390,10 +8285,22 @@ "type": "integer", "example": 1 }, + "first_name": { + "type": "string", + "example": "John" + }, "id": { "type": "integer", "example": 1 }, + "last_name": { + "type": "string", + "example": "Smith" + }, + "phone_number": { + "type": "string", + "example": "0911111111" + }, "regular_balance": { "type": "number", "example": 100 @@ -7402,6 +8309,10 @@ "type": "integer", "example": 1 }, + "regular_is_active": { + "type": "boolean", + "example": true + }, "regular_updated_at": { "type": "string" }, @@ -7413,11 +8324,59 @@ "type": "integer", "example": 1 }, + "static_is_active": { + "type": "boolean", + "example": true + }, "static_updated_at": { "type": "string" } } }, + "handlers.CustomersRes": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "email": { + "type": "string" + }, + "email_verified": { + "type": "boolean" + }, + "first_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_login": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "phone_number": { + "type": "string" + }, + "phone_verified": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/domain.Role" + }, + "suspended": { + "type": "boolean" + }, + "suspended_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "handlers.GetCashierRes": { "type": "object", "properties": { @@ -7520,9 +8479,6 @@ }, "handlers.RegisterCodeReq": { "type": "object", - "required": [ - "provider" - ], "properties": { "email": { "type": "string", @@ -7531,22 +8487,11 @@ "phone_number": { "type": "string", "example": "1234567890" - }, - "provider": { - "allOf": [ - { - "$ref": "#/definitions/domain.OtpProvider" - } - ], - "example": "twilio" } } }, "handlers.RegisterUserReq": { "type": "object", - "required": [ - "provider" - ], "properties": { "email": { "type": "string", @@ -7572,14 +8517,6 @@ "type": "string", "example": "1234567890" }, - "provider": { - "allOf": [ - { - "$ref": "#/definitions/domain.OtpProvider" - } - ], - "example": "twilio" - }, "referal_code": { "type": "string", "example": "ABC123" @@ -7588,9 +8525,6 @@ }, "handlers.ResetCodeReq": { "type": "object", - "required": [ - "provider" - ], "properties": { "email": { "type": "string", @@ -7599,14 +8533,6 @@ "phone_number": { "type": "string", "example": "1234567890" - }, - "provider": { - "allOf": [ - { - "$ref": "#/definitions/domain.OtpProvider" - } - ], - "example": "twilio" } } }, @@ -7658,118 +8584,34 @@ } } }, - "handlers.SupportedOperationRes": { + "handlers.SetLeagueActiveReq": { "type": "object", "properties": { - "description": { - "type": "string", - "example": "Betting on sport events" - }, - "id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "SportsBook" + "is_active": { + "type": "boolean" } } }, - "handlers.TransactionRes": { + "handlers.TopLeague": { "type": "object", "properties": { - "account_name": { + "events": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.UpcomingEvent" + } + }, + "league_cc": { "type": "string" }, - "account_number": { + "league_id": { + "type": "integer" + }, + "league_name": { "type": "string" }, - "amount": { - "type": "number", - "example": 100 - }, - "approved_by": { - "type": "integer", - "example": 1 - }, - "approver_name": { - "type": "string", - "example": "John Smith" - }, - "bank_code": { - "type": "string" - }, - "beneficiary_name": { - "type": "string" - }, - "bet_id": { - "type": "integer", - "example": 1 - }, - "branch_id": { - "type": "integer", - "example": 1 - }, - "branch_location": { - "type": "string", - "example": "Branch Location" - }, - "branch_name": { - "type": "string", - "example": "Branch Name" - }, - "cashier_id": { - "type": "integer", - "example": 1 - }, - "cashier_name": { - "type": "string", - "example": "John Smith" - }, - "company_id": { - "type": "integer", - "example": 1 - }, - "created_at": { - "type": "string" - }, - "full_name": { - "type": "string", - "example": "John Smith" - }, - "id": { - "type": "integer", - "example": 1 - }, - "number_of_outcomes": { - "type": "integer", - "example": 1 - }, - "payment_option": { - "allOf": [ - { - "$ref": "#/definitions/domain.PaymentOption" - } - ], - "example": 1 - }, - "phone_number": { - "type": "string", - "example": "0911111111" - }, - "reference_number": { - "type": "string" - }, - "type": { - "type": "integer", - "example": 1 - }, - "updated_at": { - "type": "string" - }, - "verified": { - "type": "boolean", - "example": true + "league_sport_id": { + "type": "integer" } } }, @@ -7779,15 +8621,27 @@ "amount": { "type": "number" }, - "cashier_id": { + "created_at": { + "type": "string" + }, + "depositor_first_name": { + "type": "string" + }, + "depositor_id": { "type": "integer" }, - "created_at": { + "depositor_last_name": { + "type": "string" + }, + "depositor_phone_number": { "type": "string" }, "id": { "type": "integer" }, + "message": { + "type": "string" + }, "payment_method": { "type": "string" }, @@ -7820,32 +8674,9 @@ } } }, - "handlers.UpdateCompanyReq": { - "type": "object", - "properties": { - "admin_id": { - "type": "integer", - "example": 1 - }, - "name": { - "type": "string", - "example": "CompanyName" - } - } - }, - "handlers.UpdateTransactionVerifiedReq": { - "type": "object", - "properties": { - "verified": { - "type": "boolean", - "example": true - } - } - }, "handlers.UpdateUserSuspendReq": { "type": "object", "required": [ - "suspended", "user_id" ], "properties": { @@ -7979,7 +8810,7 @@ }, "game_id": { "type": "string", - "example": "crash_001" + "example": "1" }, "mode": { "type": "string", @@ -8100,6 +8931,27 @@ } } }, + "handlers.updateCustomerReq": { + "type": "object", + "properties": { + "company_id": { + "type": "integer", + "example": 1 + }, + "first_name": { + "type": "string", + "example": "John" + }, + "last_name": { + "type": "string", + "example": "Doe" + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, "handlers.updateManagerReq": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e1968f5..ca6e5d8 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -121,20 +121,16 @@ definitions: amount: example: 100 type: number - branch_id: - example: 2 - type: integer - cashed_id: - example: "21234" - type: string cashed_out: example: false type: boolean created_at: example: "2025-04-08T12:00:00Z" type: string + fast_code: + type: string full_name: - example: John + example: John Smith type: string id: example: 1 @@ -146,9 +142,6 @@ definitions: items: $ref: '#/definitions/domain.BetOutcome' type: array - phone_number: - example: "1234567890" - type: string status: allOf: - $ref: '#/definitions/domain.OutcomeStatus' @@ -160,6 +153,104 @@ definitions: example: 2 type: integer type: object + domain.BranchDetailRes: + properties: + balance: + example: 100.5 + type: number + branch_manager_id: + example: 1 + type: integer + company_id: + example: 1 + type: integer + id: + example: 1 + type: integer + is_active: + example: false + type: boolean + is_self_owned: + example: false + type: boolean + is_wallet_active: + example: false + type: boolean + location: + example: Addis Ababa + type: string + manager_name: + example: John Smith + type: string + manager_phone_number: + example: "0911111111" + type: string + name: + example: 4-kilo Branch + type: string + wallet_id: + example: 1 + type: integer + type: object + domain.BranchOperationRes: + properties: + description: + example: Betting on sport events + type: string + name: + example: SportsBook + type: string + type: object + domain.BranchRes: + properties: + branch_manager_id: + example: 1 + type: integer + company_id: + example: 1 + type: integer + id: + example: 1 + type: integer + is_active: + example: false + type: boolean + is_self_owned: + example: false + type: boolean + location: + example: Addis Ababa + type: string + name: + example: 4-kilo Branch + type: string + wallet_id: + example: 1 + type: integer + type: object + domain.CashoutReq: + properties: + account_name: + type: string + account_number: + type: string + bank_code: + type: string + beneficiary_name: + type: string + branch_id: + example: 1 + type: integer + cashout_id: + example: "1234" + type: string + payment_option: + allOf: + - $ref: '#/definitions/domain.PaymentOption' + example: 1 + reference_number: + type: string + type: object domain.ChapaDepositRequestPayload: properties: amount: @@ -212,6 +303,27 @@ definitions: reference: type: string type: object + domain.CompanyRes: + properties: + admin_id: + example: 1 + type: integer + deducted_percentage: + example: 0.1 + type: number + id: + example: 1 + type: integer + is_active: + example: true + type: boolean + name: + example: CompanyName + type: string + wallet_id: + example: 1 + type: integer + type: object domain.CreateBetOutcomeReq: properties: event_id: @@ -232,20 +344,68 @@ definitions: branch_id: example: 1 type: integer - full_name: - example: John - type: string outcomes: items: $ref: '#/definitions/domain.CreateBetOutcomeReq' type: array - phone_number: - example: "1234567890" - type: string - status: - allOf: - - $ref: '#/definitions/domain.OutcomeStatus' + type: object + domain.CreateBranchOperationReq: + properties: + branch_id: example: 1 + type: integer + operation_id: + example: 1 + type: integer + type: object + domain.CreateBranchReq: + properties: + branch_manager_id: + example: 1 + type: integer + company_id: + example: 1 + type: integer + is_self_owned: + example: false + type: boolean + location: + example: Addis Ababa + maxLength: 100 + minLength: 3 + type: string + name: + example: 4-kilo Branch + maxLength: 100 + minLength: 3 + type: string + operations: + items: + type: integer + type: array + required: + - branch_manager_id + - location + - name + - operations + type: object + domain.CreateCompanyReq: + properties: + admin_id: + example: 1 + type: integer + name: + example: CompanyName + type: string + type: object + domain.CreateSupportedOperationReq: + properties: + description: + example: Betting on sport events + type: string + name: + example: SportsBook + type: string type: object domain.CreateTicketOutcomeReq: properties: @@ -565,6 +725,42 @@ definitions: meta: $ref: '#/definitions/domain.PaginationMeta' type: object + domain.GetCompanyRes: + properties: + admin_first_name: + example: John + type: string + admin_id: + example: 1 + type: integer + admin_last_name: + example: Doe + type: string + admin_phone_number: + example: "1234567890" + type: string + balance: + example: 1 + type: number + deducted_percentage: + example: 0.1 + type: number + id: + example: 1 + type: integer + is_active: + example: false + type: boolean + is_wallet_active: + example: false + type: boolean + name: + example: CompanyName + type: string + wallet_id: + example: 1 + type: integer + type: object domain.League: properties: bet365_id: @@ -643,14 +839,6 @@ definitions: source: type: string type: object - domain.OtpProvider: - enum: - - twilio - - aformessage - type: string - x-enum-varnames: - - TwilioSms - - AfroMessage domain.OutcomeStatus: enum: - 0 @@ -833,8 +1021,6 @@ definitions: properties: created_at: type: string - customer_id: - type: integer description: type: string id: @@ -850,6 +1036,10 @@ definitions: type: string updated_at: type: string + user_id: + type: integer + user_role: + $ref: '#/definitions/domain.Role' type: object domain.Response: properties: @@ -875,6 +1065,172 @@ definitions: - RoleBranchManager - RoleCustomer - RoleCashier + domain.ShopBetReq: + properties: + account_name: + type: string + account_number: + type: string + amount: + example: 100 + type: number + bank_code: + type: string + beneficiary_name: + type: string + bet_id: + example: 1 + type: integer + branch_id: + example: 1 + type: integer + full_name: + example: John Smith + type: string + outcomes: + items: + $ref: '#/definitions/domain.CreateBetOutcomeReq' + type: array + payment_option: + allOf: + - $ref: '#/definitions/domain.PaymentOption' + example: 1 + phone_number: + example: "0911111111" + type: string + reference_number: + type: string + type: object + domain.ShopDepositReq: + properties: + account_name: + type: string + account_number: + type: string + amount: + example: 100 + type: number + bank_code: + description: |- + FullName string `json:"full_name" example:"John Smith"` + PhoneNumber string `json:"phone_number" example:"0911111111"` + type: string + beneficiary_name: + type: string + branch_id: + example: 1 + type: integer + customer_id: + example: 1 + type: integer + payment_option: + allOf: + - $ref: '#/definitions/domain.PaymentOption' + example: 1 + reference_number: + type: string + type: object + domain.ShopDepositRes: + properties: + customer_id: + type: integer + id: + type: integer + shop_transaction_id: + type: integer + wallet_transfer_id: + type: integer + type: object + domain.ShopTransactionRes: + properties: + account_name: + type: string + account_number: + type: string + amount: + example: 100 + type: number + approved_by: + example: 1 + type: integer + approver_first_name: + example: John + type: string + approver_last_name: + example: Smith + type: string + approver_phone_number: + example: "0911111111" + type: string + bank_code: + type: string + beneficiary_name: + type: string + branch_id: + example: 1 + type: integer + branch_location: + example: Branch Location + type: string + branch_name: + example: Branch Name + type: string + cashier_name: + example: John Smith + type: string + company_id: + example: 1 + type: integer + created_at: + type: string + creator_first_name: + example: John + type: string + creator_last_name: + example: Smith + type: string + creator_phone_number: + example: "0911111111" + type: string + full_name: + example: John Smith + type: string + id: + example: 1 + type: integer + payment_option: + allOf: + - $ref: '#/definitions/domain.PaymentOption' + example: 1 + phone_number: + example: "0911111111" + type: string + reference_number: + type: string + type: + example: 1 + type: integer + updated_at: + type: string + user_id: + example: 1 + type: integer + verified: + example: true + type: boolean + type: object + domain.SupportedOperationRes: + properties: + description: + example: Betting on sport events + type: string + id: + example: 1 + type: integer + name: + example: SportsBook + type: string + type: object domain.TicketOutcome: properties: away_team_name: @@ -948,6 +1304,9 @@ definitions: away_team_id: description: Away team ID (can be empty/null) type: integer + flagged: + description: Whether the event is flagged or not + type: boolean home_kit_image: description: Kit or image for home team (optional) type: string @@ -986,6 +1345,27 @@ definitions: - $ref: '#/definitions/domain.EventStatus' description: Match Status for event type: object + domain.UpdateCompanyReq: + properties: + admin_id: + example: 1 + type: integer + deducted_percentage: + example: 0.1 + type: number + is_active: + example: true + type: boolean + name: + example: CompanyName + type: string + type: object + domain.UpdateTransactionVerifiedReq: + properties: + verified: + example: true + type: boolean + type: object handlers.AdminRes: properties: created_at: @@ -1015,72 +1395,6 @@ definitions: updated_at: type: string type: object - handlers.BranchDetailRes: - properties: - balance: - example: 100.5 - type: number - branch_manager_id: - example: 1 - type: integer - company_id: - example: 1 - type: integer - id: - example: 1 - type: integer - is_self_owned: - example: false - type: boolean - location: - example: Addis Ababa - type: string - manager_name: - example: John Smith - type: string - manager_phone_number: - example: "0911111111" - type: string - name: - example: 4-kilo Branch - type: string - wallet_id: - example: 1 - type: integer - type: object - handlers.BranchOperationRes: - properties: - description: - example: Betting on sport events - type: string - name: - example: SportsBook - type: string - type: object - handlers.BranchRes: - properties: - branch_manager_id: - example: 1 - type: integer - company_id: - example: 1 - type: integer - id: - example: 1 - type: integer - is_self_owned: - example: false - type: boolean - location: - example: Addis Ababa - type: string - name: - example: 4-kilo Branch - type: string - wallet_id: - example: 1 - type: integer - type: object handlers.CheckPhoneEmailExistReq: properties: email: @@ -1097,21 +1411,6 @@ definitions: phone_number_exist: type: boolean type: object - handlers.CompanyRes: - properties: - admin_id: - example: 1 - type: integer - id: - example: 1 - type: integer - name: - example: CompanyName - type: string - wallet_id: - example: 1 - type: integer - type: object handlers.CreateAdminReq: properties: company_id: @@ -1133,46 +1432,6 @@ definitions: example: "1234567890" type: string type: object - handlers.CreateBranchOperationReq: - properties: - branch_id: - example: 1 - type: integer - operation_id: - example: 1 - type: integer - type: object - handlers.CreateBranchReq: - properties: - branch_manager_id: - example: 1 - type: integer - company_id: - example: 1 - type: integer - is_self_owned: - example: false - type: boolean - location: - example: Addis Ababa - maxLength: 100 - minLength: 3 - type: string - name: - example: 4-kilo Branch - maxLength: 100 - minLength: 3 - type: string - operations: - items: - type: integer - type: array - required: - - branch_manager_id - - location - - name - - operations - type: object handlers.CreateCashierReq: properties: branch_id: @@ -1197,15 +1456,6 @@ definitions: example: false type: boolean type: object - handlers.CreateCompanyReq: - properties: - admin_id: - example: 1 - type: integer - name: - example: CompanyName - type: string - type: object handlers.CreateManagerReq: properties: company_id: @@ -1227,53 +1477,6 @@ definitions: example: "1234567890" type: string type: object - handlers.CreateSupportedOperationReq: - properties: - description: - example: Betting on sport events - type: string - name: - example: SportsBook - type: string - type: object - handlers.CreateTransactionReq: - properties: - account_name: - type: string - account_number: - type: string - amount: - example: 100 - type: number - bank_code: - type: string - beneficiary_name: - type: string - bet_id: - example: 1 - type: integer - branch_id: - example: 1 - type: integer - cashout_id: - example: "191212" - type: string - full_name: - example: John Smith - type: string - payment_option: - allOf: - - $ref: '#/definitions/domain.PaymentOption' - example: 1 - phone_number: - example: "0911111111" - type: string - reference_number: - type: string - type: - example: 1 - type: integer - type: object handlers.CreateTransferReq: properties: amount: @@ -1290,15 +1493,27 @@ definitions: customer_id: example: 1 type: integer + first_name: + example: John + type: string id: example: 1 type: integer + last_name: + example: Smith + type: string + phone_number: + example: "0911111111" + type: string regular_balance: example: 100 type: number regular_id: example: 1 type: integer + regular_is_active: + example: true + type: boolean regular_updated_at: type: string static_balance: @@ -1307,9 +1522,41 @@ definitions: static_id: example: 1 type: integer + static_is_active: + example: true + type: boolean static_updated_at: type: string type: object + handlers.CustomersRes: + properties: + created_at: + type: string + email: + type: string + email_verified: + type: boolean + first_name: + type: string + id: + type: integer + last_login: + type: string + last_name: + type: string + phone_number: + type: string + phone_verified: + type: boolean + role: + $ref: '#/definitions/domain.Role' + suspended: + type: boolean + suspended_at: + type: string + updated_at: + type: string + type: object handlers.GetCashierRes: properties: branch_id: @@ -1384,12 +1631,6 @@ definitions: phone_number: example: "1234567890" type: string - provider: - allOf: - - $ref: '#/definitions/domain.OtpProvider' - example: twilio - required: - - provider type: object handlers.RegisterUserReq: properties: @@ -1411,15 +1652,9 @@ definitions: phone_number: example: "1234567890" type: string - provider: - allOf: - - $ref: '#/definitions/domain.OtpProvider' - example: twilio referal_code: example: ABC123 type: string - required: - - provider type: object handlers.ResetCodeReq: properties: @@ -1429,12 +1664,6 @@ definitions: phone_number: example: "1234567890" type: string - provider: - allOf: - - $ref: '#/definitions/domain.OtpProvider' - example: twilio - required: - - provider type: object handlers.ResetPasswordReq: properties: @@ -1469,97 +1698,44 @@ definitions: role: $ref: '#/definitions/domain.Role' type: object - handlers.SupportedOperationRes: + handlers.SetLeagueActiveReq: properties: - description: - example: Betting on sport events - type: string - id: - example: 1 - type: integer - name: - example: SportsBook - type: string - type: object - handlers.TransactionRes: - properties: - account_name: - type: string - account_number: - type: string - amount: - example: 100 - type: number - approved_by: - example: 1 - type: integer - approver_name: - example: John Smith - type: string - bank_code: - type: string - beneficiary_name: - type: string - bet_id: - example: 1 - type: integer - branch_id: - example: 1 - type: integer - branch_location: - example: Branch Location - type: string - branch_name: - example: Branch Name - type: string - cashier_id: - example: 1 - type: integer - cashier_name: - example: John Smith - type: string - company_id: - example: 1 - type: integer - created_at: - type: string - full_name: - example: John Smith - type: string - id: - example: 1 - type: integer - number_of_outcomes: - example: 1 - type: integer - payment_option: - allOf: - - $ref: '#/definitions/domain.PaymentOption' - example: 1 - phone_number: - example: "0911111111" - type: string - reference_number: - type: string - type: - example: 1 - type: integer - updated_at: - type: string - verified: - example: true + is_active: type: boolean type: object + handlers.TopLeague: + properties: + events: + items: + $ref: '#/definitions/domain.UpcomingEvent' + type: array + league_cc: + type: string + league_id: + type: integer + league_name: + type: string + league_sport_id: + type: integer + type: object handlers.TransferWalletRes: properties: amount: type: number - cashier_id: - type: integer created_at: type: string + depositor_first_name: + type: string + depositor_id: + type: integer + depositor_last_name: + type: string + depositor_phone_number: + type: string id: type: integer + message: + type: string payment_method: type: string receiver_wallet_id: @@ -1581,21 +1757,6 @@ definitions: cashedOut: type: boolean type: object - handlers.UpdateCompanyReq: - properties: - admin_id: - example: 1 - type: integer - name: - example: CompanyName - type: string - type: object - handlers.UpdateTransactionVerifiedReq: - properties: - verified: - example: true - type: boolean - type: object handlers.UpdateUserSuspendReq: properties: suspended: @@ -1605,7 +1766,6 @@ definitions: example: 123 type: integer required: - - suspended - user_id type: object handlers.UpdateUserSuspendRes: @@ -1686,7 +1846,7 @@ definitions: example: USD type: string game_id: - example: crash_001 + example: "1" type: string mode: enum: @@ -1774,6 +1934,21 @@ definitions: example: false type: boolean type: object + handlers.updateCustomerReq: + properties: + company_id: + example: 1 + type: integer + first_name: + example: John + type: string + last_name: + example: Doe + type: string + suspended: + example: false + type: boolean + type: object handlers.updateManagerReq: properties: company_id: @@ -1825,7 +2000,7 @@ info: title: FortuneBet API version: 1.0.1 paths: - /admin: + /api/v1/admin: get: consumes: - application/json @@ -1894,7 +2069,30 @@ paths: summary: Create Admin tags: - admin - /admin/{id}: + /api/v1/admin-company: + get: + consumes: + - application/json + description: Gets a single company by id + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.GetCompanyRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets company by id + tags: + - company + /api/v1/admin/{id}: get: consumes: - application/json @@ -2007,6 +2205,108 @@ paths: summary: Launch an Alea Play virtual game tags: - Alea Virtual Games + /api/v1/auth/login: + post: + consumes: + - application/json + description: Login customer + parameters: + - description: Login customer + in: body + name: login + required: true + schema: + $ref: '#/definitions/handlers.loginCustomerReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.loginCustomerRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Login customer + tags: + - auth + /api/v1/auth/logout: + post: + consumes: + - application/json + description: Logout customer + parameters: + - description: Logout customer + in: body + name: logout + required: true + schema: + $ref: '#/definitions/handlers.logoutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Logout customer + tags: + - auth + /api/v1/auth/refresh: + post: + consumes: + - application/json + description: Refresh token + parameters: + - description: tokens + in: body + name: refresh + required: true + schema: + $ref: '#/definitions/handlers.refreshToken' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.loginCustomerRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Refresh token + tags: + - auth /api/v1/banks: get: produces: @@ -2145,6 +2445,502 @@ paths: summary: Update a bank tags: - Institutions - Banks + /api/v1/branch: + get: + consumes: + - application/json + description: Gets all branches + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BranchDetailRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all branches + tags: + - branch + post: + consumes: + - application/json + description: Creates a branch + parameters: + - description: Creates branch + in: body + name: createBranch + required: true + schema: + $ref: '#/definitions/domain.CreateBranchReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BranchRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a branch + tags: + - branch + /api/v1/branch/{id}: + delete: + consumes: + - application/json + description: Delete the branch + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Delete the branch + tags: + - branch + get: + consumes: + - application/json + description: Gets a single branch by id + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BranchDetailRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets branch by id + tags: + - branch + put: + consumes: + - application/json + description: Updates a branch + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + - description: Update Branch + in: body + name: updateBranch + required: true + schema: + $ref: '#/definitions/domain.CreateBranchReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BranchRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Updates a branch + tags: + - branch + /api/v1/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/domain.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 + /api/v1/branch/{id}/cashier: + get: + consumes: + - application/json + description: Gets branch cashiers + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/handlers.GetCashierRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets branch cashiers + tags: + - branch + /api/v1/branch/{id}/operation: + get: + consumes: + - application/json + description: Gets branch operations + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BranchOperationRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets branch operations + tags: + - branch + /api/v1/branch/{id}/operation/{opID}: + delete: + consumes: + - application/json + description: Delete the branch operation + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + - description: Branch Operation ID + in: path + name: opID + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Delete the branch operation + tags: + - branch + /api/v1/branchCashier: + get: + consumes: + - application/json + description: Gets branch for cahier + parameters: + - description: Branch ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BranchDetailRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets branch for cahier + tags: + - branch + /api/v1/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 + /api/v1/cashier/{id}: + get: + consumes: + - application/json + description: Get a single cashier by id + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UserProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get cashier by id + tags: + - cashier + /api/v1/cashierWallet: + get: + consumes: + - application/json + description: Get wallet for cashier + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UserProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get wallet for cashier + tags: + - cashier + /api/v1/cashiers: + get: + consumes: + - application/json + description: Get all cashiers + parameters: + - description: Page number + in: query + name: page + type: integer + - description: Page size + in: query + name: page_size + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/handlers.GetCashierRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get all cashiers + tags: + - cashier + post: + consumes: + - application/json + description: Create cashier + parameters: + - description: Create cashier + in: body + name: cashier + required: true + schema: + $ref: '#/definitions/handlers.CreateCashierReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create cashier + tags: + - cashier + /api/v1/cashiers/{id}: + put: + consumes: + - application/json + description: Update cashier + parameters: + - description: Cashier ID + in: path + name: id + required: true + type: integer + - description: Update cashier + in: body + name: cashier + required: true + schema: + $ref: '#/definitions/handlers.updateCashierReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Update cashier + tags: + - cashier /api/v1/chapa/banks: get: consumes: @@ -2297,6 +3093,182 @@ paths: summary: Initiate a withdrawal tags: - Chapa + /api/v1/company: + get: + consumes: + - application/json + description: Gets all companies + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.GetCompanyRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all companies + tags: + - company + post: + consumes: + - application/json + description: Creates a company + parameters: + - description: Creates company + in: body + name: createCompany + required: true + schema: + $ref: '#/definitions/domain.CreateCompanyReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.CompanyRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a company + tags: + - company + /api/v1/company/{id}: + delete: + consumes: + - application/json + description: Delete the company + parameters: + - description: Company ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Delete the company + tags: + - company + get: + consumes: + - application/json + description: Gets a single company by id + parameters: + - description: Company ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.GetCompanyRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets company by id + tags: + - company + put: + consumes: + - application/json + description: Updates a company + parameters: + - description: Company ID + in: path + name: id + required: true + type: integer + - description: Update Company + in: body + name: updateCompany + required: true + schema: + $ref: '#/definitions/domain.UpdateCompanyReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.CompanyRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Updates a company + tags: + - company + /api/v1/company/{id}/branch: + get: + consumes: + - application/json + description: Gets branches by company id + parameters: + - description: Company ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BranchDetailRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets branches by company id + tags: + - branch /api/v1/currencies: get: description: Returns list of supported currencies @@ -2355,6 +3327,269 @@ paths: summary: Convert currency tags: - Multi-Currency + /api/v1/customer: + get: + consumes: + - application/json + description: Get all Customers + parameters: + - description: Page number + in: query + name: page + type: integer + - description: Page size + in: query + name: page_size + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CustomersRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get all Customers + tags: + - customer + /api/v1/customer/{id}: + get: + consumes: + - application/json + description: Get a single customer by id + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CustomersRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get customer by id + tags: + - customer + put: + consumes: + - application/json + description: Update Customers + parameters: + - description: Update Customers + in: body + name: Customers + required: true + schema: + $ref: '#/definitions/handlers.updateCustomerReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Update Customers + tags: + - customer + /api/v1/customerWallet: + get: + consumes: + - application/json + description: Retrieve all customer wallets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/handlers.CustomerWalletRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get all customer wallets + tags: + - wallet + /api/v1/events: + get: + consumes: + - application/json + description: Retrieve all upcoming events from the database + parameters: + - description: Page number + in: query + name: page + type: integer + - description: Page size + in: query + name: page_size + type: integer + - description: League ID Filter + in: query + name: league_id + type: string + - description: Sport ID Filter + in: query + name: sport_id + type: string + - description: Country Code Filter + in: query + name: cc + type: string + - description: Start Time + in: query + name: first_start_time + type: string + - description: End Time + in: query + name: last_start_time + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.UpcomingEvent' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve all upcoming events + tags: + - prematch + /api/v1/events/{id}: + delete: + consumes: + - application/json + description: Set the event status to removed + parameters: + - description: Event ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Set the event status to removed + tags: + - event + get: + consumes: + - application/json + description: Retrieve an upcoming event by ID + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.UpcomingEvent' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve an upcoming by ID + tags: + - prematch + /api/v1/events/{id}/flag: + put: + consumes: + - application/json + description: Update the event flagged + parameters: + - description: Event ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: update the event flagged + tags: + - event /api/v1/issues: get: description: Admin endpoint to list all reported issues with pagination @@ -2466,13 +3701,13 @@ paths: summary: Update issue status tags: - Issues - /api/v1/issues/customer/{customer_id}: + /api/v1/issues/user/{user_id}: get: - description: Returns all issues reported by a specific customer + description: Returns all issues reported by a specific user parameters: - - description: Customer ID + - description: User ID in: path - name: customer_id + name: user_id required: true type: integer - description: Limit @@ -2500,9 +3735,69 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/domain.ErrorResponse' - summary: Get reported issues by a customer + summary: Get reported issues by a user tags: - Issues + /api/v1/leagues: + get: + consumes: + - application/json + description: Gets all leagues + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.League' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all leagues + tags: + - leagues + /api/v1/leagues/{id}/set-active: + put: + consumes: + - application/json + description: Set the league to active + parameters: + - description: League ID + in: path + name: id + required: true + type: integer + - description: League Active Request + in: body + name: active + required: true + schema: + $ref: '#/definitions/handlers.SetLeagueActiveReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Set the league to active + tags: + - leagues /api/v1/logs: get: description: Fetches the 100 most recent application logs from MongoDB @@ -2522,6 +3817,388 @@ paths: summary: Retrieve latest application logs tags: - Logs + /api/v1/manager/{id}/branch: + get: + consumes: + - application/json + description: Gets a branches by manager id + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BranchDetailRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets branches by manager id + tags: + - branch + /api/v1/managers: + get: + consumes: + - application/json + description: Get all Managers + parameters: + - description: Page number + in: query + name: page + type: integer + - description: Page size + in: query + name: page_size + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.ManagersRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get all Managers + tags: + - manager + post: + consumes: + - application/json + description: Create Manager + parameters: + - description: Create manager + in: body + name: manger + required: true + schema: + $ref: '#/definitions/handlers.CreateManagerReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create Manager + tags: + - manager + /api/v1/managers/{id}: + get: + consumes: + - application/json + description: Get a single manager by id + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.ManagersRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get manager by id + tags: + - manager + put: + consumes: + - application/json + description: Update Managers + parameters: + - description: Update Managers + in: body + name: Managers + required: true + schema: + $ref: '#/definitions/handlers.updateManagerReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Update Managers + tags: + - manager + /api/v1/odds: + get: + consumes: + - application/json + description: Retrieve all prematch odds from the database + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.Odd' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve all prematch odds + tags: + - prematch + /api/v1/odds/upcoming/{upcoming_id}: + get: + consumes: + - application/json + description: Retrieve prematch odds by upcoming event ID (FI from Bet365) with + optional pagination + parameters: + - description: Upcoming Event ID (FI) + in: path + name: upcoming_id + required: true + type: string + - description: 'Number of results to return (default: 10)' + in: query + name: limit + type: integer + - description: 'Number of results to skip (default: 0)' + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.Odd' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve prematch odds by upcoming ID (FI) + tags: + - prematch + /api/v1/odds/upcoming/{upcoming_id}/market/{market_id}: + get: + consumes: + - application/json + description: Retrieve raw odds records using a Market ID + parameters: + - description: Upcoming ID + in: path + name: upcoming_id + required: true + type: string + - description: Market ID + in: path + name: market_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.RawOddsByMarketID' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve raw odds by Market ID + tags: + - prematch + /api/v1/operation: + post: + consumes: + - application/json + description: Creates a operation + parameters: + - description: Creates operation + in: body + name: createBranchOperation + required: true + schema: + $ref: '#/definitions/domain.CreateBranchOperationReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BranchOperationRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a operation + tags: + - branch + /api/v1/referral/settings: + get: + consumes: + - application/json + description: Retrieves current referral settings (admin only) + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ReferralSettings' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get referral settings + tags: + - referral + put: + consumes: + - application/json + description: Updates referral settings (admin only) + parameters: + - description: Referral settings + in: body + name: settings + required: true + schema: + $ref: '#/definitions/domain.ReferralSettings' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Update referral settings + tags: + - referral + /api/v1/referral/stats: + get: + consumes: + - application/json + description: Retrieves referral statistics for the authenticated user + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ReferralStats' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get referral statistics + tags: + - referral /api/v1/report-files/download/{filename}: get: description: Downloads a generated report CSV file from the server @@ -2636,6 +4313,1196 @@ paths: summary: Get dashboard report tags: - Reports + /api/v1/result/{id}: + get: + consumes: + - application/json + description: Get results for an event + parameters: + - description: Event ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/handlers.ResultRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get results for an event + tags: + - result + /api/v1/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/domain.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 + /api/v1/search/company: + get: + consumes: + - application/json + description: Gets all companies + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.CompanyRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all companies + tags: + - company + /api/v1/shop/bet: + post: + consumes: + - application/json + description: Create bet at branch + parameters: + - description: create bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.ShopBetReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create bet at branch + tags: + - transaction + /api/v1/shop/bet/{id}: + get: + consumes: + - application/json + description: Cashout bet at branch + parameters: + - description: cashout bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.CashoutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Cashout bet at branch + tags: + - transaction + /api/v1/shop/bet/{id}/cashout: + post: + consumes: + - application/json + description: Cashout bet at branch + parameters: + - description: cashout bet + in: body + name: cashoutBet + required: true + schema: + $ref: '#/definitions/domain.CashoutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Cashout bet at branch + tags: + - transaction + /api/v1/shop/cashout: + post: + consumes: + - application/json + description: Cashout bet by cashoutID + parameters: + - description: cashout bet + in: body + name: cashoutBet + required: true + schema: + $ref: '#/definitions/domain.CashoutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Cashout bet by cashoutID + tags: + - transaction + /api/v1/shop/cashout/{id}: + get: + consumes: + - application/json + description: Cashout bet at branch + parameters: + - description: cashout bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.CashoutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Cashout bet at branch + tags: + - transaction + /api/v1/shop/deposit: + post: + consumes: + - application/json + description: Transfers money from branch wallet to customer wallet + parameters: + - description: ShopDepositReq + in: body + name: transferToWallet + required: true + schema: + $ref: '#/definitions/domain.ShopDepositReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopDepositRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Shop deposit into customer wallet + tags: + - transaction + /api/v1/shop/transaction: + get: + consumes: + - application/json + description: Gets all the transactions + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.ShopTransactionRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all transactions + tags: + - transaction + /api/v1/shop/transaction/{id}: + get: + consumes: + - application/json + description: Gets a single transaction by id + parameters: + - description: Transaction ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets transaction by id + tags: + - transaction + put: + consumes: + - application/json + description: Updates the verified status of a transaction + parameters: + - description: Transaction ID + in: path + name: id + required: true + type: integer + - description: Updates Transaction Verification + in: body + name: updateVerified + required: true + schema: + $ref: '#/definitions/domain.UpdateTransactionVerifiedReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Updates the verified field of a transaction + tags: + - transaction + /api/v1/shop/transaction/{id}/bet: + get: + consumes: + - application/json + description: Gets a single shop bet by transaction id + parameters: + - description: Transaction ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.ShopTransactionRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets shop bet by transaction id + tags: + - transaction + /api/v1/sport/bet: + get: + consumes: + - application/json + description: Gets all the bets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BetRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all bets + tags: + - bet + post: + consumes: + - application/json + description: Creates a bet + parameters: + - description: Creates bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.CreateBetReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a bet + tags: + - bet + /api/v1/sport/bet/{id}: + delete: + consumes: + - application/json + description: Deletes bet by id + parameters: + - description: Bet ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Deletes bet by id + tags: + - bet + get: + consumes: + - application/json + description: Gets a single bet by id + parameters: + - description: Bet ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets bet by id + tags: + - bet + patch: + consumes: + - application/json + description: Updates the cashed out field + parameters: + - description: Bet ID + in: path + name: id + required: true + type: integer + - description: Updates Cashed Out + in: body + name: updateCashOut + required: true + schema: + $ref: '#/definitions/handlers.UpdateCashOutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Updates the cashed out field + tags: + - bet + /api/v1/sport/bet/fastcode: + post: + consumes: + - application/json + description: Creates a bet with fast code + parameters: + - description: Creates bet + in: body + name: createBetWithFastCode + required: true + schema: + $ref: '#/definitions/domain.CreateBetReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a bet with fast code + tags: + - bet + /api/v1/sport/random/bet: + post: + consumes: + - application/json + description: Generate a random bet + parameters: + - description: Create Random bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.RandomBetReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Generate a random bet + tags: + - bet + /api/v1/supportedOperation: + get: + consumes: + - application/json + description: Gets all supported operations + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BranchDetailRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all supported operations + tags: + - branch + post: + consumes: + - application/json + description: Creates a supported operation + parameters: + - description: Creates supported operation + in: body + name: createSupportedOperation + required: true + schema: + $ref: '#/definitions/domain.CreateSupportedOperationReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.SupportedOperationRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a supported operation + tags: + - branch + /api/v1/ticket: + get: + consumes: + - application/json + description: Retrieve all tickets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.TicketRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get all tickets + tags: + - ticket + post: + consumes: + - application/json + description: Creates a temporary ticket + parameters: + - description: Creates ticket + in: body + name: createTicket + required: true + schema: + $ref: '#/definitions/domain.CreateTicketReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.CreateTicketRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a temporary ticket + tags: + - ticket + /api/v1/ticket/{id}: + get: + consumes: + - application/json + description: Retrieve ticket details by ticket ID + parameters: + - description: Ticket ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.TicketRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get ticket by ID + tags: + - ticket + /api/v1/top-leagues: + get: + consumes: + - application/json + description: Retrieve all top leagues + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/handlers.TopLeague' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve all top leagues + tags: + - prematch + /api/v1/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 + /api/v1/transfer/wallet/:id: + post: + consumes: + - application/json + description: Create a transfer to 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: Create a transfer to wallet + tags: + - transfer + /api/v1/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 + /api/v1/user/bets: + get: + consumes: + - application/json + description: Gets user bets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BetRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets user bets + tags: + - user + /api/v1/user/checkPhoneEmailExist: + post: + consumes: + - application/json + description: Check if phone number or email exist + parameters: + - description: Check phone number or email exist + in: body + name: checkPhoneEmailExist + required: true + schema: + $ref: '#/definitions/handlers.CheckPhoneEmailExistReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CheckPhoneEmailExistRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Check if phone number or email exist + tags: + - user + /api/v1/user/delete/{id}: + delete: + consumes: + - application/json + description: Delete a user by their ID + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Delete user by ID + tags: + - user + /api/v1/user/profile: + get: + consumes: + - application/json + description: Get user profile + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UserProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get user profile + tags: + - user + /api/v1/user/register: + post: + consumes: + - application/json + description: Register user + parameters: + - description: Register user + in: body + name: registerUser + required: true + schema: + $ref: '#/definitions/handlers.RegisterUserReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Register user + tags: + - user + /api/v1/user/resetPassword: + post: + consumes: + - application/json + description: Reset password + parameters: + - description: Reset password + in: body + name: resetPassword + required: true + schema: + $ref: '#/definitions/handlers.ResetPasswordReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Reset password + tags: + - user + /api/v1/user/search: + post: + consumes: + - application/json + description: Search for user using name or phone + parameters: + - description: Search for using his name or phone + in: body + name: searchUserByNameOrPhone + required: true + schema: + $ref: '#/definitions/handlers.SearchUserByNameOrPhoneReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UserProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Search for user using name or phone + tags: + - user + /api/v1/user/sendRegisterCode: + post: + consumes: + - application/json + description: Send register code + parameters: + - description: Send register code + in: body + name: registerCode + required: true + schema: + $ref: '#/definitions/handlers.RegisterCodeReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Send register code + tags: + - user + /api/v1/user/sendResetCode: + post: + consumes: + - application/json + description: Send reset code + parameters: + - description: Send reset code + in: body + name: resetCode + required: true + schema: + $ref: '#/definitions/handlers.ResetCodeReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Send reset code + tags: + - user + /api/v1/user/single/{id}: + get: + consumes: + - application/json + description: Get a single user by id + parameters: + - description: User ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UserProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get user by id + tags: + - user + /api/v1/user/suspend: + post: + consumes: + - application/json + description: Suspend or unsuspend a user + parameters: + - description: Suspend or unsuspend a user + in: body + name: updateUserSuspend + required: true + schema: + $ref: '#/definitions/handlers.UpdateUserSuspendReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UpdateUserSuspendRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Suspend or unsuspend a user + tags: + - user + /api/v1/user/wallet: + get: + consumes: + - application/json + description: Retrieve customer wallet details + parameters: + - description: Company ID + in: header + name: company_id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CustomerWalletRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get customer wallet + tags: + - wallet /api/v1/veli/games-list: post: consumes: @@ -2890,6 +5757,94 @@ paths: summary: Remove game from favorites tags: - VirtualGames - Favourites + /api/v1/wallet: + get: + consumes: + - application/json + description: Retrieve all 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 wallets + tags: + - wallet + /api/v1/wallet/{id}: + get: + consumes: + - application/json + description: Retrieve wallet details by wallet ID + parameters: + - description: Wallet ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.WalletRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get wallet by ID + tags: + - wallet + patch: + consumes: + - application/json + description: Can activate and deactivate wallet + parameters: + - description: Wallet ID + in: path + name: id + required: true + type: integer + - description: Update Wallet Active + in: body + name: updateCashOut + required: true + schema: + $ref: '#/definitions/handlers.UpdateWalletActiveReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Activate and Deactivate Wallet + tags: + - wallet /api/v1/webhooks/alea: post: consumes: @@ -2920,1203 +5875,6 @@ paths: summary: Process Alea Play game callback tags: - Alea Virtual Games - /auth/login: - post: - consumes: - - application/json - description: Login customer - parameters: - - description: Login customer - in: body - name: login - required: true - schema: - $ref: '#/definitions/handlers.loginCustomerReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.loginCustomerRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Login customer - tags: - - auth - /auth/logout: - post: - consumes: - - application/json - description: Logout customer - parameters: - - description: Logout customer - in: body - name: logout - required: true - schema: - $ref: '#/definitions/handlers.logoutReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Logout customer - tags: - - auth - /auth/refresh: - post: - consumes: - - application/json - description: Refresh token - parameters: - - description: tokens - in: body - name: refresh - required: true - schema: - $ref: '#/definitions/handlers.refreshToken' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.loginCustomerRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Refresh token - tags: - - auth - /branch: - get: - consumes: - - application/json - description: Gets all branches - 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: Gets all branches - tags: - - branch - post: - consumes: - - application/json - description: Creates a branch - parameters: - - description: Creates branch - in: body - name: createBranch - required: true - schema: - $ref: '#/definitions/handlers.CreateBranchReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.BranchRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a branch - tags: - - branch - /branch/{id}: - delete: - consumes: - - application/json - description: Delete the branch - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Delete the branch - tags: - - branch - get: - consumes: - - application/json - description: Gets a single branch by id - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.BranchDetailRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets branch by id - tags: - - branch - put: - consumes: - - application/json - description: Updates a branch - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - - description: Update Branch - in: body - name: updateBranch - required: true - schema: - $ref: '#/definitions/handlers.CreateBranchReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.BranchRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - 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/domain.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}/cashier: - get: - consumes: - - application/json - description: Gets branch cashiers - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.GetCashierRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets branch cashiers - tags: - - branch - /branch/{id}/operation: - get: - consumes: - - application/json - description: Gets branch operations - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.BranchOperationRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets branch operations - tags: - - branch - /branch/{id}/operation/{opID}: - delete: - consumes: - - application/json - description: Delete the branch operation - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - - description: Branch Operation ID - in: path - name: opID - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Delete the branch operation - tags: - - branch - /branchCashier: - get: - consumes: - - application/json - description: Gets branch for cahier - parameters: - - description: Branch ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.BranchDetailRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets branch for cahier - 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 - /cashier/{id}: - get: - consumes: - - application/json - description: Get a single cashier by id - parameters: - - description: User ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UserProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get cashier by id - tags: - - cashier - /cashierWallet: - get: - consumes: - - application/json - description: Get wallet for cashier - parameters: - - description: User ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UserProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get wallet for cashier - tags: - - cashier - /cashiers: - get: - consumes: - - application/json - description: Get all cashiers - parameters: - - description: Page number - in: query - name: page - type: integer - - description: Page size - in: query - name: page_size - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get all cashiers - tags: - - cashier - post: - consumes: - - application/json - description: Create cashier - parameters: - - description: Create cashier - in: body - name: cashier - required: true - schema: - $ref: '#/definitions/handlers.CreateCashierReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create cashier - tags: - - cashier - /cashiers/{id}: - put: - consumes: - - application/json - description: Update cashier - parameters: - - description: Cashier ID - in: path - name: id - required: true - type: integer - - description: Update cashier - in: body - name: cashier - required: true - schema: - $ref: '#/definitions/handlers.updateCashierReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Update cashier - tags: - - cashier - /company: - get: - consumes: - - application/json - description: Gets all companies - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.CompanyRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets all companies - tags: - - company - post: - consumes: - - application/json - description: Creates a company - parameters: - - description: Creates company - in: body - name: createCompany - required: true - schema: - $ref: '#/definitions/handlers.CreateCompanyReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CompanyRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a company - tags: - - company - /company/{id}: - delete: - consumes: - - application/json - description: Delete the company - parameters: - - description: Company ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Delete the company - tags: - - company - get: - consumes: - - application/json - description: Gets a single company by id - parameters: - - description: Company ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CompanyRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets company by id - tags: - - company - put: - consumes: - - application/json - description: Updates a company - parameters: - - description: Company ID - in: path - name: id - required: true - type: integer - - description: Update Company - in: body - name: updateCompany - required: true - schema: - $ref: '#/definitions/handlers.UpdateCompanyReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CompanyRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Updates a company - tags: - - company - /company/{id}/branch: - get: - consumes: - - application/json - description: Gets branches by company id - parameters: - - description: Company ID - in: path - name: id - required: true - type: integer - 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: Gets branches by company id - tags: - - branch - /events: - get: - consumes: - - application/json - description: Retrieve all upcoming events from the database - parameters: - - description: Page number - in: query - name: page - type: integer - - description: Page size - in: query - name: page_size - type: integer - - description: League ID Filter - in: query - name: league_id - type: string - - description: Sport ID Filter - in: query - name: sport_id - type: string - - description: Country Code Filter - in: query - name: cc - type: string - - description: Start Time - in: query - name: first_start_time - type: string - - description: End Time - in: query - name: last_start_time - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.UpcomingEvent' - type: array - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve all upcoming events - tags: - - prematch - /events/{id}: - delete: - consumes: - - application/json - description: Set the event status to removed - parameters: - - description: Event ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Set the event status to removed - tags: - - event - get: - consumes: - - application/json - description: Retrieve an upcoming event by ID - parameters: - - description: ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.UpcomingEvent' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve an upcoming by ID - tags: - - prematch - /leagues: - get: - consumes: - - application/json - description: Gets all leagues - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.League' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets all leagues - tags: - - leagues - /manager/{id}/branch: - get: - consumes: - - application/json - description: Gets a branches by manager id - parameters: - - description: User ID - in: path - name: id - required: true - type: integer - 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: Gets branches by manager id - tags: - - branch - /managers: - get: - consumes: - - application/json - description: Get all Managers - parameters: - - description: Page number - in: query - name: page - type: integer - - description: Page size - in: query - name: page_size - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.ManagersRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get all Managers - tags: - - manager - post: - consumes: - - application/json - description: Create Manager - parameters: - - description: Create manager - in: body - name: manger - required: true - schema: - $ref: '#/definitions/handlers.CreateManagerReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create Manager - tags: - - manager - /managers/{id}: - get: - consumes: - - application/json - description: Get a single manager by id - parameters: - - description: User ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.ManagersRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get manager by id - tags: - - manager - put: - consumes: - - application/json - description: Update Managers - parameters: - - description: Update Managers - in: body - name: Managers - required: true - schema: - $ref: '#/definitions/handlers.updateManagerReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Update Managers - tags: - - manager - /odds: - get: - consumes: - - application/json - description: Retrieve all prematch odds from the database - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.Odd' - type: array - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve all prematch odds - tags: - - prematch - /odds/upcoming/{upcoming_id}: - get: - consumes: - - application/json - description: Retrieve prematch odds by upcoming event ID (FI from Bet365) with - optional pagination - parameters: - - description: Upcoming Event ID (FI) - in: path - name: upcoming_id - required: true - type: string - - description: 'Number of results to return (default: 10)' - in: query - name: limit - type: integer - - description: 'Number of results to skip (default: 0)' - in: query - name: offset - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.Odd' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve prematch odds by upcoming ID (FI) - tags: - - prematch - /odds/upcoming/{upcoming_id}/market/{market_id}: - get: - consumes: - - application/json - description: Retrieve raw odds records using a Market ID - parameters: - - description: Upcoming ID - in: path - name: upcoming_id - required: true - type: string - - description: Market ID - in: path - name: market_id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.RawOddsByMarketID' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve raw odds by Market ID - tags: - - prematch - /operation: - post: - consumes: - - application/json - description: Creates a operation - parameters: - - description: Creates operation - in: body - name: createBranchOperation - required: true - schema: - $ref: '#/definitions/handlers.CreateBranchOperationReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.BranchOperationRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a operation - tags: - - branch /popok/games: get: consumes: @@ -4169,1104 +5927,6 @@ paths: summary: Recommend virtual games tags: - Virtual Games - PopOK - /referral/settings: - get: - consumes: - - application/json - description: Retrieves current referral settings (admin only) - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.ReferralSettings' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "403": - description: Forbidden - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get referral settings - tags: - - referral - put: - consumes: - - application/json - description: Updates referral settings (admin only) - parameters: - - description: Referral settings - in: body - name: settings - required: true - schema: - $ref: '#/definitions/domain.ReferralSettings' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "403": - description: Forbidden - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Update referral settings - tags: - - referral - /referral/stats: - get: - consumes: - - application/json - description: Retrieves referral statistics for the authenticated user - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.ReferralStats' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get referral statistics - tags: - - referral - /result/{id}: - get: - consumes: - - application/json - description: Get results for an event - parameters: - - description: Event ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.ResultRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get results for an event - tags: - - result - /search/branch: - 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 - /search/company: - get: - consumes: - - application/json - description: Gets all companies - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.CompanyRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets all companies - tags: - - company - /sport/bet: - get: - consumes: - - application/json - description: Gets all the bets - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.BetRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets all bets - tags: - - bet - post: - consumes: - - application/json - description: Creates a bet - parameters: - - description: Creates bet - in: body - name: createBet - required: true - schema: - $ref: '#/definitions/domain.CreateBetReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a bet - tags: - - bet - /sport/bet/{id}: - delete: - consumes: - - application/json - description: Deletes bet by id - parameters: - - description: Bet ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Deletes bet by id - tags: - - bet - get: - consumes: - - application/json - description: Gets a single bet by id - parameters: - - description: Bet ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets bet by id - tags: - - bet - patch: - consumes: - - application/json - description: Updates the cashed out field - parameters: - - description: Bet ID - in: path - name: id - required: true - type: integer - - description: Updates Cashed Out - in: body - name: updateCashOut - required: true - schema: - $ref: '#/definitions/handlers.UpdateCashOutReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Updates the cashed out field - tags: - - bet - /sport/bet/cashout/{id}: - get: - consumes: - - application/json - description: Gets a single bet by cashout id - parameters: - - description: cashout ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets bet by cashout id - tags: - - bet - /sport/random/bet: - post: - consumes: - - application/json - description: Generate a random bet - parameters: - - description: Create Random bet - in: body - name: createBet - required: true - schema: - $ref: '#/definitions/domain.RandomBetReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Generate a random bet - tags: - - bet - /supportedOperation: - get: - consumes: - - application/json - description: Gets all supported operations - 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: Gets all supported operations - tags: - - branch - post: - consumes: - - application/json - description: Creates a supported operation - parameters: - - description: Creates supported operation - in: body - name: createSupportedOperation - required: true - schema: - $ref: '#/definitions/handlers.CreateSupportedOperationReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.SupportedOperationRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a supported operation - tags: - - branch - /ticket: - get: - consumes: - - application/json - description: Retrieve all tickets - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.TicketRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get all tickets - tags: - - ticket - post: - consumes: - - application/json - description: Creates a temporary ticket - parameters: - - description: Creates ticket - in: body - name: createTicket - required: true - schema: - $ref: '#/definitions/domain.CreateTicketReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.CreateTicketRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a temporary ticket - tags: - - ticket - /ticket/{id}: - get: - consumes: - - application/json - description: Retrieve ticket details by ticket ID - parameters: - - description: Ticket ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.TicketRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get ticket by ID - tags: - - ticket - /top-leagues: - get: - consumes: - - application/json - description: Retrieve all top leagues - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.UpcomingEvent' - type: array - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve all top leagues - tags: - - prematch - /transaction: - get: - consumes: - - application/json - description: Gets all the transactions - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.TransactionRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets all transactions - tags: - - transaction - post: - consumes: - - application/json - description: Creates a transaction - parameters: - - description: Creates transaction - in: body - name: createBet - required: true - schema: - $ref: '#/definitions/handlers.CreateTransactionReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.TransactionRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a transaction - tags: - - transaction - /transaction/{id}: - get: - consumes: - - application/json - description: Gets a single transaction by id - parameters: - - description: Transaction ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.TransactionRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets transaction by id - tags: - - transaction - put: - consumes: - - application/json - description: Updates the verified status of a transaction - parameters: - - description: Transaction ID - in: path - name: id - required: true - type: integer - - description: Updates Transaction Verification - in: body - name: updateVerified - required: true - schema: - $ref: '#/definitions/handlers.UpdateTransactionVerifiedReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Updates the verified field of a transaction - tags: - - transaction - /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 - description: Create a transfer to 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: 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/bets: - get: - consumes: - - application/json - description: Gets user bets - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.BetRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets user bets - tags: - - user - /user/checkPhoneEmailExist: - post: - consumes: - - application/json - description: Check if phone number or email exist - parameters: - - description: Check phone number or email exist - in: body - name: checkPhoneEmailExist - required: true - schema: - $ref: '#/definitions/handlers.CheckPhoneEmailExistReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CheckPhoneEmailExistRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Check if phone number or email exist - tags: - - user - /user/delete/{id}: - delete: - consumes: - - application/json - description: Delete a user by their ID - parameters: - - description: User ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Delete user by ID - tags: - - user - /user/profile: - get: - consumes: - - application/json - description: Get user profile - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UserProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get user profile - tags: - - user - /user/register: - post: - consumes: - - application/json - description: Register user - parameters: - - description: Register user - in: body - name: registerUser - required: true - schema: - $ref: '#/definitions/handlers.RegisterUserReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Register user - tags: - - user - /user/resetPassword: - post: - consumes: - - application/json - description: Reset password - parameters: - - description: Reset password - in: body - name: resetPassword - required: true - schema: - $ref: '#/definitions/handlers.ResetPasswordReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Reset password - tags: - - user - /user/search: - post: - consumes: - - application/json - description: Search for user using name or phone - parameters: - - description: Search for using his name or phone - in: body - name: searchUserByNameOrPhone - required: true - schema: - $ref: '#/definitions/handlers.SearchUserByNameOrPhoneReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UserProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Search for user using name or phone - tags: - - user - /user/sendRegisterCode: - post: - consumes: - - application/json - description: Send register code - parameters: - - description: Send register code - in: body - name: registerCode - required: true - schema: - $ref: '#/definitions/handlers.RegisterCodeReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Send register code - tags: - - user - /user/sendResetCode: - post: - consumes: - - application/json - description: Send reset code - parameters: - - description: Send reset code - in: body - name: resetCode - required: true - schema: - $ref: '#/definitions/handlers.ResetCodeReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Send reset code - tags: - - user - /user/single/{id}: - get: - consumes: - - application/json - description: Get a single user by id - parameters: - - description: User ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UserProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get user by id - tags: - - user - /user/suspend: - post: - consumes: - - application/json - description: Suspend or unsuspend a user - parameters: - - description: Suspend or unsuspend a user - in: body - name: updateUserSuspend - required: true - schema: - $ref: '#/definitions/handlers.UpdateUserSuspendReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UpdateUserSuspendRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Suspend or unsuspend a user - tags: - - user - /user/wallet: - get: - consumes: - - application/json - description: Retrieve customer wallet details - parameters: - - description: Company ID - in: header - name: company_id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CustomerWalletRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get customer wallet - tags: - - wallet /virtual-game/callback: post: consumes: @@ -5333,94 +5993,6 @@ paths: summary: Launch a PopOK virtual game tags: - Virtual Games - PopOK - /wallet: - get: - consumes: - - application/json - description: Retrieve all 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 wallets - tags: - - wallet - /wallet/{id}: - get: - consumes: - - application/json - description: Retrieve wallet details by wallet ID - parameters: - - description: Wallet ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.WalletRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get wallet by ID - tags: - - wallet - patch: - consumes: - - application/json - description: Can activate and deactivate wallet - parameters: - - description: Wallet ID - in: path - name: id - required: true - type: integer - - description: Update Wallet Active - in: body - name: updateCashOut - required: true - schema: - $ref: '#/definitions/handlers.UpdateWalletActiveReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Activate and Deactivate Wallet - tags: - - wallet securityDefinitions: Bearer: in: header diff --git a/gen/db/bet_stat.sql.go b/gen/db/bet_stat.sql.go new file mode 100644 index 0000000..275ef07 --- /dev/null +++ b/gen/db/bet_stat.sql.go @@ -0,0 +1,307 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: bet_stat.sql + +package dbgen + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const GetBetStats = `-- name: GetBetStats :many +SELECT DATE(created_at) as date, + COUNT(*) as total_bets, + SUM(amount) as total_stakes, + SUM( + CASE + WHEN status = 1 THEN 1 + ELSE 0 + END + ) as total_wins, + SUM( + CASE + WHEN status = 1 THEN amount * total_odds + ELSE 0 + END + ) as total_payouts, + AVG(total_odds) as average_odds +FROM bets +wHERE ( + user_id = $1 + OR $1 IS NULL + ) + AND ( + is_shop_bet = $2 + OR $2 IS NULL + ) + AND ( + cashed_out = $3 + OR $3 IS NULL + ) + AND ( + full_name ILIKE '%' || $4 || '%' + OR phone_number ILIKE '%' || $4 || '%' + OR $4 IS NULL + ) + AND ( + created_at > $5 + OR $5 IS NULL + ) + AND ( + created_at < $6 + OR $6 IS NULL + ) +GROUP BY DATE(created_at) +ORDER BY DATE(created_at) +` + +type GetBetStatsParams struct { + UserID pgtype.Int8 `json:"user_id"` + IsShopBet pgtype.Bool `json:"is_shop_bet"` + CashedOut pgtype.Bool `json:"cashed_out"` + Query pgtype.Text `json:"query"` + CreatedBefore pgtype.Timestamp `json:"created_before"` + CreatedAfter pgtype.Timestamp `json:"created_after"` +} + +type GetBetStatsRow struct { + Date pgtype.Date `json:"date"` + TotalBets int64 `json:"total_bets"` + TotalStakes int64 `json:"total_stakes"` + TotalWins int64 `json:"total_wins"` + TotalPayouts int64 `json:"total_payouts"` + AverageOdds float64 `json:"average_odds"` +} + +func (q *Queries) GetBetStats(ctx context.Context, arg GetBetStatsParams) ([]GetBetStatsRow, error) { + rows, err := q.db.Query(ctx, GetBetStats, + arg.UserID, + arg.IsShopBet, + arg.CashedOut, + arg.Query, + arg.CreatedBefore, + arg.CreatedAfter, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetBetStatsRow + for rows.Next() { + var i GetBetStatsRow + if err := rows.Scan( + &i.Date, + &i.TotalBets, + &i.TotalStakes, + &i.TotalWins, + &i.TotalPayouts, + &i.AverageOdds, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetBetSummary = `-- name: GetBetSummary :one +SELECT SUM(amount) as total_stakes, + COUNT(*) as total_bets, + SUM( + CASE + WHEN status = 0 THEN 1 + ELSE 0 + END + ) as active_bets, + SUM( + CASE + WHEN status = 1 THEN 1 + ELSE 0 + END + ) as total_wins, + SUM( + CASE + WHEN status = 2 THEN 1 + ELSE 0 + END + ) as total_losses, + SUM( + CASE + WHEN status = 1 THEN amount * total_odds + ELSE 0 + END + ) as win_balance +FROM bets +wHERE ( + user_id = $1 + OR $1 IS NULL + ) + AND ( + created_at > $2 + OR $2 IS NULL + ) + AND ( + created_at < $3 + OR $3 IS NULL + ) +` + +type GetBetSummaryParams struct { + UserID pgtype.Int8 `json:"user_id"` + CreatedBefore pgtype.Timestamp `json:"created_before"` + CreatedAfter pgtype.Timestamp `json:"created_after"` +} + +type GetBetSummaryRow struct { + TotalStakes int64 `json:"total_stakes"` + TotalBets int64 `json:"total_bets"` + ActiveBets int64 `json:"active_bets"` + TotalWins int64 `json:"total_wins"` + TotalLosses int64 `json:"total_losses"` + WinBalance int64 `json:"win_balance"` +} + +func (q *Queries) GetBetSummary(ctx context.Context, arg GetBetSummaryParams) (GetBetSummaryRow, error) { + row := q.db.QueryRow(ctx, GetBetSummary, arg.UserID, arg.CreatedBefore, arg.CreatedAfter) + var i GetBetSummaryRow + err := row.Scan( + &i.TotalStakes, + &i.TotalBets, + &i.ActiveBets, + &i.TotalWins, + &i.TotalLosses, + &i.WinBalance, + ) + return i, err +} + +const GetMarketPopularity = `-- name: GetMarketPopularity :one +WITH market_counts AS ( + SELECT DATE(b.created_at) as date, + bo.market_name, + COUNT(*) as bet_count, + ROW_NUMBER() OVER ( + PARTITION BY DATE(b.created_at) + ORDER BY COUNT(*) DESC + ) as rank + FROM bets b + JOIN bet_outcomes bo ON b.id = bo.bet_id + WHERE bo.market_name IS NOT NULL + AND ( + user_id = $1 + OR $1 IS NULL + ) + AND ( + created_at > $2 + OR $2 IS NULL + ) + AND ( + created_at < $3 + OR $3 IS NULL + ) + GROUP BY DATE(b.created_at), + bo.market_name +) +SELECT date, + market_name +FROM market_counts +WHERE rank = 1 +` + +type GetMarketPopularityParams struct { + UserID pgtype.Int8 `json:"user_id"` + CreatedBefore pgtype.Timestamp `json:"created_before"` + CreatedAfter pgtype.Timestamp `json:"created_after"` +} + +type GetMarketPopularityRow struct { + Date pgtype.Date `json:"date"` + MarketName string `json:"market_name"` +} + +func (q *Queries) GetMarketPopularity(ctx context.Context, arg GetMarketPopularityParams) (GetMarketPopularityRow, error) { + row := q.db.QueryRow(ctx, GetMarketPopularity, arg.UserID, arg.CreatedBefore, arg.CreatedAfter) + var i GetMarketPopularityRow + err := row.Scan(&i.Date, &i.MarketName) + return i, err +} + +const GetTotalBetsMadeInRange = `-- name: GetTotalBetsMadeInRange :one +SELECT COUNT(*) AS total_bets +FROM bets +WHERE created_at BETWEEN $1 AND $2 +` + +type GetTotalBetsMadeInRangeParams struct { + From pgtype.Timestamp `json:"from"` + To pgtype.Timestamp `json:"to"` +} + +func (q *Queries) GetTotalBetsMadeInRange(ctx context.Context, arg GetTotalBetsMadeInRangeParams) (int64, error) { + row := q.db.QueryRow(ctx, GetTotalBetsMadeInRange, arg.From, arg.To) + var total_bets int64 + err := row.Scan(&total_bets) + return total_bets, err +} + +const GetTotalCashBacksInRange = `-- name: GetTotalCashBacksInRange :one +SELECT COALESCE(SUM(amount), 0) AS total_cash_backs +FROM bets +WHERE created_at BETWEEN $1 AND $2 + AND status = 5 +` + +type GetTotalCashBacksInRangeParams struct { + From pgtype.Timestamp `json:"from"` + To pgtype.Timestamp `json:"to"` +} + +func (q *Queries) GetTotalCashBacksInRange(ctx context.Context, arg GetTotalCashBacksInRangeParams) (interface{}, error) { + row := q.db.QueryRow(ctx, GetTotalCashBacksInRange, arg.From, arg.To) + var total_cash_backs interface{} + err := row.Scan(&total_cash_backs) + return total_cash_backs, err +} + +const GetTotalCashMadeInRange = `-- name: GetTotalCashMadeInRange :one +SELECT COALESCE(SUM(amount), 0) AS total_cash_made +FROM bets +WHERE created_at BETWEEN $1 AND $2 +` + +type GetTotalCashMadeInRangeParams struct { + From pgtype.Timestamp `json:"from"` + To pgtype.Timestamp `json:"to"` +} + +func (q *Queries) GetTotalCashMadeInRange(ctx context.Context, arg GetTotalCashMadeInRangeParams) (interface{}, error) { + row := q.db.QueryRow(ctx, GetTotalCashMadeInRange, arg.From, arg.To) + var total_cash_made interface{} + err := row.Scan(&total_cash_made) + return total_cash_made, err +} + +const GetTotalCashOutInRange = `-- name: GetTotalCashOutInRange :one +SELECT COALESCE(SUM(amount), 0) AS total_cash_out +FROM bets +WHERE created_at BETWEEN $1 AND $2 + AND cashed_out = true +` + +type GetTotalCashOutInRangeParams struct { + From pgtype.Timestamp `json:"from"` + To pgtype.Timestamp `json:"to"` +} + +func (q *Queries) GetTotalCashOutInRange(ctx context.Context, arg GetTotalCashOutInRangeParams) (interface{}, error) { + row := q.db.QueryRow(ctx, GetTotalCashOutInRange, arg.From, arg.To) + var total_cash_out interface{} + err := row.Scan(&total_cash_out) + return total_cash_out, err +} diff --git a/gen/db/company.sql.go b/gen/db/company.sql.go index 2cb5371..ac5980a 100644 --- a/gen/db/company.sql.go +++ b/gen/db/company.sql.go @@ -15,26 +15,35 @@ const CreateCompany = `-- name: CreateCompany :one INSERT INTO companies ( name, admin_id, - wallet_id + wallet_id, + deducted_percentage ) -VALUES ($1, $2, $3) -RETURNING id, name, admin_id, wallet_id, created_at, updated_at +VALUES ($1, $2, $3, $4) +RETURNING id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at ` type CreateCompanyParams struct { - Name string `json:"name"` - AdminID int64 `json:"admin_id"` - WalletID int64 `json:"wallet_id"` + Name string `json:"name"` + AdminID int64 `json:"admin_id"` + WalletID int64 `json:"wallet_id"` + DeductedPercentage float32 `json:"deducted_percentage"` } func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Company, error) { - row := q.db.QueryRow(ctx, CreateCompany, arg.Name, arg.AdminID, arg.WalletID) + row := q.db.QueryRow(ctx, CreateCompany, + arg.Name, + arg.AdminID, + arg.WalletID, + arg.DeductedPercentage, + ) var i Company err := row.Scan( &i.ID, &i.Name, &i.AdminID, &i.WalletID, + &i.DeductedPercentage, + &i.IsActive, &i.CreatedAt, &i.UpdatedAt, ) @@ -52,7 +61,7 @@ func (q *Queries) DeleteCompany(ctx context.Context, id int64) error { } const GetAllCompanies = `-- name: GetAllCompanies :many -SELECT id, name, admin_id, wallet_id, created_at, updated_at, balance, is_active, admin_first_name, admin_last_name, admin_phone_number +SELECT id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number FROM companies_details WHERE ( name ILIKE '%' || $1 || '%' @@ -91,10 +100,12 @@ func (q *Queries) GetAllCompanies(ctx context.Context, arg GetAllCompaniesParams &i.Name, &i.AdminID, &i.WalletID, + &i.DeductedPercentage, + &i.IsActive, &i.CreatedAt, &i.UpdatedAt, &i.Balance, - &i.IsActive, + &i.WalletIsActive, &i.AdminFirstName, &i.AdminLastName, &i.AdminPhoneNumber, @@ -110,7 +121,7 @@ func (q *Queries) GetAllCompanies(ctx context.Context, arg GetAllCompaniesParams } const GetCompanyByID = `-- name: GetCompanyByID :one -SELECT id, name, admin_id, wallet_id, created_at, updated_at, balance, is_active, admin_first_name, admin_last_name, admin_phone_number +SELECT id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number FROM companies_details WHERE id = $1 ` @@ -123,10 +134,12 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail &i.Name, &i.AdminID, &i.WalletID, + &i.DeductedPercentage, + &i.IsActive, &i.CreatedAt, &i.UpdatedAt, &i.Balance, - &i.IsActive, + &i.WalletIsActive, &i.AdminFirstName, &i.AdminLastName, &i.AdminPhoneNumber, @@ -135,7 +148,7 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail } const SearchCompanyByName = `-- name: SearchCompanyByName :many -SELECT id, name, admin_id, wallet_id, created_at, updated_at, balance, is_active, admin_first_name, admin_last_name, admin_phone_number +SELECT id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at, balance, wallet_is_active, admin_first_name, admin_last_name, admin_phone_number FROM companies_details WHERE name ILIKE '%' || $1 || '%' ` @@ -154,10 +167,12 @@ func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text) &i.Name, &i.AdminID, &i.WalletID, + &i.DeductedPercentage, + &i.IsActive, &i.CreatedAt, &i.UpdatedAt, &i.Balance, - &i.IsActive, + &i.WalletIsActive, &i.AdminFirstName, &i.AdminLastName, &i.AdminPhoneNumber, @@ -176,25 +191,40 @@ const UpdateCompany = `-- name: UpdateCompany :one UPDATE companies SET name = COALESCE($2, name), admin_id = COALESCE($3, admin_id), + is_active = COALESCE($4, is_active), + deducted_percentage = COALESCE( + $5, + deducted_percentage + ), updated_at = CURRENT_TIMESTAMP WHERE id = $1 -RETURNING id, name, admin_id, wallet_id, created_at, updated_at +RETURNING id, name, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at ` type UpdateCompanyParams struct { - ID int64 `json:"id"` - Name pgtype.Text `json:"name"` - AdminID pgtype.Int8 `json:"admin_id"` + ID int64 `json:"id"` + Name pgtype.Text `json:"name"` + AdminID pgtype.Int8 `json:"admin_id"` + IsActive pgtype.Bool `json:"is_active"` + DeductedPercentage pgtype.Float4 `json:"deducted_percentage"` } func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (Company, error) { - row := q.db.QueryRow(ctx, UpdateCompany, arg.ID, arg.Name, arg.AdminID) + row := q.db.QueryRow(ctx, UpdateCompany, + arg.ID, + arg.Name, + arg.AdminID, + arg.IsActive, + arg.DeductedPercentage, + ) var i Company err := row.Scan( &i.ID, &i.Name, &i.AdminID, &i.WalletID, + &i.DeductedPercentage, + &i.IsActive, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/gen/db/events.sql.go b/gen/db/events.sql.go index 18cc922..9e11418 100644 --- a/gen/db/events.sql.go +++ b/gen/db/events.sql.go @@ -187,8 +187,12 @@ WHERE start_time > now() leagues.country_code = $5 OR $5 IS NULL ) + AND ( + flagged = $6 + OR $6 IS NULL + ) ORDER BY start_time ASC -LIMIT $7 OFFSET $6 +LIMIT $8 OFFSET $7 ` type GetPaginatedUpcomingEventsParams struct { @@ -197,6 +201,7 @@ type GetPaginatedUpcomingEventsParams struct { LastStartTime pgtype.Timestamp `json:"last_start_time"` FirstStartTime pgtype.Timestamp `json:"first_start_time"` CountryCode pgtype.Text `json:"country_code"` + Flagged pgtype.Bool `json:"flagged"` Offset pgtype.Int4 `json:"offset"` Limit pgtype.Int4 `json:"limit"` } @@ -235,6 +240,7 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat arg.LastStartTime, arg.FirstStartTime, arg.CountryCode, + arg.Flagged, arg.Offset, arg.Limit, ) @@ -307,6 +313,10 @@ WHERE is_live = false leagues.country_code = $5 OR $5 IS NULL ) + AND ( + flagged = $6 + OR $6 IS NULL + ) ` type GetTotalEventsParams struct { @@ -315,6 +325,7 @@ type GetTotalEventsParams struct { LastStartTime pgtype.Timestamp `json:"last_start_time"` FirstStartTime pgtype.Timestamp `json:"first_start_time"` CountryCode pgtype.Text `json:"country_code"` + Flagged pgtype.Bool `json:"flagged"` } func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams) (int64, error) { @@ -324,6 +335,7 @@ func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams) arg.LastStartTime, arg.FirstStartTime, arg.CountryCode, + arg.Flagged, ) var count int64 err := row.Scan(&count) diff --git a/gen/db/models.go b/gen/db/models.go index 0f3912b..7aa1bc2 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -173,26 +173,30 @@ type BranchOperation struct { } type CompaniesDetail struct { - ID int64 `json:"id"` - Name string `json:"name"` - AdminID int64 `json:"admin_id"` - WalletID int64 `json:"wallet_id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` - Balance int64 `json:"balance"` - IsActive bool `json:"is_active"` - AdminFirstName string `json:"admin_first_name"` - AdminLastName string `json:"admin_last_name"` - AdminPhoneNumber pgtype.Text `json:"admin_phone_number"` + ID int64 `json:"id"` + Name string `json:"name"` + AdminID int64 `json:"admin_id"` + WalletID int64 `json:"wallet_id"` + DeductedPercentage float32 `json:"deducted_percentage"` + IsActive bool `json:"is_active"` + CreatedAt pgtype.Timestamp `json:"created_at"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` + Balance int64 `json:"balance"` + WalletIsActive bool `json:"wallet_is_active"` + AdminFirstName string `json:"admin_first_name"` + AdminLastName string `json:"admin_last_name"` + AdminPhoneNumber pgtype.Text `json:"admin_phone_number"` } type Company struct { - ID int64 `json:"id"` - Name string `json:"name"` - AdminID int64 `json:"admin_id"` - WalletID int64 `json:"wallet_id"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` + ID int64 `json:"id"` + Name string `json:"name"` + AdminID int64 `json:"admin_id"` + WalletID int64 `json:"wallet_id"` + DeductedPercentage float32 `json:"deducted_percentage"` + IsActive bool `json:"is_active"` + CreatedAt pgtype.Timestamp `json:"created_at"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` } type CustomerWallet struct { diff --git a/gen/db/report.sql.go b/gen/db/report.sql.go index cb1bb6f..63f097d 100644 --- a/gen/db/report.sql.go +++ b/gen/db/report.sql.go @@ -156,77 +156,3 @@ func (q *Queries) GetCompanyWiseReport(ctx context.Context, arg GetCompanyWiseRe } return items, nil } - -const GetTotalBetsMadeInRange = `-- name: GetTotalBetsMadeInRange :one -SELECT COUNT(*) AS total_bets -FROM bets -WHERE created_at BETWEEN $1 AND $2 -` - -type GetTotalBetsMadeInRangeParams struct { - From pgtype.Timestamp `json:"from"` - To pgtype.Timestamp `json:"to"` -} - -func (q *Queries) GetTotalBetsMadeInRange(ctx context.Context, arg GetTotalBetsMadeInRangeParams) (int64, error) { - row := q.db.QueryRow(ctx, GetTotalBetsMadeInRange, arg.From, arg.To) - var total_bets int64 - err := row.Scan(&total_bets) - return total_bets, err -} - -const GetTotalCashBacksInRange = `-- name: GetTotalCashBacksInRange :one -SELECT COALESCE(SUM(amount), 0) AS total_cash_backs -FROM bets -WHERE created_at BETWEEN $1 AND $2 - AND status = 5 -` - -type GetTotalCashBacksInRangeParams struct { - From pgtype.Timestamp `json:"from"` - To pgtype.Timestamp `json:"to"` -} - -func (q *Queries) GetTotalCashBacksInRange(ctx context.Context, arg GetTotalCashBacksInRangeParams) (interface{}, error) { - row := q.db.QueryRow(ctx, GetTotalCashBacksInRange, arg.From, arg.To) - var total_cash_backs interface{} - err := row.Scan(&total_cash_backs) - return total_cash_backs, err -} - -const GetTotalCashMadeInRange = `-- name: GetTotalCashMadeInRange :one -SELECT COALESCE(SUM(amount), 0) AS total_cash_made -FROM bets -WHERE created_at BETWEEN $1 AND $2 -` - -type GetTotalCashMadeInRangeParams struct { - From pgtype.Timestamp `json:"from"` - To pgtype.Timestamp `json:"to"` -} - -func (q *Queries) GetTotalCashMadeInRange(ctx context.Context, arg GetTotalCashMadeInRangeParams) (interface{}, error) { - row := q.db.QueryRow(ctx, GetTotalCashMadeInRange, arg.From, arg.To) - var total_cash_made interface{} - err := row.Scan(&total_cash_made) - return total_cash_made, err -} - -const GetTotalCashOutInRange = `-- name: GetTotalCashOutInRange :one -SELECT COALESCE(SUM(amount), 0) AS total_cash_out -FROM bets -WHERE created_at BETWEEN $1 AND $2 - AND cashed_out = true -` - -type GetTotalCashOutInRangeParams struct { - From pgtype.Timestamp `json:"from"` - To pgtype.Timestamp `json:"to"` -} - -func (q *Queries) GetTotalCashOutInRange(ctx context.Context, arg GetTotalCashOutInRangeParams) (interface{}, error) { - row := q.db.QueryRow(ctx, GetTotalCashOutInRange, arg.From, arg.To) - var total_cash_out interface{} - err := row.Scan(&total_cash_out) - return total_cash_out, err -} diff --git a/internal/domain/bet.go b/internal/domain/bet.go index cb48793..449cf0b 100644 --- a/internal/domain/bet.go +++ b/internal/domain/bet.go @@ -95,6 +95,7 @@ type CreateBetOutcomeReq struct { type CreateBetReq struct { Outcomes []CreateBetOutcomeReq `json:"outcomes"` Amount float32 `json:"amount" example:"100.0"` + BranchID *int64 `json:"branch_id,omitempty" example:"1"` } type RandomBetReq struct { diff --git a/internal/domain/branch.go b/internal/domain/branch.go index 6f1be95..610af17 100644 --- a/internal/domain/branch.go +++ b/internal/domain/branch.go @@ -74,3 +74,98 @@ type CreateBranchOperation struct { BranchID int64 OperationID int64 } + +type CreateBranchReq struct { + Name string `json:"name" validate:"required,min=3,max=100" example:"4-kilo Branch"` + Location string `json:"location" validate:"required,min=3,max=100" example:"Addis Ababa"` + BranchManagerID int64 `json:"branch_manager_id" validate:"required,gt=0" example:"1"` + CompanyID *int64 `json:"company_id,omitempty" example:"1"` + IsSelfOwned *bool `json:"is_self_owned,omitempty" example:"false"` + Operations []int64 `json:"operations" validate:"required,dive,gt=0"` +} + +type UpdateBranchReq struct { + Name *string `json:"name,omitempty" example:"4-kilo Branch"` + Location *string `json:"location,omitempty" example:"Addis Ababa"` + BranchManagerID *int64 `json:"branch_manager_id,omitempty" example:"1"` + CompanyID *int64 `json:"company_id,omitempty" example:"1"` + IsSelfOwned *bool `json:"is_self_owned,omitempty" example:"false"` + IsActive *bool `json:"is_active,omitempty" example:"false"` +} + +type CreateSupportedOperationReq struct { + Name string `json:"name" example:"SportsBook"` + Description string `json:"description" example:"Betting on sport events"` +} + +type SupportedOperationRes struct { + ID int64 `json:"id" example:"1"` + Name string `json:"name" example:"SportsBook"` + Description string `json:"description" example:"Betting on sport events"` +} + +type CreateBranchOperationReq struct { + BranchID int64 `json:"branch_id" example:"1"` + OperationID int64 `json:"operation_id" example:"1"` +} + +type BranchOperationRes struct { + Name string `json:"name" example:"SportsBook"` + Description string `json:"description" example:"Betting on sport events"` +} + +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"` + BranchManagerID int64 `json:"branch_manager_id" example:"1"` + CompanyID int64 `json:"company_id" example:"1"` + IsSelfOwned bool `json:"is_self_owned" example:"false"` + IsActive bool `json:"is_active" example:"false"` +} + +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"` + BranchManagerID int64 `json:"branch_manager_id" example:"1"` + CompanyID int64 `json:"company_id" example:"1"` + IsSelfOwned bool `json:"is_self_owned" example:"false"` + ManagerName string `json:"manager_name" example:"John Smith"` + ManagerPhoneNumber string `json:"manager_phone_number" example:"0911111111"` + Balance float32 `json:"balance" example:"100.5"` + IsActive bool `json:"is_active" example:"false"` + WalletIsActive bool `json:"is_wallet_active" example:"false"` +} + +func ConvertBranch(branch Branch) BranchRes { + return BranchRes{ + ID: branch.ID, + Name: branch.Name, + Location: branch.Location, + WalletID: branch.WalletID, + BranchManagerID: branch.BranchManagerID, + CompanyID: branch.CompanyID, + IsSelfOwned: branch.IsSelfOwned, + IsActive: branch.IsActive, + } +} + +func ConvertBranchDetail(branch BranchDetail) BranchDetailRes { + return BranchDetailRes{ + ID: branch.ID, + Name: branch.Name, + Location: branch.Location, + WalletID: branch.WalletID, + BranchManagerID: branch.BranchManagerID, + CompanyID: branch.CompanyID, + IsSelfOwned: branch.IsSelfOwned, + ManagerName: branch.ManagerName, + ManagerPhoneNumber: branch.ManagerPhoneNumber, + Balance: branch.Balance.Float32(), + IsActive: branch.IsActive, + WalletIsActive: branch.WalletIsActive, + } +} diff --git a/internal/domain/common.go b/internal/domain/common.go index 54433ab..1f268ff 100644 --- a/internal/domain/common.go +++ b/internal/domain/common.go @@ -22,6 +22,11 @@ type ValidInt32 struct { Valid bool } +type ValidFloat32 struct { + Value float32 + Valid bool +} + type ValidString struct { Value string Valid bool diff --git a/internal/domain/company.go b/internal/domain/company.go index dbb609e..b21e519 100644 --- a/internal/domain/company.go +++ b/internal/domain/company.go @@ -1,42 +1,226 @@ package domain +import ( + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" + "github.com/jackc/pgx/v5/pgtype" +) + // Company represents the client that we will contract the services with // they are the ones that manage the branches and branch managers // they will have their own wallet that they will use to distribute to the branch wallets type Company struct { - ID int64 - Name string - AdminID int64 - WalletID int64 + ID int64 + Name string + AdminID int64 + WalletID int64 + DeductedPercentage float32 + IsActive bool } type CompanyFilter struct { - IsActive ValidBool - Query ValidString - CreatedBefore ValidTime - CreatedAfter ValidTime + IsActive ValidBool + Query ValidString + CreatedBefore ValidTime + CreatedAfter ValidTime } type GetCompany struct { - ID int64 - Name string - AdminID int64 - AdminFirstName string - AdminLastName string - AdminPhoneNumber string - WalletID int64 - WalletBalance Currency - IsWalletActive bool + ID int64 + Name string + AdminID int64 + AdminFirstName string + AdminLastName string + AdminPhoneNumber string + WalletID int64 + WalletBalance Currency + IsWalletActive bool + DeductedPercentage float32 + IsActive bool } type CreateCompany struct { - Name string - AdminID int64 - WalletID int64 + Name string + AdminID int64 + WalletID int64 + DeductedPercentage float32 } type UpdateCompany struct { - ID int64 - Name *string - AdminID *int64 + ID int64 + Name ValidString + AdminID ValidInt64 + IsActive ValidBool + DeductedPercentage ValidFloat32 +} + +type CreateCompanyReq struct { + Name string `json:"name" example:"CompanyName"` + AdminID int64 `json:"admin_id" example:"1"` +} +type UpdateCompanyReq struct { + Name *string `json:"name,omitempty" example:"CompanyName"` + AdminID *int64 `json:"admin_id,omitempty" example:"1"` + IsActive *bool `json:"is_active,omitempty" example:"true"` + DeductedPercentage *float32 `json:"deducted_percentage,omitempty" example:"0.1" validate:"lt=1"` +} + +type CompanyRes struct { + ID int64 `json:"id" example:"1"` + Name string `json:"name" example:"CompanyName"` + AdminID int64 `json:"admin_id" example:"1"` + WalletID int64 `json:"wallet_id" example:"1"` + DeductedPercentage float32 `json:"deducted_percentage" example:"0.1"` + IsActive bool `json:"is_active" example:"true"` +} + +type GetCompanyRes struct { + ID int64 `json:"id" example:"1"` + Name string `json:"name" example:"CompanyName"` + AdminID int64 `json:"admin_id" example:"1"` + WalletID int64 `json:"wallet_id" example:"1"` + WalletBalance float32 `json:"balance" example:"1"` + WalletIsActive bool `json:"is_wallet_active" example:"false"` + IsActive bool `json:"is_active" example:"false"` + DeductedPercentage float32 `json:"deducted_percentage" example:"0.1"` + AdminFirstName string `json:"admin_first_name" example:"John"` + AdminLastName string `json:"admin_last_name" example:"Doe"` + AdminPhoneNumber string `json:"admin_phone_number" example:"1234567890"` +} + +func ConvertCompany(company Company) CompanyRes { + return CompanyRes{ + ID: company.ID, + Name: company.Name, + AdminID: company.AdminID, + WalletID: company.WalletID, + IsActive: company.IsActive, + DeductedPercentage: company.DeductedPercentage, + } +} + +func ConvertGetCompany(company GetCompany) GetCompanyRes { + return GetCompanyRes{ + ID: company.ID, + Name: company.Name, + AdminID: company.AdminID, + WalletID: company.WalletID, + WalletBalance: company.WalletBalance.Float32(), + IsActive: company.IsActive, + WalletIsActive: company.IsWalletActive, + DeductedPercentage: company.DeductedPercentage, + AdminFirstName: company.AdminFirstName, + AdminLastName: company.AdminLastName, + AdminPhoneNumber: company.AdminPhoneNumber, + } +} + +func ConvertCreateCompany(company CreateCompany) dbgen.CreateCompanyParams { + return dbgen.CreateCompanyParams{ + Name: company.Name, + AdminID: company.AdminID, + WalletID: company.WalletID, + DeductedPercentage: company.DeductedPercentage, + } +} + +func ConvertDBCompany(dbCompany dbgen.Company) Company { + return Company{ + ID: dbCompany.ID, + Name: dbCompany.Name, + AdminID: dbCompany.AdminID, + WalletID: dbCompany.WalletID, + DeductedPercentage: dbCompany.DeductedPercentage, + IsActive: dbCompany.IsActive, + } +} + +func ConvertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) GetCompany { + return GetCompany{ + ID: dbCompany.ID, + Name: dbCompany.Name, + AdminID: dbCompany.AdminID, + WalletID: dbCompany.WalletID, + WalletBalance: Currency(dbCompany.Balance), + IsWalletActive: dbCompany.WalletIsActive, + AdminFirstName: dbCompany.AdminFirstName, + AdminLastName: dbCompany.AdminLastName, + AdminPhoneNumber: dbCompany.AdminPhoneNumber.String, + DeductedPercentage: dbCompany.DeductedPercentage, + IsActive: dbCompany.IsActive, + } +} + +func ConvertUpdateCompany(updateCompany UpdateCompany) dbgen.UpdateCompanyParams { + newUpdateCompany := dbgen.UpdateCompanyParams{ + ID: updateCompany.ID, + Name: pgtype.Text{ + String: updateCompany.Name.Value, + Valid: updateCompany.Name.Valid, + }, + AdminID: pgtype.Int8{ + Int64: updateCompany.AdminID.Value, + Valid: updateCompany.AdminID.Valid, + }, + IsActive: pgtype.Bool{ + Bool: updateCompany.IsActive.Value, + Valid: updateCompany.IsActive.Valid, + }, + DeductedPercentage: pgtype.Float4{ + Float32: updateCompany.DeductedPercentage.Value, + Valid: updateCompany.DeductedPercentage.Valid, + }, + } + + return newUpdateCompany +} + +func ConvertUpdateCompanyReq(req UpdateCompanyReq) UpdateCompany { + var updateCompany UpdateCompany + + if req.Name != nil { + updateCompany.Name = ValidString{ + Value: *req.Name, + Valid: true, + } + } + + if req.AdminID != nil { + updateCompany.AdminID = ValidInt64{ + Value: *req.AdminID, + Valid: true, + } + } + + if req.IsActive != nil { + updateCompany.IsActive = ValidBool{ + Value: *req.IsActive, + Valid: true, + } + } + + if req.DeductedPercentage != nil { + updateCompany.DeductedPercentage = ValidFloat32{ + Value: *req.DeductedPercentage, + Valid: true, + } + } + + return updateCompany +} + +func ConvertGetAllCompaniesParams(filter CompanyFilter) dbgen.GetAllCompaniesParams { + return dbgen.GetAllCompaniesParams{ + Query: pgtype.Text{ + String: filter.Query.Value, + Valid: filter.Query.Valid, + }, + CreatedBefore: pgtype.Timestamp{ + Time: filter.CreatedBefore.Value, + Valid: filter.CreatedBefore.Valid, + }, + CreatedAfter: pgtype.Timestamp{ + Time: filter.CreatedAfter.Value, + Valid: filter.CreatedAfter.Valid, + }, + } } diff --git a/internal/domain/event.go b/internal/domain/event.go index 874cbaa..431d998 100644 --- a/internal/domain/event.go +++ b/internal/domain/event.go @@ -128,4 +128,5 @@ type EventFilter struct { Limit ValidInt64 Offset ValidInt64 MatchStatus ValidString // e.g., "upcoming", "in_play", "ended" + Flagged ValidBool } diff --git a/internal/domain/settings.go b/internal/domain/settings.go index c0c8368..d619945 100644 --- a/internal/domain/settings.go +++ b/internal/domain/settings.go @@ -1,6 +1,8 @@ package domain -import "time" +import ( + "time" +) type Setting struct { Key string @@ -15,8 +17,37 @@ type SettingRes struct { } type SettingList struct { - MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"` - BetAmountLimit Currency `json:"bet_amount_limit"` - DailyTicketPerIP int64 `json:"daily_ticket_limit"` - TotalWinningLimit Currency `json:"total_winning_limit"` + MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"` + BetAmountLimit Currency `json:"bet_amount_limit"` + DailyTicketPerIP int64 `json:"daily_ticket_limit"` + TotalWinningLimit Currency `json:"total_winning_limit"` + AmountForBetReferral Currency `json:"amount_for_bet_referral"` +} + +type DBSettingList struct { + MaxNumberOfOutcomes ValidInt64 + BetAmountLimit ValidInt64 + DailyTicketPerIP ValidInt64 + TotalWinningLimit ValidInt64 + AmountForBetReferral ValidInt64 +} + +func ConvertInt64SettingsMap(dbSettingList *DBSettingList) map[string]*ValidInt64 { + return map[string]*ValidInt64{ + "max_number_of_outcomes": &dbSettingList.MaxNumberOfOutcomes, + "bet_amount_limit": &dbSettingList.BetAmountLimit, + "daily_ticket_limit": &dbSettingList.DailyTicketPerIP, + "total_winnings_limit": &dbSettingList.TotalWinningLimit, + "amount_for_bet_referral": &dbSettingList.AmountForBetReferral, + } +} + +func ConvertDBSetting(dbSettingList DBSettingList) SettingList { + return SettingList{ + MaxNumberOfOutcomes: dbSettingList.MaxNumberOfOutcomes.Value, + BetAmountLimit: Currency(dbSettingList.BetAmountLimit.Value), + DailyTicketPerIP: dbSettingList.DailyTicketPerIP.Value, + TotalWinningLimit: Currency(dbSettingList.TotalWinningLimit.Value), + AmountForBetReferral: Currency(dbSettingList.AmountForBetReferral.Value), + } } diff --git a/internal/domain/shop_transaction.go b/internal/domain/shop_transaction.go index ea4fde5..234d974 100644 --- a/internal/domain/shop_transaction.go +++ b/internal/domain/shop_transaction.go @@ -187,3 +187,7 @@ func ConvertShopTransactionDetail(transaction ShopTransactionDetail) ShopTransac return newTransaction } + +type UpdateTransactionVerifiedReq struct { + Verified bool `json:"verified" example:"true"` +} diff --git a/internal/repository/bet.go b/internal/repository/bet.go index fe9f1db..5d864bc 100644 --- a/internal/repository/bet.go +++ b/internal/repository/bet.go @@ -406,7 +406,7 @@ func (s *Store) GetBetSummary(ctx context.Context, filter domain.ReportFilter) ( // argPos++ // } if filter.UserID.Valid { - query += fmt.Sprintf(" AND %suser_id = $%d", func() string { + query += fmt.Sprintf(" %suser_id = $%d", func() string { if len(args) == 0 { return " WHERE " } @@ -480,21 +480,21 @@ func (s *Store) GetBetStats(ctx context.Context, filter domain.ReportFilter) ([] argPos := 1 // Add filters if provided - if filter.CompanyID.Valid { - query += fmt.Sprintf(" WHERE company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND %sbranch_id = $%d", func() string { - if len(args) == 0 { - return " WHERE " - } - return " AND " - }(), argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" WHERE company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND %sbranch_id = $%d", func() string { + // if len(args) == 0 { + // return " WHERE " + // } + // return " AND " + // }(), argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND %suser_id = $%d", func() string { if len(args) == 0 { @@ -594,16 +594,16 @@ func (s *Store) GetSportPopularity(ctx context.Context, filter domain.ReportFilt argPos := 1 // Add filters if provided - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND b.company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" AND b.company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND b.user_id = $%d", argPos) args = append(args, filter.UserID.Value) @@ -684,16 +684,6 @@ func (s *Store) GetMarketPopularity(ctx context.Context, filter domain.ReportFil argPos := 1 // Add filters if provided - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND b.company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } if filter.UserID.Valid { query += fmt.Sprintf(" AND b.user_id = $%d", argPos) args = append(args, filter.UserID.Value) @@ -770,21 +760,21 @@ func (s *Store) GetExtremeValues(ctx context.Context, filter domain.ReportFilter argPos := 1 // Add filters if provided - if filter.CompanyID.Valid { - query += fmt.Sprintf(" WHERE company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND %sbranch_id = $%d", func() string { - if len(args) == 0 { - return " WHERE " - } - return " AND " - }(), argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" WHERE company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND %sbranch_id = $%d", func() string { + // if len(args) == 0 { + // return " WHERE " + // } + // return " AND " + // }(), argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND %suser_id = $%d", func() string { if len(args) == 0 { @@ -880,16 +870,16 @@ func (s *Store) GetCustomerBetActivity(ctx context.Context, filter domain.Report argPos := 1 // Add filters if provided - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" AND company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND branch_id = $%d", argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND user_id = $%d", argPos) args = append(args, filter.UserID.Value) @@ -975,16 +965,16 @@ func (s *Store) GetBranchBetActivity(ctx context.Context, filter domain.ReportFi argPos := 1 // Add filters if provided - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" AND company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND branch_id = $%d", argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.StartTime.Valid { query += fmt.Sprintf(" AND created_at >= $%d", argPos) args = append(args, filter.StartTime.Value) @@ -1059,16 +1049,16 @@ func (s *Store) GetSportBetActivity(ctx context.Context, filter domain.ReportFil args := []interface{}{} argPos := 1 - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND b.company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" AND b.company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND b.user_id = $%d", argPos) args = append(args, filter.UserID.Value) @@ -1144,16 +1134,16 @@ func (s *Store) GetSportDetails(ctx context.Context, filter domain.ReportFilter) args := []interface{}{} argPos := 1 - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND b.company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" AND b.company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND b.user_id = $%d", argPos) args = append(args, filter.UserID.Value) @@ -1220,16 +1210,16 @@ func (s *Store) GetSportMarketPopularity(ctx context.Context, filter domain.Repo args := []interface{}{} argPos := 1 - if filter.CompanyID.Valid { - query += fmt.Sprintf(" AND b.company_id = $%d", argPos) - args = append(args, filter.CompanyID.Value) - argPos++ - } - if filter.BranchID.Valid { - query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) - args = append(args, filter.BranchID.Value) - argPos++ - } + // if filter.CompanyID.Valid { + // query += fmt.Sprintf(" AND b.company_id = $%d", argPos) + // args = append(args, filter.CompanyID.Value) + // argPos++ + // } + // if filter.BranchID.Valid { + // query += fmt.Sprintf(" AND b.branch_id = $%d", argPos) + // args = append(args, filter.BranchID.Value) + // argPos++ + // } if filter.UserID.Valid { query += fmt.Sprintf(" AND b.user_id = $%d", argPos) args = append(args, filter.UserID.Value) diff --git a/internal/repository/company.go b/internal/repository/company.go index ddd0404..a877b23 100644 --- a/internal/repository/company.go +++ b/internal/repository/company.go @@ -3,95 +3,28 @@ package repository import ( "context" "fmt" - - dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/jackc/pgx/v5/pgtype" ) -func convertCreateCompany(company domain.CreateCompany) dbgen.CreateCompanyParams { - return dbgen.CreateCompanyParams{ - Name: company.Name, - AdminID: company.AdminID, - WalletID: company.WalletID, - } -} - -func convertDBCompany(dbCompany dbgen.Company) domain.Company { - return domain.Company{ - ID: dbCompany.ID, - Name: dbCompany.Name, - AdminID: dbCompany.AdminID, - WalletID: dbCompany.WalletID, - } -} - -func convertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) domain.GetCompany { - return domain.GetCompany{ - ID: dbCompany.ID, - Name: dbCompany.Name, - AdminID: dbCompany.AdminID, - WalletID: dbCompany.WalletID, - WalletBalance: domain.Currency(dbCompany.Balance), - IsWalletActive: dbCompany.IsActive, - AdminFirstName: dbCompany.AdminFirstName, - AdminLastName: dbCompany.AdminLastName, - AdminPhoneNumber: dbCompany.AdminPhoneNumber.String, - } -} - -func convertUpdateCompany(updateCompany domain.UpdateCompany) dbgen.UpdateCompanyParams { - var newUpdateCompany dbgen.UpdateCompanyParams - - newUpdateCompany.ID = updateCompany.ID - - if updateCompany.Name != nil { - newUpdateCompany.Name = pgtype.Text{ - String: *updateCompany.Name, - Valid: true, - } - } - - if updateCompany.AdminID != nil { - newUpdateCompany.AdminID = pgtype.Int8{ - Int64: *updateCompany.AdminID, - Valid: true, - } - } - - return newUpdateCompany -} func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) { - dbCompany, err := s.queries.CreateCompany(ctx, convertCreateCompany(company)) + dbCompany, err := s.queries.CreateCompany(ctx, domain.ConvertCreateCompany(company)) if err != nil { return domain.Company{}, err } - return convertDBCompany(dbCompany), nil + return domain.ConvertDBCompany(dbCompany), nil } func (s *Store) GetAllCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.GetCompany, error) { - dbCompanies, err := s.queries.GetAllCompanies(ctx, dbgen.GetAllCompaniesParams{ - Query: pgtype.Text{ - String: filter.Query.Value, - Valid: filter.Query.Valid, - }, - CreatedBefore: pgtype.Timestamp{ - Time: filter.CreatedBefore.Value, - Valid: filter.CreatedBefore.Valid, - }, - CreatedAfter: pgtype.Timestamp{ - Time: filter.CreatedAfter.Value, - Valid: filter.CreatedAfter.Valid, - }, - }) + dbCompanies, err := s.queries.GetAllCompanies(ctx, domain.ConvertGetAllCompaniesParams(filter)) if err != nil { return nil, err } var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies)) for _, dbCompany := range dbCompanies { - companies = append(companies, convertDBCompanyDetails(dbCompany)) + companies = append(companies, domain.ConvertDBCompanyDetails(dbCompany)) } return companies, nil @@ -109,7 +42,7 @@ func (s *Store) SearchCompanyByName(ctx context.Context, name string) ([]domain. var companies []domain.GetCompany = make([]domain.GetCompany, 0, len(dbCompanies)) for _, dbCompany := range dbCompanies { - companies = append(companies, convertDBCompanyDetails(dbCompany)) + companies = append(companies, domain.ConvertDBCompanyDetails(dbCompany)) } return companies, nil } @@ -120,17 +53,17 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany if err != nil { return domain.GetCompany{}, err } - return convertDBCompanyDetails(dbCompany), nil + return domain.ConvertDBCompanyDetails(dbCompany), nil } func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) { - dbCompany, err := s.queries.UpdateCompany(ctx, convertUpdateCompany(company)) + dbCompany, err := s.queries.UpdateCompany(ctx, domain.ConvertUpdateCompany(company)) if err != nil { return domain.Company{}, err } - return convertDBCompany(dbCompany), nil + return domain.ConvertDBCompany(dbCompany), nil } func (s *Store) DeleteCompany(ctx context.Context, id int64) error { diff --git a/internal/repository/event.go b/internal/repository/event.go index 674c51a..0d266b3 100644 --- a/internal/repository/event.go +++ b/internal/repository/event.go @@ -89,6 +89,7 @@ func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEven StartTime: e.StartTime.Time.UTC(), Source: e.Source.String, Status: domain.EventStatus(e.Status.String), + Flagged: e.Flagged, } } return upcomingEvents, nil @@ -121,6 +122,7 @@ func (s *Store) GetExpiredUpcomingEvents(ctx context.Context, filter domain.Even StartTime: e.StartTime.Time.UTC(), Source: e.Source.String, Status: domain.EventStatus(e.Status.String), + Flagged: e.Flagged, } } return upcomingEvents, nil @@ -157,6 +159,10 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.Ev String: filter.CountryCode.Value, Valid: filter.CountryCode.Valid, }, + Flagged: pgtype.Bool{ + Bool: filter.Flagged.Valid, + Valid: filter.Flagged.Valid, + }, }) if err != nil { @@ -180,7 +186,7 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.Ev StartTime: e.StartTime.Time.UTC(), Source: e.Source.String, Status: domain.EventStatus(e.Status.String), - + Flagged: e.Flagged, } } totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{ @@ -204,6 +210,10 @@ func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, filter domain.Ev String: filter.CountryCode.Value, Valid: filter.CountryCode.Valid, }, + Flagged: pgtype.Bool{ + Bool: filter.Flagged.Valid, + Valid: filter.Flagged.Valid, + }, }) if err != nil { return nil, 0, err @@ -234,6 +244,7 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc StartTime: event.StartTime.Time.UTC(), Source: event.Source.String, Status: domain.EventStatus(event.Status.String), + Flagged: event.Flagged, }, nil } func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error { @@ -269,10 +280,9 @@ func (s *Store) UpdateEventStatus(ctx context.Context, eventID string, status do } - -func (s *Store) UpdateFlagged(ctx context.Context, eventID string, flagged bool) error { +func (s *Store) UpdateFlagged(ctx context.Context, eventID string, flagged bool) error { return s.queries.UpdateFlagged(ctx, dbgen.UpdateFlaggedParams{ - ID: eventID, + ID: eventID, Flagged: flagged, }) } diff --git a/internal/repository/settings.go b/internal/repository/settings.go index 7cf0d29..b49689a 100644 --- a/internal/repository/settings.go +++ b/internal/repository/settings.go @@ -10,21 +10,16 @@ import ( "go.uber.org/zap" ) -type DBSettingList struct { - MaxNumberOfOutcomes domain.ValidInt64 - BetAmountLimit domain.ValidInt64 - DailyTicketPerIP domain.ValidInt64 - TotalWinningLimit domain.ValidInt64 -} - func GetDBSettingList(settings []dbgen.Setting) (domain.SettingList, error) { - var dbSettingList DBSettingList - var int64SettingsMap = map[string]*domain.ValidInt64{ - "max_number_of_outcomes": &dbSettingList.MaxNumberOfOutcomes, - "bet_amount_limit": &dbSettingList.BetAmountLimit, - "daily_ticket_limit": &dbSettingList.DailyTicketPerIP, - "total_winnings_limit": &dbSettingList.TotalWinningLimit, - } + var dbSettingList domain.DBSettingList + // var int64SettingsMap = map[string]*domain.ValidInt64{ + // "max_number_of_outcomes": &dbSettingList.MaxNumberOfOutcomes, + // "bet_amount_limit": &dbSettingList.BetAmountLimit, + // "daily_ticket_limit": &dbSettingList.DailyTicketPerIP, + // "total_winnings_limit": &dbSettingList.TotalWinningLimit, + // } + + var int64SettingsMap = domain.ConvertInt64SettingsMap(&dbSettingList) for _, setting := range settings { is_setting_unknown := true @@ -54,12 +49,7 @@ func GetDBSettingList(settings []dbgen.Setting) (domain.SettingList, error) { } } - return domain.SettingList{ - MaxNumberOfOutcomes: dbSettingList.MaxNumberOfOutcomes.Value, - BetAmountLimit: domain.Currency(dbSettingList.BetAmountLimit.Value), - DailyTicketPerIP: dbSettingList.DailyTicketPerIP.Value, - TotalWinningLimit: domain.Currency(dbSettingList.TotalWinningLimit.Value), - }, nil + return domain.ConvertDBSetting(dbSettingList), nil } func (s *Store) GetSettingList(ctx context.Context) (domain.SettingList, error) { settings, err := s.queries.GetSettings(ctx) diff --git a/internal/services/bet/port.go b/internal/services/bet/port.go index 58a5610..70d2634 100644 --- a/internal/services/bet/port.go +++ b/internal/services/bet/port.go @@ -10,10 +10,8 @@ import ( type BetStore interface { CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error) - GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) - GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error) GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) diff --git a/internal/services/bet/service.go b/internal/services/bet/service.go index 8e0df56..a7d149d 100644 --- a/internal/services/bet/service.go +++ b/internal/services/bet/service.go @@ -19,6 +19,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/pkgs/helpers" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/company" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event" notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds" @@ -39,8 +40,9 @@ var ( ErrOutcomeLimit = errors.New("Too many outcomes on a single bet") ErrTotalBalanceNotEnough = errors.New("Total Wallet balance is insufficient to create bet") - ErrInvalidAmount = errors.New("Invalid amount") - ErrBetAmountTooHigh = errors.New("Cannot create a bet with an amount above limit") + ErrInvalidAmount = errors.New("Invalid amount") + ErrBetAmountTooHigh = errors.New("Cannot create a bet with an amount above limit") + ErrBetWinningTooHigh = errors.New("Total Winnings over set limit") ) type Service struct { @@ -49,6 +51,7 @@ type Service struct { prematchSvc odds.ServiceImpl walletSvc wallet.Service branchSvc branch.Service + companySvc company.Service settingSvc settings.Service notificationSvc *notificationservice.Service logger *slog.Logger @@ -61,6 +64,7 @@ func NewService( prematchSvc odds.ServiceImpl, walletSvc wallet.Service, branchSvc branch.Service, + companySvc company.Service, settingSvc settings.Service, notificationSvc *notificationservice.Service, logger *slog.Logger, @@ -72,6 +76,7 @@ func NewService( prematchSvc: prematchSvc, walletSvc: walletSvc, branchSvc: branchSvc, + companySvc: companySvc, settingSvc: settingSvc, notificationSvc: notificationSvc, logger: logger, @@ -206,7 +211,7 @@ func (s *Service) GenerateBetOutcome(ctx context.Context, eventID int64, marketI return newOutcome, nil } -func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID int64, role domain.Role) (domain.CreateBetRes, error) { +func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID int64, role domain.Role, companyID domain.ValidInt64) (domain.CreateBetRes, error) { settingsList, err := s.settingSvc.GetSettingList(ctx) if req.Amount < 1 { @@ -214,11 +219,11 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID } if req.Amount > settingsList.BetAmountLimit.Float32() { - return domain.CreateBetRes{}, ErrInvalidAmount + return domain.CreateBetRes{}, ErrBetAmountTooHigh } if len(req.Outcomes) > int(settingsList.MaxNumberOfOutcomes) { - s.mongoLogger.Error("too many outcomes", + s.mongoLogger.Info("too many outcomes", zap.Int("count", len(req.Outcomes)), zap.Int64("user_id", userID), ) @@ -244,6 +249,16 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID outcomes = append(outcomes, newOutcome) } + totalWinnings := req.Amount * totalOdds + + if totalWinnings > settingsList.TotalWinningLimit.Float32() { + s.mongoLogger.Info("Total Winnings over limit", + zap.Float32("Total Odds", totalOdds), + zap.Float32("amount", req.Amount), + zap.Float32("limit", settingsList.TotalWinningLimit.Float32())) + return domain.CreateBetRes{}, ErrBetWinningTooHigh + } + outcomesHash, err := generateOutcomeHash(outcomes) if err != nil { s.mongoLogger.Error("failed to generate outcome hash", @@ -254,14 +269,6 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID } count, err := s.GetBetCount(ctx, userID, outcomesHash) - if err != nil { - return domain.CreateBetRes{}, err - } - if count >= 2 { - return domain.CreateBetRes{}, fmt.Errorf("bet already placed twice") - } - - cashoutID, err := s.GenerateCashoutID() if err != nil { s.mongoLogger.Error("failed to generate cashout ID", zap.Int64("user_id", userID), @@ -269,6 +276,9 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID ) return domain.CreateBetRes{}, err } + if count >= 2 { + return domain.CreateBetRes{}, fmt.Errorf("bet already placed twice") + } fastCode := helpers.GenerateFastCode() @@ -276,15 +286,14 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID Amount: domain.ToCurrency(req.Amount), TotalOdds: totalOdds, Status: domain.OUTCOME_STATUS_PENDING, - FullName: req.FullName, - PhoneNumber: req.PhoneNumber, - CashoutID: cashoutID, OutcomesHash: outcomesHash, FastCode: fastCode, + UserID: userID, } switch role { case domain.RoleCashier: + newBet.IsShopBet = true branch, err := s.branchSvc.GetBranchByCashier(ctx, userID) if err != nil { s.mongoLogger.Error("failed to get branch by cashier", @@ -294,30 +303,20 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID return domain.CreateBetRes{}, err } - deductedAmount := req.Amount / 10 - _, err = s.walletSvc.DeductFromWallet(ctx, - branch.WalletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{ - Value: userID, - Valid: true, - }, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount)) + err = s.DeductBetFromBranchWallet(ctx, req.Amount, branch.WalletID, branch.CompanyID, userID) if err != nil { - s.mongoLogger.Error("failed to deduct from wallet", - zap.Int64("wallet_id", branch.WalletID), - zap.Float32("amount", deductedAmount), + s.mongoLogger.Error("wallet deduction for bet failed", + zap.String("role", string(role)), zap.Error(err), ) return domain.CreateBetRes{}, err } - newBet.BranchID = domain.ValidInt64{Value: branch.ID, Valid: true} - newBet.CompanyID = domain.ValidInt64{Value: branch.CompanyID, Valid: true} - newBet.UserID = domain.ValidInt64{Value: userID, Valid: true} - newBet.IsShopBet = true - case domain.RoleBranchManager, domain.RoleAdmin, domain.RoleSuperAdmin: + newBet.IsShopBet = true + // Branch Manager, Admin and Super Admin are required to pass a branch id if they want to create a bet if req.BranchID == nil { - s.mongoLogger.Error("branch ID required for admin/manager", + s.mongoLogger.Warn("branch ID required for admin/manager", zap.Int64("user_id", userID), ) return domain.CreateBetRes{}, ErrBranchIDRequired @@ -332,87 +331,42 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID return domain.CreateBetRes{}, err } - deductedAmount := req.Amount / 10 - _, err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{ - Value: userID, - Valid: true, - }, domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount)) - if err != nil { - s.mongoLogger.Error("wallet deduction failed", - zap.Int64("wallet_id", branch.WalletID), - zap.Float32("amount", deductedAmount), + if branch.BranchManagerID != userID { + s.mongoLogger.Warn("unauthorized branch for branch manager", + zap.Int64("branch_id", *req.BranchID), zap.Error(err), ) return domain.CreateBetRes{}, err } - newBet.BranchID = domain.ValidInt64{Value: branch.ID, Valid: true} - newBet.CompanyID = domain.ValidInt64{Value: branch.CompanyID, Valid: true} - newBet.UserID = domain.ValidInt64{Value: userID, Valid: true} - newBet.IsShopBet = true + if companyID.Valid && branch.CompanyID == companyID.Value { + s.mongoLogger.Warn("unauthorized company", + zap.Int64("branch_id", *req.BranchID), + zap.Error(err), + ) + } + + err = s.DeductBetFromBranchWallet(ctx, req.Amount, branch.WalletID, branch.CompanyID, userID) + if err != nil { + s.mongoLogger.Error("wallet deduction for bet failed", + zap.String("role", string(role)), + zap.Error(err), + ) + return domain.CreateBetRes{}, err + } case domain.RoleCustomer: - wallets, err := s.walletSvc.GetCustomerWallet(ctx, userID) + // Only the customer is able to create a online bet + newBet.IsShopBet = false + err = s.DeductBetFromCustomerWallet(ctx, req.Amount, userID) if err != nil { - s.mongoLogger.Error("failed to get customer wallets", + s.mongoLogger.Error("customer wallet deduction failed", + zap.Float32("amount", req.Amount), zap.Int64("user_id", userID), zap.Error(err), ) return domain.CreateBetRes{}, err } - if req.Amount < wallets.RegularBalance.Float32() { - _, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID, - domain.ToCurrency(req.Amount), domain.CustomerWalletType, domain.ValidInt64{}, - domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", req.Amount)) - if err != nil { - s.mongoLogger.Error("wallet deduction failed for customer regular wallet", - zap.Int64("customer_id", wallets.CustomerID), - zap.Int64("customer_wallet_id", wallets.ID), - zap.Int64("regular wallet_id", wallets.RegularID), - zap.Float32("amount", req.Amount), - zap.Error(err), - ) - return domain.CreateBetRes{}, err - } - } else { - combinedBalance := wallets.RegularBalance + wallets.StaticBalance - if req.Amount > combinedBalance.Float32() { - return domain.CreateBetRes{}, ErrTotalBalanceNotEnough - } - // Empty the regular balance - _, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID, - wallets.RegularBalance, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", wallets.RegularBalance.Float32())) - if err != nil { - s.mongoLogger.Error("wallet deduction failed for customer regular wallet", - zap.Int64("customer_id", wallets.CustomerID), - zap.Int64("customer_wallet_id", wallets.ID), - zap.Int64("regular wallet_id", wallets.RegularID), - zap.Float32("amount", req.Amount), - zap.Error(err), - ) - return domain.CreateBetRes{}, err - } - // Empty remaining from static balance - remainingAmount := wallets.RegularBalance - domain.Currency(req.Amount) - _, err = s.walletSvc.DeductFromWallet(ctx, wallets.StaticID, - remainingAmount, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", remainingAmount.Float32())) - if err != nil { - s.mongoLogger.Error("wallet deduction failed for customer static wallet", - zap.Int64("customer_id", wallets.CustomerID), - zap.Int64("customer_wallet_id", wallets.ID), - zap.Int64("static wallet_id", wallets.StaticID), - zap.Float32("amount", req.Amount), - zap.Error(err), - ) - return domain.CreateBetRes{}, err - } - - } - - newBet.UserID = domain.ValidInt64{Value: userID, Valid: true} - newBet.IsShopBet = false default: s.mongoLogger.Error("unknown role type", zap.String("role", string(role)), @@ -447,6 +401,100 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID return res, nil } +func (s *Service) DeductBetFromBranchWallet(ctx context.Context, amount float32, walletID int64, companyID int64, userID int64) error { + + company, err := s.companySvc.GetCompanyByID(ctx, companyID) + + if err != nil { + s.mongoLogger.Error("failed to get company", + zap.Int64("company_id", companyID), + zap.Error(err), + ) + return err + } + + deductedAmount := amount * company.DeductedPercentage + _, err = s.walletSvc.DeductFromWallet(ctx, + walletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{ + Value: userID, + Valid: true, + }, domain.TRANSFER_DIRECT, + fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount)) + + if err != nil { + s.mongoLogger.Error("failed to deduct from wallet", + zap.Int64("wallet_id", walletID), + zap.Float32("amount", deductedAmount), + zap.Error(err), + ) + return err + } + + return nil +} + +func (s *Service) DeductBetFromCustomerWallet(ctx context.Context, amount float32, userID int64) error { + wallets, err := s.walletSvc.GetCustomerWallet(ctx, userID) + if err != nil { + s.mongoLogger.Error("failed to get customer wallets", + zap.Int64("user_id", userID), + zap.Error(err), + ) + return err + } + if amount < wallets.RegularBalance.Float32() { + _, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID, + domain.ToCurrency(amount), domain.CustomerWalletType, domain.ValidInt64{}, + domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", amount)) + if err != nil { + s.mongoLogger.Error("wallet deduction failed for customer regular wallet", + zap.Int64("customer_id", wallets.CustomerID), + zap.Int64("customer_wallet_id", wallets.ID), + zap.Int64("regular wallet_id", wallets.RegularID), + zap.Float32("amount", amount), + zap.Error(err), + ) + return err + } + } else { + combinedBalance := wallets.RegularBalance + wallets.StaticBalance + if amount > combinedBalance.Float32() { + return ErrTotalBalanceNotEnough + } + // Empty the regular balance + _, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID, + wallets.RegularBalance, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, + fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", wallets.RegularBalance.Float32())) + if err != nil { + s.mongoLogger.Error("wallet deduction failed for customer regular wallet", + zap.Int64("customer_id", wallets.CustomerID), + zap.Int64("customer_wallet_id", wallets.ID), + zap.Int64("regular wallet_id", wallets.RegularID), + zap.Float32("amount", amount), + zap.Error(err), + ) + return err + } + // Empty remaining from static balance + remainingAmount := wallets.RegularBalance - domain.Currency(amount) + _, err = s.walletSvc.DeductFromWallet(ctx, wallets.StaticID, + remainingAmount, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, + fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", remainingAmount.Float32())) + if err != nil { + s.mongoLogger.Error("wallet deduction failed for customer static wallet", + zap.Int64("customer_id", wallets.CustomerID), + zap.Int64("customer_wallet_id", wallets.ID), + zap.Int64("static wallet_id", wallets.StaticID), + zap.Float32("amount", amount), + zap.Error(err), + ) + return err + } + } + + return nil +} + func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string, sportID int32, HomeTeam, AwayTeam string, StartTime time.Time, numMarkets int) ([]domain.CreateBetOutcome, float32, error) { var newOdds []domain.CreateBetOutcome @@ -657,26 +705,38 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID int64, le // s.logger.Info("Generated Random bet Outcome", "randomOdds", len(randomOdds)) - var cashoutID string - - cashoutID, err = s.GenerateCashoutID() + outcomesHash, err := generateOutcomeHash(randomOdds) if err != nil { - s.mongoLogger.Error("Failed to generate cash out ID", - zap.Int64("userID", userID), - zap.Int64("branchID", branchID)) + s.mongoLogger.Error("failed to generate outcome hash", + zap.Int64("user_id", userID), + zap.Error(err), + ) return domain.CreateBetRes{}, err } - randomNumber := strconv.FormatInt(int64(random.Intn(100000000000)), 10) + count, err := s.GetBetCount(ctx, userID, outcomesHash) + if err != nil { + s.mongoLogger.Error("failed to get bet count", + zap.Int64("user_id", userID), + zap.String("outcome_hash", outcomesHash), + zap.Error(err), + ) + return domain.CreateBetRes{}, err + } + + if count >= 2 { + return domain.CreateBetRes{}, fmt.Errorf("bet already placed twice") + } + + fastCode := helpers.GenerateFastCode() + newBet := domain.CreateBet{ - Amount: domain.ToCurrency(123.5), - TotalOdds: totalOdds, - Status: domain.OUTCOME_STATUS_PENDING, - FullName: "test" + randomNumber, - PhoneNumber: "0900000000", - CashoutID: cashoutID, - BranchID: domain.ValidInt64{Valid: true, Value: branchID}, - UserID: domain.ValidInt64{Valid: true, Value: userID}, + Amount: domain.ToCurrency(123.5), + TotalOdds: totalOdds, + Status: domain.OUTCOME_STATUS_PENDING, + UserID: userID, + IsShopBet: true, + FastCode: fastCode, } bet, err := s.CreateBet(ctx, newBet) @@ -721,17 +781,10 @@ func (s *Service) CreateBetOutcome(ctx context.Context, outcomes []domain.Create func (s *Service) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) { return s.betStore.GetBetByID(ctx, id) } -func (s *Service) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) { - return s.betStore.GetBetByCashoutID(ctx, id) -} func (s *Service) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) { return s.betStore.GetAllBets(ctx, filter) } -func (s *Service) GetBetByBranchID(ctx context.Context, branchID int64) ([]domain.GetBet, error) { - return s.betStore.GetBetByBranchID(ctx, branchID) -} - func (s *Service) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error) { return s.betStore.GetBetByUserID(ctx, UserID) } @@ -948,3 +1001,27 @@ func generateOutcomeHash(outcomes []domain.CreateBetOutcome) (string, error) { sum := sha256.Sum256([]byte(sb.String())) return hex.EncodeToString(sum[:]), nil } + +func (s *Service) CheckIfBetError(err error) bool { + betErrors := []error{ + ErrNoEventsAvailable, + ErrGenerateRandomOutcome, + ErrOutcomesNotCompleted, + ErrEventHasBeenRemoved, + ErrEventHasNotEnded, + ErrRawOddInvalid, + ErrBranchIDRequired, + ErrOutcomeLimit, + ErrTotalBalanceNotEnough, + ErrInvalidAmount, + ErrBetAmountTooHigh, + ErrBetWinningTooHigh, + } + + for _, e := range betErrors { + if errors.Is(err, e) { + return true + } + } + return false +} diff --git a/internal/services/report/service.go b/internal/services/report/service.go index 6d4cb6a..1b0d098 100644 --- a/internal/services/report/service.go +++ b/internal/services/report/service.go @@ -184,7 +184,7 @@ func (s *Service) GetBetAnalysis(ctx context.Context, filter domain.ReportFilter s.logger.Error("failed to get sport popularity", "error", err) return nil, err } - + // Get market popularity marketPopularity, err := s.betStore.GetMarketPopularity(ctx, filter) if err != nil { @@ -649,7 +649,7 @@ func (s *Service) fetchReportData(ctx context.Context, period string) (domain.Re totalCashBacks = 0 } companyReports = append(companyReports, domain.CompanyReport{ - CompanyID: row.CompanyID.Int64, + CompanyID: row.CompanyID, CompanyName: row.CompanyName, TotalBets: row.TotalBets, TotalCashIn: totalCashIn, @@ -702,7 +702,7 @@ func (s *Service) fetchReportData(ctx context.Context, period string) (domain.Re totalCashBacks = 0 } branchReports = append(branchReports, domain.BranchReport{ - BranchID: row.BranchID.Int64, + BranchID: row.BranchID, BranchName: row.BranchName, CompanyID: row.CompanyID, TotalBets: row.TotalBets, diff --git a/internal/services/ticket/service.go b/internal/services/ticket/service.go index 1fd521e..13929ed 100644 --- a/internal/services/ticket/service.go +++ b/internal/services/ticket/service.go @@ -25,7 +25,7 @@ var ( ErrTicketAmountTooHigh = errors.New("Cannot create a ticket with an amount above limit") ErrTicketLimitForSingleUser = errors.New("Number of Ticket Limit reached") ErrTicketWinningTooHigh = errors.New("Total Winnings over set limit") - ErrInvalidAmount = errors.New("Invalid amount") + ErrInvalidAmount = errors.New("Invalid amount") ErrRawOddInvalid = errors.New("Prematch Raw Odd is Invalid") ) @@ -167,11 +167,10 @@ func (s *Service) CreateTicket(ctx context.Context, req domain.CreateTicketReq, } - if req.Amount < 1 { return domain.Ticket{}, 0, ErrInvalidAmount } - + // Check to see if the amount is above a set limit if req.Amount > settingsList.BetAmountLimit.Float32() { return domain.Ticket{}, 0, ErrTicketAmountTooHigh @@ -211,7 +210,7 @@ func (s *Service) CreateTicket(ctx context.Context, req domain.CreateTicketReq, // Check to see if the total winning amount is over a set limit if totalWinnings > settingsList.TotalWinningLimit.Float32() { - s.mongoLogger.Error("Total Winnings over limit", + s.mongoLogger.Info("Total Winnings over limit", zap.Float32("Total Odds", totalOdds), zap.Float32("amount", req.Amount), zap.Float32("limit", settingsList.TotalWinningLimit.Float32())) @@ -280,3 +279,24 @@ func (s *Service) DeleteTicket(ctx context.Context, id int64) error { func (s *Service) DeleteOldTickets(ctx context.Context) error { return s.ticketStore.DeleteOldTickets(ctx) } + +func (s *Service) CheckTicketError(err error) bool { + ticketError := []error{ + ErrTicketHasExpired, + ErrNoEventsAvailable, + ErrEventHasBeenRemoved, + ErrTooManyOutcomesForTicket, + ErrTicketAmountTooHigh, + ErrTicketLimitForSingleUser, + ErrTicketWinningTooHigh, + ErrInvalidAmount, + ErrRawOddInvalid, + } + + for _, e := range ticketError { + if errors.Is(err, e) { + return true + } + } + return false +} diff --git a/internal/services/transaction/shop_bet.go b/internal/services/transaction/shop_bet.go index d634639..8296952 100644 --- a/internal/services/transaction/shop_bet.go +++ b/internal/services/transaction/shop_bet.go @@ -50,12 +50,9 @@ func (s *Service) CreateShopBet(ctx context.Context, userID int64, role domain.R } newBet, err := s.betSvc.PlaceBet(ctx, domain.CreateBetReq{ - Outcomes: req.Outcomes, - Amount: req.Amount, - FullName: req.FullName, - PhoneNumber: req.PhoneNumber, - BranchID: branchID, - }, userID, role) + Outcomes: req.Outcomes, + Amount: req.Amount, + }, userID, role, userCompanyID) if err != nil { return domain.ShopBet{}, err diff --git a/internal/web_server/handlers/admin.go b/internal/web_server/handlers/admin.go index 23b86e7..48843c6 100644 --- a/internal/web_server/handlers/admin.go +++ b/internal/web_server/handlers/admin.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "strconv" "time" @@ -31,28 +32,32 @@ type CreateAdminReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /admin [post] +// @Router /api/v1/admin [post] func (h *Handler) CreateAdmin(c *fiber.Ctx) error { var companyID domain.ValidInt64 var req CreateAdminReq if err := c.BodyParser(&req); err != nil { - h.mongoLoggerSvc.Error("failed to parse CreateAdmin request", + h.mongoLoggerSvc.Info("failed to parse CreateAdmin request", zap.Int64("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } h.mongoLoggerSvc.Error("validation failed for CreateAdmin request", zap.Int64("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } if req.CompanyID == nil { @@ -69,7 +74,7 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Company ID is invalid", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error()) } companyID = domain.ValidInt64{ Value: *req.CompanyID, @@ -95,13 +100,16 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create admin", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error()) } if req.CompanyID != nil { _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ - ID: *req.CompanyID, - AdminID: &newUser.ID, + ID: *req.CompanyID, + AdminID: domain.ValidInt64{ + Value: newUser.ID, + Valid: true, + }, }) if err != nil { h.mongoLoggerSvc.Error("failed to update company with new admin", @@ -111,7 +119,7 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update company", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company"+err.Error()) } } @@ -152,7 +160,7 @@ type AdminRes struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /admin [get] +// @Router /api/v1/admin [get] func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { searchQuery := c.Query("query") @@ -166,8 +174,8 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.logger.Info("invalid start_time format", "error", err) + return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -180,8 +188,8 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.logger.Info("invalid start_time format", "error", err) + return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -209,12 +217,16 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { valErrs, ok := h.validator.Validate(c, filter) if !ok { - h.mongoLoggerSvc.Error("invalid filter values in GetAllAdmins request", + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("invalid filter values in GetAllAdmins request", zap.Int("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } admins, total, err := h.userSvc.GetAllUsers(c.Context(), filter) @@ -225,7 +237,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Admins", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Admins"+err.Error()) } result := make([]AdminRes, len(admins)) @@ -241,7 +253,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error()) } } @@ -283,7 +295,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /admin/{id} [get] +// @Router /api/v1/admin/{id} [get] func (h *Handler) GetAdminByID(c *fiber.Ctx) error { userIDstr := c.Params("id") userID, err := strconv.ParseInt(userIDstr, 10, 64) @@ -294,7 +306,7 @@ func (h *Handler) GetAdminByID(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid admin ID", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Invalid admin ID") } user, err := h.userSvc.GetUserByID(c.Context(), userID) @@ -305,7 +317,7 @@ func (h *Handler) GetAdminByID(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get admin", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get admin"+err.Error()) } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) @@ -316,7 +328,7 @@ func (h *Handler) GetAdminByID(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } if err == authentication.ErrRefreshTokenNotFound { lastLogin = &user.CreatedAt @@ -365,7 +377,7 @@ type updateAdminReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /admin/{id} [put] +// @Router /api/v1/admin/{id} [put] func (h *Handler) UpdateAdmin(c *fiber.Ctx) error { var req updateAdminReq if err := c.BodyParser(&req); err != nil { @@ -374,29 +386,33 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } h.mongoLoggerSvc.Error("UpdateAdmin failed - validation errors", zap.Int("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } AdminIDStr := c.Params("id") AdminID, err := strconv.ParseInt(AdminIDStr, 10, 64) if err != nil { - h.mongoLoggerSvc.Error("UpdateAdmin failed - invalid Admin ID param", + h.mongoLoggerSvc.Info("UpdateAdmin failed - invalid Admin ID param", zap.Int("status_code", fiber.StatusBadRequest), zap.String("admin_id_param", AdminIDStr), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Admin ID", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Invalid Admin ID") } var companyID domain.ValidInt64 @@ -430,13 +446,16 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update admin", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error()) } if req.CompanyID != nil { _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ - ID: *req.CompanyID, - AdminID: &AdminID, + ID: *req.CompanyID, + AdminID: domain.ValidInt64{ + Value: AdminID, + Valid: true, + }, }) if err != nil { h.mongoLoggerSvc.Error("UpdateAdmin failed to update company", @@ -445,7 +464,7 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update company", nil, nil) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company:"+err.Error()) } } diff --git a/internal/web_server/handlers/auth_handler.go b/internal/web_server/handlers/auth_handler.go index 4368266..9507669 100644 --- a/internal/web_server/handlers/auth_handler.go +++ b/internal/web_server/handlers/auth_handler.go @@ -2,6 +2,7 @@ package handlers import ( "errors" + "fmt" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" @@ -36,41 +37,47 @@ type loginCustomerRes struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /auth/login [post] +// @Router /api/v1/auth/login [post] func (h *Handler) LoginCustomer(c *fiber.Ctx) error { var req loginCustomerReq if err := c.BodyParser(&req); err != nil { - h.mongoLoggerSvc.Error("Failed to parse LoginCustomer request", + h.mongoLoggerSvc.Info("Failed to parse LoginCustomer request", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body"+err.Error()) } - if _, ok := h.validator.Validate(c, req); !ok { - h.mongoLoggerSvc.Error("LoginCustomer validation failed", - zap.Int("status_code", fiber.StatusBadRequest), - zap.Any("request", req), - zap.Time("timestamp", time.Now()), - ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid Request") + if valErrs, ok := h.validator.Validate(c, req); !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password) if err != nil { - h.mongoLoggerSvc.Info("Login attempt failed", - zap.Int("status_code", fiber.StatusUnauthorized), - zap.String("email", req.Email), - zap.String("phone", req.PhoneNumber), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) switch { case errors.Is(err, authentication.ErrInvalidPassword), errors.Is(err, authentication.ErrUserNotFound): + h.mongoLoggerSvc.Info("Login attempt failed: Invalid credentials", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("email", req.Email), + zap.String("phone", req.PhoneNumber), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Invalid credentials") case errors.Is(err, authentication.ErrUserSuspended): + h.mongoLoggerSvc.Info("Login attempt failed: User login has been locked", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("email", req.Email), + zap.String("phone", req.PhoneNumber), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "User login has been locked") default: h.mongoLoggerSvc.Error("Login failed", @@ -125,7 +132,7 @@ type refreshToken struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /auth/refresh [post] +// @Router /api/v1/auth/refresh [post] func (h *Handler) RefreshToken(c *fiber.Ctx) error { type loginCustomerRes struct { @@ -136,35 +143,47 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error { var req refreshToken if err := c.BodyParser(&req); err != nil { - h.mongoLoggerSvc.Error("Failed to parse RefreshToken request", + h.mongoLoggerSvc.Info("Failed to parse RefreshToken request", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - h.mongoLoggerSvc.Error("RefreshToken validation failed", + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + + h.mongoLoggerSvc.Info("Failed to validate request", zap.Int("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } refreshToken, err := h.authSvc.RefreshToken(c.Context(), req.RefreshToken) if err != nil { - h.mongoLoggerSvc.Info("Refresh token attempt failed", - zap.Int("status_code", fiber.StatusUnauthorized), - zap.String("refresh_token", req.RefreshToken), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) + switch { case errors.Is(err, authentication.ErrExpiredToken): + h.mongoLoggerSvc.Info("Refresh token attempt failed: The refresh token has expired", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("refresh_token", req.RefreshToken), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "The refresh token has expired") case errors.Is(err, authentication.ErrRefreshTokenNotFound): + h.mongoLoggerSvc.Info("Refresh token attempt failed: Refresh token not found", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("refresh_token", req.RefreshToken), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Refresh token not found") default: h.mongoLoggerSvc.Error("Refresh token failed", @@ -184,7 +203,7 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user information") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user information:"+err.Error()) } accessToken, err := jwtutil.CreateJwt(user.ID, user.Role, user.CompanyID, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry) @@ -195,7 +214,7 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to generate access token") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to generate access token:"+err.Error()) } res := loginCustomerRes{ @@ -204,7 +223,7 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error { Role: string(user.Role), } - h.mongoLoggerSvc.Info("Refresh token successful", + h.mongoLoggerSvc.Info("Token Refreshed Successfully", zap.Int("status_code", fiber.StatusOK), zap.Int64("user_id", user.ID), zap.String("role", string(user.Role)), @@ -229,39 +248,53 @@ type logoutReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /auth/logout [post] +// @Router /api/v1/auth/logout [post] func (h *Handler) LogOutCustomer(c *fiber.Ctx) error { var req logoutReq if err := c.BodyParser(&req); err != nil { - h.mongoLoggerSvc.Error("Failed to parse LogOutCustomer request", + h.mongoLoggerSvc.Info("Failed to parse LogOutCustomer request", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - h.mongoLoggerSvc.Error("LogOutCustomer validation failed", + + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + + h.mongoLoggerSvc.Info("LogOutCustomer validation failed", + zap.String("errMsg", errMsg), zap.Int("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } err := h.authSvc.Logout(c.Context(), req.RefreshToken) if err != nil { - h.mongoLoggerSvc.Info("Logout attempt failed", - zap.Int("status_code", fiber.StatusUnauthorized), - zap.String("refresh_token", req.RefreshToken), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) + switch { case errors.Is(err, authentication.ErrExpiredToken): + h.mongoLoggerSvc.Info("Logout attempt failed:The refresh token has expired", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("refresh_token", req.RefreshToken), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "The refresh token has expired") case errors.Is(err, authentication.ErrRefreshTokenNotFound): + h.mongoLoggerSvc.Info("Logout attempt failed: Refresh token not found", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("refresh_token", req.RefreshToken), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Refresh token not found") default: h.mongoLoggerSvc.Error("Logout failed", @@ -269,7 +302,7 @@ func (h *Handler) LogOutCustomer(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Internal server error") + return fiber.NewError(fiber.StatusInternalServerError, "Internal server error"+err.Error()) } } diff --git a/internal/web_server/handlers/bet_handler.go b/internal/web_server/handlers/bet_handler.go index 52a5e6c..33a4309 100644 --- a/internal/web_server/handlers/bet_handler.go +++ b/internal/web_server/handlers/bet_handler.go @@ -23,10 +23,11 @@ import ( // @Success 200 {object} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/bet [post] +// @Router /api/v1/sport/bet [post] func (h *Handler) CreateBet(c *fiber.Ctx) error { userID := c.Locals("user_id").(int64) role := c.Locals("role").(domain.Role) + companyID := c.Locals("company_id").(domain.ValidInt64) var req domain.CreateBetReq if err := c.BodyParser(&req); err != nil { @@ -35,16 +36,18 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } - res, err := h.CreateBetInternal(c, req, userID, role) + res, err := h.CreateBetInternal(c, req, userID, role, companyID) if err != nil { h.mongoLoggerSvc.Error("Failed to create bet", - zap.Int("status_code", fiber.StatusOK), + zap.Int("status_code", fiber.StatusInternalServerError), zap.Int64("user_id", userID), + zap.String("role", string(role)), zap.Time("timestamp", time.Now()), ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create bet:"+err.Error()) } h.mongoLoggerSvc.Info("Bet created successfully", @@ -66,10 +69,11 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error { // @Success 200 {object} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/bet/fastcode [post] +// @Router /api/v1/sport/bet/fastcode [post] func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error { userID := c.Locals("user_id").(int64) role := c.Locals("role").(domain.Role) + companyID := c.Locals("company_id").(domain.ValidInt64) var req struct { FastCode string `json:"fast_code"` @@ -81,27 +85,29 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } bet, err := h.betSvc.GetBetByFastCode(c.Context(), req.FastCode) if err != nil { - h.mongoLoggerSvc.Error("falied to get bet with fast code", - zap.Int("status_code", fiber.StatusInternalServerError), + h.mongoLoggerSvc.Info("failed to get bet with fast code", + zap.String("fast_code", req.FastCode), + zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "falied to get bet with fast code") + return fiber.NewError(fiber.StatusBadRequest, "failed to get bet with fast code:"+err.Error()) } outcomes, err := h.betSvc.GetBetOutcomeByBetID(c.Context(), bet.ID) if err != nil { - h.mongoLoggerSvc.Error("falied to get BetOutcomes by BetID", - zap.Int("status_code", fiber.StatusInternalServerError), - zap.Error(err), + h.mongoLoggerSvc.Info("failed to get BetOutcomes by BetID", + zap.Int64("bet_id", bet.ID), + zap.Int("status_code", fiber.StatusBadRequest), zap.Time("timestamp", time.Now()), + zap.Error(err), ) - return fiber.NewError(fiber.StatusBadRequest, "falied to get BetOutcomes by BetID") + return fiber.NewError(fiber.StatusBadRequest, "failed to get BetOutcomes by BetID:"+err.Error()) } bet_outcomes := []domain.CreateBetOutcomeReq{} @@ -113,58 +119,43 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error { }) } - user, err := h.userSvc.GetUserByID(c.Context(), userID) - if err != nil { - h.mongoLoggerSvc.Error("falied to get user information", - zap.Int("status_code", fiber.StatusInternalServerError), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return fiber.NewError(fiber.StatusBadRequest, "falied to get user information") - } - - // branch, err := h.branchSvc.GetBranchByID(c.Context(), user) - // if err != nil { - // h.mongoLoggerSvc.Error("falied to get branch of user", - // zap.Int("status_code", fiber.StatusInternalServerError), - // zap.Error(err), - // zap.Time("timestamp", time.Now()), - // ) - // return fiber.NewError(fiber.StatusBadRequest, "falied to get branch of user") - // } - newReq := domain.CreateBetReq{ - Amount: float32(bet.Amount), - Outcomes: bet_outcomes, - BranchID: nil, - FullName: user.FirstName, - PhoneNumber: user.PhoneNumber, + Amount: float32(bet.Amount), + Outcomes: bet_outcomes, + BranchID: nil, } - res, err := h.CreateBetInternal(c, newReq, userID, role) + res, err := h.CreateBetInternal(c, newReq, userID, role, companyID) if err != nil { h.mongoLoggerSvc.Error("Failed to create bet", - zap.Int("status_code", fiber.StatusOK), + zap.Int("status_code", fiber.StatusInternalServerError), zap.Int64("user_id", userID), + zap.String("role", string(role)), + zap.Any("newReq", newReq), zap.Time("timestamp", time.Now()), + zap.Error(err), ) - return fiber.NewError(fiber.StatusBadRequest, "Failed to create bet") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create bet:"+err.Error()) } - wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), bet.UserID.Value) + wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), bet.UserID) // amount added for fast code owner can be fetched from settings in db - amount := domain.Currency(100) + settingList, err := h.settingSvc.GetSettingList(c.Context()) + amount := settingList.AmountForBetReferral _, err = h.walletSvc.AddToWallet(c.Context(), wallet.StaticID, amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to static wallet by referring using fast_code", amount.Float32())) if err != nil { h.mongoLoggerSvc.Error("Failed to add reward to static bet", - zap.Int("status_code", fiber.StatusOK), + zap.Int("status_code", fiber.StatusBadRequest), zap.Int64("user_id", userID), + zap.Float32("amount", amount.Float32()), + zap.Int64("static wallet_id", wallet.StaticID), zap.Time("timestamp", time.Now()), + zap.Error(err), ) - return fiber.NewError(fiber.StatusBadRequest, "Failed to add reward to static bet") + return fiber.NewError(fiber.StatusBadRequest, "Failed to add reward to static bet:"+err.Error()) } h.mongoLoggerSvc.Info("Bet created successfully", @@ -175,7 +166,7 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil) } -func (h *Handler) CreateBetInternal(c *fiber.Ctx, req domain.CreateBetReq, userID int64, role domain.Role) (domain.CreateBetRes, error) { +func (h *Handler) CreateBetInternal(c *fiber.Ctx, req domain.CreateBetReq, userID int64, role domain.Role, companyID domain.ValidInt64) (domain.CreateBetRes, error) { valErrs, ok := h.validator.Validate(c, req) if !ok { h.mongoLoggerSvc.Error("CreateBet validation failed", @@ -186,19 +177,30 @@ func (h *Handler) CreateBetInternal(c *fiber.Ctx, req domain.CreateBetReq, userI return domain.CreateBetRes{}, fmt.Errorf("%s", valErrs) } - res, err := h.betSvc.PlaceBet(c.Context(), req, userID, role) + res, err := h.betSvc.PlaceBet(c.Context(), req, userID, role, companyID) if err != nil { + switch err { + case bet.ErrEventHasBeenRemoved, bet.ErrEventHasNotEnded, bet.ErrRawOddInvalid, wallet.ErrBalanceInsufficient: + h.mongoLoggerSvc.Info("PlaceBet failed", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Int64("userID", userID), + zap.Int64("companyID", companyID.Value), + zap.String("role", string(role)), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return domain.CreateBetRes{}, fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + h.mongoLoggerSvc.Error("PlaceBet failed", zap.Int("status_code", fiber.StatusInternalServerError), + zap.Int64("userID", userID), + zap.Int64("companyID", companyID.Value), + zap.String("role", string(role)), zap.Error(err), zap.Time("timestamp", time.Now()), ) - switch err { - case bet.ErrEventHasBeenRemoved, bet.ErrEventHasNotEnded, bet.ErrRawOddInvalid, wallet.ErrBalanceInsufficient: - return domain.CreateBetRes{}, fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - return domain.CreateBetRes{}, fiber.NewError(fiber.StatusInternalServerError, "Unable to create bet") } @@ -215,28 +217,28 @@ func (h *Handler) CreateBetInternal(c *fiber.Ctx, req domain.CreateBetReq, userI // @Success 200 {object} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/random/bet [post] +// @Router /api/v1/sport/random/bet [post] func (h *Handler) RandomBet(c *fiber.Ctx) error { userID := c.Locals("user_id").(int64) leagueIDQuery, err := strconv.Atoi(c.Query("league_id")) if err != nil { - h.mongoLoggerSvc.Error("invalid league id", + h.mongoLoggerSvc.Info("invalid league id", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "invalid league id") } sportIDQuery, err := strconv.Atoi(c.Query("sport_id")) if err != nil { - h.mongoLoggerSvc.Error("invalid sport id", + h.mongoLoggerSvc.Info("invalid sport id", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "invalid sport id") } firstStartTimeQuery := c.Query("first_start_time") @@ -255,12 +257,13 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error { if firstStartTimeQuery != "" { firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery) if err != nil { - h.mongoLoggerSvc.Error("invalid start_time format", + h.mongoLoggerSvc.Info("invalid first_start_time format", + zap.String("first_start_time", firstStartTimeQuery), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Invalid first_start_time format") } firstStartTime = domain.ValidTime{ Value: firstStartTimeParsed, @@ -272,12 +275,13 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error { if lastStartTimeQuery != "" { lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery) if err != nil { - h.mongoLoggerSvc.Error("invalid start_time format", + h.mongoLoggerSvc.Info("invalid last_start_time format", + zap.String("last_start_time", lastStartTimeQuery), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Invalid last_start_time format") } lastStartTime = domain.ValidTime{ Value: lastStartTimeParsed, @@ -287,38 +291,45 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error { var req domain.RandomBetReq if err := c.BodyParser(&req); err != nil { - h.mongoLoggerSvc.Error("Failed to parse RandomBet request", + h.mongoLoggerSvc.Info("Failed to parse RandomBet request", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } h.mongoLoggerSvc.Error("RandomBet validation failed", zap.Int("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } var res domain.CreateBetRes for i := 0; i < int(req.NumberOfBets); i++ { res, err = h.betSvc.PlaceRandomBet(c.Context(), userID, req.BranchID, leagueID, sportID, firstStartTime, lastStartTime) if err != nil { - h.mongoLoggerSvc.Error("Random Bet failed", + switch err { + case bet.ErrNoEventsAvailable: + return fiber.NewError(fiber.StatusNotFound, "No events found") + } + + h.mongoLoggerSvc.Error("Random Bet failed place random bet", + zap.Int64("userID", userID), + zap.Int64("branch_id", req.BranchID), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) - switch err { - case bet.ErrNoEventsAvailable: - return fiber.NewError(fiber.StatusBadRequest, "No events found") - } - return fiber.NewError(fiber.StatusInternalServerError, "Unable to create random bet") + return fiber.NewError(fiber.StatusInternalServerError, "Unable to create random bet:"+err.Error()) } } @@ -340,23 +351,24 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error { // @Success 200 {array} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/bet [get] +// @Router /api/v1/sport/bet [get] func (h *Handler) GetAllBet(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) - companyID := c.Locals("company_id").(domain.ValidInt64) - branchID := c.Locals("branch_id").(domain.ValidInt64) + // companyID := c.Locals("company_id").(domain.ValidInt64) + // branchID := c.Locals("branch_id").(domain.ValidInt64) var isShopBet domain.ValidBool isShopBetQuery := c.Query("is_shop") if isShopBetQuery != "" && role == domain.RoleSuperAdmin { isShopBetParse, err := strconv.ParseBool(isShopBetQuery) if err != nil { - h.mongoLoggerSvc.Error("Failed to parse is_shop_bet", + h.mongoLoggerSvc.Info("failed to parse is_shop_bet", zap.Int("status_code", fiber.StatusBadRequest), + zap.String("is_shop", isShopBetQuery), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_shop_bet") + return fiber.NewError(fiber.StatusBadRequest, "failed to parse is_shop_bet") } isShopBet = domain.ValidBool{ Value: isShopBetParse, @@ -375,8 +387,13 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_before format", + zap.String("time", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -389,8 +406,13 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_after format", + zap.String("created_after", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -398,24 +420,19 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { } } - fmt.Printf("Filters - BranchID: %+v, CompanyID: %+v, IsShopBet: %+v, Query: %+v, CreatedBefore: %+v, CreatedAfter: %+v\n", - branchID, companyID, isShopBet, searchString, createdBefore, createdAfter) - bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{ - BranchID: branchID, - CompanyID: companyID, IsShopBet: isShopBet, Query: searchString, CreatedBefore: createdBefore, CreatedAfter: createdAfter, }) if err != nil { - h.mongoLoggerSvc.Error("Failed to get bets", + h.mongoLoggerSvc.Error("Failed to get all bets", zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets፡"+err.Error()) } res := make([]domain.BetRes, len(bets)) @@ -423,11 +440,6 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { res[i] = domain.ConvertBet(bet) } - h.mongoLoggerSvc.Info("All bets retrieved successfully", - zap.Int("status_code", fiber.StatusOK), - zap.Time("timestamp", time.Now()), - ) - return response.WriteJSON(c, fiber.StatusOK, "All bets retrieved successfully", res, nil) } @@ -441,12 +453,12 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { // @Success 200 {object} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/bet/{id} [get] +// @Router /api/v1/sport/bet/{id} [get] func (h *Handler) GetBetByID(c *fiber.Ctx) error { betID := c.Params("id") id, err := strconv.ParseInt(betID, 10, 64) if err != nil { - h.mongoLoggerSvc.Error("Invalid bet ID", + h.mongoLoggerSvc.Info("Invalid bet ID", zap.String("betID", betID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), @@ -457,7 +469,7 @@ func (h *Handler) GetBetByID(c *fiber.Ctx) error { bet, err := h.betSvc.GetBetByID(c.Context(), id) if err != nil { - h.mongoLoggerSvc.Error("Failed to get bet by ID", + h.mongoLoggerSvc.Info("Failed to get bet by ID", zap.Int64("betID", id), zap.Int("status_code", fiber.StatusNotFound), zap.Error(err), @@ -468,47 +480,11 @@ func (h *Handler) GetBetByID(c *fiber.Ctx) error { res := domain.ConvertBet(bet) - h.mongoLoggerSvc.Info("Bet retrieved successfully", - zap.Int64("betID", id), - zap.Int("status_code", fiber.StatusOK), - zap.Time("timestamp", time.Now()), - ) - - return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil) -} - -// GetBetByCashoutID godoc -// @Summary Gets bet by cashout id -// @Description Gets a single bet by cashout id -// @Tags bet -// @Accept json -// @Produce json -// @Param id path string true "cashout ID" -// @Success 200 {object} domain.BetRes -// @Failure 400 {object} response.APIResponse -// @Failure 500 {object} response.APIResponse -// @Router /sport/bet/cashout/{id} [get] -func (h *Handler) GetBetByCashoutID(c *fiber.Ctx) error { - cashoutID := c.Params("id") - - bet, err := h.betSvc.GetBetByCashoutID(c.Context(), cashoutID) - if err != nil { - h.mongoLoggerSvc.Error("Failed to get bet by cashout ID", - zap.String("cashoutID", cashoutID), - zap.Int("status_code", fiber.StatusInternalServerError), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bet", err, nil) - } - - res := domain.ConvertBet(bet) - - h.mongoLoggerSvc.Info("Bet retrieved successfully by cashout ID", - zap.String("cashoutID", cashoutID), - zap.Int("status_code", fiber.StatusOK), - zap.Time("timestamp", time.Now()), - ) + // h.mongoLoggerSvc.Info("Bet retrieved successfully", + // zap.Int64("betID", id), + // zap.Int("status_code", fiber.StatusOK), + // zap.Time("timestamp", time.Now()), + // ) return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil) } @@ -528,7 +504,7 @@ type UpdateCashOutReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/bet/{id} [patch] +// @Router /api/v1/sport/bet/{id} [patch] func (h *Handler) UpdateCashOut(c *fiber.Ctx) error { type UpdateCashOutReq struct { CashedOut bool `json:"cashed_out" validate:"required" example:"true"` @@ -554,11 +530,15 @@ func (h *Handler) UpdateCashOut(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request body", err, nil) + return fiber.NewError(fiber.StatusBadRequest, "failed to parse request body:"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } err = h.betSvc.UpdateCashOut(c.Context(), id, req.CashedOut) @@ -591,7 +571,7 @@ func (h *Handler) UpdateCashOut(c *fiber.Ctx) error { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /sport/bet/{id} [delete] +// @Router /api/v1/sport/bet/{id} [delete] func (h *Handler) DeleteBet(c *fiber.Ctx) error { betID := c.Params("id") id, err := strconv.ParseInt(betID, 10, 64) @@ -613,7 +593,7 @@ func (h *Handler) DeleteBet(c *fiber.Ctx) error { zap.Error(err), zap.Time("timestamp", time.Now()), ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete bet") + return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete bet:"+err.Error()) } h.mongoLoggerSvc.Info("Bet removed successfully", diff --git a/internal/web_server/handlers/bonus.go b/internal/web_server/handlers/bonus.go index f4e5a27..f796827 100644 --- a/internal/web_server/handlers/bonus.go +++ b/internal/web_server/handlers/bonus.go @@ -1,8 +1,11 @@ package handlers import ( + "time" + "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) func (h *Handler) CreateBonusMultiplier(c *fiber.Ctx) error { @@ -12,8 +15,13 @@ func (h *Handler) CreateBonusMultiplier(c *fiber.Ctx) error { } if err := c.BodyParser(&req); err != nil { - h.logger.Error("failed to parse bonus multiplier", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.logger.Error("failed to parse bonus multiplier request", "error", err) + h.mongoLoggerSvc.Info("failed to parse bonus multiplier", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } // currently only one multiplier is allowed @@ -21,29 +29,42 @@ func (h *Handler) CreateBonusMultiplier(c *fiber.Ctx) error { multipliers, err := h.bonusSvc.GetBonusMultiplier(c.Context()) if err != nil { h.logger.Error("failed to get bonus multiplier", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("Failed to get bonus multiplier", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if len(multipliers) > 0 { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + return fiber.NewError(fiber.StatusBadRequest, "only one multiplier is allowed") } if err := h.bonusSvc.CreateBonusMultiplier(c.Context(), req.Multiplier, req.BalanceCap); err != nil { - h.logger.Error("failed to create bonus multiplier", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "failed to create bonus mulitplier", nil, nil) + h.mongoLoggerSvc.Error("failed to create bonus multiplier", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "failed to create bonus multiplier"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "Create bonus mulitplier successfully", nil, nil) + return response.WriteJSON(c, fiber.StatusOK, "Create bonus multiplier successfully", nil, nil) } func (h *Handler) GetBonusMultiplier(c *fiber.Ctx) error { multipliers, err := h.bonusSvc.GetBonusMultiplier(c.Context()) if err != nil { - h.logger.Error("failed to get bonus multiplier", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("failed to get bonus multiplier", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "Fetched bonus mulitplier successfully", multipliers, nil) + return response.WriteJSON(c, fiber.StatusOK, "Fetched bonus multiplier successfully", multipliers, nil) } func (h *Handler) UpdateBonusMultiplier(c *fiber.Ctx) error { @@ -54,14 +75,24 @@ func (h *Handler) UpdateBonusMultiplier(c *fiber.Ctx) error { } if err := c.BodyParser(&req); err != nil { - h.logger.Error("failed to parse bonus multiplier", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("failed to parse bonus multiplier", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if err := h.bonusSvc.UpdateBonusMultiplier(c.Context(), req.ID, req.Multiplier, req.BalanceCap); err != nil { h.logger.Error("failed to update bonus multiplier", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "failed to update bonus mulitplier", nil, nil) + h.mongoLoggerSvc.Error("failed to update bonus multiplier", + zap.Int64("id", req.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "failed to update bonus multiplier:"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "Updated bonus mulitplier successfully", nil, nil) + return response.WriteJSON(c, fiber.StatusOK, "Updated bonus multiplier successfully", nil, nil) } diff --git a/internal/web_server/handlers/branch_handler.go b/internal/web_server/handlers/branch_handler.go index d00297e..4f42491 100644 --- a/internal/web_server/handlers/branch_handler.go +++ b/internal/web_server/handlers/branch_handler.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "strconv" "strings" "time" @@ -9,113 +10,20 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) -type CreateBranchReq struct { - Name string `json:"name" validate:"required,min=3,max=100" example:"4-kilo Branch"` - Location string `json:"location" validate:"required,min=3,max=100" example:"Addis Ababa"` - BranchManagerID int64 `json:"branch_manager_id" validate:"required,gt=0" example:"1"` - CompanyID *int64 `json:"company_id,omitempty" example:"1"` - IsSelfOwned *bool `json:"is_self_owned,omitempty" example:"false"` - Operations []int64 `json:"operations" validate:"required,dive,gt=0"` -} - -type UpdateBranchReq struct { - Name *string `json:"name,omitempty" example:"4-kilo Branch"` - Location *string `json:"location,omitempty" example:"Addis Ababa"` - BranchManagerID *int64 `json:"branch_manager_id,omitempty" example:"1"` - CompanyID *int64 `json:"company_id,omitempty" example:"1"` - IsSelfOwned *bool `json:"is_self_owned,omitempty" example:"false"` -} - -type CreateSupportedOperationReq struct { - Name string `json:"name" example:"SportsBook"` - Description string `json:"description" example:"Betting on sport events"` -} - -type SupportedOperationRes struct { - ID int64 `json:"id" example:"1"` - Name string `json:"name" example:"SportsBook"` - Description string `json:"description" example:"Betting on sport events"` -} - -type CreateBranchOperationReq struct { - BranchID int64 `json:"branch_id" example:"1"` - OperationID int64 `json:"operation_id" example:"1"` -} - -type BranchOperationRes struct { - Name string `json:"name" example:"SportsBook"` - Description string `json:"description" example:"Betting on sport events"` -} - -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"` - BranchManagerID int64 `json:"branch_manager_id" example:"1"` - CompanyID int64 `json:"company_id" example:"1"` - IsSelfOwned bool `json:"is_self_owned" example:"false"` - IsActive bool `json:"is_active" example:"false"` -} - -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"` - BranchManagerID int64 `json:"branch_manager_id" example:"1"` - CompanyID int64 `json:"company_id" example:"1"` - IsSelfOwned bool `json:"is_self_owned" example:"false"` - ManagerName string `json:"manager_name" example:"John Smith"` - ManagerPhoneNumber string `json:"manager_phone_number" example:"0911111111"` - Balance float32 `json:"balance" example:"100.5"` - IsActive bool `json:"is_active" example:"false"` - WalletIsActive bool `json:"is_wallet_active" example:"false"` -} - -func convertBranch(branch domain.Branch) BranchRes { - return BranchRes{ - ID: branch.ID, - Name: branch.Name, - Location: branch.Location, - WalletID: branch.WalletID, - BranchManagerID: branch.BranchManagerID, - CompanyID: branch.CompanyID, - IsSelfOwned: branch.IsSelfOwned, - IsActive: branch.IsActive, - } -} - -func convertBranchDetail(branch domain.BranchDetail) BranchDetailRes { - return BranchDetailRes{ - ID: branch.ID, - Name: branch.Name, - Location: branch.Location, - WalletID: branch.WalletID, - BranchManagerID: branch.BranchManagerID, - CompanyID: branch.CompanyID, - IsSelfOwned: branch.IsSelfOwned, - ManagerName: branch.ManagerName, - ManagerPhoneNumber: branch.ManagerPhoneNumber, - Balance: branch.Balance.Float32(), - IsActive: branch.IsActive, - WalletIsActive: branch.WalletIsActive, - } -} - // CreateBranch godoc // @Summary Create a branch // @Description Creates a branch // @Tags branch // @Accept json // @Produce json -// @Param createBranch body CreateBranchReq true "Creates branch" -// @Success 200 {object} BranchRes +// @Param createBranch body domain.CreateBranchReq true "Creates branch" +// @Success 200 {object} domain.BranchRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch [post] +// @Router /api/v1/branch [post] func (h *Handler) CreateBranch(c *fiber.Ctx) error { // Check if user is either branch manager / super main // role := string(c.Locals("role").(domain.Role)) @@ -128,32 +36,48 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyID := c.Locals("company_id").(domain.ValidInt64) - var req CreateBranchReq + var req domain.CreateBranchReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateBranchReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + // h.logger.Error("CreateBranchReq failed", "error", err) + h.mongoLoggerSvc.Info("CreateBranchReq failed", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } var IsSelfOwned bool var checkedCompanyID int64 if role == domain.RoleSuperAdmin { if req.IsSelfOwned == nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "is_self_owned is required for super admin", nil, nil) + h.mongoLoggerSvc.Info("is_self_owned is required for super admin", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "is_self_owned is required for super admin") } if req.CompanyID == nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "company_id is required for super admin", nil, nil) + h.mongoLoggerSvc.Info("company_id is required for super admin", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "company_id is required for super admin") } IsSelfOwned = *req.IsSelfOwned checkedCompanyID = *req.CompanyID } else { IsSelfOwned = false checkedCompanyID = companyID.Value - //TODO:check that the company id is always valid when its not a super admin } // Create Branch Wallet @@ -165,8 +89,13 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("Create Branch Wallet failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create branch wallet", err, nil) + h.mongoLoggerSvc.Error("Create Branch Wallet failed", + zap.Int64("branch_manager_id", req.BranchManagerID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } branch, err := h.branchSvc.CreateBranch(c.Context(), domain.CreateBranch{ @@ -179,10 +108,12 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("CreateBranchReq failed", "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Internal server error", - }) + h.mongoLoggerSvc.Error("Failed to create branch", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } for _, operation := range req.Operations { @@ -191,14 +122,18 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { OperationID: operation, }) if err != nil { - h.logger.Error("Failed to create branch operations", "BranchID", branch.ID, "operation", operation, "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Internal server error", - }) + h.mongoLoggerSvc.Error("Failed to create branch operations", + zap.Int64("branchID", branch.ID), + zap.Int64("operation", operation), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } } - res := convertBranch(branch) + res := domain.ConvertBranch(branch) return response.WriteJSON(c, fiber.StatusCreated, "Branch Created", res, nil) } @@ -209,22 +144,36 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { // @Tags branch // @Accept json // @Produce json -// @Param createSupportedOperation body CreateSupportedOperationReq true "Creates supported operation" -// @Success 200 {object} SupportedOperationRes +// @Param createSupportedOperation body domain.CreateSupportedOperationReq true "Creates supported operation" +// @Success 200 {object} domain.SupportedOperationRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /supportedOperation [post] +// @Router /api/v1/supportedOperation [post] func (h *Handler) CreateSupportedOperation(c *fiber.Ctx) error { - var req CreateSupportedOperationReq + var req domain.CreateSupportedOperationReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateSupportedOperationReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("Failed to parse CreateSupportedOperationReq", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + h.mongoLoggerSvc.Error("Failed to validate CreateSupportedOperationReq", + zap.Any("request", req), + zap.String("error", errMsg), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } operation, err := h.branchSvc.CreateSupportedOperation(c.Context(), domain.CreateSupportedOperation{ Name: req.Name, @@ -232,13 +181,17 @@ func (h *Handler) CreateSupportedOperation(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("CreateSupportedOperationReq failed", "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Internal server error", - }) + h.mongoLoggerSvc.Error("Failed to create supported operation", + zap.String("name", req.Name), + zap.String("description", req.Description), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create supported operation") } - res := SupportedOperationRes{ + res := domain.SupportedOperationRes{ Name: operation.Name, Description: operation.Description, } @@ -252,21 +205,35 @@ func (h *Handler) CreateSupportedOperation(c *fiber.Ctx) error { // @Tags branch // @Accept json // @Produce json -// @Param createBranchOperation body CreateBranchOperationReq true "Creates operation" -// @Success 200 {object} BranchOperationRes +// @Param createBranchOperation body domain.CreateBranchOperationReq true "Creates operation" +// @Success 200 {object} domain.BranchOperationRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /operation [post] +// @Router /api/v1/operation [post] func (h *Handler) CreateBranchOperation(c *fiber.Ctx) error { - var req CreateBranchOperationReq + var req domain.CreateBranchOperationReq if err := c.BodyParser(&req); err != nil { h.logger.Error("CreateBranchOperationReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("Failed to parse CreateBranchOperationReq", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validated CreateBranchOperationReq", + zap.String("errMsg", errMsg), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } err := h.branchSvc.CreateBranchOperation(c.Context(), domain.CreateBranchOperation{ @@ -275,8 +242,12 @@ func (h *Handler) CreateBranchOperation(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("CreateBranchOperationReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil) + h.mongoLoggerSvc.Error("Failed to create branch operation", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Branch Operation Created", nil, nil) @@ -289,26 +260,36 @@ func (h *Handler) CreateBranchOperation(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Branch ID" -// @Success 200 {object} BranchDetailRes +// @Success 200 {object} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id} [get] +// @Router /api/v1/branch/{id} [get] func (h *Handler) GetBranchByID(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) + h.mongoLoggerSvc.Info("Invalid branch ID", + zap.String("branch", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } branch, err := h.branchSvc.GetBranchByID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get branch by ID", "branchID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil) + h.mongoLoggerSvc.Info("Failed to get branch by ID", + zap.Int64("branchID", id), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertBranchDetail(branch) + res := domain.ConvertBranchDetail(branch) return response.WriteJSON(c, fiber.StatusOK, "Branch retrieved successfully", res, nil) } @@ -320,28 +301,38 @@ func (h *Handler) GetBranchByID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "User ID" -// @Success 200 {array} BranchDetailRes +// @Success 200 {array} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /manager/{id}/branch [get] +// @Router /api/v1/manager/{id}/branch [get] func (h *Handler) GetBranchByManagerID(c *fiber.Ctx) error { // TODO: Restrict any who isn't branch manager or higher userID := c.Params("id") id, err := strconv.ParseInt(userID, 10, 64) if err != nil { - h.logger.Error("Invalid user ID", "userID", userID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid user ID", err, nil) + h.mongoLoggerSvc.Info("Invalid user ID", + zap.String("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") } branches, err := h.branchSvc.GetBranchByManagerID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get branches", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil) + h.mongoLoggerSvc.Info("Failed to get branches", + zap.String("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } - var result []BranchDetailRes = make([]BranchDetailRes, 0, len(branches)) + var result []domain.BranchDetailRes = make([]domain.BranchDetailRes, 0, len(branches)) for _, branch := range branches { - result = append(result, convertBranchDetail(branch)) + result = append(result, domain.ConvertBranchDetail(branch)) } return response.WriteJSON(c, fiber.StatusOK, "Branches for Branch Manager retrieved", result, nil) } @@ -353,27 +344,37 @@ func (h *Handler) GetBranchByManagerID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Company ID" -// @Success 200 {array} BranchDetailRes +// @Success 200 {array} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /company/{id}/branch [get] +// @Router /api/v1/company/{id}/branch [get] func (h *Handler) GetBranchByCompanyID(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { - h.logger.Error("Invalid company ID", "companyID", companyID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil) + h.mongoLoggerSvc.Info("Invalid company ID", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid company ID") } branches, err := h.branchSvc.GetBranchByCompanyID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get branches", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil) + h.mongoLoggerSvc.Info("Failed to get branches", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var result []BranchDetailRes = make([]BranchDetailRes, 0, len(branches)) + var result []domain.BranchDetailRes = make([]domain.BranchDetailRes, 0, len(branches)) for _, branch := range branches { - result = append(result, convertBranchDetail(branch)) + result = append(result, domain.ConvertBranchDetail(branch)) } return response.WriteJSON(c, fiber.StatusOK, "Branches for Company retrieved", result, nil) } @@ -384,10 +385,10 @@ func (h *Handler) GetBranchByCompanyID(c *fiber.Ctx) error { // @Tags branch // @Accept json // @Produce json -// @Success 200 {array} BranchDetailRes +// @Success 200 {array} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch [get] +// @Router /api/v1/branch [get] func (h *Handler) GetAllBranches(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) isActiveParam := c.Params("is_active") @@ -395,7 +396,13 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error { isActive, err := strconv.ParseBool(isActiveParam) if isActiveValid && err != nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid is_active param", err, nil) + h.mongoLoggerSvc.Info("Invalid is_active param", + zap.String("isActive", isActiveParam), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid is_active param") } branchManagerQuery := c.Query("branch_manager_id") @@ -403,6 +410,12 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error { if branchManagerQuery != "" { parseManagerID, err := strconv.ParseInt(branchManagerQuery, 10, 64) if err != nil { + h.mongoLoggerSvc.Info("Failed to parse branch_manager_id", + zap.String("userID", branchManagerQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Failed to parse branch_manager_id") } branchManagerID = domain.ValidInt64{ @@ -421,8 +434,13 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_before format", + zap.String("createdBeforeQuery", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -435,8 +453,13 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_after format", + zap.String("createdAfterQuery", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -457,13 +480,17 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error { CreatedAfter: createdAfter, }) if err != nil { - h.logger.Error("Failed to get branches", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil) + h.mongoLoggerSvc.Info("Failed to get branches", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var result []BranchDetailRes = make([]BranchDetailRes, 0, len(branches)) + var result []domain.BranchDetailRes = make([]domain.BranchDetailRes, 0, len(branches)) for _, branch := range branches { - result = append(result, convertBranchDetail(branch)) + result = append(result, domain.ConvertBranchDetail(branch)) } return response.WriteJSON(c, fiber.StatusOK, "Branches for Company retrieved", result, nil) } @@ -475,28 +502,37 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param q query string true "Search query" -// @Success 200 {array} BranchDetailRes +// @Success 200 {array} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /search/branch [get] +// @Router /api/v1/search/branch [get] func (h *Handler) SearchBranch(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) + h.mongoLoggerSvc.Info("Search query is required", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Search query is required") } // Call the service to search for branches branches, err := h.branchSvc.SearchBranchByName(c.Context(), searchQuery) if err != nil { - h.logger.Error("Failed to search branches", "query", searchQuery, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to search branches", err, nil) + h.mongoLoggerSvc.Info("Failed to search branches", + zap.String("query", searchQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } // Convert branches to response format - var result []BranchDetailRes + var result []domain.BranchDetailRes for _, branch := range branches { - result = append(result, convertBranchDetail(branch)) + result = append(result, domain.ConvertBranchDetail(branch)) } return response.WriteJSON(c, fiber.StatusOK, "Branches retrieved successfully", result, nil) @@ -508,20 +544,24 @@ func (h *Handler) SearchBranch(c *fiber.Ctx) error { // @Tags branch // @Accept json // @Produce json -// @Success 200 {array} BranchDetailRes +// @Success 200 {array} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /supportedOperation [get] +// @Router /api/v1/supportedOperation [get] func (h *Handler) GetAllSupportedOperations(c *fiber.Ctx) error { operations, err := h.branchSvc.GetAllSupportedOperations(c.Context()) if err != nil { - h.logger.Error("Failed to get operations", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get operations", err, nil) + h.mongoLoggerSvc.Error("Failed to get operations", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var result []SupportedOperationRes = make([]SupportedOperationRes, 0, len(operations)) + var result []domain.SupportedOperationRes = make([]domain.SupportedOperationRes, 0, len(operations)) for _, operation := range operations { - result = append(result, SupportedOperationRes{ + result = append(result, domain.SupportedOperationRes{ ID: operation.ID, Name: operation.Name, Description: operation.Description, @@ -538,29 +578,39 @@ func (h *Handler) GetAllSupportedOperations(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Branch ID" -// @Success 200 {array} BranchOperationRes +// @Success 200 {array} domain.BranchOperationRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id}/operation [get] +// @Router /api/v1/branch/{id}/operation [get] func (h *Handler) GetBranchOperations(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) + h.mongoLoggerSvc.Error("Invalid branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } operations, err := h.branchSvc.GetBranchOperations(c.Context(), id) if err != nil { - h.logger.Error("Failed to get operation by ID", "branchID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve operation", err, nil) + h.mongoLoggerSvc.Error("Failed to get operation by ID", + zap.Int64("branchID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var result []BranchOperationRes = make([]BranchOperationRes, 0, len(operations)) + var result []domain.BranchOperationRes = make([]domain.BranchOperationRes, 0, len(operations)) for _, branch := range operations { - result = append(result, BranchOperationRes{ + result = append(result, domain.BranchOperationRes{ Name: branch.OperationName, Description: branch.OperationDescription, }) @@ -579,20 +629,30 @@ func (h *Handler) GetBranchOperations(c *fiber.Ctx) error { // @Success 200 {array} GetCashierRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id}/cashier [get] +// @Router /api/v1/branch/{id}/cashier [get] func (h *Handler) GetBranchCashiers(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) + h.mongoLoggerSvc.Info("Invalid branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } cashiers, err := h.userSvc.GetCashiersByBranch(c.Context(), id) if err != nil { - h.logger.Error("Failed to get cashier by branch ID", "branchID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier", err, nil) + h.mongoLoggerSvc.Error("Failed to get cashier by branch ID", + zap.Int64("branchID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } var result []GetCashierRes = make([]GetCashierRes, 0, len(cashiers)) @@ -603,7 +663,12 @@ func (h *Handler) GetBranchCashiers(c *fiber.Ctx) error { if err == authentication.ErrRefreshTokenNotFound { lastLogin = &cashier.CreatedAt } else { - h.logger.Error("Failed to get user last login", "userID", cashier.ID, "error", err) + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("cashier ID", cashier.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") } } @@ -634,39 +699,58 @@ func (h *Handler) GetBranchCashiers(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Branch ID" -// @Success 200 {object} BranchDetailRes +// @Success 200 {object} domain.BranchDetailRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branchCashier [get] +// @Router /api/v1/branchCashier [get] func (h *Handler) GetBranchForCashier(c *fiber.Ctx) error { cashierID, ok := c.Locals("user_id").(int64) if !ok { - h.logger.Error("Invalid cashier ID in context") - return response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid cashier identification", nil, nil) + h.mongoLoggerSvc.Error("Invalid cashier ID in context", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user_id") } role, ok := c.Locals("role").(domain.Role) if !ok || role != domain.RoleCashier { - h.logger.Error("Unauthorized access", "cashierID", cashierID, "role", role) - return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) + + h.mongoLoggerSvc.Error("Unauthorized access", + zap.Int64("cashierID", cashierID), + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusForbidden), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "Unauthorized access") } branchID, ok := c.Locals("branch_id").(domain.ValidInt64) if !ok || !branchID.Valid { - h.logger.Error("Invalid branch ID in context", "cashierID", cashierID) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", nil, nil) + h.mongoLoggerSvc.Info("Invalid branch ID in context", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } branch, err := h.branchSvc.GetBranchByID(c.Context(), branchID.Value) if err != nil { - h.logger.Error("Failed to get branch by ID", "branchID", branchID.Value, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil) + h.mongoLoggerSvc.Error("Failed to get branch by ID", + zap.Int64("branchID", branchID.Value), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertBranchDetail(branch) + res := domain.ConvertBranchDetail(branch) return response.WriteJSON(c, fiber.StatusOK, "Branch retrieved successfully", res, nil) } @@ -680,25 +764,39 @@ func (h *Handler) GetBranchForCashier(c *fiber.Ctx) error { // @Success 200 {array} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id}/bets [get] +// @Router /api/v1/branch/{id}/bets [get] func (h *Handler) GetBetByBranchID(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) + h.mongoLoggerSvc.Info("Invalid branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } - bets, err := h.betSvc.GetBetByBranchID(c.Context(), id) + bets, err := h.transactionSvc.GetAllShopBet(c.Context(), domain.ShopBetFilter{ + BranchID: domain.ValidInt64{ + Value: id, + Valid: true, + }, + }) if err != nil { - h.logger.Error("Failed to get bets", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bets", err, nil) + h.mongoLoggerSvc.Error("Failed to get bets", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var res []domain.BetRes = make([]domain.BetRes, 0, len(bets)) + var res []domain.ShopBetRes = make([]domain.ShopBetRes, 0, len(bets)) for _, bet := range bets { - res = append(res, domain.ConvertBet(bet)) + res = append(res, domain.ConvertShopBetDetail(bet)) } return response.WriteJSON(c, fiber.StatusOK, "Branch Bets Retrieved", res, nil) @@ -711,28 +809,48 @@ func (h *Handler) GetBetByBranchID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Branch ID" -// @Param updateBranch body CreateBranchReq true "Update Branch" -// @Success 200 {object} BranchRes +// @Param updateBranch body domain.CreateBranchReq true "Update Branch" +// @Success 200 {object} domain.BranchRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id} [put] +// @Router /api/v1/branch/{id} [put] func (h *Handler) UpdateBranch(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) + h.mongoLoggerSvc.Info("Invalid branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } - var req UpdateBranchReq + var req domain.UpdateBranchReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateBranchReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("Failed to parse CreateBranchReq", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate UpdateBranchReq", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.String("errMsg", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } branch, err := h.branchSvc.UpdateBranch(c.Context(), domain.UpdateBranch{ @@ -742,14 +860,20 @@ func (h *Handler) UpdateBranch(c *fiber.Ctx) error { BranchManagerID: req.BranchManagerID, CompanyID: req.CompanyID, IsSelfOwned: req.IsSelfOwned, + IsActive: req.IsActive, }) if err != nil { - h.logger.Error("Failed to update branch", "branchID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update branch", err, nil) + h.mongoLoggerSvc.Error("Failed to update branch", + zap.Int64("branchID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertBranch(branch) + res := domain.ConvertBranch(branch) return response.WriteJSON(c, fiber.StatusOK, "Branch Updated", res, nil) @@ -759,8 +883,13 @@ func (h *Handler) UpdateBranchStatus(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) + h.mongoLoggerSvc.Info("Invalid branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } var isActive bool @@ -771,8 +900,14 @@ func (h *Handler) UpdateBranchStatus(c *fiber.Ctx) error { } else if path[len(path)-1] == "set-inactive" { isActive = false } else { - h.logger.Error("Invalid branch status", "status", isActive, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch status", err, nil) + h.mongoLoggerSvc.Info("Invalid branch status", + zap.Bool("status", isActive), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch status") } branch, err := h.branchSvc.UpdateBranch(c.Context(), domain.UpdateBranch{ @@ -781,11 +916,16 @@ func (h *Handler) UpdateBranchStatus(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("Failed to update branch", "branchID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update branch", err, nil) + h.mongoLoggerSvc.Error("Failed to update branch", + zap.Int64("branchID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertBranch(branch) + res := domain.ConvertBranch(branch) return response.WriteJSON(c, fiber.StatusOK, "Branch Updated", res, nil) @@ -801,21 +941,31 @@ func (h *Handler) UpdateBranchStatus(c *fiber.Ctx) error { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id} [delete] +// @Router /api/v1/branch/{id} [delete] func (h *Handler) DeleteBranch(c *fiber.Ctx) error { branchID := c.Params("id") id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid Branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Branch ID", err, nil) + h.mongoLoggerSvc.Info("Invalid Branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid Branch ID") } err = h.branchSvc.DeleteBranch(c.Context(), id) if err != nil { - h.logger.Error("Failed to delete by ID", "Branch ID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Branch", err, nil) + h.mongoLoggerSvc.Error("Failed to delete by ID", + zap.Int64("Branch ID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Branch removed successfully", nil, nil) @@ -832,7 +982,7 @@ func (h *Handler) DeleteBranch(c *fiber.Ctx) error { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branch/{id}/operation/{opID} [delete] +// @Router /api/v1/branch/{id}/operation/{opID} [delete] func (h *Handler) DeleteBranchOperation(c *fiber.Ctx) error { branchID := c.Params("id") opID := c.Params("opID") @@ -840,22 +990,39 @@ func (h *Handler) DeleteBranchOperation(c *fiber.Ctx) error { id, err := strconv.ParseInt(branchID, 10, 64) if err != nil { - h.logger.Error("Invalid Branch ID", "branchID", branchID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Branch ID", err, nil) + + h.mongoLoggerSvc.Error("Invalid Branch ID", + zap.String("branchID", branchID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid Branch ID") } operationID, err := strconv.ParseInt(opID, 10, 64) if err != nil { - h.logger.Error("Invalid Operation ID", "operationID", opID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Operation ID", err, nil) + + h.mongoLoggerSvc.Info("Invalid Operation ID", + zap.String("operationID", opID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid Operation ID") } err = h.branchSvc.DeleteBranchOperation(c.Context(), id, operationID) if err != nil { - h.logger.Error("Failed to delete operation", "Branch ID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Operation", err, nil) + h.mongoLoggerSvc.Error("Failed to delete operation", + zap.Int64("Branch ID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Branch Operation removed successfully", nil, nil) diff --git a/internal/web_server/handlers/cashier.go b/internal/web_server/handlers/cashier.go index 8474cde..139f4a4 100644 --- a/internal/web_server/handlers/cashier.go +++ b/internal/web_server/handlers/cashier.go @@ -9,6 +9,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) type CreateCashierReq struct { @@ -32,7 +33,7 @@ type CreateCashierReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /cashiers [post] +// @Router /api/v1/cashiers [post] func (h *Handler) CreateCashier(c *fiber.Ctx) error { // Get user_id from middleware @@ -40,19 +41,33 @@ func (h *Handler) CreateCashier(c *fiber.Ctx) error { var req CreateCashierReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("RegisterUser failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("failed to parse CreateCashier request body", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate CreateCashier", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } // Cashiers inherit the company id from the branch id + // TODO add a check here to make sure that the admin/manager if from same company branch, err := h.branchSvc.GetBranchByID(c.Context(), req.BranchID) if err != nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID is invalid", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Branch ID is invalid") } userRequest := domain.CreateUserReq{ FirstName: req.FirstName, @@ -70,14 +85,25 @@ func (h *Handler) CreateCashier(c *fiber.Ctx) error { fmt.Print(req.Suspended) newUser, err := h.userSvc.CreateUser(c.Context(), userRequest, true) if err != nil { - h.logger.Error("CreateCashier failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil) + h.mongoLoggerSvc.Error("Failed to create cashier user", + zap.Any("userRequest", userRequest), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create cashier user:"+err.Error()) } err = h.branchSvc.CreateBranchCashier(c.Context(), req.BranchID, newUser.ID) if err != nil { - h.logger.Error("CreateCashier failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil) + h.mongoLoggerSvc.Error("failed to create branch cashier", + zap.Int64("branchID", req.BranchID), + zap.Int64("userID", newUser.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create branch cashier:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Cashier created successfully", nil, nil) @@ -111,17 +137,22 @@ type GetCashierRes struct { // @Produce json // @Param page query int false "Page number" // @Param page_size query int false "Page size" -// @Success 200 {object} response.APIResponse +// @Success 200 {array} GetCashierRes // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /cashiers [get] +// @Router /api/v1/cashiers [get] func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyId := c.Locals("company_id").(domain.ValidInt64) if role != domain.RoleSuperAdmin && !companyId.Valid { - return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID") + h.mongoLoggerSvc.Error("Cannot get company ID in context", + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID in context") } searchQuery := c.Query("query") searchString := domain.ValidString{ @@ -134,8 +165,13 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_before format", + zap.String("createdBefore", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -148,8 +184,13 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_after format", + zap.String("created_after", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -174,7 +215,16 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { valErrs, ok := h.validator.Validate(c, filter) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate filters for GetAllCashier", + zap.Any("filter", filter), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } cashiers, total, err := h.userSvc.GetAllCashiers(c.Context(), domain.UserFilter{ @@ -183,8 +233,12 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { CreatedAfter: createdAfter, }) if err != nil { - h.logger.Error("GetAllCashiers failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil) + h.mongoLoggerSvc.Error("failed to get all cashiers", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get cashiers:"+err.Error()) } var result []GetCashierRes = make([]GetCashierRes, 0, len(cashiers)) @@ -195,8 +249,13 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { if err == authentication.ErrRefreshTokenNotFound { lastLogin = &cashier.CreatedAt } else { - h.logger.Error("Failed to get user last login", "userID", cashier.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", cashier.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } } @@ -236,7 +295,7 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /cashier/{id} [get] +// @Router /api/v1/cashier/{id} [get] func (h *Handler) GetCashierByID(c *fiber.Ctx) error { // branchId := int64(12) //c.Locals("branch_id").(int64) // filter := user.Filter{ @@ -256,22 +315,37 @@ func (h *Handler) GetCashierByID(c *fiber.Ctx) error { stringID := c.Params("id") cashierID, err := strconv.ParseInt(stringID, 10, 64) if err != nil { - h.logger.Error("failed to fetch user using UserID", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil) + h.mongoLoggerSvc.Info("failed to parse user_id", + zap.String("stringID", stringID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid cashier ID") } user, err := h.userSvc.GetCashierByID(c.Context(), cashierID) if err != nil { - h.logger.Error("Get User By ID failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil) + h.mongoLoggerSvc.Error("Get User By ID failed", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get cashiers:"+err.Error()) } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { - h.logger.Error("Failed to get user last login", "cashierID", user.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", user.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } lastLogin = &user.CreatedAt } @@ -316,24 +390,42 @@ type updateCashierReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /cashiers/{id} [put] +// @Router /api/v1/cashiers/{id} [put] func (h *Handler) UpdateCashier(c *fiber.Ctx) error { cashierIdStr := c.Params("id") cashierId, err := strconv.ParseInt(cashierIdStr, 10, 64) if err != nil { - h.logger.Error("UpdateCashier failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil) + h.mongoLoggerSvc.Info("UpdateCashier invalid cashier ID", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid cashier ID") } var req updateCashierReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("UpdateCashier failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) + h.mongoLoggerSvc.Info("UpdateCashier failed to parse request body", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate update cashier request", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{ @@ -353,8 +445,14 @@ func (h *Handler) UpdateCashier(c *fiber.Ctx) error { }, ) if err != nil { - h.logger.Error("UpdateCashier failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update cashier", nil, nil) + h.mongoLoggerSvc.Error("failed to update cashier", + zap.Int64("userID", cashierId), + zap.Any("request", req), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update cashier"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Cashier updated successfully", nil, nil) diff --git a/internal/web_server/handlers/common.go b/internal/web_server/handlers/common.go new file mode 100644 index 0000000..5ac8282 --- /dev/null +++ b/internal/web_server/handlers/common.go @@ -0,0 +1 @@ +package handlers diff --git a/internal/web_server/handlers/company_handler.go b/internal/web_server/handlers/company_handler.go index 0501fbc..d7c8551 100644 --- a/internal/web_server/handlers/company_handler.go +++ b/internal/web_server/handlers/company_handler.go @@ -1,92 +1,60 @@ package handlers import ( + "fmt" "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) -type CreateCompanyReq struct { - Name string `json:"name" example:"CompanyName"` - AdminID int64 `json:"admin_id" example:"1"` -} -type UpdateCompanyReq struct { - Name *string `json:"name,omitempty" example:"CompanyName"` - AdminID *int64 `json:"admin_id,omitempty" example:"1"` -} - -type CompanyRes struct { - ID int64 `json:"id" example:"1"` - Name string `json:"name" example:"CompanyName"` - AdminID int64 `json:"admin_id" example:"1"` - WalletID int64 `json:"wallet_id" example:"1"` -} - -type GetCompanyRes struct { - ID int64 `json:"id" example:"1"` - Name string `json:"name" example:"CompanyName"` - AdminID int64 `json:"admin_id" example:"1"` - WalletID int64 `json:"wallet_id" example:"1"` - WalletBalance float32 `json:"balance" example:"1"` - IsActive bool `json:"is_active" example:"false"` - AdminFirstName string `json:"admin_first_name" example:"John"` - AdminLastName string `json:"admin_last_name" example:"Doe"` - AdminPhoneNumber string `json:"admin_phone_number" example:"1234567890"` -} - -func convertCompany(company domain.Company) CompanyRes { - return CompanyRes{ - ID: company.ID, - Name: company.Name, - AdminID: company.AdminID, - WalletID: company.WalletID, - } -} - -func convertGetCompany(company domain.GetCompany) GetCompanyRes { - return GetCompanyRes{ - ID: company.ID, - Name: company.Name, - AdminID: company.AdminID, - WalletID: company.WalletID, - WalletBalance: company.WalletBalance.Float32(), - IsActive: company.IsWalletActive, - AdminFirstName: company.AdminFirstName, - AdminLastName: company.AdminLastName, - AdminPhoneNumber: company.AdminPhoneNumber, - } -} - // CreateCompany godoc // @Summary Create a company // @Description Creates a company // @Tags company // @Accept json // @Produce json -// @Param createCompany body CreateCompanyReq true "Creates company" -// @Success 200 {object} CompanyRes +// @Param createCompany body domain.CreateCompanyReq true "Creates company" +// @Success 200 {object} domain.CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /company [post] +// @Router /api/v1/company [post] func (h *Handler) CreateCompany(c *fiber.Ctx) error { - var req CreateCompanyReq + var req domain.CreateCompanyReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateCompanyReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("CreateCompanyReq failed", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate create company", + zap.String("errMsg", errMsg), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } user, err := h.userSvc.GetUserByID(c.Context(), req.AdminID) if err != nil { - h.logger.Error("Error fetching user", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get user", err, nil) + h.mongoLoggerSvc.Error("Error fetching user", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } // Create Company Wallet @@ -98,8 +66,13 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("Create Company Wallet failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create company wallet", err, nil) + h.mongoLoggerSvc.Error("Create Company Wallet failed", + zap.Int64("admin", req.AdminID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } company, err := h.companySvc.CreateCompany(c.Context(), domain.CreateCompany{ @@ -109,20 +82,29 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("CreateCompanyReq failed", "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Internal server error", - }) + h.mongoLoggerSvc.Error("CreateCompanyReq failed to create company", + zap.Int64("userID", user.ID), + zap.String("name", req.Name), + zap.String("Name", req.Name), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } err = h.userSvc.UpdateUserCompany(c.Context(), user.ID, company.ID) if err != nil { - h.logger.Error("CreateCompanyReq failed", "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Internal server error", - }) + h.mongoLoggerSvc.Error("Failed to update user company", + zap.Int64("userID", user.ID), + zap.Int64("companyID", company.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertCompany(company) + res := domain.ConvertCompany(company) return response.WriteJSON(c, fiber.StatusCreated, "Company Created", res, nil) } @@ -133,10 +115,10 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error { // @Tags company // @Accept json // @Produce json -// @Success 200 {array} CompanyRes +// @Success 200 {array} domain.GetCompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /company [get] +// @Router /api/v1/company [get] func (h *Handler) GetAllCompanies(c *fiber.Ctx) error { searchQuery := c.Query("query") searchString := domain.ValidString{ @@ -149,8 +131,13 @@ func (h *Handler) GetAllCompanies(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_before format", + zap.String("createdBeforeQuery", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -163,8 +150,13 @@ func (h *Handler) GetAllCompanies(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_after format", + zap.String("created_after", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -178,14 +170,18 @@ func (h *Handler) GetAllCompanies(c *fiber.Ctx) error { CreatedAfter: createdAfter, }) if err != nil { - h.logger.Error("Failed to get companies", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get companies", err, nil) + h.mongoLoggerSvc.Error("Failed to get companies", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var result []GetCompanyRes = make([]GetCompanyRes, 0, len(companies)) + var result []domain.GetCompanyRes = make([]domain.GetCompanyRes, 0, len(companies)) for _, company := range companies { - result = append(result, convertGetCompany(company)) + result = append(result, domain.ConvertGetCompany(company)) } return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil) @@ -199,27 +195,37 @@ func (h *Handler) GetAllCompanies(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Company ID" -// @Success 200 {object} CompanyRes +// @Success 200 {object} domain.GetCompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /company/{id} [get] +// @Router /api/v1/company/{id} [get] func (h *Handler) GetCompanyByID(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { - h.logger.Error("Invalid company ID", "companyID", companyID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil) + h.mongoLoggerSvc.Info("Invalid company ID", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid company ID") } company, err := h.companySvc.GetCompanyByID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get company by ID", "companyID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to company branch", err, nil) + h.mongoLoggerSvc.Error("Failed to get company by ID", + zap.Int64("companyID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertGetCompany(company) + res := domain.ConvertGetCompany(company) return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil) } @@ -230,24 +236,33 @@ func (h *Handler) GetCompanyByID(c *fiber.Ctx) error { // @Tags company // @Accept json // @Produce json -// @Success 200 {object} CompanyRes +// @Success 200 {object} domain.GetCompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /admin-company [get] +// @Router /api/v1/admin-company [get] func (h *Handler) GetCompanyForAdmin(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { - return response.WriteJSON(c, fiber.StatusInternalServerError, "Invalid company ID", nil, nil) + h.mongoLoggerSvc.Error("Invalid company ID", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid company ID") } company, err := h.companySvc.GetCompanyByID(c.Context(), companyID.Value) if err != nil { - h.logger.Error("Failed to get company by ID", "companyID", companyID.Value, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to company branch", err, nil) + h.mongoLoggerSvc.Error("Failed to get company by ID", + zap.Int64("companyID", companyID.Value), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertGetCompany(company) + res := domain.ConvertGetCompany(company) return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil) } @@ -258,25 +273,34 @@ func (h *Handler) GetCompanyForAdmin(c *fiber.Ctx) error { // @Tags company // @Accept json // @Produce json -// @Success 200 {array} CompanyRes +// @Success 200 {array} domain.CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /search/company [get] +// @Router /api/v1/search/company [get] func (h *Handler) SearchCompany(c *fiber.Ctx) error { searchQuery := c.Query("q") if searchQuery == "" { - return response.WriteJSON(c, fiber.StatusBadRequest, "Search query is required", nil, nil) + h.mongoLoggerSvc.Info("Search query is required", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Search query is required") } companies, err := h.companySvc.SearchCompanyByName(c.Context(), searchQuery) if err != nil { - h.logger.Error("Failed to get companies", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get companies", err, nil) + h.mongoLoggerSvc.Info("Failed to get companies", + zap.String("search query", searchQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - var result []GetCompanyRes = make([]GetCompanyRes, 0, len(companies)) + var result []domain.GetCompanyRes = make([]domain.GetCompanyRes, 0, len(companies)) for _, company := range companies { - result = append(result, convertGetCompany(company)) + result = append(result, domain.ConvertGetCompany(company)) } return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil) @@ -290,42 +314,63 @@ func (h *Handler) SearchCompany(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Company ID" -// @Param updateCompany body UpdateCompanyReq true "Update Company" -// @Success 200 {object} CompanyRes +// @Param updateCompany body domain.UpdateCompanyReq true "Update Company" +// @Success 200 {object} domain.CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /company/{id} [put] +// @Router /api/v1/company/{id} [put] func (h *Handler) UpdateCompany(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { - h.logger.Error("Invalid company ID", "companyID", companyID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil) + h.mongoLoggerSvc.Info("Invalid company ID", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid company ID") } - var req UpdateCompanyReq + var req domain.UpdateCompanyReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("UpdateCompanyReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("UpdateCompanyReq failed", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("UpdateCompanyReq failed to validate", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } - company, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ - ID: id, - Name: req.Name, - AdminID: req.AdminID, - }) + company, err := h.companySvc.UpdateCompany(c.Context(), domain.ConvertUpdateCompanyReq(req)) if err != nil { - h.logger.Error("Failed to update company", "companyID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update company", err, nil) + h.mongoLoggerSvc.Error("Failed to update company", + zap.Int64("companyID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } - res := convertCompany(company) + res := domain.ConvertCompany(company) return response.WriteJSON(c, fiber.StatusOK, "Company Updated", res, nil) @@ -341,21 +386,31 @@ func (h *Handler) UpdateCompany(c *fiber.Ctx) error { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /company/{id} [delete] +// @Router /api/v1/company/{id} [delete] func (h *Handler) DeleteCompany(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { - h.logger.Error("Invalid Company ID", "companyID", companyID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Company ID", err, nil) + h.mongoLoggerSvc.Info("Invalid Company ID", + zap.String("companyID", companyID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid Company ID") } err = h.companySvc.DeleteCompany(c.Context(), id) if err != nil { - h.logger.Error("Failed to delete by ID", "Company ID", id, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Company", err, nil) + h.mongoLoggerSvc.Info("Failed to delete by ID", + zap.Int64("Company ID", id), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Company removed successfully", nil, nil) diff --git a/internal/web_server/handlers/customer.go b/internal/web_server/handlers/customer.go index d340531..af444c3 100644 --- a/internal/web_server/handlers/customer.go +++ b/internal/web_server/handlers/customer.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "strconv" "time" @@ -8,9 +9,9 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) - type CustomersRes struct { ID int64 `json:"id"` FirstName string `json:"first_name"` @@ -26,6 +27,7 @@ type CustomersRes struct { SuspendedAt time.Time `json:"suspended_at"` Suspended bool `json:"suspended"` } + // GetAllCustomers godoc // @Summary Get all Customers // @Description Get all Customers @@ -38,13 +40,18 @@ type CustomersRes struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /customer [get] +// @Router /api/v1/customer [get] func (h *Handler) GetAllCustomers(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyId := c.Locals("company_id").(domain.ValidInt64) // Checking to make sure that admin user has a company id in the token if role != domain.RoleSuperAdmin && !companyId.Valid { + h.mongoLoggerSvc.Error("Cannot get company ID from context", + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID") } @@ -59,8 +66,13 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_before format", + zap.String("createdBefore", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -73,8 +85,13 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_after format", + zap.String("createdAfter", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -99,12 +116,27 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error { } valErrs, ok := h.validator.Validate(c, filter) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate GetAllCustomer filters", + zap.Any("filter", filter), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("errMsg", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } customers, total, err := h.userSvc.GetAllUsers(c.Context(), filter) if err != nil { - h.logger.Error("GetAllCustomers failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Customers", err, nil) + h.mongoLoggerSvc.Error("GetAllCustomers failed to get all users", + zap.Any("filter", filter), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Customers:"+err.Error()) } var result []CustomersRes = make([]CustomersRes, len(customers)) @@ -114,8 +146,14 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error { if err == authentication.ErrRefreshTokenNotFound { lastLogin = &customer.CreatedAt } else { - h.logger.Error("Failed to get user last login", "userID", customer.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", customer.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, + "Failed to retrieve user last login:"+err.Error()) } } result[index] = CustomersRes{ @@ -150,7 +188,7 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /customer/{id} [get] +// @Router /api/v1/customer/{id} [get] func (h *Handler) GetCustomerByID(c *fiber.Ctx) error { userIDstr := c.Params("id") userID, err := strconv.ParseInt(userIDstr, 10, 64) @@ -160,14 +198,25 @@ func (h *Handler) GetCustomerByID(c *fiber.Ctx) error { user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customers") + h.mongoLoggerSvc.Error("Failed to get customers", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customers:"+err.Error()) } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { - h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } lastLogin = &user.CreatedAt @@ -210,28 +259,47 @@ type updateCustomerReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /customer/{id} [put] +// @Router /api/v1/customer/{id} [put] func (h *Handler) UpdateCustomer(c *fiber.Ctx) error { var req updateCustomerReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("UpdateCustomers failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) + h.mongoLoggerSvc.Error("UpdateCustomers invalid request body", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate UpdateCustomerReq", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("ErrMsg", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } CustomersIdStr := c.Params("id") CustomersId, err := strconv.ParseInt(CustomersIdStr, 10, 64) if err != nil { - h.logger.Error("UpdateCustomers failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Customers ID", nil, nil) + h.mongoLoggerSvc.Info("Invalid Customers ID", + zap.String("userID", CustomersIdStr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid Customers ID") } - + // var companyID domain.ValidInt64 // role := c.Locals("role").(domain.Role) // if req.CompanyID != nil { @@ -262,8 +330,13 @@ func (h *Handler) UpdateCustomer(c *fiber.Ctx) error { }, ) if err != nil { - h.logger.Error("UpdateCustomers failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update Customers", nil, nil) + h.mongoLoggerSvc.Error("Failed to update Customers", + zap.Int64("userID", CustomersId), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update Customers:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Customers updated successfully", nil, nil) diff --git a/internal/web_server/handlers/event_handler.go b/internal/web_server/handlers/event_handler.go index 13d7bac..2695332 100644 --- a/internal/web_server/handlers/event_handler.go +++ b/internal/web_server/handlers/event_handler.go @@ -8,6 +8,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) // @Summary Retrieve all upcoming events @@ -24,7 +25,7 @@ import ( // @Param last_start_time query string false "End Time" // @Success 200 {array} domain.UpcomingEvent // @Failure 500 {object} response.APIResponse -// @Router /events [get] +// @Router /api/v1/events [get] func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { page := c.QueryInt("page", 1) pageSize := c.QueryInt("page_size", 10) @@ -42,8 +43,13 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { if leagueIDQuery != "" { leagueIDInt, err := strconv.Atoi(leagueIDQuery) if err != nil { - h.logger.Error("invalid league id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil) + h.mongoLoggerSvc.Error("invalid league id", + zap.String("league_id", leagueIDQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid league id") } leagueID = domain.ValidInt32{ Value: int32(leagueIDInt), @@ -55,8 +61,13 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { if sportIDQuery != "" { sportIDint, err := strconv.Atoi(sportIDQuery) if err != nil { - h.logger.Error("invalid sport id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil) + h.mongoLoggerSvc.Info("invalid sport id", + zap.String("sportID", sportIDQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid sport id") } sportID = domain.ValidInt32{ Value: int32(sportIDint), @@ -68,8 +79,13 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { if firstStartTimeQuery != "" { firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid start_time format", + zap.String("first_start_time", firstStartTimeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") } firstStartTime = domain.ValidTime{ Value: firstStartTimeParsed, @@ -82,8 +98,13 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { if lastStartTimeQuery != "" { lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid start_time format", + zap.String("last_start_time", lastStartTimeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") } lastStartTime = domain.ValidTime{ Value: lastStartTimeParsed, @@ -97,9 +118,25 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { Valid: countryCodeQuery != "", } - flaggedQuery := c.Query("flagged") - if flaggedQuery != "" && + var flagged domain.ValidBool + if flaggedQuery != "" { + flaggedParsed, err := strconv.ParseBool(flaggedQuery) + if err != nil { + h.mongoLoggerSvc.Error("Failed to parse flagged", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_shop_bet") + } + + flagged = domain.ValidBool{ + Value: flaggedParsed, + Valid: true, + } + } + events, total, err := h.eventSvc.GetPaginatedUpcomingEvents( c.Context(), domain.EventFilter{ SportID: sportID, @@ -109,12 +146,17 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error { Limit: limit, Offset: offset, CountryCode: countryCode, + Flagged: flagged, }) // fmt.Printf("League ID: %v", leagueID) if err != nil { - h.logger.Error("getting error", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all upcoming events", nil, nil) + h.mongoLoggerSvc.Error("Failed to retrieve all upcoming events", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil, page, int(total)) @@ -141,14 +183,18 @@ type TopLeague struct { // @Produce json // @Success 200 {array} TopLeague // @Failure 500 {object} response.APIResponse -// @Router /top-leagues [get] +// @Router /api/v1/top-leagues [get] func (h *Handler) GetTopLeagues(c *fiber.Ctx) error { leagues, err := h.leagueSvc.GetFeaturedLeagues(c.Context()) if err != nil { - h.logger.Error("Error while fetching top leagues", "err", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get featured leagues", nil, nil) + h.mongoLoggerSvc.Error("Error while fetching top leagues", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } var topLeague []TopLeague = make([]TopLeague, 0, len(leagues)) @@ -161,8 +207,12 @@ func (h *Handler) GetTopLeagues(c *fiber.Ctx) error { }, }) if err != nil { - fmt.Printf("Error while fetching events for top league %v \n", league.ID) - h.logger.Error("Error while fetching events for top league", "League ID", league.ID) + h.mongoLoggerSvc.Warn("Error while fetching events for top league", + zap.Int64("LeagueID", league.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) } topLeague = append(topLeague, TopLeague{ LeagueID: league.ID, @@ -189,17 +239,28 @@ func (h *Handler) GetTopLeagues(c *fiber.Ctx) error { // @Success 200 {object} domain.UpcomingEvent // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /events/{id} [get] +// @Router /api/v1/events/{id} [get] func (h *Handler) GetUpcomingEventByID(c *fiber.Ctx) error { id := c.Params("id") if id == "" { - return response.WriteJSON(c, fiber.StatusBadRequest, "Missing id", nil, nil) + h.mongoLoggerSvc.Info("Failed to parse event id", + zap.String("id", id), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Missing id") } event, err := h.eventSvc.GetUpcomingEventByID(c.Context(), id) if err != nil { - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve upcoming event", nil, nil) + h.mongoLoggerSvc.Error("Failed to get upcoming event by id", + zap.String("eventID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", event, nil) @@ -219,13 +280,19 @@ type UpdateEventStatusReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /events/{id} [delete] +// @Router /api/v1/events/{id} [delete] func (h *Handler) SetEventStatusToRemoved(c *fiber.Ctx) error { eventID := c.Params("id") err := h.eventSvc.UpdateEventStatus(c.Context(), eventID, domain.STATUS_REMOVED) if err != nil { - h.logger.Error("Failed to update event status", "eventID", eventID, "error", err) + h.mongoLoggerSvc.Error("Failed to update event status", + zap.String("EventID", eventID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update event status") } return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil) @@ -246,13 +313,19 @@ type UpdateEventFlaggedReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /events/{id}/flag [put] +// @Router /api/v1/events/{id}/flag [put] func (h *Handler) UpdateEventFlagged(c *fiber.Ctx) error { eventID := c.Params("id") var req UpdateEventFlaggedReq if err := c.BodyParser(&req); err != nil { + h.mongoLoggerSvc.Info("Failed to parse user id", + zap.String("eventID", eventID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } @@ -262,12 +335,23 @@ func (h *Handler) UpdateEventFlagged(c *fiber.Ctx) error { for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } + h.mongoLoggerSvc.Error("Failed to update event flagged", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } err := h.eventSvc.UpdateFlagged(c.Context(), eventID, req.Flagged) if err != nil { - h.logger.Error("Failed to update event flagged", "eventID", eventID, "error", err) + h.mongoLoggerSvc.Error("Failed to update event flagged", + zap.String("eventID", eventID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil) diff --git a/internal/web_server/handlers/issue_reporting.go b/internal/web_server/handlers/issue_reporting.go index 245156b..8cc45c9 100644 --- a/internal/web_server/handlers/issue_reporting.go +++ b/internal/web_server/handlers/issue_reporting.go @@ -2,9 +2,11 @@ package handlers import ( "strconv" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) // CreateIssue godoc @@ -24,12 +26,25 @@ func (h *Handler) CreateIssue(c *fiber.Ctx) error { var req domain.ReportedIssueReq if err := c.BodyParser(&req); err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Invalid request body", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } created, err := h.issueReportingSvc.CreateReportedIssue(c.Context(), req, userID, role) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + h.mongoLoggerSvc.Error("Failed to report issue", + zap.String("role", string(role)), + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "failed to report issue:"+err.Error()) } return c.Status(fiber.StatusCreated).JSON(created) @@ -50,6 +65,12 @@ func (h *Handler) CreateIssue(c *fiber.Ctx) error { func (h *Handler) GetUserIssues(c *fiber.Ctx) error { userID, err := strconv.ParseInt(c.Params("user_id"), 10, 64) if err != nil { + h.mongoLoggerSvc.Info("Failed to parse user id", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") } @@ -57,7 +78,13 @@ func (h *Handler) GetUserIssues(c *fiber.Ctx) error { issues, err := h.issueReportingSvc.GetIssuesForUser(c.Context(), userID, limit, offset) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + h.mongoLoggerSvc.Error("Failed to get user issue", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get user issue"+err.Error()) } return c.JSON(issues) @@ -78,7 +105,14 @@ func (h *Handler) GetAllIssues(c *fiber.Ctx) error { issues, err := h.issueReportingSvc.GetAllIssues(c.Context(), limit, offset) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + h.mongoLoggerSvc.Error("Failed to get all issues", + zap.Int("limit", limit), + zap.Int("offset", offset), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get all issues:"+err.Error()) } return c.JSON(issues) @@ -104,11 +138,24 @@ func (h *Handler) UpdateIssueStatus(c *fiber.Ctx) error { Status string `json:"status"` } if err := c.BodyParser(&body); err != nil || body.Status == "" { - return fiber.NewError(fiber.StatusBadRequest, "Invalid status payload") + h.mongoLoggerSvc.Info("Invalid status payload", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid status payload"+err.Error()) } if err := h.issueReportingSvc.UpdateIssueStatus(c.Context(), issueID, body.Status); err != nil { + h.mongoLoggerSvc.Error("Failed to update issue status", + zap.Int64("issueID", issueID), + zap.String("status", body.Status), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } return c.SendStatus(fiber.StatusNoContent) @@ -130,6 +177,12 @@ func (h *Handler) DeleteIssue(c *fiber.Ctx) error { } if err := h.issueReportingSvc.DeleteIssue(c.Context(), issueID); err != nil { + h.mongoLoggerSvc.Error("Failed to delete issue", + zap.Int64("issueID", issueID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } diff --git a/internal/web_server/handlers/leagues.go b/internal/web_server/handlers/leagues.go index 000c557..794bac2 100644 --- a/internal/web_server/handlers/leagues.go +++ b/internal/web_server/handlers/leagues.go @@ -3,10 +3,12 @@ package handlers import ( "fmt" "strconv" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) // GetAllLeagues godoc @@ -18,7 +20,7 @@ import ( // @Success 200 {array} domain.League // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /leagues [get] +// @Router /api/v1/leagues [get] func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { page := c.QueryInt("page", 1) pageSize := c.QueryInt("page_size", 10) @@ -49,8 +51,13 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { if sportIDQuery != "" { sportIDint, err := strconv.Atoi(sportIDQuery) if err != nil { - h.logger.Error("invalid sport id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "invalid sport id", nil, nil) + h.mongoLoggerSvc.Info("invalid sport id", + zap.String("sport_id", sportIDQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid sport id") } sportID = domain.ValidInt32{ Value: int32(sportIDint), @@ -68,8 +75,12 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { if err != nil { fmt.Printf("Error fetching league %v \n", err) - h.logger.Error("Failed to get leagues", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get leagues", err, nil) + h.mongoLoggerSvc.Error("Failed to get all leagues", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get leagues:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", leagues, nil) } @@ -78,59 +89,132 @@ type SetLeagueActiveReq struct { IsActive bool `json:"is_active"` } +// SetLeagueActive godoc +// @Summary Set the league to active +// @Description Set the league to active +// @Tags leagues +// @Accept json +// @Produce json +// @Param id path int true "League ID" +// @Param active body SetLeagueActiveReq true "League Active Request" +// @Success 200 {object} response.APIResponse +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/leagues/{id}/set-active [put] func (h *Handler) SetLeagueActive(c *fiber.Ctx) error { - fmt.Printf("Set Active Leagues") leagueIdStr := c.Params("id") if leagueIdStr == "" { - response.WriteJSON(c, fiber.StatusBadRequest, "Missing league id", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Missing league id") } leagueId, err := strconv.Atoi(leagueIdStr) if err != nil { - response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "invalid league id") } var req SetLeagueActiveReq if err := c.BodyParser(&req); err != nil { h.logger.Error("SetLeagueReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to parse request", err, nil) + h.mongoLoggerSvc.Error("SetLeagueReq failed to parse request body", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse request:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate SetLeagueActiveReq", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } if err := h.leagueSvc.SetLeagueActive(c.Context(), int64(leagueId), req.IsActive); err != nil { - response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update league", err, nil) + h.mongoLoggerSvc.Error("Failed to update league active", + zap.Int64("userID", int64(leagueId)), + zap.Bool("is_active", req.IsActive), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update league:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil) } -func (h *Handler) SetLeagueAsFeatured(c *fiber.Ctx) error { - fmt.Printf("Set Active Leagues") +type SetLeagueAsFeatured struct { + IsFeatured bool `json:"is_featured" example:"true"` +} + +// SetLeagueFeatured godoc +// @Summary Set the league to featured/un-featured +// @Description Set the league to featured/un-featured +// @Tags leagues +// @Accept json +// @Produce json +// @Param id path int true "League ID" +// @Param active body SetLeagueAsFeatured true "League Featured Request" +// @Success 200 {object} response.APIResponse +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/leagues/{id}/featured [put] +func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error { leagueIdStr := c.Params("id") if leagueIdStr == "" { - response.WriteJSON(c, fiber.StatusBadRequest, "Missing league id", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "Missing league id") } leagueId, err := strconv.Atoi(leagueIdStr) if err != nil { - response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil) + return fiber.NewError(fiber.StatusBadRequest, "invalid league id") } - var req SetLeagueActiveReq + var req SetLeagueAsFeatured if err := c.BodyParser(&req); err != nil { - h.logger.Error("SetLeagueReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to parse request", err, nil) + h.logger.Error("SetLeagueFeaturedReq failed", "error", err) + h.mongoLoggerSvc.Info("SetLeagueFeaturedReq failed to parse request body", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) - } + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate SetLeagueFeaturedReq", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) - if err := h.leagueSvc.SetLeagueActive(c.Context(), int64(leagueId), req.IsActive); err != nil { - response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update league", err, nil) + } + err = h.leagueSvc.UpdateLeague(c.Context(), domain.UpdateLeague{ + ID: int64(leagueId), + }) + if err != nil { + h.mongoLoggerSvc.Error("Failed to update league", + zap.Int64("leagueID", int64(leagueId)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update league:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil) diff --git a/internal/web_server/handlers/manager.go b/internal/web_server/handlers/manager.go index 2993a70..c0eafa9 100644 --- a/internal/web_server/handlers/manager.go +++ b/internal/web_server/handlers/manager.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "strconv" "time" @@ -8,6 +9,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) type CreateManagerReq struct { @@ -30,7 +32,7 @@ type CreateManagerReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /managers [post] +// @Router /api/v1/managers [post] func (h *Handler) CreateManager(c *fiber.Ctx) error { // Get user_id from middleware @@ -38,11 +40,26 @@ func (h *Handler) CreateManager(c *fiber.Ctx) error { var req CreateManagerReq if err := c.BodyParser(&req); err != nil { h.logger.Error("RegisterUser failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("CreateManager failed to create manager", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate CreateManager", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("errMsg", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } var companyID domain.ValidInt64 @@ -50,7 +67,11 @@ func (h *Handler) CreateManager(c *fiber.Ctx) error { if role == domain.RoleSuperAdmin { if req.CompanyID == nil { h.logger.Error("RegisterUser failed error: company id is required") - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", "Company ID is required", nil) + h.mongoLoggerSvc.Info("RegisterUser failed error: company id is required", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Company ID is required for super-admin") } companyID = domain.ValidInt64{ Value: *req.CompanyID, @@ -71,8 +92,12 @@ func (h *Handler) CreateManager(c *fiber.Ctx) error { } _, err := h.userSvc.CreateUser(c.Context(), user, true) if err != nil { - h.logger.Error("CreateManager failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create manager", nil, nil) + h.mongoLoggerSvc.Error("CreateManager failed to create manager", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create manager:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Manager created successfully", nil, nil) @@ -106,14 +131,19 @@ type ManagersRes struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /managers [get] +// @Router /api/v1/managers [get] func (h *Handler) GetAllManagers(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyId := c.Locals("company_id").(domain.ValidInt64) // Checking to make sure that admin user has a company id in the token if role != domain.RoleSuperAdmin && !companyId.Valid { - return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID") + h.mongoLoggerSvc.Error("Cannot get company ID from context", + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID from context") } searchQuery := c.Query("query") @@ -127,8 +157,13 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_before format", + zap.String("created_before", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -141,8 +176,13 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid created_after format", + zap.String("created_after", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -167,12 +207,28 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error { } valErrs, ok := h.validator.Validate(c, filter) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate get all filters", + zap.Any("filter", filter), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("errMsg", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter) if err != nil { h.logger.Error("GetAllManagers failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Managers", err, nil) + h.mongoLoggerSvc.Error("GetAllManagers failed to get all managers", + zap.Any("filter", filter), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Managers"+err.Error()) } var result []ManagersRes = make([]ManagersRes, len(managers)) @@ -182,8 +238,13 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error { if err == authentication.ErrRefreshTokenNotFound { lastLogin = &manager.CreatedAt } else { - h.logger.Error("Failed to get user last login", "userID", manager.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", manager.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } } result[index] = ManagersRes{ @@ -218,7 +279,7 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /managers/{id} [get] +// @Router /api/v1/managers/{id} [get] func (h *Handler) GetManagerByID(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyId := c.Locals("company_id").(domain.ValidInt64) @@ -226,11 +287,22 @@ func (h *Handler) GetManagerByID(c *fiber.Ctx) error { // Only Super Admin / Admin / Branch Manager can view this route if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager { - return fiber.NewError(fiber.StatusUnauthorized, "Role Unauthorized") + h.mongoLoggerSvc.Warn("Attempt to access from unauthorized role", + zap.Int64("userID", requestUserID), + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusForbidden), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "This role cannot view this route") } if role != domain.RoleSuperAdmin && !companyId.Valid { - return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID") + h.mongoLoggerSvc.Error("Cannot get company ID in context", + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID in context") } userIDstr := c.Params("id") @@ -241,24 +313,47 @@ func (h *Handler) GetManagerByID(c *fiber.Ctx) error { user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers") + h.mongoLoggerSvc.Error("Failed to get manager by id", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers:"+err.Error()) } // A Branch Manager can only fetch his own branch info if role == domain.RoleBranchManager && user.ID != requestUserID { - return fiber.NewError(fiber.StatusBadRequest, "User Access Not Allowed") + h.mongoLoggerSvc.Warn("Attempt to access another branch manager info", + zap.String("userID", userIDstr), + zap.Int("status_code", fiber.StatusForbidden), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "User Access Not Allowed") } // Check that only admin from company can view this route if role != domain.RoleSuperAdmin && user.CompanyID.Value != companyId.Value { - return fiber.NewError(fiber.StatusBadRequest, "Only company user can view manager info") + h.mongoLoggerSvc.Warn("Attempt to access info from another company", + zap.String("userID", userIDstr), + zap.Int("status_code", fiber.StatusForbidden), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "Cannot access another company information") } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { - h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error()) } lastLogin = &user.CreatedAt @@ -301,13 +396,14 @@ type updateManagerReq struct { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /managers/{id} [put] +// @Router /api/v1/managers/{id} [put] func (h *Handler) UpdateManagers(c *fiber.Ctx) error { var req updateManagerReq if err := c.BodyParser(&req); err != nil { h.logger.Error("UpdateManagers failed", "error", err) + return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) } diff --git a/internal/web_server/handlers/notification_handler.go b/internal/web_server/handlers/notification_handler.go index 8af6fed..4a5e106 100644 --- a/internal/web_server/handlers/notification_handler.go +++ b/internal/web_server/handlers/notification_handler.go @@ -7,6 +7,8 @@ import ( "net" "net/http" "strconv" + "strings" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/ws" @@ -14,6 +16,7 @@ import ( "github.com/gofiber/fiber/v2/middleware/adaptor" "github.com/gorilla/websocket" "github.com/valyala/fasthttp/fasthttpadaptor" + "go.uber.org/zap" ) func hijackHTTP(c *fiber.Ctx) (net.Conn, http.ResponseWriter, error) { @@ -45,30 +48,49 @@ func hijackHTTP(c *fiber.Ctx) (net.Conn, http.ResponseWriter, error) { func (h *Handler) ConnectSocket(c *fiber.Ctx) error { userID, ok := c.Locals("userID").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") + h.mongoLoggerSvc.Info("Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusUnauthorized), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") } // Convert *fiber.Ctx to *http.Request req, err := adaptor.ConvertRequest(c, false) if err != nil { - h.logger.Error("Failed to convert request", "error", err) + h.mongoLoggerSvc.Error("Failed to convert socket request", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to convert request") } // Create a net.Conn hijacked from the fasthttp context netConn, rw, err := hijackHTTP(c) if err != nil { - h.logger.Error("Failed to hijack connection", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to hijack connection") + h.mongoLoggerSvc.Error("Failed to hijack connection", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to hijack connection:"+err.Error()) } // Upgrade the connection using Gorilla's Upgrader conn, err := ws.Upgrader.Upgrade(rw, req, nil) if err != nil { - h.logger.Error("WebSocket upgrade failed", "error", err) + h.mongoLoggerSvc.Error("WebSocket upgrade failed", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) netConn.Close() - return fiber.NewError(fiber.StatusInternalServerError, "WebSocket upgrade failed") + return fiber.NewError(fiber.StatusInternalServerError, "WebSocket upgrade failed:"+err.Error()) } client := &ws.Client{ @@ -88,9 +110,19 @@ func (h *Handler) ConnectSocket(c *fiber.Ctx) error { _, _, err := conn.ReadMessage() if err != nil { if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) { - h.logger.Info("WebSocket closed normally", "userID", userID) + h.mongoLoggerSvc.Info("WebSocket closed normally", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) } else { - h.logger.Warn("Unexpected WebSocket closure", "userID", userID, "error", err) + h.mongoLoggerSvc.Warn("Unexpected WebSocket closure", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) } break } @@ -106,20 +138,34 @@ func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error { var req Request if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse request body", "error", err) + h.mongoLoggerSvc.Info("Failed to parse request body", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "invalid user identification") + h.mongoLoggerSvc.Error("Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "invalid user ID in context") } fmt.Printf("Notification IDs: %v \n", req.NotificationIDs) if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationIDs, userID); err != nil { - h.logger.Error("Failed to mark notifications as read", "notificationID", req.NotificationIDs, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to update notification status") + h.mongoLoggerSvc.Error("Failed to mark notifications as read", + zap.String("notificationID", strings.Join(req.NotificationIDs, ",")), + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update notification status:", err.Error()) } return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Notification marked as read"}) @@ -141,7 +187,11 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error { var req Request if err := c.BodyParser(&req); err != nil { - h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to parse request body", "error", err) + h.mongoLoggerSvc.Info("[NotificationSvc.CreateAndSendNotification] Failed to parse request body", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } @@ -174,11 +224,20 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error { } if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil { - h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to send single notification", "recipientID", req.RecipientID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to send notification") + h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Failed to send single notification", + zap.Int64("recipientID", req.RecipientID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to send notification:"+err.Error()) } - h.logger.Info("[NotificationSvc.CreateAndSendNotification] Single notification sent successfully", "recipientID", req.RecipientID, "type", req.Type) + h.mongoLoggerSvc.Info("[NotificationSvc.CreateAndSendNotification] Single notification sent successfully", + zap.Int64("recipientID", req.RecipientID), + zap.String("type", string(req.Type)), + zap.Time("timestamp", time.Now()), + ) return c.Status(fiber.StatusCreated).JSON(fiber.Map{"message": "Single notification sent successfully", "notification_id": notification.ID}) case domain.NotificationDeliverySchemeBulk: @@ -186,12 +245,16 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error { Role: string(req.Reciever), }) if err != nil { - h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to fetch recipients for bulk notification", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch recipients") + h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Failed to fetch recipients for bulk notification", + zap.Int64("RecipientID", req.RecipientID), + zap.String("Reciever", string(req.Reciever)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch recipients:"+err.Error()) } - fmt.Printf("Number of Recipients %d \n", len(recipients)) - notificationIDs := make([]string, 0, len(recipients)) for _, user := range recipients { notification := &domain.Notification{ @@ -210,13 +273,23 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error { } if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil { - h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to send bulk notification", "UserID", user.ID, "error", err) + h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Failed to send bulk notification", + zap.Int64("UserID", user.ID), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) continue } notificationIDs = append(notificationIDs, notification.ID) } - h.logger.Info("[NotificationSvc.CreateAndSendNotification] Bulk notification sent successfully", "recipient_count", len(recipients), "type", req.Type) + h.mongoLoggerSvc.Error("[NotificationSvc.CreateAndSendNotification] Bulk notification sent successfully", + zap.Int("recipient_count", len(recipients)), + zap.String("type", string(req.Type)), + zap.Int("status_code", fiber.StatusCreated), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return c.Status(fiber.StatusCreated).JSON(fiber.Map{ "message": "Bulk notification sent successfully", "recipient_count": len(recipients), @@ -224,7 +297,11 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error { }) default: - h.logger.Error("[NotificationSvc.CreateAndSendNotification] Invalid delivery scheme", "delivery_scheme", req.DeliveryScheme) + h.mongoLoggerSvc.Info("[NotificationSvc.CreateAndSendNotification] Invalid delivery scheme", + zap.String("delivery_scheme", string(req.DeliveryScheme)), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid delivery scheme") } } @@ -236,25 +313,45 @@ func (h *Handler) GetNotifications(c *fiber.Ctx) error { // Convert limit and offset to integers limit, err := strconv.Atoi(limitStr) if err != nil || limit <= 0 { - h.logger.Error("[NotificationSvc.GetNotifications] Invalid limit value", "error", err) + h.mongoLoggerSvc.Info("[NotificationSvc.GetNotifications] Invalid limit value", + zap.String("limit", limitStr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } offset, err := strconv.Atoi(offsetStr) if err != nil || offset < 0 { - h.logger.Error("[NotificationSvc.GetNotifications] Invalid offset value", "error", err) + h.mongoLoggerSvc.Info("[NotificationSvc.GetNotifications] Invalid offset value", + zap.String("offset", offsetStr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid offset value") } userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("[NotificationSvc.GetNotifications] Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Error("[NotificationSvc.GetNotifications] Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification") } notifications, err := h.notificationSvc.ListNotifications(context.Background(), userID, limit, offset) if err != nil { - h.logger.Error("[NotificationSvc.GetNotifications] Failed to fetch notifications", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications") + h.mongoLoggerSvc.Error("[NotificationSvc.GetNotifications] Failed to fetch notifications", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications:"+err.Error()) } return c.Status(fiber.StatusOK).JSON(fiber.Map{ @@ -274,15 +371,24 @@ func (h *Handler) CountUnreadNotifications(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("[NotificationSvc.GetNotifications] Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Error("NotificationSvc.GetNotifications] Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification") } total, err := h.notificationSvc.CountUnreadNotifications(c.Context(), userID) if err != nil { - h.logger.Error("[NotificationSvc.CountUnreadNotifications] Failed to fetch unread notification count", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications") + h.mongoLoggerSvc.Error("[NotificationSvc.CountUnreadNotifications] Failed to fetch unread notification count", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications:"+err.Error()) } return c.Status(fiber.StatusOK).JSON(fiber.Map{ @@ -297,18 +403,33 @@ func (h *Handler) GetAllNotifications(c *fiber.Ctx) error { // Convert limit and offset to integers limit, err := strconv.Atoi(limitStr) if err != nil || limit <= 0 { - h.logger.Error("[NotificationSvc.GetNotifications] Invalid limit value", "error", err) + h.mongoLoggerSvc.Info("[NotificationSvc.GetNotifications] Invalid limit value", + zap.String("limit", limitStr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } page, err := strconv.Atoi(pageStr) if err != nil || page <= 0 { - h.logger.Error("[NotificationSvc.GetNotifications] Invalid page value", "error", err) + h.mongoLoggerSvc.Info("[NotificationSvc.GetNotifications] Invalid page value", + zap.String("page", pageStr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid page value") } notifications, err := h.notificationSvc.GetAllNotifications(context.Background(), limit, ((page - 1) * limit)) if err != nil { - h.logger.Error("[NotificationSvc.GetNotifications] Failed to fetch notifications", "error", err) + h.mongoLoggerSvc.Error("[NotificationSvc.GetNotifications] Failed to fetch notifications", + zap.Int64("limit", int64(limit)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications") } diff --git a/internal/web_server/handlers/odd_handler.go b/internal/web_server/handlers/odd_handler.go index 397d6f2..84ff7e9 100644 --- a/internal/web_server/handlers/odd_handler.go +++ b/internal/web_server/handlers/odd_handler.go @@ -2,9 +2,11 @@ package handlers import ( "strconv" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) // GetALLPrematchOdds @@ -15,12 +17,17 @@ import ( // @Produce json // @Success 200 {array} domain.Odd // @Failure 500 {object} response.APIResponse -// @Router /odds [get] +// @Router /api/v1/odds [get] func (h *Handler) GetALLPrematchOdds(c *fiber.Ctx) error { odds, err := h.prematchSvc.GetALLPrematchOdds(c.Context()) if err != nil { - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all prematch odds", nil, nil) + h.mongoLoggerSvc.Error("Failed to retrieve all prematch odds", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "All prematch odds retrieved successfully", odds, nil) @@ -38,24 +45,39 @@ func (h *Handler) GetALLPrematchOdds(c *fiber.Ctx) error { // @Success 200 {array} domain.RawOddsByMarketID // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /odds/upcoming/{upcoming_id}/market/{market_id} [get] +// @Router /api/v1/odds/upcoming/{upcoming_id}/market/{market_id} [get] func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error { marketID := c.Params("market_id") - upcomingID := c.Params("upcoming_id") if marketID == "" { - return response.WriteJSON(c, fiber.StatusBadRequest, "Missing market_id", nil, nil) + h.mongoLoggerSvc.Info("Missing market_id", + zap.String("market_id", marketID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Missing market_id") } + upcomingID := c.Params("upcoming_id") if upcomingID == "" { - return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil) + h.mongoLoggerSvc.Info("Missing upcoming_id", + zap.String("upcoming", upcomingID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Missing upcoming_id") } rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID) if err != nil { - // fmt.Printf("Failed to fetch raw odds: %v market_id:%v upcomingID:%v\n", err, marketID, upcomingID) - h.logger.Error("Failed to get raw odds by market ID", "marketID", marketID, "upcomingID", upcomingID, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil) + h.mongoLoggerSvc.Error("Failed to get raw odds by market ID", + zap.String("marketID", marketID), + zap.String("upcomingID", upcomingID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Raw odds retrieved successfully", rawOdds, nil) @@ -73,30 +95,52 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error { // @Success 200 {array} domain.Odd // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /odds/upcoming/{upcoming_id} [get] +// @Router /api/v1/odds/upcoming/{upcoming_id} [get] func (h *Handler) GetOddsByUpcomingID(c *fiber.Ctx) error { upcomingID := c.Params("upcoming_id") if upcomingID == "" { - return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil) + h.mongoLoggerSvc.Info("Missing upcoming_id", + zap.String("upcoming", upcomingID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Missing upcoming_id") } limit, err := strconv.Atoi(c.Query("limit", "10")) // Default limit is 10 if err != nil || limit <= 0 { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid limit value", nil, nil) + h.mongoLoggerSvc.Info("Invalid limit value", + zap.Int("limit", limit), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value") } offset, err := strconv.Atoi(c.Query("offset", "0")) // Default offset is 0 if err != nil || offset < 0 { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid offset value", nil, nil) + h.mongoLoggerSvc.Info("Invalid offset value", + zap.Int("offset", offset), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } odds, err := h.prematchSvc.GetPrematchOddsByUpcomingID(c.Context(), upcomingID) if err != nil { - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve prematch odds", nil, nil) + h.mongoLoggerSvc.Error("Failed to retrieve prematch odds", + zap.String("upcoming", upcomingID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve prematch odds"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil) } - diff --git a/internal/web_server/handlers/referal_handlers.go b/internal/web_server/handlers/referal_handlers.go index a2fe09e..ef8cb06 100644 --- a/internal/web_server/handlers/referal_handlers.go +++ b/internal/web_server/handlers/referal_handlers.go @@ -1,20 +1,33 @@ package handlers import ( + "fmt" + "time" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) func (h *Handler) CreateReferralCode(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Info("Invalid user ID in context", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Int64("userID", userID), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification") } if err := h.referralSvc.CreateReferral(c.Context(), userID); err != nil { - h.logger.Error("Failed to create referral", "userID", userID, "error", err) + h.mongoLoggerSvc.Error("Failed to create referral", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral") } @@ -24,29 +37,54 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error { func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error { var req domain.ReferralSettingsReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse settings", "error", err) + h.mongoLoggerSvc.Info("Failed to parse settings", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate settings", + zap.String("errMsg", errMsg), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } settings, err := h.referralSvc.GetReferralSettings(c.Context()) if err != nil { - h.logger.Error("Failed to fetch previous referral setting", "error", err) + h.mongoLoggerSvc.Error("Failed to fetch previous referral setting", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral") } // only allow one referral setting for now // for future it can be multiple and be able to choose from them if settings != nil { - h.logger.Error("referral setting already exists", "error", err) + h.mongoLoggerSvc.Error("referral setting already exists", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "referral setting already exists") } if err := h.referralSvc.CreateReferralSettings(c.Context(), req); err != nil { - h.logger.Error("Failed to create referral setting", "error", err) + h.mongoLoggerSvc.Error("Failed to create referral setting", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral") } @@ -63,23 +101,37 @@ func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error { // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security Bearer -// @Router /referral/stats [get] +// @Router /api/v1/referral/stats [get] func (h *Handler) GetReferralStats(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Error("Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user id") } user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get user", "userID", userID, "error", err) + h.mongoLoggerSvc.Error("Failed to get user", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user") } stats, err := h.referralSvc.GetReferralStats(c.Context(), user.PhoneNumber) if err != nil { - h.logger.Error("Failed to get referral stats", "userID", userID, "error", err) + h.mongoLoggerSvc.Error("Failed to get referral stats", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve referral stats") } @@ -98,34 +150,60 @@ func (h *Handler) GetReferralStats(c *fiber.Ctx) error { // @Failure 403 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security Bearer -// @Router /referral/settings [put] +// @Router /api/v1/referral/settings [put] func (h *Handler) UpdateReferralSettings(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Error("Failed to delete user", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user id") } user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get user", "userID", userID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user") + h.mongoLoggerSvc.Error("Failed to get user", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } if user.Role != domain.RoleAdmin { + h.mongoLoggerSvc.Error("Access Forbidden", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusForbidden), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusForbidden, "Admin access required") } var settings domain.ReferralSettings if err := c.BodyParser(&settings); err != nil { - h.logger.Error("Failed to parse settings", "error", err) + h.mongoLoggerSvc.Info("Failed to parse settings", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } settings.UpdatedBy = user.PhoneNumber if err := h.referralSvc.UpdateReferralSettings(c.Context(), &settings); err != nil { - h.logger.Error("Failed to update referral settings", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to update referral settings") + h.mongoLoggerSvc.Error("Failed to update referral settings", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Referral settings updated successfully", nil, nil) @@ -142,7 +220,7 @@ func (h *Handler) UpdateReferralSettings(c *fiber.Ctx) error { // @Failure 403 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security Bearer -// @Router /referral/settings [get] +// @Router /api/v1/referral/settings [get] func (h *Handler) GetReferralSettings(c *fiber.Ctx) error { // userID, ok := c.Locals("user_id").(int64) // if !ok || userID == 0 { @@ -153,18 +231,34 @@ func (h *Handler) GetReferralSettings(c *fiber.Ctx) error { user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get user", "userID", userID, "error", err) + h.mongoLoggerSvc.Error("Failed to get user", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user") } if user.Role != domain.RoleAdmin { + h.mongoLoggerSvc.Error("Admin access required", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusForbidden), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusForbidden, "Admin access required") } settings, err := h.referralSvc.GetReferralSettings(c.Context()) if err != nil { - h.logger.Error("Failed to get referral settings", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve referral settings") + h.mongoLoggerSvc.Error("Failed to get referral settings", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Referral settings retrieved successfully", settings, nil) diff --git a/internal/web_server/handlers/result_handler.go b/internal/web_server/handlers/result_handler.go index 23bd466..e045b36 100644 --- a/internal/web_server/handlers/result_handler.go +++ b/internal/web_server/handlers/result_handler.go @@ -2,10 +2,12 @@ package handlers import ( "encoding/json" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) type ResultRes struct { @@ -24,17 +26,26 @@ type ResultRes struct { // @Success 200 {array} ResultRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /result/{id} [get] +// @Router /api/v1/result/{id} [get] func (h *Handler) GetResultsByEventID(c *fiber.Ctx) error { eventID := c.Params("id") if eventID == "" { - h.logger.Error("Event ID is required") + h.mongoLoggerSvc.Info("Event ID is required", + zap.String("eventID", eventID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Event ID is required") } results, outcomes, err := h.resultSvc.GetResultsForEvent(c.Context(), eventID) if err != nil { - h.logger.Error("Failed to get results by Event ID", "eventID", eventID, "error", err) + h.mongoLoggerSvc.Error("Failed to get results by Event ID", + zap.String("eventID", eventID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve results") } diff --git a/internal/web_server/handlers/shop_handler.go b/internal/web_server/handlers/shop_handler.go index af2b2d5..a81de8f 100644 --- a/internal/web_server/handlers/shop_handler.go +++ b/internal/web_server/handlers/shop_handler.go @@ -2,13 +2,13 @@ package handlers import ( "fmt" - "log/slog" "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) // CreateShopBet godoc @@ -18,10 +18,10 @@ import ( // @Accept json // @Produce json // @Param createBet body domain.ShopBetReq true "create bet" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/bet [post] +// @Router /api/v1/shop/bet [post] func (h *Handler) CreateShopBet(c *fiber.Ctx) error { userID := c.Locals("user_id").(int64) @@ -30,20 +30,42 @@ func (h *Handler) CreateShopBet(c *fiber.Ctx) error { var req domain.ShopBetReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateBetReq failed to parse request", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("CreateBetReq failed to parse request", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid request body"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - h.logger.Error("CreateBetReq failed v", "error", valErrs) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } shopBet, err := h.transactionSvc.CreateShopBet(c.Context(), userID, role, company_id, req) if err != nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil) + var statusCode int + if isBetError := h.betSvc.CheckIfBetError(err); isBetError { + statusCode = fiber.StatusBadRequest + } else { + statusCode = fiber.StatusInternalServerError + } + + h.mongoLoggerSvc.Info("Failed to create shop bet", + zap.Int64("userID", userID), + zap.String("role", string(role)), + zap.Int("status_code", statusCode), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(statusCode, "failed to create shop bet"+err.Error()) } res := domain.ConvertShopBet(shopBet) @@ -57,10 +79,10 @@ func (h *Handler) CreateShopBet(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param createBet body domain.CashoutReq true "cashout bet" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/bet/{id} [get] +// @Router /api/v1/shop/bet/{id} [get] func (h *Handler) GetShopBetByBetID(c *fiber.Ctx) error { betIDstr := c.Params("id") @@ -68,15 +90,25 @@ func (h *Handler) GetShopBetByBetID(c *fiber.Ctx) error { betID, err := strconv.ParseInt(betIDstr, 10, 64) if err != nil { - h.logger.Error("CashoutReq failed bet id is invalid", "error", nil) - return response.WriteJSON(c, fiber.StatusBadRequest, "bet ID is invalid", nil, nil) + h.mongoLoggerSvc.Info("GetShopBetByBetID failed bet id is invalid", + zap.String("betID", betIDstr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "bet ID is invalid:"+err.Error()) } bet, err := h.transactionSvc.GetShopBetByBetID(c.Context(), betID) if err != nil { - h.logger.Error("CashoutReq failed invalid bet id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid bet ID", err, nil) + h.mongoLoggerSvc.Error("GetShopBetByBetID failed invalid bet id", + zap.Int64("betID", betID), + zap.Int("status_code", fiber.StatusNotFound), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusNotFound, err.Error()) } res := domain.ConvertShopBetDetail(bet) @@ -91,10 +123,10 @@ func (h *Handler) GetShopBetByBetID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param cashoutBet body domain.CashoutReq true "cashout bet" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/bet/{id}/cashout [post] +// @Router /api/v1/shop/bet/{id}/cashout [post] func (h *Handler) CashoutBet(c *fiber.Ctx) error { betIDStr := c.Params("id") @@ -102,8 +134,13 @@ func (h *Handler) CashoutBet(c *fiber.Ctx) error { betID, err := strconv.ParseInt(betIDStr, 10, 64) if err != nil { - h.logger.Error("CashoutReq invalid bet id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid bet id", err, nil) + h.mongoLoggerSvc.Info("CashoutReq invalid bet id", + zap.String("betID", betIDStr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid bet id") } userID := c.Locals("user_id").(int64) @@ -112,20 +149,41 @@ func (h *Handler) CashoutBet(c *fiber.Ctx) error { var req domain.CashoutReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CashoutReq failed to parse request", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("CashoutReq failed to parse request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - h.logger.Error("CashoutReq failed v", "error", valErrs) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("CashoutReq validation failed", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } transaction, err := h.transactionSvc.CashoutBet(c.Context(), betID, userID, role, req, companyID) if err != nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil) + h.mongoLoggerSvc.Error("Failed to cashout bet", + zap.Int64("userID", userID), + zap.Int64("betID", betID), + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := domain.ConvertShopTransaction(transaction) @@ -139,10 +197,10 @@ func (h *Handler) CashoutBet(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param cashoutBet body domain.CashoutReq true "cashout bet" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/cashout [post] +// @Router /api/v1/shop/cashout [post] func (h *Handler) CashoutByCashoutID(c *fiber.Ctx) error { userID := c.Locals("user_id").(int64) @@ -151,27 +209,52 @@ func (h *Handler) CashoutByCashoutID(c *fiber.Ctx) error { var req domain.CashoutReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CashoutReq failed to parse request", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("CashoutReq failed to parse request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - h.logger.Error("CashoutReq failed v", "error", valErrs) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("CashoutReq validation failed", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("error", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } bet, err := h.transactionSvc.GetShopBetByCashoutID(c.Context(), req.CashoutID) if err != nil { - h.logger.Error("CashoutReq failed invalid cashout id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashout ID", err, nil) + h.mongoLoggerSvc.Info("CashoutReq failed invalid cashout id", + zap.String("CashoutID", req.CashoutID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } transaction, err := h.transactionSvc.CashoutBet(c.Context(), bet.BetID, userID, role, req, companyID) if err != nil { - return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil) + h.mongoLoggerSvc.Info("Failed to cashout bet", + zap.Int64("BetID", bet.BetID), + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } res := domain.ConvertShopTransaction(transaction) @@ -185,24 +268,33 @@ func (h *Handler) CashoutByCashoutID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param createBet body domain.CashoutReq true "cashout bet" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/cashout/{id} [get] +// @Router /api/v1/shop/cashout/{id} [get] func (h *Handler) GetShopBetByCashoutID(c *fiber.Ctx) error { cashoutID := c.Params("id") if cashoutID == "" { - h.logger.Error("CashoutReq failed cashout id is required", "error", nil) - return response.WriteJSON(c, fiber.StatusBadRequest, "cashout ID is required", nil, nil) + h.mongoLoggerSvc.Info("CashoutReq failed cashout id is required", + zap.String("cashoutID", cashoutID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "cashout ID is required") } bet, err := h.transactionSvc.GetShopBetByCashoutID(c.Context(), cashoutID) if err != nil { - h.logger.Error("CashoutReq failed invalid cashout id", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashout ID", err, nil) + h.mongoLoggerSvc.Info("CashoutReq failed invalid cashout id", + zap.String("CashoutID", cashoutID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } res := domain.ConvertShopBetDetail(bet) @@ -217,10 +309,10 @@ func (h *Handler) GetShopBetByCashoutID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param transferToWallet body domain.ShopDepositReq true "ShopDepositReq" -// @Success 200 {object} TransferWalletRes +// @Success 200 {object} domain.ShopDepositRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/deposit [post] +// @Router /api/v1/shop/deposit [post] func (h *Handler) DepositForCustomer(c *fiber.Ctx) error { // Get sender ID from the cashier @@ -230,7 +322,12 @@ func (h *Handler) DepositForCustomer(c *fiber.Ctx) error { var req domain.ShopDepositReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateTransferReq failed", "error", err) + h.mongoLoggerSvc.Info("CreateTransferReq failed", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } @@ -240,14 +337,26 @@ func (h *Handler) DepositForCustomer(c *fiber.Ctx) error { for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } + h.mongoLoggerSvc.Info("Failed to validate customer deposit", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("error", errMsg), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } deposit, err := h.transactionSvc.CreateShopDeposit(c.Context(), userID, role, req) if err != nil { - fmt.Printf("Shop Deposit Error %v \n", err) - return fiber.NewError(fiber.StatusBadRequest, err.Error()) + h.mongoLoggerSvc.Info("failed to create shop deposit", + zap.Int64("userID", userID), + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := domain.ConvertShopDeposit(deposit) @@ -262,10 +371,10 @@ func (h *Handler) DepositForCustomer(c *fiber.Ctx) error { // @Tags transaction // @Accept json // @Produce json -// @Success 200 {array} TransactionRes +// @Success 200 {array} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/transaction [get] +// @Router /api/v1/shop/transaction [get] func (h *Handler) GetAllTransactions(c *fiber.Ctx) error { // Get user_id from middleware // userID := c.Locals("user_id").(int64) @@ -284,8 +393,13 @@ func (h *Handler) GetAllTransactions(c *fiber.Ctx) error { if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid start_time format", + zap.String("createdBefore", createdBeforeQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, @@ -298,8 +412,13 @@ func (h *Handler) GetAllTransactions(c *fiber.Ctx) error { if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { - h.logger.Error("invalid start_time format", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) + h.mongoLoggerSvc.Info("invalid start_time format", + zap.String("createdAfter", createdAfterQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, @@ -317,8 +436,12 @@ func (h *Handler) GetAllTransactions(c *fiber.Ctx) error { }) if err != nil { - h.logger.Error("Failed to get transactions", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transactions", err, nil) + h.mongoLoggerSvc.Info("Failed to get transactions", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := make([]domain.ShopTransactionRes, len(transactions)) @@ -337,21 +460,31 @@ func (h *Handler) GetAllTransactions(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Transaction ID" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/transaction/{id} [get] +// @Router /api/v1/shop/transaction/{id} [get] func (h *Handler) GetTransactionByID(c *fiber.Ctx) error { transactionID := c.Params("id") id, err := strconv.ParseInt(transactionID, 10, 64) if err != nil { - h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err) + h.mongoLoggerSvc.Info("Invalid transaction ID", + zap.String("transactionID", transactionID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID") } transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get transaction by ID", "transactionID", id, "error", err) + h.mongoLoggerSvc.Error("Failed to get shop transaction by ID", + zap.Int64("transactionID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transaction") } @@ -366,31 +499,37 @@ func (h *Handler) GetTransactionByID(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Transaction ID" -// @Success 200 {object} TransactionRes +// @Success 200 {object} domain.ShopTransactionRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/transaction/{id}/bet [get] +// @Router /api/v1/shop/transaction/{id}/bet [get] func (h *Handler) GetShopBetByTransactionID(c *fiber.Ctx) error { transactionID := c.Params("id") id, err := strconv.ParseInt(transactionID, 10, 64) if err != nil { - h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID") + h.mongoLoggerSvc.Info("Invalid transaction ID", + zap.String("transactionID", transactionID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) } transaction, err := h.transactionSvc.GetShopBetByShopTransactionID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get transaction by ID", "transactionID", id, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transaction") + h.mongoLoggerSvc.Error("Failed to get transaction by ID", + zap.Int64("transactionID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := domain.ConvertShopBetDetail(transaction) return response.WriteJSON(c, fiber.StatusOK, "Shop bet retrieved successfully", res, nil) } -type UpdateTransactionVerifiedReq struct { - Verified bool `json:"verified" example:"true"` -} - // UpdateTransactionVerified godoc // @Summary Updates the verified field of a transaction // @Description Updates the verified status of a transaction @@ -398,11 +537,11 @@ type UpdateTransactionVerifiedReq struct { // @Accept json // @Produce json // @Param id path int true "Transaction ID" -// @Param updateVerified body UpdateTransactionVerifiedReq true "Updates Transaction Verification" +// @Param updateVerified body domain.UpdateTransactionVerifiedReq true "Updates Transaction Verification" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /shop/transaction/{id} [put] +// @Router /api/v1/shop/transaction/{id} [put] func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error { transactionID := c.Params("id") userID := c.Locals("user_id").(int64) @@ -412,25 +551,48 @@ func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error { id, err := strconv.ParseInt(transactionID, 10, 64) if err != nil { - h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err) + h.mongoLoggerSvc.Info("Invalid transaction ID", + zap.String("transactionID", transactionID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID") } - var req UpdateTransactionVerifiedReq + var req domain.UpdateTransactionVerifiedReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("Failed to parse UpdateTransactionVerified request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } - h.logger.Info("Update Transaction Verified", slog.Bool("verified", req.Verified)) - if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate UpdateTransactionVerified", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + zap.String("errMsg", errMsg), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, role, companyID, branchID) if err != nil { - h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err) + h.mongoLoggerSvc.Error("Failed to update transaction verification", + zap.Int64("transactionID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification") } diff --git a/internal/web_server/handlers/ticket_handler.go b/internal/web_server/handlers/ticket_handler.go index 17e6276..306ded4 100644 --- a/internal/web_server/handlers/ticket_handler.go +++ b/internal/web_server/handlers/ticket_handler.go @@ -1,12 +1,15 @@ package handlers import ( + "fmt" "strconv" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) // CreateTicket godoc @@ -19,29 +22,51 @@ import ( // @Success 200 {object} domain.CreateTicketRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /ticket [post] +// @Router /api/v1/ticket [post] func (h *Handler) CreateTicket(c *fiber.Ctx) error { var req domain.CreateTicketReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse CreateTicket request", "error", err) + h.mongoLoggerSvc.Info("Failed to parse CreateTicket request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate CreateTicketReq", + zap.Any("CreateTicketReq", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.String("error", errMsg), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } newTicket, rows, err := h.ticketSvc.CreateTicket(c.Context(), req, c.IP()) if err != nil { - switch err { - case ticket.ErrEventHasBeenRemoved, ticket.ErrTicketHasExpired, - ticket.ErrRawOddInvalid, ticket.ErrTooManyOutcomesForTicket, - ticket.ErrTicketAmountTooHigh, ticket.ErrTicketLimitForSingleUser, - ticket.ErrTicketWinningTooHigh: - return fiber.NewError(fiber.StatusBadRequest, err.Error()) + + var statusCode int + + if isTicketError := h.ticketSvc.CheckTicketError(err); isTicketError { + statusCode = fiber.StatusBadRequest + } else { + statusCode = fiber.StatusInternalServerError } - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + + h.mongoLoggerSvc.Error("Failed to create ticket", + zap.Any("req", req), + zap.Int("status_code", statusCode), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(statusCode, err.Error()) } res := domain.CreateTicketRes{ FastCode: newTicket.ID, @@ -61,18 +86,28 @@ func (h *Handler) CreateTicket(c *fiber.Ctx) error { // @Success 200 {object} domain.TicketRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /ticket/{id} [get] +// @Router /api/v1/ticket/{id} [get] func (h *Handler) GetTicketByID(c *fiber.Ctx) error { ticketID := c.Params("id") id, err := strconv.ParseInt(ticketID, 10, 64) if err != nil { - h.logger.Error("Invalid ticket ID", "ticketID", ticketID, "error", err) + h.mongoLoggerSvc.Info("Invalid ticket ID", + zap.String("ticketID", ticketID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid ticket ID") } ticket, err := h.ticketSvc.GetTicketByID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get ticket by ID", "ticketID", id, "error", err) + h.mongoLoggerSvc.Info("Failed to get ticket by ID", + zap.Int64("ticketID", id), + zap.Int("status_code", fiber.StatusNotFound), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusNotFound, "Failed to retrieve ticket") } @@ -94,12 +129,16 @@ func (h *Handler) GetTicketByID(c *fiber.Ctx) error { // @Success 200 {array} domain.TicketRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /ticket [get] +// @Router /api/v1/ticket [get] func (h *Handler) GetAllTickets(c *fiber.Ctx) error { tickets, err := h.ticketSvc.GetAllTickets(c.Context()) if err != nil { - h.logger.Error("Failed to get tickets", "error", err) + h.mongoLoggerSvc.Error("Failed to get tickets", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve tickets") } diff --git a/internal/web_server/handlers/transfer_handler.go b/internal/web_server/handlers/transfer_handler.go index 02ccd07..efe9f5a 100644 --- a/internal/web_server/handlers/transfer_handler.go +++ b/internal/web_server/handlers/transfer_handler.go @@ -127,7 +127,7 @@ type CreateRefillReq struct { // @Success 200 {object} TransferWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /transfer/wallet/{id} [get] +// @Router /api/v1/transfer/wallet/{id} [get] func (h *Handler) GetTransfersByWallet(c *fiber.Ctx) error { walletID := c.Params("id") @@ -135,14 +135,24 @@ func (h *Handler) GetTransfersByWallet(c *fiber.Ctx) error { id, err := strconv.ParseInt(walletID, 10, 64) if err != nil { - h.logger.Error("Invalid wallet ID", "walletID", walletID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil) + h.mongoLoggerSvc.Error("Invalid wallet ID", + zap.String("walletID", walletID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } transfers, err := h.walletSvc.GetTransfersByWallet(c.Context(), int64(id)) if err != nil { - h.logger.Error("Failed to get transfers by wallet", "walletID", walletID, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transfers", err, nil) + h.mongoLoggerSvc.Error("Failed to get transfers by wallet", + zap.String("walletID", walletID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } var transferResponses []TransferWalletRes @@ -164,7 +174,7 @@ func (h *Handler) GetTransfersByWallet(c *fiber.Ctx) error { // @Success 200 {object} TransferWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /transfer/wallet/:id [post] +// @Router /api/v1/transfer/wallet/:id [post] func (h *Handler) TransferToWallet(c *fiber.Ctx) error { receiverIDString := c.Params("id") @@ -172,59 +182,100 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { receiverID, err := strconv.ParseInt(receiverIDString, 10, 64) if err != nil { - h.logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil) + h.mongoLoggerSvc.Info("Invalid wallet ID", + zap.Int64("walletID", receiverID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } // Get sender ID from the cashier userID := c.Locals("user_id").(int64) role := c.Locals("role").(domain.Role) companyID := c.Locals("company_id").(domain.ValidInt64) - fmt.Printf("\n\nCompany ID: %v\n\n", companyID.Value) + // fmt.Printf("\n\nCompany ID: %v\n\n", companyID.Value) var senderID int64 //TODO: check to make sure that the cashiers aren't transferring TO branch wallet switch role { case domain.RoleCustomer: - h.logger.Error("Unauthorized access", "userID", userID, "role", role) - return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) + h.mongoLoggerSvc.Error("Unauthorized access", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusForbidden), + zap.String("role", string(role)), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "Unauthorized access") case domain.RoleAdmin: company, err := h.companySvc.GetCompanyByID(c.Context(), companyID.Value) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ - Message: "Failed to fetch company", - Error: err.Error(), - }) - // return response.WriteJSON(c, fiber.StatusInternalServerError, "Error fetching company", err, nil) + h.mongoLoggerSvc.Error("Failed to fetch company", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } senderID = company.WalletID - h.logger.Error("Will", "userID", userID, "role", role) + // h.logger.Error("Will", "userID", userID, "role", role) case domain.RoleSuperAdmin: - return response.WriteJSON(c, fiber.StatusBadRequest, "Super Admin does not have a wallet", err, nil) + return fiber.NewError(fiber.StatusBadRequest, "Super Admin does not have a wallet") case domain.RoleBranchManager: - return response.WriteJSON(c, fiber.StatusBadRequest, "Branch Manager does not have a wallet", err, nil) + return fiber.NewError(fiber.StatusBadRequest, "Branch Manager does not have a wallet") case domain.RoleCashier: cashierBranch, err := h.branchSvc.GetBranchByCashier(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get branch", "user ID", userID, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier branch", err, nil) + h.mongoLoggerSvc.Error("Failed to get branch by cashier", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } senderID = cashierBranch.WalletID default: - return response.WriteJSON(c, fiber.StatusInternalServerError, "Unknown Role", err, nil) + h.mongoLoggerSvc.Error("Unknown Role", + zap.Int64("userID", userID), + zap.String("role", string(role)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Unknown Role") } var req CreateTransferReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateTransferReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Error("CreateTransferReq failed to parse body", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + + h.mongoLoggerSvc.Error("Failed to validate CreateTransferReq", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + + return fiber.NewError(fiber.StatusBadRequest, errMsg) } transfer, err := h.walletSvc.TransferToWallet(c.Context(), @@ -234,8 +285,13 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { ) if err != nil { - h.mongoLoggerSvc.Error("Failed to transfer money to wallet", zap.Error(err)) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Transfer Failed", err, nil) + h.mongoLoggerSvc.Error("Failed to transfer money to wallet", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := convertTransfer(transfer) @@ -243,7 +299,6 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil) } - // RefillWallet godoc // @Summary Refill wallet // @Description Super Admin route to refill a wallet @@ -254,7 +309,7 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { // @Success 200 {object} TransferWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /transfer/refill/:id [post] +// @Router /api/v1/transfer/refill/:id [post] func (h *Handler) RefillWallet(c *fiber.Ctx) error { receiverIDString := c.Params("id") @@ -263,21 +318,42 @@ func (h *Handler) RefillWallet(c *fiber.Ctx) error { receiverID, err := strconv.ParseInt(receiverIDString, 10, 64) if err != nil { - h.logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil) + h.mongoLoggerSvc.Error("Invalid wallet ID", + zap.Int64("walletID", receiverID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } // Get sender ID from the cashier var req CreateRefillReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("CreateRefillReq failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + h.mongoLoggerSvc.Info("CreateRefillReq failed to parse CreateRefillReq", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate CreateRefillReq", + zap.Int64("userID", userID), + zap.String("errMsg", errMsg), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + } transfer, err := h.walletSvc.AddToWallet( @@ -287,7 +363,15 @@ func (h *Handler) RefillWallet(c *fiber.Ctx) error { }, domain.TRANSFER_BANK, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet directly by super-admin", req.Amount)) if !ok { - return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil) + h.mongoLoggerSvc.Error("Creating Transfer Failed", + zap.Int64("userID", userID), + zap.Float32("Amount", req.Amount), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } res := convertTransfer(transfer) diff --git a/internal/web_server/handlers/user.go b/internal/web_server/handlers/user.go index 22ca0b1..5344919 100644 --- a/internal/web_server/handlers/user.go +++ b/internal/web_server/handlers/user.go @@ -11,6 +11,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) type CheckPhoneEmailExistReq struct { @@ -32,23 +33,36 @@ type CheckPhoneEmailExistRes struct { // @Success 200 {object} CheckPhoneEmailExistRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/checkPhoneEmailExist [post] +// @Router /api/v1/user/checkPhoneEmailExist [post] func (h *Handler) CheckPhoneEmailExist(c *fiber.Ctx) error { var req CheckPhoneEmailExistReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse CheckPhoneEmailExist request", "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Failed to parse CheckPhoneEmailExist request", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } emailExist, phoneExist, err := h.userSvc.CheckPhoneEmailExist(c.Context(), req.PhoneNumber, req.Email) if err != nil { - h.logger.Error("Failed to check phone/email existence", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to check phone/email existence") + h.mongoLoggerSvc.Error("Failed to check phone/email existence", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to check phone/email existence:"+err.Error()) } res := CheckPhoneEmailExistRes{ @@ -73,17 +87,25 @@ type RegisterCodeReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/sendRegisterCode [post] +// @Router /api/v1/user/sendRegisterCode [post] func (h *Handler) SendRegisterCode(c *fiber.Ctx) error { var req RegisterCodeReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse SendRegisterCode request", "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Failed to parse SendRegisterCode request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } var sentTo string @@ -99,8 +121,14 @@ func (h *Handler) SendRegisterCode(c *fiber.Ctx) error { } if err := h.userSvc.SendRegisterCode(c.Context(), medium, sentTo, "twilio"); err != nil { - h.logger.Error("Failed to send register code", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to send register code") + h.mongoLoggerSvc.Error("Failed to send register code", + zap.String("Medium", string(medium)), + zap.String("Send To", string(sentTo)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to send register code:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil) @@ -126,17 +154,25 @@ type RegisterUserReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/register [post] +// @Router /api/v1/user/register [post] func (h *Handler) RegisterUser(c *fiber.Ctx) error { var req RegisterUserReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse RegisterUser request", "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Failed to parse RegisterUser request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } user := domain.RegisterUserReq{ FirstName: req.FirstName, @@ -150,7 +186,13 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error { } medium, err := getMedium(req.Email, req.PhoneNumber) if err != nil { - h.logger.Error("RegisterUser failed", "error", err) + h.mongoLoggerSvc.Info("Failed to get medium", + zap.String("email", req.Email), + zap.String("phone number", req.PhoneNumber), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } @@ -170,20 +212,36 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error { if errors.Is(err, domain.ErrOtpNotFound) { return fiber.NewError(fiber.StatusBadRequest, "User already exist") } - h.logger.Error("RegisterUser failed", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Unknown Error") + h.mongoLoggerSvc.Error("Failed to register user", + zap.String("email", req.Email), + zap.String("phone number", req.PhoneNumber), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "failed to register user:"+err.Error()) } newWallet, err := h.walletSvc.CreateCustomerWallet(c.Context(), newUser.ID) if err != nil { - h.logger.Error("Failed to create wallet for user", "userID", newUser.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to create user wallet") + h.mongoLoggerSvc.Error("Failed to create wallet for user", + zap.Int64("userID", newUser.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to create user wallet:"+err.Error()) } if req.ReferalCode != "" { err = h.referralSvc.ProcessReferral(c.Context(), req.PhoneNumber, req.ReferalCode) if err != nil { - h.logger.Warn("Failed to process referral during registration", "phone", req.PhoneNumber, "code", req.ReferalCode, "error", err) + h.mongoLoggerSvc.Error("Failed to process referral during registration", + zap.String("phone", req.PhoneNumber), + zap.String("code", req.ReferalCode), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) } } @@ -193,8 +251,13 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error { "Added 100.0 to wallet only as test for deployment") if err != nil { - h.logger.Error("Failed to update wallet for user", "userID", newUser.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to update user wallet") + h.mongoLoggerSvc.Error("Failed to update wallet for user", + zap.Int64("userID", newUser.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update user wallet:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Registration successful", nil, nil) @@ -216,17 +279,25 @@ type ResetCodeReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/sendResetCode [post] +// @Router /api/v1/user/sendResetCode [post] func (h *Handler) SendResetCode(c *fiber.Ctx) error { var req ResetCodeReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse SendResetCode request", "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Failed to parse SendResetCode request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } var sentTo string @@ -238,13 +309,24 @@ func (h *Handler) SendResetCode(c *fiber.Ctx) error { sentTo = req.PhoneNumber medium = domain.OtpMediumSms } else { + h.mongoLoggerSvc.Info("Email or PhoneNumber must be provided", + zap.String("Email", req.Email), + zap.String("Phone Number", req.PhoneNumber), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Email or PhoneNumber must be provided") } if err := h.userSvc.SendResetCode(c.Context(), medium, sentTo, "twilio"); err != nil { - h.logger.Error("Failed to send reset code", "error", err) - fmt.Println(err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to send reset code") + h.mongoLoggerSvc.Error("Failed to send reset code", + zap.String("medium", string(medium)), + zap.String("sentTo", string(sentTo)), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to send reset code:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil) @@ -267,22 +349,36 @@ type ResetPasswordReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/resetPassword [post] +// @Router /api/v1/user/resetPassword [post] func (h *Handler) ResetPassword(c *fiber.Ctx) error { var req ResetPasswordReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse ResetPassword request", "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Failed to parse ResetPassword request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } medium, err := getMedium(req.Email, req.PhoneNumber) if err != nil { - h.logger.Error("Failed to determine medium for ResetPassword", "error", err) + h.mongoLoggerSvc.Info("Failed to determine medium for ResetPassword", + zap.String("Email", req.Email), + zap.String("Phone Number", req.PhoneNumber), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, err.Error()) } @@ -295,8 +391,13 @@ func (h *Handler) ResetPassword(c *fiber.Ctx) error { } if err := h.userSvc.ResetPassword(c.Context(), resetReq); err != nil { - h.logger.Error("Failed to reset password", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to reset password") + h.mongoLoggerSvc.Error("Failed to reset password", + zap.Any("userID", resetReq), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to reset password:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Password reset successful", nil, nil) @@ -328,26 +429,40 @@ type UserProfileRes struct { // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security Bearer -// @Router /user/profile [get] +// @Router /api/v1/user/profile [get] func (h *Handler) UserProfile(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Error("Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification") } user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get user profile", "userID", userID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile") + h.mongoLoggerSvc.Error("Failed to get user profile", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile:"+err.Error()) } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { - h.logger.Error("Failed to get user last login", "userID", userID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } lastLogin = &user.CreatedAt @@ -396,37 +511,51 @@ type SearchUserByNameOrPhoneReq struct { // @Success 200 {object} UserProfileRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/search [post] +// @Router /api/v1/user/search [post] func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error { // TODO: Add filtering by role based on which user is calling this var req SearchUserByNameOrPhoneReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("SearchUserByNameOrPhone failed", "error", err) - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ - "error": "Invalid request", - }) + h.mongoLoggerSvc.Error("Failed to Search UserBy Name Or Phone failed", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } valErrs, ok := h.validator.Validate(c, req) if !ok { - response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) - return nil + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + return fiber.NewError(fiber.StatusBadRequest, errMsg) } companyID := c.Locals("company_id").(domain.ValidInt64) users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, req.Role, companyID) if err != nil { - h.logger.Error("SearchUserByNameOrPhone failed", "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Internal server error", - }) + h.mongoLoggerSvc.Error("Failed to get user by name or phone", + zap.Any("request", req), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "failed to get users"+err.Error()) } var res []UserProfileRes = make([]UserProfileRes, 0, len(users)) for _, user := range users { lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { - h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Any("userID", user.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error()) } lastLogin = &user.CreatedAt @@ -462,7 +591,7 @@ func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/single/{id} [get] +// @Router /api/v1/user/single/{id} [get] func (h *Handler) GetUserByID(c *fiber.Ctx) error { // branchId := int64(12) //c.Locals("branch_id").(int64) // filter := user.Filter{ @@ -482,21 +611,36 @@ func (h *Handler) GetUserByID(c *fiber.Ctx) error { userIDstr := c.Params("id") userID, err := strconv.ParseInt(userIDstr, 10, 64) if err != nil { - h.logger.Error("failed to fetch user using UserID", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil) + h.mongoLoggerSvc.Info("failed to parse user id", + zap.String("userID", userIDstr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid user id") } user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { - h.logger.Error("Get User By ID failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil) + h.mongoLoggerSvc.Error("Get User By ID failed", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to get cashiers:"+err.Error()) } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { - h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") + h.mongoLoggerSvc.Error("Failed to get user last login", + zap.Int64("userID", user.ID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } lastLogin = &user.CreatedAt @@ -532,19 +676,29 @@ func (h *Handler) GetUserByID(c *fiber.Ctx) error { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/delete/{id} [delete] +// @Router /api/v1/user/delete/{id} [delete] func (h *Handler) DeleteUser(c *fiber.Ctx) error { userIDstr := c.Params("id") userID, err := strconv.ParseInt(userIDstr, 10, 64) if err != nil { - h.logger.Error("DeleteUser failed", "error", err) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid user ID", nil, nil) + h.mongoLoggerSvc.Info("Failed to parse user id", + zap.String("userID", userIDstr), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") } err = h.userSvc.DeleteUser(c.Context(), userID) if err != nil { - h.logger.Error("Failed to delete user", "userID", userID, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to delete user", nil, nil) + h.mongoLoggerSvc.Error("Failed to delete user", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete user:"+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "User deleted successfully", nil, nil) @@ -569,14 +723,17 @@ type UpdateUserSuspendRes struct { // @Success 200 {object} UpdateUserSuspendRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/suspend [post] +// @Router /api/v1/user/suspend [post] func (h *Handler) UpdateUserSuspend(c *fiber.Ctx) error { var req UpdateUserSuspendReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse UpdateUserSuspend request", "error", err) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + h.mongoLoggerSvc.Info("Failed to parse UpdateUserSuspend request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) } - fmt.Printf("user suspended %v \n", req) if valErrs, ok := h.validator.Validate(c, req); !ok { var errMsg string for field, msg := range valErrs { @@ -587,8 +744,13 @@ func (h *Handler) UpdateUserSuspend(c *fiber.Ctx) error { err := h.userSvc.UpdateUserSuspend(c.Context(), req.UserID, req.Suspended) if err != nil { - h.logger.Error("Failed to update user suspend status", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to update user suspend status") + h.mongoLoggerSvc.Error("Failed to update user suspend status", + zap.Any("UpdateUserSuspendReq", req), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update user suspend status:"+err.Error()) } res := UpdateUserSuspendRes{ @@ -607,18 +769,27 @@ func (h *Handler) UpdateUserSuspend(c *fiber.Ctx) error { // @Success 200 {array} domain.BetRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/bets [get] +// @Router /api/v1/user/bets [get] func (h *Handler) GetBetByUserID(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") + h.mongoLoggerSvc.Error("Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification") } bets, err := h.betSvc.GetBetByUserID(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get bets", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets") + h.mongoLoggerSvc.Error("Failed to get bets", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets:"+err.Error()) } res := make([]domain.BetRes, len(bets)) diff --git a/internal/web_server/handlers/wallet_handler.go b/internal/web_server/handlers/wallet_handler.go index 853a4af..6abd899 100644 --- a/internal/web_server/handlers/wallet_handler.go +++ b/internal/web_server/handlers/wallet_handler.go @@ -1,12 +1,14 @@ package handlers import ( + "fmt" "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) type WalletRes struct { @@ -94,18 +96,28 @@ type BranchWalletRes struct { // @Success 200 {object} WalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /wallet/{id} [get] +// @Router /api/v1/wallet/{id} [get] func (h *Handler) GetWalletByID(c *fiber.Ctx) error { walletID := c.Params("id") id, err := strconv.ParseInt(walletID, 10, 64) if err != nil { - h.logger.Error("Invalid wallet ID", "walletID", walletID, "error", err) + h.mongoLoggerSvc.Error("Invalid wallet ID", + zap.String("walletID", walletID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } wallet, err := h.walletSvc.GetWalletByID(c.Context(), id) if err != nil { - h.logger.Error("Failed to get wallet by ID", "walletID", id, "error", err) + h.mongoLoggerSvc.Error("Failed to get wallet by ID", + zap.Int64("walletID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet") } @@ -123,14 +135,18 @@ func (h *Handler) GetWalletByID(c *fiber.Ctx) error { // @Success 200 {array} WalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /wallet [get] +// @Router /api/v1/wallet [get] func (h *Handler) GetAllWallets(c *fiber.Ctx) error { wallets, err := h.walletSvc.GetAllWallets(c.Context()) if err != nil { - h.logger.Error("Failed to get wallets", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil) + h.mongoLoggerSvc.Error("Failed to get wallets", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } var res []WalletRes = make([]WalletRes, 0, len(wallets)) @@ -152,14 +168,18 @@ func (h *Handler) GetAllWallets(c *fiber.Ctx) error { // @Success 200 {array} WalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /branchWallet [get] +// @Router /api/v1/branchWallet [get] func (h *Handler) GetAllBranchWallets(c *fiber.Ctx) error { wallets, err := h.walletSvc.GetAllBranchWallets(c.Context()) if err != nil { - h.logger.Error("Failed to get wallets", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil) + h.mongoLoggerSvc.Error("Failed to get wallets", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallets") } var res []BranchWalletRes = make([]BranchWalletRes, 0, len(wallets)) @@ -191,14 +211,18 @@ func (h *Handler) GetAllBranchWallets(c *fiber.Ctx) error { // @Success 200 {array} CustomerWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /customerWallet [get] +// @Router /api/v1/customerWallet [get] func (h *Handler) GetAllCustomerWallets(c *fiber.Ctx) error { wallets, err := h.walletSvc.GetAllCustomerWallet(c.Context()) if err != nil { - h.logger.Error("Failed to get wallets", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil) + h.mongoLoggerSvc.Error("Failed to get customer wallets", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallets") } var res []CustomerWalletRes = make([]CustomerWalletRes, 0, len(wallets)) @@ -225,29 +249,53 @@ type UpdateWalletActiveReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /wallet/{id} [patch] +// @Router /api/v1/wallet/{id} [patch] func (h *Handler) UpdateWalletActive(c *fiber.Ctx) error { walletID := c.Params("id") id, err := strconv.ParseInt(walletID, 10, 64) if err != nil { - h.logger.Error("Invalid wallet ID", "walletID", walletID, "error", err) + h.mongoLoggerSvc.Info("Invalid wallet ID", + zap.String("walletID", walletID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } var req UpdateWalletActiveReq if err := c.BodyParser(&req); err != nil { - h.logger.Error("Failed to parse UpdateWalletActive request", "error", err) + h.mongoLoggerSvc.Info("Failed to parse UpdateWalletActive request", + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } if valErrs, ok := h.validator.Validate(c, req); !ok { - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.mongoLoggerSvc.Info("Failed to validate UpdateWalletActiveReq", + zap.String("errMsg", errMsg), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) } err = h.walletSvc.UpdateWalletActive(c.Context(), id, req.IsActive) if err != nil { - h.logger.Error("Failed to update wallet active status", "walletID", id, "error", err) + h.mongoLoggerSvc.Error("Failed to update wallet active status", + zap.Int64("walletID", id), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update wallet") } @@ -265,24 +313,37 @@ func (h *Handler) UpdateWalletActive(c *fiber.Ctx) error { // @Success 200 {object} CustomerWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /user/wallet [get] +// @Router /api/v1/user/wallet [get] func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + h.mongoLoggerSvc.Info("Invalid user ID in context", + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user id in context") } role, ok := c.Locals("role").(domain.Role) if !ok { - h.logger.Error("Invalid role in context", "userID", userID) - return fiber.NewError(fiber.StatusUnauthorized, "Invalid role") + h.mongoLoggerSvc.Error("Invalid role in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.String("role", string(role)), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid role") } if role != domain.RoleCustomer { - h.logger.Error("Unauthorized access", "userID", userID, "role", role) - return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized access") + h.mongoLoggerSvc.Error("Unauthorized access", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusForbidden), + zap.String("role", string(role)), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "Unauthorized access") } // companyID, err := strconv.ParseInt(c.Get("company_id"), 10, 64) @@ -295,7 +356,12 @@ func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error { wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), userID) if err != nil { - h.logger.Error("Failed to get customer wallet", "userID", userID, "error", err) + h.mongoLoggerSvc.Error("Failed to get customer wallet", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet") } @@ -315,40 +381,63 @@ func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error { // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /cashierWallet [get] +// @Router /api/v1/cashierWallet [get] func (h *Handler) GetWalletForCashier(c *fiber.Ctx) error { cashierID, ok := c.Locals("user_id").(int64) if !ok || cashierID == 0 { - h.logger.Error("Invalid cashier ID in context") - return response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid cashier identification", nil, nil) + h.mongoLoggerSvc.Error("Invalid cashier ID in context", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusUnauthorized, "Invalid cashier id") } role, ok := c.Locals("role").(domain.Role) if !ok || role != domain.RoleCashier { - h.logger.Error("Unauthorized access", "cashierID", cashierID, "role", role) - return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) + h.mongoLoggerSvc.Error("Unauthorized access", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusForbidden), + zap.String("role", string(role)), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "Unauthorized access") } branchID, ok := c.Locals("branch_id").(domain.ValidInt64) if !ok || !branchID.Valid { - h.logger.Error("Invalid branch ID in context", "cashierID", cashierID) - return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", nil, nil) + h.mongoLoggerSvc.Info("Invalid branch ID in context", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID") } branch, err := h.branchSvc.GetBranchByID(c.Context(), branchID.Value) if err != nil { - h.logger.Error("Failed to get branch by ID", "branchID", branchID.Value, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil) + h.mongoLoggerSvc.Error("Failed to get branch by ID", + zap.Int64("branchID", branchID.Value), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } wallet, err := h.walletSvc.GetWalletByID(c.Context(), branch.WalletID) if err != nil { - h.logger.Error("Failed to get wallet for cashier", "cashierID", cashierID, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallet", err, nil) + h.mongoLoggerSvc.Error("Failed to get wallet for cashier", + zap.Int64("cashierID", cashierID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := WalletRes{ diff --git a/internal/web_server/middleware.go b/internal/web_server/middleware.go index 47dabc3..2329547 100644 --- a/internal/web_server/middleware.go +++ b/internal/web_server/middleware.go @@ -4,22 +4,38 @@ import ( "errors" "fmt" "strings" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) func (a *App) authMiddleware(c *fiber.Ctx) error { - + ip := c.IP() + userAgent := c.Get("User-Agent") + c.Locals("ip_address", ip) + c.Locals("user_agent", userAgent) authHeader := c.Get("Authorization") if authHeader == "" { - // fmt.Println("Auth Header Missing") + a.mongoLoggerSvc.Info("Authorization header missing", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Authorization header missing") } if !strings.HasPrefix(authHeader, "Bearer ") { - fmt.Println("Invalid authorization header format") + a.mongoLoggerSvc.Info("Invalid authorization header format", + zap.String("authHeader", authHeader), + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Invalid authorization header format") } @@ -28,10 +44,20 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { claim, err := jwtutil.ParseJwt(accessToken, a.JwtConfig.JwtAccessKey) if err != nil { if errors.Is(err, jwtutil.ErrExpiredToken) { - fmt.Println("Token Expired") + a.mongoLoggerSvc.Info("Access Token Expired", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Access token expired") } - fmt.Println("Invalid Token") + a.mongoLoggerSvc.Info("Invalid Access Token", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") } @@ -44,7 +70,12 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { } // Asserting to make sure that there is no company role without a valid company id if claim.Role != domain.RoleSuperAdmin && claim.Role != domain.RoleCustomer && !claim.CompanyID.Valid { - fmt.Println("Company Role without Company ID") + a.mongoLoggerSvc.Error("Company Role without Company ID", + zap.Int64("userID", claim.UserId), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusInternalServerError, "Company Role without Company ID") } c.Locals("user_id", claim.UserId) @@ -57,8 +88,13 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { if claim.Role == domain.RoleCashier { branch, err := a.branchSvc.GetBranchByCashier(c.Context(), claim.UserId) if err != nil { - a.logger.Error("Failed to get branch id for bet", "error", err) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to branch id for bet") + a.mongoLoggerSvc.Error("Failed to get branch id for cashier", + zap.Int64("userID", claim.UserId), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to branch id for cashier") } branchID = domain.ValidInt64{ Value: branch.ID, @@ -72,61 +108,116 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { } func (a *App) SuperAdminOnly(c *fiber.Ctx) error { + userID := c.Locals("user_id").(int64) userRole := c.Locals("role").(domain.Role) if userRole != domain.RoleSuperAdmin { - return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") + a.mongoLoggerSvc.Warn("Attempt to access restricted SuperAdminOnly route", + zap.Int64("userID", userID), + zap.String("role", string(userRole)), + zap.Int("status_code", fiber.StatusForbidden), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "This route is restricted") } return c.Next() } func (a *App) CompanyOnly(c *fiber.Ctx) error { + userID := c.Locals("user_id").(int64) userRole := c.Locals("role").(domain.Role) if userRole == domain.RoleCustomer { - return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") + a.mongoLoggerSvc.Warn("Attempt to access restricted CompanyOnly route", + zap.Int64("userID", userID), + zap.String("role", string(userRole)), + zap.Int("status_code", fiber.StatusForbidden), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "This route is restricted") } return c.Next() } func (a *App) OnlyAdminAndAbove(c *fiber.Ctx) error { + userID := c.Locals("user_id").(int64) userRole := c.Locals("role").(domain.Role) if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin { - return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") + a.mongoLoggerSvc.Warn("Attempt to access restricted OnlyAdminAndAbove route", + zap.Int64("userID", userID), + zap.String("role", string(userRole)), + zap.Int("status_code", fiber.StatusForbidden), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "This route is restricted") } return c.Next() } func (a *App) OnlyBranchManagerAndAbove(c *fiber.Ctx) error { + userID := c.Locals("user_id").(int64) userRole := c.Locals("role").(domain.Role) if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin && userRole != domain.RoleBranchManager { - return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") + a.mongoLoggerSvc.Warn("Attempt to access restricted OnlyBranchMangerAndAbove route", + zap.Int64("userID", userID), + zap.String("role", string(userRole)), + zap.Int("status_code", fiber.StatusForbidden), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "This route is restricted") } return c.Next() } func (a *App) WebsocketAuthMiddleware(c *fiber.Ctx) error { tokenStr := c.Query("token") + ip := c.IP() + userAgent := c.Get("User-Agent") + if tokenStr == "" { - a.logger.Error("Missing token in query parameter") + a.mongoLoggerSvc.Info("Missing token in query parameter", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Missing token") } claim, err := jwtutil.ParseJwt(tokenStr, a.JwtConfig.JwtAccessKey) if err != nil { if errors.Is(err, jwtutil.ErrExpiredToken) { - a.logger.Error("Token expired") + a.mongoLoggerSvc.Info("Token expired", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Token expired") } a.logger.Error("Invalid token", "error", err) + a.mongoLoggerSvc.Info("Invalid token", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Invalid token") } userID := claim.UserId if userID == 0 { - a.logger.Error("Invalid user ID in token claims") + a.mongoLoggerSvc.Info("Invalid user ID in token claims", + zap.Int("status_code", fiber.StatusUnauthorized), + zap.String("ip_address", ip), + zap.String("user_agent", userAgent), + zap.Time("timestamp", time.Now()), + ) return fiber.NewError(fiber.StatusUnauthorized, "Invalid user ID") } c.Locals("userID", userID) - a.logger.Info("Authenticated WebSocket connection", "userID", userID) + a.mongoLoggerSvc.Info("Authenticated WebSocket connection", + zap.Int64("userID", userID), + zap.Time("timestamp", time.Now()), + ) return c.Next() } diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 2cad0c2..d5bf75a 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -52,26 +52,27 @@ func (a *App) initAppRoutes() { a.mongoLoggerSvc, ) - group := a.fiber.Group("/api/v1") - a.fiber.Get("/", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{ "message": "Welcome to the FortuneBet API", - "version": "1.0dev8.5", + "version": "1.0dev10", }) }) + // Swagger + a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler()) - group.Get("/", func(c *fiber.Ctx) error { + groupV1 := a.fiber.Group("/api/v1") + groupV1.Get("/", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{ "message": "FortuneBet API V1 pre-alpha", - "version": "1.0dev9", + "version": "1.0dev10", }) }) // Auth Routes - a.fiber.Post("/auth/login", h.LoginCustomer) - a.fiber.Post("/auth/refresh", h.RefreshToken) - a.fiber.Post("/auth/logout", a.authMiddleware, h.LogOutCustomer) - a.fiber.Get("/auth/test", a.authMiddleware, func(c *fiber.Ctx) error { + groupV1.Post("/auth/login", h.LoginCustomer) + groupV1.Post("/auth/refresh", h.RefreshToken) + groupV1.Post("/auth/logout", a.authMiddleware, h.LogOutCustomer) + groupV1.Get("/auth/test", a.authMiddleware, func(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok { return fiber.NewError(fiber.StatusUnauthorized, "Invalid user ID") @@ -98,149 +99,146 @@ func (a *App) initAppRoutes() { }) // User Routes - a.fiber.Post("/user/resetPassword", h.ResetPassword) - a.fiber.Post("/user/sendResetCode", h.SendResetCode) - a.fiber.Post("/user/register", h.RegisterUser) - a.fiber.Post("/user/sendRegisterCode", h.SendRegisterCode) - a.fiber.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist) - a.fiber.Get("/user/profile", a.authMiddleware, h.UserProfile) - a.fiber.Get("/user/single/:id", a.authMiddleware, h.GetUserByID) - a.fiber.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser) - a.fiber.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend) - a.fiber.Get("/user/ress", a.authMiddleware, h.GetBetByUserID) + groupV1.Post("/user/resetPassword", h.ResetPassword) + groupV1.Post("/user/sendResetCode", h.SendResetCode) + groupV1.Post("/user/register", h.RegisterUser) + groupV1.Post("/user/sendRegisterCode", h.SendRegisterCode) + groupV1.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist) + groupV1.Get("/user/profile", a.authMiddleware, h.UserProfile) + groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID) + groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser) + groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend) + groupV1.Get("/user/bets", a.authMiddleware, h.GetBetByUserID) - a.fiber.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet) - a.fiber.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone) + groupV1.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet) + groupV1.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone) // Referral Routes - a.fiber.Post("/referral/create", a.authMiddleware, h.CreateReferralCode) - a.fiber.Get("/referral/stats", a.authMiddleware, h.GetReferralStats) - a.fiber.Post("/referral/settings", a.authMiddleware, h.CreateReferralSettings) - a.fiber.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings) - a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings) + groupV1.Post("/referral/create", a.authMiddleware, h.CreateReferralCode) + groupV1.Get("/referral/stats", a.authMiddleware, h.GetReferralStats) + groupV1.Post("/referral/settings", a.authMiddleware, h.CreateReferralSettings) + groupV1.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings) + groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings) // Bonus Routes - a.fiber.Get("/bonus", a.authMiddleware, h.GetBonusMultiplier) - a.fiber.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier) - a.fiber.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier) + groupV1.Get("/bonus", a.authMiddleware, h.GetBonusMultiplier) + groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier) + groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier) - a.fiber.Get("/cashiers", a.authMiddleware, h.GetAllCashiers) - a.fiber.Get("/cashiers/:id", a.authMiddleware, h.GetCashierByID) - a.fiber.Post("/cashiers", a.authMiddleware, h.CreateCashier) - a.fiber.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier) + groupV1.Get("/cashiers", a.authMiddleware, h.GetAllCashiers) + groupV1.Get("/cashiers/:id", a.authMiddleware, h.GetCashierByID) + groupV1.Post("/cashiers", a.authMiddleware, h.CreateCashier) + groupV1.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier) - a.fiber.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers) - a.fiber.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID) - a.fiber.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer) + groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers) + groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID) + groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer) - a.fiber.Get("/admin", a.authMiddleware, h.GetAllAdmins) - a.fiber.Get("/admin/:id", a.authMiddleware, h.GetAdminByID) - a.fiber.Post("/admin", a.authMiddleware, h.CreateAdmin) - a.fiber.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin) + groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins) + groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID) + groupV1.Post("/admin", a.authMiddleware, h.CreateAdmin) + groupV1.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin) - a.fiber.Get("/managers", a.authMiddleware, h.GetAllManagers) - a.fiber.Get("/managers/:id", a.authMiddleware, h.GetManagerByID) - a.fiber.Post("/managers", a.authMiddleware, h.CreateManager) - a.fiber.Put("/managers/:id", a.authMiddleware, h.UpdateManagers) - a.fiber.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID) + groupV1.Get("/managers", a.authMiddleware, h.GetAllManagers) + groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID) + groupV1.Post("/managers", a.authMiddleware, h.CreateManager) + groupV1.Put("/managers/:id", a.authMiddleware, h.UpdateManagers) + groupV1.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID) - a.fiber.Get("/odds", h.GetALLPrematchOdds) - a.fiber.Get("/odds/upcoming/:upcoming_id", h.GetOddsByUpcomingID) - a.fiber.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetRawOddsByMarketID) + groupV1.Get("/odds", h.GetALLPrematchOdds) + groupV1.Get("/odds/upcoming/:upcoming_id", h.GetOddsByUpcomingID) + groupV1.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetRawOddsByMarketID) - a.fiber.Get("/events", h.GetAllUpcomingEvents) - a.fiber.Get("/events/:id", h.GetUpcomingEventByID) - a.fiber.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved) - a.fiber.Get("/top-leagues", h.GetTopLeagues) - a.fiber.Get("/events/:id/flag", h.UpdateEventFlagged) + groupV1.Get("/events", h.GetAllUpcomingEvents) + groupV1.Get("/events/:id", h.GetUpcomingEventByID) + groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved) + groupV1.Get("/top-leagues", h.GetTopLeagues) + groupV1.Get("/events/:id/flag", h.UpdateEventFlagged) // Leagues - a.fiber.Get("/leagues", h.GetAllLeagues) - a.fiber.Put("/leagues/:id/set-active", h.SetLeagueActive) - - a.fiber.Get("/result/:id", h.GetResultsByEventID) - - // Swagger - a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler()) + groupV1.Get("/leagues", h.GetAllLeagues) + groupV1.Put("/leagues/:id/set-active", h.SetLeagueActive) + groupV1.Put("/leagues/:id/featured", h.SetLeagueFeatured) + groupV1.Get("/result/:id", h.GetResultsByEventID) + // Branch - a.fiber.Post("/branch", a.authMiddleware, h.CreateBranch) - a.fiber.Get("/branch", a.authMiddleware, h.GetAllBranches) - a.fiber.Get("/branch/:id", a.authMiddleware, h.GetBranchByID) - a.fiber.Get("/branch/:id/bets", a.authMiddleware, h.GetBetByBranchID) - a.fiber.Put("/branch/:id", a.authMiddleware, h.UpdateBranch) - a.fiber.Put("/branch/:id/set-active", a.authMiddleware, h.UpdateBranchStatus) - a.fiber.Put("/branch/:id/set-inactive", a.authMiddleware, h.UpdateBranchStatus) - a.fiber.Delete("/branch/:id", a.authMiddleware, h.DeleteBranch) - a.fiber.Get("/search/branch", a.authMiddleware, h.SearchBranch) + groupV1.Post("/branch", a.authMiddleware, h.CreateBranch) + groupV1.Get("/branch", a.authMiddleware, h.GetAllBranches) + groupV1.Get("/branch/:id", a.authMiddleware, h.GetBranchByID) + groupV1.Get("/branch/:id/bets", a.authMiddleware, h.GetBetByBranchID) + groupV1.Put("/branch/:id", a.authMiddleware, h.UpdateBranch) + groupV1.Put("/branch/:id/set-active", a.authMiddleware, h.UpdateBranchStatus) + groupV1.Put("/branch/:id/set-inactive", a.authMiddleware, h.UpdateBranchStatus) + groupV1.Delete("/branch/:id", a.authMiddleware, h.DeleteBranch) + groupV1.Get("/search/branch", a.authMiddleware, h.SearchBranch) // /branch/search // branch/wallet - a.fiber.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers) - a.fiber.Get("/branchCashier", a.authMiddleware, h.GetBranchForCashier) + groupV1.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers) + groupV1.Get("/branchCashier", a.authMiddleware, h.GetBranchForCashier) // Branch Operation - a.fiber.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations) - a.fiber.Post("/supportedOperation", a.authMiddleware, h.CreateSupportedOperation) - a.fiber.Post("/operation", a.authMiddleware, h.CreateBranchOperation) - a.fiber.Get("/branch/:id/operation", a.authMiddleware, h.GetBranchOperations) + groupV1.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations) + groupV1.Post("/supportedOperation", a.authMiddleware, h.CreateSupportedOperation) + groupV1.Post("/operation", a.authMiddleware, h.CreateBranchOperation) + groupV1.Get("/branch/:id/operation", a.authMiddleware, h.GetBranchOperations) - a.fiber.Delete("/branch/:id/operation/:opID", a.authMiddleware, h.DeleteBranchOperation) + groupV1.Delete("/branch/:id/operation/:opID", a.authMiddleware, h.DeleteBranchOperation) // Company - a.fiber.Post("/company", a.authMiddleware, a.SuperAdminOnly, h.CreateCompany) - a.fiber.Get("/company", a.authMiddleware, a.SuperAdminOnly, h.GetAllCompanies) - a.fiber.Get("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCompanyByID) - a.fiber.Put("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCompany) - a.fiber.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany) - a.fiber.Get("/company/:id/branch", a.authMiddleware, h.GetBranchByCompanyID) - a.fiber.Get("/search/company", a.authMiddleware, h.SearchCompany) - a.fiber.Get("/admin-company", a.authMiddleware, h.GetCompanyForAdmin) + groupV1.Post("/company", a.authMiddleware, a.SuperAdminOnly, h.CreateCompany) + groupV1.Get("/company", a.authMiddleware, a.SuperAdminOnly, h.GetAllCompanies) + groupV1.Get("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCompanyByID) + groupV1.Put("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCompany) + groupV1.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany) + groupV1.Get("/company/:id/branch", a.authMiddleware, h.GetBranchByCompanyID) + groupV1.Get("/search/company", a.authMiddleware, h.SearchCompany) + groupV1.Get("/admin-company", a.authMiddleware, h.GetCompanyForAdmin) // Ticket Routes - a.fiber.Post("/ticket", h.CreateTicket) - a.fiber.Get("/ticket", h.GetAllTickets) - a.fiber.Get("/ticket/:id", h.GetTicketByID) + groupV1.Post("/ticket", h.CreateTicket) + groupV1.Get("/ticket", h.GetAllTickets) + groupV1.Get("/ticket/:id", h.GetTicketByID) // Bet Routes - a.fiber.Post("/sport/bet", a.authMiddleware, h.CreateBet) - a.fiber.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode) - a.fiber.Get("/sport/bet", a.authMiddleware, h.GetAllBet) - a.fiber.Get("/sport/bet/:id", h.GetBetByID) - a.fiber.Get("/sport/bet/cashout/:id", a.authMiddleware, h.GetBetByCashoutID) - a.fiber.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut) - a.fiber.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteBet) + groupV1.Post("/sport/bet", a.authMiddleware, h.CreateBet) + groupV1.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode) + groupV1.Get("/sport/bet", a.authMiddleware, h.GetAllBet) + groupV1.Get("/sport/bet/:id", h.GetBetByID) + groupV1.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut) + groupV1.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteBet) - a.fiber.Post("/sport/random/bet", a.authMiddleware, h.RandomBet) + groupV1.Post("/sport/random/bet", a.authMiddleware, h.RandomBet) // Wallet - a.fiber.Get("/wallet", h.GetAllWallets) - a.fiber.Get("/wallet/:id", h.GetWalletByID) - a.fiber.Put("/wallet/:id", h.UpdateWalletActive) - a.fiber.Get("/branchWallet", a.authMiddleware, h.GetAllBranchWallets) - a.fiber.Get("/customerWallet", a.authMiddleware, h.GetAllCustomerWallets) - a.fiber.Get("/cashierWallet", a.authMiddleware, h.GetWalletForCashier) + groupV1.Get("/wallet", h.GetAllWallets) + groupV1.Get("/wallet/:id", h.GetWalletByID) + groupV1.Put("/wallet/:id", h.UpdateWalletActive) + groupV1.Get("/branchWallet", a.authMiddleware, h.GetAllBranchWallets) + groupV1.Get("/customerWallet", a.authMiddleware, h.GetAllCustomerWallets) + groupV1.Get("/cashierWallet", a.authMiddleware, h.GetWalletForCashier) // Transfer // /transfer/wallet - transfer from one wallet to another wallet - a.fiber.Post("/transfer/wallet/:id", a.authMiddleware, h.TransferToWallet) - a.fiber.Get("/transfer/wallet/:id", a.authMiddleware, h.GetTransfersByWallet) - a.fiber.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet) + groupV1.Post("/transfer/wallet/:id", a.authMiddleware, h.TransferToWallet) + groupV1.Get("/transfer/wallet/:id", a.authMiddleware, h.GetTransfersByWallet) + groupV1.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet) //Chapa Routes - group.Post("/chapa/payments/webhook/verify", h.WebhookCallback) - group.Get("/chapa/payments/manual/verify/:tx_ref", h.ManualVerifyTransaction) - group.Post("/chapa/payments/deposit", a.authMiddleware, h.InitiateDeposit) - group.Post("/chapa/payments/withdraw", a.authMiddleware, h.InitiateWithdrawal) - group.Get("/chapa/banks", h.GetSupportedBanks) + a.fiber.Post("/chapa/payments/webhook/verify", h.WebhookCallback) + a.fiber.Get("/chapa/payments/manual/verify/:tx_ref", h.ManualVerifyTransaction) + a.fiber.Post("/chapa/payments/deposit", a.authMiddleware, h.InitiateDeposit) + a.fiber.Post("/chapa/payments/withdraw", a.authMiddleware, h.InitiateWithdrawal) + a.fiber.Get("/chapa/banks", h.GetSupportedBanks) // Currencies - group.Get("/currencies", h.GetSupportedCurrencies) - group.Get("/currencies/convert", h.ConvertCurrency) + groupV1.Get("/currencies", h.GetSupportedCurrencies) + groupV1.Get("/currencies/convert", h.ConvertCurrency) //Report Routes - group.Get("/reports/dashboard", h.GetDashboardReport) - group.Get("/report-files/download/:filename", a.authMiddleware, a.OnlyAdminAndAbove, h.DownloadReportFile) - group.Get("/report-files/list", a.authMiddleware, a.OnlyAdminAndAbove, h.ListReportFiles) + groupV1.Get("/reports/dashboard", h.GetDashboardReport) + groupV1.Get("/report-files/download/:filename", a.authMiddleware, a.OnlyAdminAndAbove, h.DownloadReportFile) + groupV1.Get("/report-files/list", a.authMiddleware, a.OnlyAdminAndAbove, h.ListReportFiles) //Wallet Monitor Service // group.Get("/debug/wallet-monitor/status", func(c *fiber.Ctx) error { @@ -263,48 +261,48 @@ func (a *App) initAppRoutes() { // group.Get("/chapa/transfers/verify/:transfer_ref", h.VerifyTransfer) //Alea Play Virtual Game Routes - group.Get("/alea-play/launch", a.authMiddleware, h.LaunchAleaGame) - group.Post("/webhooks/alea-play", a.authMiddleware, h.HandleAleaCallback) + groupV1.Get("/alea-play/launch", a.authMiddleware, h.LaunchAleaGame) + groupV1.Post("/webhooks/alea-play", a.authMiddleware, h.HandleAleaCallback) //Veli Virtual Game Routes - group.Post("/veli/providers", h.GetProviders) - group.Post("/veli/games-list", h.GetGamesByProvider) - group.Post("/veli/start-game", a.authMiddleware, h.StartGame) - group.Post("/veli/start-demo-game", a.authMiddleware, h.StartDemoGame) + groupV1.Post("/veli/providers", h.GetProviders) + groupV1.Post("/veli/games-list", h.GetGamesByProvider) + groupV1.Post("/veli/start-game", a.authMiddleware, h.StartGame) + groupV1.Post("/veli/start-demo-game", a.authMiddleware, h.StartDemoGame) a.fiber.Post("/balance", h.GetBalance) // a.fiber.Post("/bet", h.PlaceBet) // a.fiber.Post("/win", h.RegisterWin) // a.fiber.Post("/cancel", h.CancelTransaction) - group.Post("/veli/gaming-activity", h.GetGamingActivity) + groupV1.Post("/veli/gaming-activity", h.GetGamingActivity) //mongoDB logs ctx := context.Background() - group.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(ctx)) + groupV1.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(ctx)) // Recommendation Routes // group.Get("/virtual-games/recommendations/:userID", h.GetRecommendations) // Transactions /shop/transactions - a.fiber.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet) - a.fiber.Get("/shop/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByBetID) - a.fiber.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet) - a.fiber.Post("/shop/bet/:id/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet) - a.fiber.Get("/shop/cashout/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByCashoutID) - a.fiber.Post("/shop/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutByCashoutID) - a.fiber.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer) - // a.fiber.Get("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer) - a.fiber.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions) - a.fiber.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID) - a.fiber.Get("/shop/transaction/:id/bet", a.authMiddleware, h.GetShopBetByTransactionID) - a.fiber.Put("/shop/transaction/:id", a.authMiddleware, h.UpdateTransactionVerified) + groupV1.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet) + groupV1.Get("/shop/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByBetID) + groupV1.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet) + groupV1.Post("/shop/bet/:id/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet) + groupV1.Get("/shop/cashout/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByCashoutID) + groupV1.Post("/shop/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutByCashoutID) + groupV1.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer) + // groupV1.Get("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer) + groupV1.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions) + groupV1.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID) + groupV1.Get("/shop/transaction/:id/bet", a.authMiddleware, h.GetShopBetByTransactionID) + groupV1.Put("/shop/transaction/:id", a.authMiddleware, h.UpdateTransactionVerified) // Notification Routes - a.fiber.Get("/ws/connect", a.WebsocketAuthMiddleware, h.ConnectSocket) - a.fiber.Get("/notifications", a.authMiddleware, h.GetNotifications) - a.fiber.Get("/notifications/all", a.authMiddleware, h.GetAllNotifications) - a.fiber.Post("/notifications/mark-as-read", a.authMiddleware, h.MarkNotificationAsRead) - a.fiber.Get("/notifications/unread", a.authMiddleware, h.CountUnreadNotifications) - a.fiber.Post("/notifications/create", a.authMiddleware, h.CreateAndSendNotification) + groupV1.Get("/ws/connect", a.WebsocketAuthMiddleware, h.ConnectSocket) + groupV1.Get("/notifications", a.authMiddleware, h.GetNotifications) + groupV1.Get("/notifications/all", a.authMiddleware, h.GetAllNotifications) + groupV1.Post("/notifications/mark-as-read", a.authMiddleware, h.MarkNotificationAsRead) + groupV1.Get("/notifications/unread", a.authMiddleware, h.CountUnreadNotifications) + groupV1.Post("/notifications/create", a.authMiddleware, h.CreateAndSendNotification) // Virtual Game Routes a.fiber.Post("/virtual-game/launch", a.authMiddleware, h.LaunchVirtualGame) @@ -317,21 +315,14 @@ func (a *App) initAppRoutes() { a.fiber.Post("/tournamentWin ", h.HandleTournamentWin) a.fiber.Get("/popok/games", h.GetGameList) a.fiber.Get("/popok/games/recommend", a.authMiddleware, h.RecommendGames) - group.Post("/virtual-game/favorites", a.authMiddleware, h.AddFavorite) - group.Delete("/virtual-game/favorites/:gameID", a.authMiddleware, h.RemoveFavorite) - group.Get("/virtual-game/favorites", a.authMiddleware, h.ListFavorites) + groupV1.Post("/virtual-game/favorites", a.authMiddleware, h.AddFavorite) + groupV1.Delete("/virtual-game/favorites/:gameID", a.authMiddleware, h.RemoveFavorite) + groupV1.Get("/virtual-game/favorites", a.authMiddleware, h.ListFavorites) //Issue Reporting Routes - group.Post("/issues", a.authMiddleware, h.CreateIssue) //anyone who has logged can report a - group.Get("/issues/customer/:customer_id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetUserIssues) - group.Get("/issues", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllIssues) - group.Patch("/issues/:issue_id/status", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateIssueStatus) - group.Delete("/issues/:issue_id", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteIssue) + groupV1.Post("/issues", a.authMiddleware, h.CreateIssue) //anyone who has logged can report a + groupV1.Get("/issues/customer/:customer_id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetUserIssues) + groupV1.Get("/issues", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllIssues) + groupV1.Patch("/issues/:issue_id/status", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateIssueStatus) + groupV1.Delete("/issues/:issue_id", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteIssue) } - -///user/profile get -// @Router /user/resetPassword [post] -// @Router /user/sendResetCode [post] -// @Router /user/register [post] -// @Router /user/sendRegisterCode [post] -// @Router /user/checkPhoneEmailExist [post] diff --git a/makefile b/makefile index 55536c7..d8ef6a1 100644 --- a/makefile +++ b/makefile @@ -43,7 +43,7 @@ migrations/up: postgres: @echo 'Running postgres db...' docker compose -f docker-compose.yml exec postgres psql -U root -d gh -.PHONY: backup +.PHONY: backup backup: @mkdir -p backup @docker exec -t fortunebet-backend-postgres-1 pg_dumpall -c -U root | gzip > backup/dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.gz @@ -56,6 +56,8 @@ restore: restore_file: @echo "Restoring latest backup..." gunzip -c $(file) | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh +seed_data: + cat db/data/seed_data.sql | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh postgres_log: docker logs fortunebet-backend-postgres-1 .PHONY: swagger