Merge branch 'main' into feature/referal
This commit is contained in:
commit
fa3b6a24d3
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -4,3 +4,5 @@ coverage
|
||||||
.env
|
.env
|
||||||
tmp
|
tmp
|
||||||
build
|
build
|
||||||
|
*.log
|
||||||
|
db.sql
|
||||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"Cashout"
|
||||||
|
]
|
||||||
|
}
|
||||||
31
cmd/main.go
31
cmd/main.go
|
|
@ -1,10 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
// "context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||||
customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger"
|
customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger"
|
||||||
mockemail "github.com/SamuelTariku/FortuneBet-Backend/internal/mocks/mock_email"
|
mockemail "github.com/SamuelTariku/FortuneBet-Backend/internal/mocks/mock_email"
|
||||||
|
|
@ -12,7 +15,11 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
|
"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"
|
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||||
|
|
@ -22,7 +29,6 @@ import (
|
||||||
httpserver "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server"
|
httpserver "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server"
|
||||||
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
||||||
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title FortuneBet API
|
// @title FortuneBet API
|
||||||
|
|
@ -41,28 +47,35 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
cfg, err := config.NewConfig()
|
cfg, err := config.NewConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error(err.Error())
|
slog.Error(" Config error:", "err", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, _, err := repository.OpenDB(cfg.DbUrl)
|
db, _, err := repository.OpenDB(cfg.DbUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Print("db", err)
|
fmt.Println(" Database error:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := customlogger.NewLogger(cfg.Env, cfg.LogLevel)
|
logger := customlogger.NewLogger(cfg.Env, cfg.LogLevel)
|
||||||
store := repository.NewStore(db)
|
store := repository.NewStore(db)
|
||||||
v := customvalidator.NewCustomValidator(validator.New())
|
v := customvalidator.NewCustomValidator(validator.New())
|
||||||
|
|
||||||
authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
|
authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
|
||||||
mockSms := mocksms.NewMockSMS()
|
mockSms := mocksms.NewMockSMS()
|
||||||
mockemail := mockemail.NewMockEmail()
|
mockEmail := mockemail.NewMockEmail()
|
||||||
|
|
||||||
|
userSvc := user.NewService(store, store, mockSms, mockEmail)
|
||||||
|
|
||||||
|
eventSvc := event.New(cfg.Bet365Token, store)
|
||||||
|
oddsSvc := odds.New(cfg.Bet365Token, store)
|
||||||
|
|
||||||
userSvc := user.NewService(store, store, mockSms, mockemail)
|
|
||||||
ticketSvc := ticket.NewService(store)
|
ticketSvc := ticket.NewService(store)
|
||||||
betSvc := bet.NewService(store)
|
betSvc := bet.NewService(store)
|
||||||
walletSvc := wallet.NewService(store)
|
walletSvc := wallet.NewService(store, store)
|
||||||
transactionSvc := transaction.NewService(store)
|
transactionSvc := transaction.NewService(store)
|
||||||
|
branchSvc := branch.NewService(store)
|
||||||
|
companySvc := company.NewService(store)
|
||||||
|
|
||||||
notificationRepo := repository.NewNotificationRepository(store)
|
notificationRepo := repository.NewNotificationRepository(store)
|
||||||
referalRepo := repository.NewReferralRepository(store)
|
referalRepo := repository.NewReferralRepository(store)
|
||||||
|
|
@ -72,15 +85,17 @@ func main() {
|
||||||
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
|
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
|
||||||
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
||||||
|
|
||||||
|
httpserver.StartDataFetchingCrons(eventSvc, oddsSvc)
|
||||||
|
|
||||||
app := httpserver.NewApp(cfg.Port, v, authSvc, logger, jwtutil.JwtConfig{
|
app := httpserver.NewApp(cfg.Port, v, authSvc, logger, jwtutil.JwtConfig{
|
||||||
JwtAccessKey: cfg.JwtKey,
|
JwtAccessKey: cfg.JwtKey,
|
||||||
JwtAccessExpiry: cfg.AccessExpiry,
|
JwtAccessExpiry: cfg.AccessExpiry,
|
||||||
}, userSvc, ticketSvc, betSvc, walletSvc, transactionSvc, notificationSvc, referalSvc, virtualGameSvc)
|
}, userSvc,
|
||||||
|
ticketSvc, betSvc, walletSvc, transactionSvc, branchSvc, companySvc, notificationSvc, oddsSvc, eventSvc, referalSvc, virtualGameSvc)
|
||||||
logger.Info("Starting server", "port", cfg.Port)
|
logger.Info("Starting server", "port", cfg.Port)
|
||||||
|
|
||||||
if err := app.Run(); err != nil {
|
if err := app.Run(); err != nil {
|
||||||
logger.Error("Failed to start server", "error", err)
|
logger.Error("Failed to start server", "error", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,18 @@
|
||||||
-- Drop tables that depend on service_type_setting
|
-- Drop tables that depend on service_type_setting
|
||||||
DROP TABLE IF EXISTS service_type_setting;
|
DROP TABLE IF EXISTS service_type_setting;
|
||||||
|
|
||||||
-- Drop product-related tables and types
|
-- Drop product-related tables and types
|
||||||
DROP TABLE IF EXISTS product;
|
DROP TABLE IF EXISTS product;
|
||||||
DROP TYPE IF EXISTS tier_group;
|
DROP TYPE IF EXISTS tier_group;
|
||||||
|
|
||||||
-- Drop onboarding-related tables and types
|
-- Drop onboarding-related tables and types
|
||||||
DROP TABLE IF EXISTS verification_key;
|
DROP TABLE IF EXISTS verification_key;
|
||||||
DROP TABLE IF EXISTS onboarding_user;
|
DROP TABLE IF EXISTS onboarding_user;
|
||||||
DROP TYPE IF EXISTS verification_status;
|
DROP TYPE IF EXISTS verification_status;
|
||||||
DROP TYPE IF EXISTS onboarding_status;
|
DROP TYPE IF EXISTS onboarding_status;
|
||||||
|
|
||||||
-- Drop staff-related tables and types
|
-- Drop staff-related tables and types
|
||||||
DROP TABLE IF EXISTS staff_session;
|
DROP TABLE IF EXISTS staff_session;
|
||||||
DROP TABLE IF EXISTS user_agent;
|
DROP TABLE IF EXISTS user_agent;
|
||||||
DROP TABLE IF EXISTS staff;
|
DROP TABLE IF EXISTS staff;
|
||||||
DROP TYPE IF EXISTS password_status;
|
DROP TYPE IF EXISTS password_status;
|
||||||
|
|
||||||
-- Drop mobile app-related tables and types
|
-- Drop mobile app-related tables and types
|
||||||
DROP TABLE IF EXISTS user_devices;
|
DROP TABLE IF EXISTS user_devices;
|
||||||
DROP TABLE IF EXISTS user_session;
|
DROP TABLE IF EXISTS user_session;
|
||||||
|
|
@ -25,17 +21,14 @@ DROP TABLE IF EXISTS users;
|
||||||
DROP TYPE IF EXISTS device_type;
|
DROP TYPE IF EXISTS device_type;
|
||||||
DROP TYPE IF EXISTS registeration_type;
|
DROP TYPE IF EXISTS registeration_type;
|
||||||
DROP TYPE IF EXISTS customer_group;
|
DROP TYPE IF EXISTS customer_group;
|
||||||
|
|
||||||
-- Drop linked accounts and beneficiary tables and types
|
-- Drop linked accounts and beneficiary tables and types
|
||||||
DROP TABLE IF EXISTS beneficiary;
|
DROP TABLE IF EXISTS beneficiary;
|
||||||
DROP TYPE IF EXISTS fund_destination;
|
DROP TYPE IF EXISTS fund_destination;
|
||||||
|
|
||||||
-- Drop maker checker-related tables and types
|
-- Drop maker checker-related tables and types
|
||||||
DROP TABLE IF EXISTS workflow;
|
DROP TABLE IF EXISTS workflow;
|
||||||
DROP TYPE IF EXISTS approval_status;
|
DROP TYPE IF EXISTS approval_status;
|
||||||
DROP TYPE IF EXISTS action_type;
|
DROP TYPE IF EXISTS action_type;
|
||||||
DROP TYPE IF EXISTS context_type;
|
DROP TYPE IF EXISTS context_type;
|
||||||
|
|
||||||
-- Drop authorization-related tables and types
|
-- Drop authorization-related tables and types
|
||||||
DROP TRIGGER IF EXISTS enforce_unique_array ON policy;
|
DROP TRIGGER IF EXISTS enforce_unique_array ON policy;
|
||||||
DROP FUNCTION IF EXISTS check_unique_array;
|
DROP FUNCTION IF EXISTS check_unique_array;
|
||||||
|
|
@ -43,11 +36,9 @@ DROP TABLE IF EXISTS policy;
|
||||||
DROP TABLE IF EXISTS roles;
|
DROP TABLE IF EXISTS roles;
|
||||||
DROP TYPE IF EXISTS policy_action;
|
DROP TYPE IF EXISTS policy_action;
|
||||||
DROP TYPE IF EXISTS policy_object;
|
DROP TYPE IF EXISTS policy_object;
|
||||||
|
|
||||||
-- Drop bank-related tables and types
|
-- Drop bank-related tables and types
|
||||||
DROP TABLE IF EXISTS bank;
|
DROP TABLE IF EXISTS bank;
|
||||||
DROP TABLE IF EXISTS flagged_users;
|
DROP TABLE IF EXISTS flagged_users;
|
||||||
|
|
||||||
-- Drop transaction-related tables and types
|
-- Drop transaction-related tables and types
|
||||||
DROP TABLE IF EXISTS transaction_daily;
|
DROP TABLE IF EXISTS transaction_daily;
|
||||||
DROP TABLE IF EXISTS system_limits;
|
DROP TABLE IF EXISTS system_limits;
|
||||||
|
|
@ -57,27 +48,31 @@ DROP TYPE IF EXISTS service_type;
|
||||||
DROP TYPE IF EXISTS channel;
|
DROP TYPE IF EXISTS channel;
|
||||||
DROP TYPE IF EXISTS transaction_category;
|
DROP TYPE IF EXISTS transaction_category;
|
||||||
DROP TYPE IF EXISTS registration_type;
|
DROP TYPE IF EXISTS registration_type;
|
||||||
|
|
||||||
-- Drop branches and related tables
|
-- Drop branches and related tables
|
||||||
DROP TABLE IF EXISTS branches;
|
DROP TABLE IF EXISTS branches;
|
||||||
DROP TABLE IF EXISTS cities;
|
DROP TABLE IF EXISTS cities;
|
||||||
DROP TABLE IF EXISTS districts;
|
DROP TABLE IF EXISTS districts;
|
||||||
DROP TABLE IF EXISTS regions;
|
DROP TABLE IF EXISTS regions;
|
||||||
|
|
||||||
-- Drop activity logs
|
-- Drop activity logs
|
||||||
DROP TABLE IF EXISTS activity;
|
DROP TABLE IF EXISTS activity;
|
||||||
|
|
||||||
-- Drop ussd account and related enums
|
-- Drop ussd account and related enums
|
||||||
DROP TABLE IF EXISTS ussd_account;
|
DROP TABLE IF EXISTS ussd_account;
|
||||||
DROP TYPE IF EXISTS ua_pin_status;
|
DROP TYPE IF EXISTS ua_pin_status;
|
||||||
DROP TYPE IF EXISTS ua_status;
|
DROP TYPE IF EXISTS ua_status;
|
||||||
DROP TYPE IF EXISTS ua_registaration_type;
|
DROP TYPE IF EXISTS ua_registaration_type;
|
||||||
|
|
||||||
-- Drop FortuneBet
|
-- Drop FortuneBet
|
||||||
DROP TABLE IF EXISTS tickets;
|
DROP TABLE IF EXISTS tickets;
|
||||||
|
DROP TABLE IF EXISTS ticket_outcomes;
|
||||||
DROP TABLE IF EXISTS bets;
|
DROP TABLE IF EXISTS bets;
|
||||||
|
DROP TABLE IF EXISTS bet_outcomes;
|
||||||
DROP TABLE IF EXISTS wallets;
|
DROP TABLE IF EXISTS wallets;
|
||||||
|
DROP TABLE IF EXISTS customer_wallets;
|
||||||
DROP TABLE IF EXISTS wallet_transfer;
|
DROP TABLE IF EXISTS wallet_transfer;
|
||||||
DROP TABLE IF EXISTS transactions;
|
DROP TABLE IF EXISTS transactions;
|
||||||
DROP TABLE IF EXISTS customer_wallets;
|
DROP TABLE IF EXISTS branches;
|
||||||
|
DROP TABLE IF EXISTS companies;
|
||||||
|
DROP TABLE IF EXISTS supported_operations;
|
||||||
|
DROP TABLE IF EXISTS refresh_tokens;
|
||||||
|
DROP TABLE IF EXISTS otps;
|
||||||
|
DROP TABLE IF EXISTS odds;
|
||||||
|
DROP TABLE IF EXISTS events;
|
||||||
|
|
@ -2,31 +2,34 @@ CREATE TABLE IF NOT EXISTS users (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
first_name VARCHAR(255) NOT NULL,
|
first_name VARCHAR(255) NOT NULL,
|
||||||
last_name VARCHAR(255) NOT NULL,
|
last_name VARCHAR(255) NOT NULL,
|
||||||
email VARCHAR(255) UNIQUE ,
|
email VARCHAR(255) UNIQUE,
|
||||||
phone_number VARCHAR(20) UNIQUE,
|
phone_number VARCHAR(20) UNIQUE,
|
||||||
role VARCHAR(50) NOT NULL,
|
role VARCHAR(50) NOT NULL,
|
||||||
password BYTEA NOT NULL,
|
password BYTEA NOT NULL,
|
||||||
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
phone_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
phone_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMPTZ ,
|
updated_at TIMESTAMPTZ,
|
||||||
--
|
--
|
||||||
suspended_at TIMESTAMPTZ NULL, -- this can be NULL if the user is not suspended
|
suspended_at TIMESTAMPTZ NULL, -- this can be NULL if the user is not suspended
|
||||||
suspended BOOLEAN NOT NULL DEFAULT FALSE,
|
suspended BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
CHECK (email IS NOT NULL OR phone_number IS NOT NULL)
|
CHECK (
|
||||||
|
email IS NOT NULL
|
||||||
|
OR phone_number IS NOT NULL
|
||||||
|
)
|
||||||
);
|
);
|
||||||
CREATE TABLE refresh_tokens (
|
CREATE TABLE refresh_tokens (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
user_id BIGINT NOT NULL,
|
user_id BIGINT NOT NULL,
|
||||||
token TEXT NOT NULL UNIQUE,
|
token TEXT NOT NULL UNIQUE,
|
||||||
expires_at TIMESTAMPTZ NOT NULL,
|
expires_at TIMESTAMPTZ NOT NULL,
|
||||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
revoked BOOLEAN DEFAULT FALSE NOT NULL,
|
revoked BOOLEAN DEFAULT FALSE NOT NULL,
|
||||||
CONSTRAINT unique_token UNIQUE (token)
|
CONSTRAINT unique_token UNIQUE (token)
|
||||||
);
|
);
|
||||||
-----
|
-----
|
||||||
CREATE TABLE otps (
|
CREATE TABLE otps (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
sent_to VARCHAR(255) NOT NULL,
|
sent_to VARCHAR(255) NOT NULL,
|
||||||
medium VARCHAR(50) NOT NULL,
|
medium VARCHAR(50) NOT NULL,
|
||||||
otp_for VARCHAR(50) NOT NULL,
|
otp_for VARCHAR(50) NOT NULL,
|
||||||
|
|
@ -36,55 +39,87 @@ CREATE TABLE refresh_tokens (
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
expires_at TIMESTAMPTZ NOT NULL
|
expires_at TIMESTAMPTZ NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS bets (
|
CREATE TABLE IF NOT EXISTS bets (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
amount BIGINT NOT NULL,
|
amount BIGINT NOT NULL,
|
||||||
total_odds REAL NOT NULL,
|
total_odds REAL NOT NULL,
|
||||||
status INT NOT NULL,
|
status INT NOT NULL,
|
||||||
full_name VARCHAR(255) NOT NULL,
|
full_name VARCHAR(255) NOT NULL,
|
||||||
phone_number VARCHAR(255) NOT NULL,
|
phone_number VARCHAR(255) NOT NULL,
|
||||||
branch_id BIGINT,
|
branch_id BIGINT,
|
||||||
user_id BIGINT,
|
user_id BIGINT,
|
||||||
cashed_out BOOLEAN DEFAULT FALSE,
|
cashed_out BOOLEAN DEFAULT FALSE NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
cashout_id VARCHAR(255) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
is_shop_bet BOOLEAN NOT NULL,
|
is_shop_bet BOOLEAN NOT NULL,
|
||||||
CHECK (user_id IS NOT NULL OR branch_id IS NOT NULL)
|
CHECK (
|
||||||
|
user_id IS NOT NULL
|
||||||
|
OR branch_id IS NOT NULL
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS tickets (
|
CREATE TABLE IF NOT EXISTS tickets (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
amount BIGINT NULL,
|
amount BIGINT NOT NULL,
|
||||||
total_odds REAL NOT NULL,
|
total_odds REAL NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS bet_outcomes (
|
||||||
-- CREATE TABLE IF NOT EXISTS bet_outcomes (
|
id BIGSERIAL PRIMARY KEY,
|
||||||
-- id BIGSERIAL PRIMARY KEY,
|
bet_id BIGINT NOT NULL,
|
||||||
-- bet_id BIGINT NOT NULL,
|
event_id BIGINT NOT null,
|
||||||
-- outcome_id BIGINT NOT NULL,
|
odd_id BIGINT NOT NULL,
|
||||||
-- );
|
home_team_name VARCHAR(255) NOT NULL,
|
||||||
|
away_team_name VARCHAR(255) NOT NULL,
|
||||||
-- CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
market_id BIGINT NOT NULL,
|
||||||
-- id BIGSERIAL PRIMARY KEY,
|
market_name VARCHAR(255) NOT NULL,
|
||||||
-- ticket_id BIGINT NOT NULL,
|
odd REAL NOT NULL,
|
||||||
-- outcome_id BIGINT NOT NULL,
|
odd_name VARCHAR(255) NOT NULL,
|
||||||
-- );
|
odd_header VARCHAR(255) NOT NULL,
|
||||||
|
odd_handicap VARCHAR(255) NOT NULL,
|
||||||
|
status INT NOT NULL DEFAULT 0,
|
||||||
|
expires TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS ticket_outcomes (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
ticket_id BIGINT NOT NULL,
|
||||||
|
event_id BIGINT NOT null,
|
||||||
|
odd_id BIGINT NOT NULL,
|
||||||
|
home_team_name VARCHAR(255) NOT NULL,
|
||||||
|
away_team_name VARCHAR(255) NOT NULL,
|
||||||
|
market_id BIGINT NOT NULL,
|
||||||
|
market_name VARCHAR(255) NOT NULL,
|
||||||
|
odd REAL NOT NULL,
|
||||||
|
odd_name VARCHAR(255) NOT NULL,
|
||||||
|
odd_header VARCHAR(255) NOT NULL,
|
||||||
|
odd_handicap VARCHAR(255) NOT NULL,
|
||||||
|
status INT NOT NULL DEFAULT 0,
|
||||||
|
expires TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
CREATE VIEW bet_with_outcomes AS
|
||||||
|
SELECT bets.*,
|
||||||
|
JSON_AGG(bet_outcomes.*) AS outcomes
|
||||||
|
FROM bets
|
||||||
|
LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id
|
||||||
|
GROUP BY bets.id;
|
||||||
|
CREATE VIEW ticket_with_outcomes AS
|
||||||
|
SELECT tickets.*,
|
||||||
|
JSON_AGG(ticket_outcomes.*) AS outcomes
|
||||||
|
FROM tickets
|
||||||
|
LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id
|
||||||
|
GROUP BY tickets.id;
|
||||||
CREATE TABLE IF NOT EXISTS wallets (
|
CREATE TABLE IF NOT EXISTS wallets (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
balance BIGINT NOT NULL DEFAULT 0,
|
balance BIGINT NOT NULL DEFAULT 0,
|
||||||
is_withdraw BOOLEAN NOT NULL,
|
is_withdraw BOOLEAN NOT NULL,
|
||||||
is_bettable BOOLEAN NOT NULL,
|
is_bettable BOOLEAN NOT NULL,
|
||||||
|
is_transferable BOOLEAN NOT NULL,
|
||||||
user_id BIGINT NOT NULL,
|
user_id BIGINT NOT NULL,
|
||||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS customer_wallets (
|
CREATE TABLE IF NOT EXISTS customer_wallets (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
customer_id BIGINT NOT NULL,
|
customer_id BIGINT NOT NULL,
|
||||||
|
|
@ -95,23 +130,25 @@ CREATE TABLE IF NOT EXISTS customer_wallets (
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
UNIQUE (customer_id, company_id)
|
UNIQUE (customer_id, company_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS wallet_transfer (
|
CREATE TABLE IF NOT EXISTS wallet_transfer (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
amount BIGINT NOT NULL,
|
amount BIGINT NOT NULL,
|
||||||
wallet_transfer VARCHAR(255) NOT NULL,
|
type VARCHAR(255) NOT NULL,
|
||||||
wallet_id BIGINT NOT NULL,
|
receiver_wallet_id BIGINT NOT NULL,
|
||||||
|
sender_wallet_id BIGINT,
|
||||||
|
cashier_id BIGINT,
|
||||||
verified BOOLEAN NOT NULL DEFAULT false,
|
verified BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
payment_method VARCHAR(255) NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS transactions (
|
CREATE TABLE IF NOT EXISTS transactions (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
amount BIGINT NOT NULL,
|
amount BIGINT NOT NULL,
|
||||||
branch_id BIGINT NOT NULL,
|
branch_id BIGINT NOT NULL,
|
||||||
cashier_id BIGINT NOT NULL,
|
cashier_id BIGINT NOT NULL,
|
||||||
bet_id BIGINT NOT NULL,
|
bet_id BIGINT NOT NULL,
|
||||||
|
type BIGINT NOT NULL,
|
||||||
payment_option BIGINT NOT NULL,
|
payment_option BIGINT NOT NULL,
|
||||||
full_name VARCHAR(255) NOT NULL,
|
full_name VARCHAR(255) NOT NULL,
|
||||||
phone_number VARCHAR(255) NOT NULL,
|
phone_number VARCHAR(255) NOT NULL,
|
||||||
|
|
@ -124,28 +161,228 @@ CREATE TABLE IF NOT EXISTS transactions (
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS branches (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
location VARCHAR(255) NOT NULL,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
CREATE VIEW branch_details AS
|
||||||
|
SELECT branches.*,
|
||||||
|
CONCAT(users.first_name, ' ', users.last_name) AS manager_name,
|
||||||
|
users.phone_number AS manager_phone_number
|
||||||
|
FROM branches
|
||||||
|
LEFT JOIN users ON branches.branch_manager_id = users.id;
|
||||||
|
CREATE TABLE IF NOT EXISTS supported_operations (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
description VARCHAR(255) NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS branch_operations (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
operation_id BIGINT NOT NULL,
|
||||||
|
branch_id BIGINT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS branch_cashiers (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
branch_id BIGINT NOT NULL,
|
||||||
|
UNIQUE(user_id, branch_id)
|
||||||
|
);
|
||||||
|
CREATE TABLE events (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
sport_id TEXT,
|
||||||
|
match_name TEXT,
|
||||||
|
home_team TEXT,
|
||||||
|
away_team TEXT,
|
||||||
|
home_team_id TEXT,
|
||||||
|
away_team_id TEXT,
|
||||||
|
home_kit_image TEXT,
|
||||||
|
away_kit_image TEXT,
|
||||||
|
league_id TEXT,
|
||||||
|
league_name TEXT,
|
||||||
|
league_cc TEXT,
|
||||||
|
start_time TIMESTAMP,
|
||||||
|
score TEXT,
|
||||||
|
match_minute INT,
|
||||||
|
timer_status TEXT,
|
||||||
|
added_time INT,
|
||||||
|
match_period INT,
|
||||||
|
is_live BOOLEAN,
|
||||||
|
status TEXT,
|
||||||
|
fetched_at TIMESTAMP DEFAULT now()
|
||||||
|
);
|
||||||
|
CREATE TABLE odds (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
event_id TEXT,
|
||||||
|
fi TEXT,
|
||||||
|
market_type TEXT NOT NULL,
|
||||||
|
market_name TEXT,
|
||||||
|
market_category TEXT,
|
||||||
|
market_id TEXT,
|
||||||
|
name TEXT,
|
||||||
|
handicap TEXT,
|
||||||
|
odds_value DOUBLE PRECISION,
|
||||||
|
section TEXT NOT NULL,
|
||||||
|
category TEXT,
|
||||||
|
raw_odds JSONB,
|
||||||
|
fetched_at TIMESTAMP DEFAULT now(),
|
||||||
|
source TEXT DEFAULT 'b365api',
|
||||||
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
UNIQUE (market_id, name, handicap),
|
||||||
|
UNIQUE (event_id, market_id, name, handicap),
|
||||||
|
UNIQUE (event_id, market_id)
|
||||||
|
);
|
||||||
|
CREATE TABLE companies (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
admin_id BIGINT NOT NULL,
|
||||||
|
wallet_id BIGINT NOT NULL
|
||||||
|
);
|
||||||
|
ALTER TABLE refresh_tokens
|
||||||
|
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id);
|
||||||
|
ALTER TABLE bets
|
||||||
|
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
ADD CONSTRAINT fk_bets_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
|
||||||
|
ALTER TABLE wallets
|
||||||
|
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id);
|
||||||
|
ALTER TABLE customer_wallets
|
||||||
|
ADD CONSTRAINT fk_customer_wallets_customers FOREIGN KEY (customer_id) REFERENCES users(id),
|
||||||
|
ADD CONSTRAINT fk_customer_wallets_regular_wallet FOREIGN KEY (regular_wallet_id) REFERENCES wallets(id),
|
||||||
|
ADD CONSTRAINT fk_customer_wallets_static_wallet FOREIGN KEY (static_wallet_id) REFERENCES wallets(id);
|
||||||
|
ALTER TABLE wallet_transfer
|
||||||
|
ADD CONSTRAINT fk_wallet_transfer_receiver_wallet FOREIGN KEY (receiver_wallet_id) REFERENCES wallets(id),
|
||||||
|
ADD CONSTRAINT fk_wallet_transfer_sender_wallet FOREIGN KEY (sender_wallet_id) REFERENCES wallets(id),
|
||||||
|
ADD CONSTRAINT fk_wallet_transfer_cashier FOREIGN KEY (cashier_id) REFERENCES users(id);
|
||||||
|
ALTER TABLE transactions
|
||||||
|
ADD CONSTRAINT fk_transactions_branches FOREIGN KEY (branch_id) REFERENCES branches(id),
|
||||||
|
ADD CONSTRAINT fk_transactions_cashiers FOREIGN KEY (cashier_id) REFERENCES users(id),
|
||||||
|
ADD CONSTRAINT fk_transactions_bets FOREIGN KEY (bet_id) REFERENCES bets(id);
|
||||||
|
ALTER TABLE branches
|
||||||
|
ADD CONSTRAINT fk_branches_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id),
|
||||||
|
ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id);
|
||||||
|
ALTER TABLE branch_operations
|
||||||
|
ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id),
|
||||||
|
ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
|
||||||
|
ALTER TABLE branch_cashiers
|
||||||
|
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
|
||||||
----------------------------------------------seed data-------------------------------------------------------------
|
----------------------------------------------seed data-------------------------------------------------------------
|
||||||
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
|
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
|
||||||
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
|
||||||
INSERT INTO users (
|
INSERT INTO users (
|
||||||
first_name, last_name, email, phone_number, password, role,
|
first_name,
|
||||||
email_verified, phone_verified, created_at, updated_at,
|
last_name,
|
||||||
suspended_at, suspended
|
email,
|
||||||
) VALUES (
|
phone_number,
|
||||||
'John',
|
password,
|
||||||
'Doe',
|
role,
|
||||||
'john.doe@example.com',
|
email_verified,
|
||||||
NULL,
|
phone_verified,
|
||||||
crypt('password123', gen_salt('bf'))::bytea,
|
created_at,
|
||||||
'customer',
|
updated_at,
|
||||||
TRUE,
|
suspended_at,
|
||||||
FALSE,
|
suspended
|
||||||
CURRENT_TIMESTAMP,
|
)
|
||||||
CURRENT_TIMESTAMP,
|
VALUES (
|
||||||
NULL,
|
'John',
|
||||||
FALSE
|
'Doe',
|
||||||
);
|
'john.doe@example.com',
|
||||||
|
NULL,
|
||||||
|
crypt('password123', gen_salt('bf'))::bytea,
|
||||||
|
'customer',
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
INSERT INTO users (
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
password,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
suspended_at,
|
||||||
|
suspended
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'Samuel',
|
||||||
|
'Tariku',
|
||||||
|
'cybersamt@gmail.com',
|
||||||
|
NULL,
|
||||||
|
crypt('password@123', gen_salt('bf'))::bytea,
|
||||||
|
'super_admin',
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
INSERT INTO users (
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
password,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
suspended_at,
|
||||||
|
suspended
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'Kirubel',
|
||||||
|
'Kibru',
|
||||||
|
'kirubeljkl679 @gmail.com',
|
||||||
|
NULL,
|
||||||
|
crypt('password@123', gen_salt('bf'))::bytea,
|
||||||
|
'super_admin',
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
INSERT INTO supported_operations (name, description)
|
||||||
|
VALUES ('SportBook', 'Sportbook operations'),
|
||||||
|
('Virtual', 'Virtual operations'),
|
||||||
|
('GameZone', 'GameZone operations');
|
||||||
|
INSERT INTO wallets (
|
||||||
|
balance,
|
||||||
|
is_withdraw,
|
||||||
|
is_bettable,
|
||||||
|
is_transferable,
|
||||||
|
user_id,
|
||||||
|
is_active,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
10000,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
1,
|
||||||
|
TRUE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
--------------------------------------------------Bet365 Data Fetching + Event Managment------------------------------------------------
|
||||||
|
|
@ -1,16 +1,78 @@
|
||||||
-- name: CreateBet :one
|
-- name: CreateBet :one
|
||||||
INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet)
|
INSERT INTO bets (
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
amount,
|
||||||
|
total_odds,
|
||||||
|
status,
|
||||||
|
full_name,
|
||||||
|
phone_number,
|
||||||
|
branch_id,
|
||||||
|
user_id,
|
||||||
|
is_shop_bet,
|
||||||
|
cashout_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
-- name: CreateBetOutcome :copyfrom
|
||||||
|
INSERT INTO bet_outcomes (
|
||||||
|
bet_id,
|
||||||
|
event_id,
|
||||||
|
odd_id,
|
||||||
|
home_team_name,
|
||||||
|
away_team_name,
|
||||||
|
market_id,
|
||||||
|
market_name,
|
||||||
|
odd,
|
||||||
|
odd_name,
|
||||||
|
odd_header,
|
||||||
|
odd_handicap,
|
||||||
|
expires
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12
|
||||||
|
);
|
||||||
-- name: GetAllBets :many
|
-- name: GetAllBets :many
|
||||||
SELECT * FROM bets;
|
SELECT *
|
||||||
|
FROM bet_with_outcomes;
|
||||||
-- name: GetBetByID :one
|
-- name: GetBetByID :one
|
||||||
SELECT * FROM bets WHERE id = $1;
|
SELECT *
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: GetBetByCashoutID :one
|
||||||
|
SELECT *
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE cashout_id = $1;
|
||||||
|
-- name: GetBetByBranchID :many
|
||||||
|
SELECT *
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE branch_id = $1;
|
||||||
-- name: UpdateCashOut :exec
|
-- name: UpdateCashOut :exec
|
||||||
UPDATE bets SET cashed_out = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1;
|
UPDATE bets
|
||||||
|
SET cashed_out = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: UpdateBetOutcomeStatus :exec
|
||||||
|
UPDATE bet_outcomes
|
||||||
|
SET status = $1
|
||||||
|
WHERE id = $2;
|
||||||
|
-- name: UpdateStatus :exec
|
||||||
|
UPDATE bets
|
||||||
|
SET status = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1;
|
||||||
-- name: DeleteBet :exec
|
-- name: DeleteBet :exec
|
||||||
DELETE FROM bets WHERE id = $1;
|
DELETE FROM bets
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: DeleteBetOutcome :exec
|
||||||
|
DELETE FROM bet_outcomes
|
||||||
|
WHERE bet_id = $1;
|
||||||
86
db/query/branch.sql
Normal file
86
db/query/branch.sql
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
-- name: CreateBranch :one
|
||||||
|
INSERT INTO branches (
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
wallet_id,
|
||||||
|
branch_manager_id,
|
||||||
|
company_id,
|
||||||
|
is_self_owned
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING *;
|
||||||
|
-- name: CreateSupportedOperation :one
|
||||||
|
INSERT INTO supported_operations (name, description)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING *;
|
||||||
|
-- name: CreateBranchOperation :one
|
||||||
|
INSERT INTO branch_operations (operation_id, branch_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING *;
|
||||||
|
-- name: CreateBranchCashier :one
|
||||||
|
INSERT INTO branch_cashiers (user_id, branch_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING *;
|
||||||
|
-- name: GetAllBranches :many
|
||||||
|
SELECT *
|
||||||
|
FROM branch_details;
|
||||||
|
|
||||||
|
-- name: GetBranchByID :one
|
||||||
|
SELECT *
|
||||||
|
FROM branch_details
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: GetBranchByCompanyID :many
|
||||||
|
SELECT *
|
||||||
|
FROM branch_details
|
||||||
|
WHERE company_id = $1;
|
||||||
|
-- name: GetBranchByManagerID :many
|
||||||
|
SELECT *
|
||||||
|
FROM branch_details
|
||||||
|
WHERE branch_manager_id = $1;
|
||||||
|
-- name: SearchBranchByName :many
|
||||||
|
SELECT *
|
||||||
|
FROM branch_details
|
||||||
|
WHERE name ILIKE '%' || $1 || '%';
|
||||||
|
-- name: GetAllSupportedOperations :many
|
||||||
|
SELECT *
|
||||||
|
FROM supported_operations;
|
||||||
|
-- name: GetBranchOperations :many
|
||||||
|
SELECT branch_operations.*,
|
||||||
|
supported_operations.name,
|
||||||
|
supported_operations.description
|
||||||
|
FROM branch_operations
|
||||||
|
JOIN supported_operations ON branch_operations.operation_id = supported_operations.id
|
||||||
|
WHERE branch_operations.branch_id = $1;
|
||||||
|
-- name: GetBranchByCashier :one
|
||||||
|
SELECT branches.*
|
||||||
|
FROM branch_cashiers
|
||||||
|
JOIN branches ON branch_cashiers.branch_id = branches.id
|
||||||
|
WHERE branch_cashiers.user_id = $1;
|
||||||
|
-- name: GetCashiersByBranch :many
|
||||||
|
SELECT users.*
|
||||||
|
FROM branch_cashiers
|
||||||
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
WHERE branch_cashiers.branch_id = $1;
|
||||||
|
-- name: GetAllCashiers :many
|
||||||
|
SELECT users.*
|
||||||
|
FROM branch_cashiers
|
||||||
|
JOIN users ON branch_cashiers.user_id = users.id;
|
||||||
|
-- name: UpdateBranch :one
|
||||||
|
UPDATE branches
|
||||||
|
SET name = $1,
|
||||||
|
location = $2,
|
||||||
|
branch_manager_id = $3,
|
||||||
|
company_id = $4,
|
||||||
|
is_self_owned = $5
|
||||||
|
WHERE id = $6
|
||||||
|
RETURNING *;
|
||||||
|
-- name: DeleteBranch :exec
|
||||||
|
DELETE FROM branches
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: DeleteBranchOperation :exec
|
||||||
|
DELETE FROM branch_operations
|
||||||
|
WHERE operation_id = $1
|
||||||
|
AND branch_id = $2;
|
||||||
|
-- name: DeleteBranchCashier :exec
|
||||||
|
DELETE FROM branch_cashiers
|
||||||
|
WHERE user_id = $1;
|
||||||
24
db/query/company.sql
Normal file
24
db/query/company.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
-- name: CreateCompany :one
|
||||||
|
INSERT INTO companies (
|
||||||
|
name,
|
||||||
|
admin_id,
|
||||||
|
wallet_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
RETURNING *;
|
||||||
|
-- name: GetAllCompanies :many
|
||||||
|
SELECT *
|
||||||
|
FROM companies;
|
||||||
|
-- name: GetCompanyByID :one
|
||||||
|
SELECT *
|
||||||
|
FROM companies
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: UpdateCompany :one
|
||||||
|
UPDATE companies
|
||||||
|
SET name = $1,
|
||||||
|
admin_id = $2
|
||||||
|
WHERE id = $3
|
||||||
|
RETURNING *;
|
||||||
|
-- name: DeleteCompany :exec
|
||||||
|
DELETE FROM companies
|
||||||
|
WHERE id = $1;
|
||||||
207
db/query/events.sql
Normal file
207
db/query/events.sql
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
-- name: InsertEvent :exec
|
||||||
|
INSERT INTO events (
|
||||||
|
id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
score,
|
||||||
|
match_minute,
|
||||||
|
timer_status,
|
||||||
|
added_time,
|
||||||
|
match_period,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15,
|
||||||
|
$16,
|
||||||
|
$17,
|
||||||
|
$18,
|
||||||
|
$19,
|
||||||
|
$20
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
|
match_name = EXCLUDED.match_name,
|
||||||
|
home_team = EXCLUDED.home_team,
|
||||||
|
away_team = EXCLUDED.away_team,
|
||||||
|
home_team_id = EXCLUDED.home_team_id,
|
||||||
|
away_team_id = EXCLUDED.away_team_id,
|
||||||
|
home_kit_image = EXCLUDED.home_kit_image,
|
||||||
|
away_kit_image = EXCLUDED.away_kit_image,
|
||||||
|
league_id = EXCLUDED.league_id,
|
||||||
|
league_name = EXCLUDED.league_name,
|
||||||
|
league_cc = EXCLUDED.league_cc,
|
||||||
|
start_time = EXCLUDED.start_time,
|
||||||
|
score = EXCLUDED.score,
|
||||||
|
match_minute = EXCLUDED.match_minute,
|
||||||
|
timer_status = EXCLUDED.timer_status,
|
||||||
|
added_time = EXCLUDED.added_time,
|
||||||
|
match_period = EXCLUDED.match_period,
|
||||||
|
is_live = EXCLUDED.is_live,
|
||||||
|
status = EXCLUDED.status,
|
||||||
|
fetched_at = now();
|
||||||
|
-- name: InsertUpcomingEvent :exec
|
||||||
|
INSERT INTO events (
|
||||||
|
id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
false,
|
||||||
|
'upcoming'
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
|
match_name = EXCLUDED.match_name,
|
||||||
|
home_team = EXCLUDED.home_team,
|
||||||
|
away_team = EXCLUDED.away_team,
|
||||||
|
home_team_id = EXCLUDED.home_team_id,
|
||||||
|
away_team_id = EXCLUDED.away_team_id,
|
||||||
|
home_kit_image = EXCLUDED.home_kit_image,
|
||||||
|
away_kit_image = EXCLUDED.away_kit_image,
|
||||||
|
league_id = EXCLUDED.league_id,
|
||||||
|
league_name = EXCLUDED.league_name,
|
||||||
|
league_cc = EXCLUDED.league_cc,
|
||||||
|
start_time = EXCLUDED.start_time,
|
||||||
|
is_live = false,
|
||||||
|
status = 'upcoming',
|
||||||
|
fetched_at = now();
|
||||||
|
-- name: ListLiveEvents :many
|
||||||
|
SELECT id
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = true;
|
||||||
|
-- name: GetAllUpcomingEvents :many
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
ORDER BY start_time ASC;
|
||||||
|
-- name: GetTotalEvents :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
AND (
|
||||||
|
league_id = $1
|
||||||
|
OR $1 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
sport_id = $2
|
||||||
|
OR $2 IS NULL
|
||||||
|
);
|
||||||
|
-- name: GetPaginatedUpcomingEvents :many
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
AND (
|
||||||
|
league_id = $3
|
||||||
|
OR $3 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
sport_id = $4
|
||||||
|
OR $4 IS NULL
|
||||||
|
)
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
LIMIT $1 OFFSET $2;
|
||||||
|
-- name: GetUpcomingByID :one
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE id = $1
|
||||||
|
AND is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
LIMIT 1;
|
||||||
121
db/query/odds.sql
Normal file
121
db/query/odds.sql
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
-- name: InsertNonLiveOdd :exec
|
||||||
|
INSERT INTO odds (
|
||||||
|
event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
is_active,
|
||||||
|
source,
|
||||||
|
fetched_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15
|
||||||
|
) ON CONFLICT (event_id, market_id) DO
|
||||||
|
UPDATE
|
||||||
|
SET odds_value = EXCLUDED.odds_value,
|
||||||
|
raw_odds = EXCLUDED.raw_odds,
|
||||||
|
market_type = EXCLUDED.market_type,
|
||||||
|
market_name = EXCLUDED.market_name,
|
||||||
|
market_category = EXCLUDED.market_category,
|
||||||
|
name = EXCLUDED.name,
|
||||||
|
handicap = EXCLUDED.handicap,
|
||||||
|
fetched_at = EXCLUDED.fetched_at,
|
||||||
|
is_active = EXCLUDED.is_active,
|
||||||
|
source = EXCLUDED.source,
|
||||||
|
fi = EXCLUDED.fi;
|
||||||
|
-- name: GetPrematchOdds :many
|
||||||
|
SELECT event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true
|
||||||
|
AND source = 'b365api';
|
||||||
|
-- name: GetALLPrematchOdds :many
|
||||||
|
SELECT event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true
|
||||||
|
AND source = 'b365api';
|
||||||
|
-- name: GetRawOddsByMarketID :one
|
||||||
|
SELECT id,
|
||||||
|
market_name,
|
||||||
|
handicap,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at
|
||||||
|
FROM odds
|
||||||
|
WHERE market_id = $1
|
||||||
|
AND fi = $2
|
||||||
|
AND is_active = true
|
||||||
|
AND source = 'b365api';
|
||||||
|
|
||||||
|
-- name: GetPrematchOddsByUpcomingID :many
|
||||||
|
SELECT o.event_id,
|
||||||
|
o.fi,
|
||||||
|
o.market_type,
|
||||||
|
o.market_name,
|
||||||
|
o.market_category,
|
||||||
|
o.market_id,
|
||||||
|
o.name,
|
||||||
|
o.handicap,
|
||||||
|
o.odds_value,
|
||||||
|
o.section,
|
||||||
|
o.category,
|
||||||
|
o.raw_odds,
|
||||||
|
o.fetched_at,
|
||||||
|
o.source,
|
||||||
|
o.is_active
|
||||||
|
FROM odds o
|
||||||
|
JOIN events e ON o.fi = e.id
|
||||||
|
WHERE e.id = $1
|
||||||
|
AND e.is_live = false
|
||||||
|
AND e.status = 'upcoming'
|
||||||
|
AND o.is_active = true
|
||||||
|
AND o.source = 'b365api'
|
||||||
|
LIMIT $2 OFFSET $3;
|
||||||
|
|
@ -2,15 +2,56 @@
|
||||||
INSERT INTO tickets (amount, total_odds)
|
INSERT INTO tickets (amount, total_odds)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
-- name: CreateTicketOutcome :copyfrom
|
||||||
|
INSERT INTO ticket_outcomes (
|
||||||
|
ticket_id,
|
||||||
|
event_id,
|
||||||
|
odd_id,
|
||||||
|
home_team_name,
|
||||||
|
away_team_name,
|
||||||
|
market_id,
|
||||||
|
market_name,
|
||||||
|
odd,
|
||||||
|
odd_name,
|
||||||
|
odd_header,
|
||||||
|
odd_handicap,
|
||||||
|
expires
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12
|
||||||
|
);
|
||||||
-- name: GetAllTickets :many
|
-- name: GetAllTickets :many
|
||||||
SELECT * FROM tickets;
|
SELECT *
|
||||||
|
FROM ticket_with_outcomes;
|
||||||
-- name: GetTicketByID :one
|
-- name: GetTicketByID :one
|
||||||
SELECT * FROM tickets WHERE id = $1;
|
SELECT *
|
||||||
|
FROM ticket_with_outcomes
|
||||||
|
WHERE id = $1;
|
||||||
|
-- name: GetTicketOutcome :many
|
||||||
|
SELECT *
|
||||||
|
FROM ticket_outcomes
|
||||||
|
WHERE ticket_id = $1;
|
||||||
|
-- name: UpdateTicketOutcomeStatus :exec
|
||||||
|
UPDATE ticket_outcomes
|
||||||
|
SET status = $1
|
||||||
|
WHERE id = $2;
|
||||||
-- name: DeleteTicket :exec
|
-- name: DeleteTicket :exec
|
||||||
DELETE FROM tickets WHERE id = $1;
|
DELETE FROM tickets
|
||||||
|
WHERE id = $1;
|
||||||
-- name: DeleteOldTickets :exec
|
-- name: DeleteOldTickets :exec
|
||||||
Delete from tickets where created_at < now() - interval '1 day';
|
Delete from tickets
|
||||||
|
where created_at < now() - interval '1 day';
|
||||||
|
-- name: DeleteTicketOutcome :exec
|
||||||
|
Delete from ticket_outcomes
|
||||||
|
where ticket_id = $1;
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
-- name: CreateTransaction :one
|
-- name: CreateTransaction :one
|
||||||
INSERT INTO transactions (amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING *;
|
INSERT INTO transactions (amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *;
|
||||||
|
|
||||||
-- name: GetAllTransactions :many
|
-- name: GetAllTransactions :many
|
||||||
SELECT * FROM transactions;
|
SELECT * FROM transactions;
|
||||||
|
|
@ -7,6 +7,9 @@ SELECT * FROM transactions;
|
||||||
-- name: GetTransactionByID :one
|
-- name: GetTransactionByID :one
|
||||||
SELECT * FROM transactions WHERE id = $1;
|
SELECT * FROM transactions WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: GetTransactionByBranch :many
|
||||||
|
SELECT * FROM transactions WHERE branch_id = $1;
|
||||||
|
|
||||||
-- name: UpdateTransactionVerified :exec
|
-- name: UpdateTransactionVerified :exec
|
||||||
UPDATE transactions SET verified = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1;
|
UPDATE transactions SET verified = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
-- name: CreateTransfer :one
|
-- name: CreateTransfer :one
|
||||||
INSERT INTO wallet_transfer (amount, wallet_transfer, wallet_id) VALUES ($1, $2, $3) RETURNING *;
|
INSERT INTO wallet_transfer (amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *;
|
||||||
|
|
||||||
-- name: GetAllTransfers :many
|
-- name: GetAllTransfers :many
|
||||||
SELECT * FROM wallet_transfer;
|
SELECT * FROM wallet_transfer;
|
||||||
|
|
||||||
-- name: GetTransfersByWallet :many
|
-- name: GetTransfersByWallet :many
|
||||||
SELECT * FROM wallet_transfer WHERE wallet_id = $1;
|
SELECT * FROM wallet_transfer WHERE receiver_wallet_id = $1 OR sender_wallet_id = $1;
|
||||||
|
|
||||||
-- name: GetTransferByID :one
|
-- name: GetTransferByID :one
|
||||||
SELECT * FROM wallet_transfer WHERE id = $1;
|
SELECT * FROM wallet_transfer WHERE id = $1;
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,114 @@
|
||||||
-- name: CreateUser :one
|
-- name: CreateUser :one
|
||||||
|
INSERT INTO users (
|
||||||
INSERT INTO users (first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at)
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
password,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||||
RETURNING id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at;
|
RETURNING id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at;
|
||||||
-- name: GetUserByID :one
|
-- name: GetUserByID :one
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: GetAllUsers :many
|
-- name: GetAllUsers :many
|
||||||
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
FROM users;
|
FROM users;
|
||||||
|
-- name: SearchUserByNameOrPhone :many
|
||||||
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM users
|
||||||
|
WHERE first_name ILIKE '%' || $1 || '%'
|
||||||
|
OR last_name ILIKE '%' || $1 || '%'
|
||||||
|
OR phone_number LIKE '%' || $1 || '%';
|
||||||
-- name: UpdateUser :exec
|
-- name: UpdateUser :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET first_name = $1, last_name = $2, email = $3, phone_number = $4, role = $5, updated_at = $6
|
SET first_name = $1,
|
||||||
|
last_name = $2,
|
||||||
|
email = $3,
|
||||||
|
phone_number = $4,
|
||||||
|
role = $5,
|
||||||
|
updated_at = $6
|
||||||
WHERE id = $7;
|
WHERE id = $7;
|
||||||
|
|
||||||
-- name: DeleteUser :exec
|
-- name: DeleteUser :exec
|
||||||
DELETE FROM users
|
DELETE FROM users
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: CheckPhoneEmailExist :one
|
-- name: CheckPhoneEmailExist :one
|
||||||
SELECT
|
SELECT EXISTS (
|
||||||
EXISTS (SELECT 1 FROM users WHERE users.phone_number = $1 AND users.phone_number IS NOT NULL) AS phone_exists,
|
SELECT 1
|
||||||
EXISTS (SELECT 1 FROM users WHERE users.email = $2 AND users.email IS NOT NULL) AS email_exists;
|
FROM users
|
||||||
|
WHERE users.phone_number = $1
|
||||||
|
AND users.phone_number IS NOT NULL
|
||||||
|
) AS phone_exists,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM users
|
||||||
|
WHERE users.email = $2
|
||||||
|
AND users.email IS NOT NULL
|
||||||
|
) AS email_exists;
|
||||||
-- name: GetUserByEmail :one
|
-- name: GetUserByEmail :one
|
||||||
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1;
|
WHERE email = $1;
|
||||||
|
|
||||||
-- name: GetUserByPhone :one
|
-- name: GetUserByPhone :one
|
||||||
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE phone_number = $1;
|
WHERE phone_number = $1;
|
||||||
|
|
||||||
-- name: UpdatePassword :exec
|
-- name: UpdatePassword :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET password = $1, updated_at = $4
|
SET password = $1,
|
||||||
WHERE (email = $2 OR phone_number = $3);
|
updated_at = $4
|
||||||
|
WHERE (
|
||||||
|
email = $2
|
||||||
|
OR phone_number = $3
|
||||||
|
);
|
||||||
|
|
@ -1,21 +1,34 @@
|
||||||
-- name: CreateWallet :one
|
-- name: CreateWallet :one
|
||||||
INSERT INTO wallets (is_withdraw, is_bettable, user_id) VALUES ($1, $2, $3) RETURNING *;
|
INSERT INTO wallets (
|
||||||
|
is_withdraw,
|
||||||
|
is_bettable,
|
||||||
|
is_transferable,
|
||||||
|
user_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
RETURNING *;
|
||||||
-- name: CreateCustomerWallet :one
|
-- name: CreateCustomerWallet :one
|
||||||
INSERT INTO customer_wallets (customer_id, company_id, regular_wallet_id, static_wallet_id) VALUES ($1, $2, $3, $4) RETURNING *;
|
INSERT INTO customer_wallets (
|
||||||
|
customer_id,
|
||||||
|
company_id,
|
||||||
|
regular_wallet_id,
|
||||||
|
static_wallet_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
RETURNING *;
|
||||||
-- name: GetAllWallets :many
|
-- name: GetAllWallets :many
|
||||||
SELECT * FROM wallets;
|
SELECT *
|
||||||
|
FROM wallets;
|
||||||
-- name: GetWalletByID :one
|
-- name: GetWalletByID :one
|
||||||
SELECT * FROM wallets WHERE id = $1;
|
SELECT *
|
||||||
|
FROM wallets
|
||||||
|
WHERE id = $1;
|
||||||
-- name: GetWalletByUserID :many
|
-- name: GetWalletByUserID :many
|
||||||
SELECT * FROM wallets WHERE user_id = $1;
|
SELECT *
|
||||||
|
FROM wallets
|
||||||
|
WHERE user_id = $1;
|
||||||
-- name: GetCustomerWallet :one
|
-- name: GetCustomerWallet :one
|
||||||
SELECT
|
SELECT cw.id,
|
||||||
cw.id,
|
|
||||||
cw.customer_id,
|
cw.customer_id,
|
||||||
cw.company_id,
|
cw.company_id,
|
||||||
rw.id AS regular_id,
|
rw.id AS regular_id,
|
||||||
|
|
@ -26,15 +39,30 @@ SELECT
|
||||||
sw.updated_at as static_updated_at,
|
sw.updated_at as static_updated_at,
|
||||||
cw.created_at
|
cw.created_at
|
||||||
FROM customer_wallets cw
|
FROM customer_wallets cw
|
||||||
JOIN wallets rw ON cw.regular_wallet_id = rw.id
|
JOIN wallets rw ON cw.regular_wallet_id = rw.id
|
||||||
JOIN wallets sw ON cw.static_wallet_id = sw.id
|
JOIN wallets sw ON cw.static_wallet_id = sw.id
|
||||||
WHERE cw.customer_id = $1 AND cw.company_id = $2;
|
WHERE cw.customer_id = $1
|
||||||
|
AND cw.company_id = $2;
|
||||||
|
-- name: GetAllBranchWallets :many
|
||||||
|
SELECT wallets.id,
|
||||||
|
wallets.balance,
|
||||||
|
wallets.is_active,
|
||||||
|
wallets.updated_at,
|
||||||
|
wallets.created_at,
|
||||||
|
branches.name,
|
||||||
|
branches.location,
|
||||||
|
branches.branch_manager_id,
|
||||||
|
branches.company_id,
|
||||||
|
branches.is_self_owned
|
||||||
|
FROM branches
|
||||||
|
JOIN wallets ON branches.wallet_id = wallets.id;
|
||||||
-- name: UpdateBalance :exec
|
-- name: UpdateBalance :exec
|
||||||
UPDATE wallets SET balance = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2;
|
UPDATE wallets
|
||||||
|
SET balance = $1,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $2;
|
||||||
-- name: UpdateWalletActive :exec
|
-- name: UpdateWalletActive :exec
|
||||||
UPDATE wallets SET is_active = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2;
|
UPDATE wallets
|
||||||
|
SET is_active = $1,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $2;
|
||||||
2413
docs/docs.go
2413
docs/docs.go
File diff suppressed because it is too large
Load Diff
2413
docs/swagger.json
2413
docs/swagger.json
File diff suppressed because it is too large
Load Diff
1635
docs/swagger.yaml
1635
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -17,11 +17,11 @@ VALUES ($1, $2, $3, $4, $5)
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateRefreshTokenParams struct {
|
type CreateRefreshTokenParams struct {
|
||||||
UserID int64
|
UserID int64 `json:"user_id"`
|
||||||
Token string
|
Token string `json:"token"`
|
||||||
ExpiresAt pgtype.Timestamptz
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
Revoked bool
|
Revoked bool `json:"revoked"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) error {
|
func (q *Queries) CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) error {
|
||||||
|
|
@ -60,8 +60,8 @@ WHERE email = $1 OR phone_number = $2
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetUserByEmailPhoneParams struct {
|
type GetUserByEmailPhoneParams struct {
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (User, error) {
|
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (User, error) {
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,31 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const CreateBet = `-- name: CreateBet :one
|
const CreateBet = `-- name: CreateBet :one
|
||||||
INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet)
|
INSERT INTO bets (
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
amount,
|
||||||
RETURNING id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, created_at, updated_at, is_shop_bet
|
total_odds,
|
||||||
|
status,
|
||||||
|
full_name,
|
||||||
|
phone_number,
|
||||||
|
branch_id,
|
||||||
|
user_id,
|
||||||
|
is_shop_bet,
|
||||||
|
cashout_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
|
RETURNING id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateBetParams struct {
|
type CreateBetParams struct {
|
||||||
Amount int64
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32
|
TotalOdds float32 `json:"total_odds"`
|
||||||
Status int32
|
Status int32 `json:"status"`
|
||||||
FullName string
|
FullName string `json:"full_name"`
|
||||||
PhoneNumber string
|
PhoneNumber string `json:"phone_number"`
|
||||||
BranchID pgtype.Int8
|
BranchID pgtype.Int8 `json:"branch_id"`
|
||||||
UserID pgtype.Int8
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
IsShopBet bool
|
IsShopBet bool `json:"is_shop_bet"`
|
||||||
|
CashoutID string `json:"cashout_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, error) {
|
func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, error) {
|
||||||
|
|
@ -38,6 +49,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro
|
||||||
arg.BranchID,
|
arg.BranchID,
|
||||||
arg.UserID,
|
arg.UserID,
|
||||||
arg.IsShopBet,
|
arg.IsShopBet,
|
||||||
|
arg.CashoutID,
|
||||||
)
|
)
|
||||||
var i Bet
|
var i Bet
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -50,6 +62,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CashedOut,
|
&i.CashedOut,
|
||||||
|
&i.CashoutID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.IsShopBet,
|
&i.IsShopBet,
|
||||||
|
|
@ -57,8 +70,24 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateBetOutcomeParams struct {
|
||||||
|
BetID int64 `json:"bet_id"`
|
||||||
|
EventID int64 `json:"event_id"`
|
||||||
|
OddID int64 `json:"odd_id"`
|
||||||
|
HomeTeamName string `json:"home_team_name"`
|
||||||
|
AwayTeamName string `json:"away_team_name"`
|
||||||
|
MarketID int64 `json:"market_id"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
Odd float32 `json:"odd"`
|
||||||
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
|
}
|
||||||
|
|
||||||
const DeleteBet = `-- name: DeleteBet :exec
|
const DeleteBet = `-- name: DeleteBet :exec
|
||||||
DELETE FROM bets WHERE id = $1
|
DELETE FROM bets
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeleteBet(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteBet(ctx context.Context, id int64) error {
|
||||||
|
|
@ -66,19 +95,30 @@ func (q *Queries) DeleteBet(ctx context.Context, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllBets = `-- name: GetAllBets :many
|
const DeleteBetOutcome = `-- name: DeleteBetOutcome :exec
|
||||||
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, created_at, updated_at, is_shop_bet FROM bets
|
DELETE FROM bet_outcomes
|
||||||
|
WHERE bet_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) {
|
func (q *Queries) DeleteBetOutcome(ctx context.Context, betID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteBetOutcome, betID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllBets = `-- name: GetAllBets :many
|
||||||
|
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllBets(ctx context.Context) ([]BetWithOutcome, error) {
|
||||||
rows, err := q.db.Query(ctx, GetAllBets)
|
rows, err := q.db.Query(ctx, GetAllBets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []Bet
|
var items []BetWithOutcome
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i Bet
|
var i BetWithOutcome
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
|
|
@ -89,9 +129,11 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) {
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CashedOut,
|
&i.CashedOut,
|
||||||
|
&i.CashoutID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.IsShopBet,
|
&i.IsShopBet,
|
||||||
|
&i.Outcomes,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -103,13 +145,56 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) {
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetBetByID = `-- name: GetBetByID :one
|
const GetBetByBranchID = `-- name: GetBetByBranchID :many
|
||||||
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, created_at, updated_at, is_shop_bet FROM bets WHERE id = $1
|
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE branch_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetBetByID(ctx context.Context, id int64) (Bet, error) {
|
func (q *Queries) GetBetByBranchID(ctx context.Context, branchID pgtype.Int8) ([]BetWithOutcome, error) {
|
||||||
row := q.db.QueryRow(ctx, GetBetByID, id)
|
rows, err := q.db.Query(ctx, GetBetByBranchID, branchID)
|
||||||
var i Bet
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BetWithOutcome
|
||||||
|
for rows.Next() {
|
||||||
|
var i BetWithOutcome
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Amount,
|
||||||
|
&i.TotalOdds,
|
||||||
|
&i.Status,
|
||||||
|
&i.FullName,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.BranchID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.CashedOut,
|
||||||
|
&i.CashoutID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.IsShopBet,
|
||||||
|
&i.Outcomes,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetBetByCashoutID = `-- name: GetBetByCashoutID :one
|
||||||
|
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE cashout_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBetByCashoutID(ctx context.Context, cashoutID string) (BetWithOutcome, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetBetByCashoutID, cashoutID)
|
||||||
|
var i BetWithOutcome
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
|
|
@ -120,23 +205,89 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (Bet, error) {
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CashedOut,
|
&i.CashedOut,
|
||||||
|
&i.CashoutID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.IsShopBet,
|
&i.IsShopBet,
|
||||||
|
&i.Outcomes,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetBetByID = `-- name: GetBetByID :one
|
||||||
|
SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes
|
||||||
|
FROM bet_with_outcomes
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetBetByID, id)
|
||||||
|
var i BetWithOutcome
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Amount,
|
||||||
|
&i.TotalOdds,
|
||||||
|
&i.Status,
|
||||||
|
&i.FullName,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.BranchID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.CashedOut,
|
||||||
|
&i.CashoutID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.IsShopBet,
|
||||||
|
&i.Outcomes,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :exec
|
||||||
|
UPDATE bet_outcomes
|
||||||
|
SET status = $1
|
||||||
|
WHERE id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateBetOutcomeStatusParams struct {
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateBetOutcomeStatus(ctx context.Context, arg UpdateBetOutcomeStatusParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateBetOutcomeStatus, arg.Status, arg.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const UpdateCashOut = `-- name: UpdateCashOut :exec
|
const UpdateCashOut = `-- name: UpdateCashOut :exec
|
||||||
UPDATE bets SET cashed_out = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1
|
UPDATE bets
|
||||||
|
SET cashed_out = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateCashOutParams struct {
|
type UpdateCashOutParams struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
CashedOut pgtype.Bool
|
CashedOut bool `json:"cashed_out"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateCashOut(ctx context.Context, arg UpdateCashOutParams) error {
|
func (q *Queries) UpdateCashOut(ctx context.Context, arg UpdateCashOutParams) error {
|
||||||
_, err := q.db.Exec(ctx, UpdateCashOut, arg.ID, arg.CashedOut)
|
_, err := q.db.Exec(ctx, UpdateCashOut, arg.ID, arg.CashedOut)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateStatus = `-- name: UpdateStatus :exec
|
||||||
|
UPDATE bets
|
||||||
|
SET status = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateStatusParams struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateStatus(ctx context.Context, arg UpdateStatusParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateStatus, arg.ID, arg.Status)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
551
gen/db/branch.sql.go
Normal file
551
gen/db/branch.sql.go
Normal file
|
|
@ -0,0 +1,551 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
// source: branch.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CreateBranch = `-- name: CreateBranch :one
|
||||||
|
INSERT INTO branches (
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
wallet_id,
|
||||||
|
branch_manager_id,
|
||||||
|
company_id,
|
||||||
|
is_self_owned
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateBranchParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
WalletID int64 `json:"wallet_id"`
|
||||||
|
BranchManagerID int64 `json:"branch_manager_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
IsSelfOwned bool `json:"is_self_owned"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateBranch(ctx context.Context, arg CreateBranchParams) (Branch, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateBranch,
|
||||||
|
arg.Name,
|
||||||
|
arg.Location,
|
||||||
|
arg.WalletID,
|
||||||
|
arg.BranchManagerID,
|
||||||
|
arg.CompanyID,
|
||||||
|
arg.IsSelfOwned,
|
||||||
|
)
|
||||||
|
var i Branch
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateBranchCashier = `-- name: CreateBranchCashier :one
|
||||||
|
INSERT INTO branch_cashiers (user_id, branch_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING id, user_id, branch_id
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateBranchCashierParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
BranchID int64 `json:"branch_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateBranchCashier(ctx context.Context, arg CreateBranchCashierParams) (BranchCashier, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateBranchCashier, arg.UserID, arg.BranchID)
|
||||||
|
var i BranchCashier
|
||||||
|
err := row.Scan(&i.ID, &i.UserID, &i.BranchID)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateBranchOperation = `-- name: CreateBranchOperation :one
|
||||||
|
INSERT INTO branch_operations (operation_id, branch_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING id, operation_id, branch_id, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateBranchOperationParams struct {
|
||||||
|
OperationID int64 `json:"operation_id"`
|
||||||
|
BranchID int64 `json:"branch_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateBranchOperation(ctx context.Context, arg CreateBranchOperationParams) (BranchOperation, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateBranchOperation, arg.OperationID, arg.BranchID)
|
||||||
|
var i BranchOperation
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.OperationID,
|
||||||
|
&i.BranchID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateSupportedOperation = `-- name: CreateSupportedOperation :one
|
||||||
|
INSERT INTO supported_operations (name, description)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING id, name, description
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateSupportedOperationParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateSupportedOperation(ctx context.Context, arg CreateSupportedOperationParams) (SupportedOperation, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateSupportedOperation, arg.Name, arg.Description)
|
||||||
|
var i SupportedOperation
|
||||||
|
err := row.Scan(&i.ID, &i.Name, &i.Description)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteBranch = `-- name: DeleteBranch :exec
|
||||||
|
DELETE FROM branches
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteBranch(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteBranch, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteBranchCashier = `-- name: DeleteBranchCashier :exec
|
||||||
|
DELETE FROM branch_cashiers
|
||||||
|
WHERE user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteBranchCashier(ctx context.Context, userID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteBranchCashier, userID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteBranchOperation = `-- name: DeleteBranchOperation :exec
|
||||||
|
DELETE FROM branch_operations
|
||||||
|
WHERE operation_id = $1
|
||||||
|
AND branch_id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type DeleteBranchOperationParams struct {
|
||||||
|
OperationID int64 `json:"operation_id"`
|
||||||
|
BranchID int64 `json:"branch_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) DeleteBranchOperation(ctx context.Context, arg DeleteBranchOperationParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteBranchOperation, arg.OperationID, arg.BranchID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllBranches = `-- name: GetAllBranches :many
|
||||||
|
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
||||||
|
FROM branch_details
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllBranches(ctx context.Context) ([]BranchDetail, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllBranches)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BranchDetail
|
||||||
|
for rows.Next() {
|
||||||
|
var i BranchDetail
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.ManagerName,
|
||||||
|
&i.ManagerPhoneNumber,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllCashiers = `-- name: GetAllCashiers :many
|
||||||
|
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.suspended_at, users.suspended
|
||||||
|
FROM branch_cashiers
|
||||||
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllCashiers(ctx context.Context) ([]User, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllCashiers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []User
|
||||||
|
for rows.Next() {
|
||||||
|
var i User
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
|
&i.Email,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.Role,
|
||||||
|
&i.Password,
|
||||||
|
&i.EmailVerified,
|
||||||
|
&i.PhoneVerified,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.SuspendedAt,
|
||||||
|
&i.Suspended,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllSupportedOperations = `-- name: GetAllSupportedOperations :many
|
||||||
|
SELECT id, name, description
|
||||||
|
FROM supported_operations
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllSupportedOperations(ctx context.Context) ([]SupportedOperation, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllSupportedOperations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SupportedOperation
|
||||||
|
for rows.Next() {
|
||||||
|
var i SupportedOperation
|
||||||
|
if err := rows.Scan(&i.ID, &i.Name, &i.Description); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetBranchByCashier = `-- name: GetBranchByCashier :one
|
||||||
|
SELECT branches.id, branches.name, branches.location, branches.wallet_id, branches.branch_manager_id, branches.company_id, branches.is_self_owned, branches.created_at, branches.updated_at
|
||||||
|
FROM branch_cashiers
|
||||||
|
JOIN branches ON branch_cashiers.branch_id = branches.id
|
||||||
|
WHERE branch_cashiers.user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBranchByCashier(ctx context.Context, userID int64) (Branch, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetBranchByCashier, userID)
|
||||||
|
var i Branch
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetBranchByCompanyID = `-- name: GetBranchByCompanyID :many
|
||||||
|
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
||||||
|
FROM branch_details
|
||||||
|
WHERE company_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]BranchDetail, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetBranchByCompanyID, companyID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BranchDetail
|
||||||
|
for rows.Next() {
|
||||||
|
var i BranchDetail
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.ManagerName,
|
||||||
|
&i.ManagerPhoneNumber,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetBranchByID = `-- name: GetBranchByID :one
|
||||||
|
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
||||||
|
FROM branch_details
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBranchByID(ctx context.Context, id int64) (BranchDetail, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetBranchByID, id)
|
||||||
|
var i BranchDetail
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.ManagerName,
|
||||||
|
&i.ManagerPhoneNumber,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetBranchByManagerID = `-- name: GetBranchByManagerID :many
|
||||||
|
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
||||||
|
FROM branch_details
|
||||||
|
WHERE branch_manager_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]BranchDetail, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetBranchByManagerID, branchManagerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BranchDetail
|
||||||
|
for rows.Next() {
|
||||||
|
var i BranchDetail
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.ManagerName,
|
||||||
|
&i.ManagerPhoneNumber,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetBranchOperations = `-- name: GetBranchOperations :many
|
||||||
|
SELECT branch_operations.id, branch_operations.operation_id, branch_operations.branch_id, branch_operations.created_at, branch_operations.updated_at,
|
||||||
|
supported_operations.name,
|
||||||
|
supported_operations.description
|
||||||
|
FROM branch_operations
|
||||||
|
JOIN supported_operations ON branch_operations.operation_id = supported_operations.id
|
||||||
|
WHERE branch_operations.branch_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetBranchOperationsRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
OperationID int64 `json:"operation_id"`
|
||||||
|
BranchID int64 `json:"branch_id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetBranchOperations(ctx context.Context, branchID int64) ([]GetBranchOperationsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetBranchOperations, branchID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetBranchOperationsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetBranchOperationsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.OperationID,
|
||||||
|
&i.BranchID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.Name,
|
||||||
|
&i.Description,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetCashiersByBranch = `-- name: GetCashiersByBranch :many
|
||||||
|
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.suspended_at, users.suspended
|
||||||
|
FROM branch_cashiers
|
||||||
|
JOIN users ON branch_cashiers.user_id = users.id
|
||||||
|
WHERE branch_cashiers.branch_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetCashiersByBranch(ctx context.Context, branchID int64) ([]User, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetCashiersByBranch, branchID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []User
|
||||||
|
for rows.Next() {
|
||||||
|
var i User
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
|
&i.Email,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.Role,
|
||||||
|
&i.Password,
|
||||||
|
&i.EmailVerified,
|
||||||
|
&i.PhoneVerified,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.SuspendedAt,
|
||||||
|
&i.Suspended,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const SearchBranchByName = `-- name: SearchBranchByName :many
|
||||||
|
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
|
||||||
|
FROM branch_details
|
||||||
|
WHERE name ILIKE '%' || $1 || '%'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) SearchBranchByName(ctx context.Context, dollar_1 pgtype.Text) ([]BranchDetail, error) {
|
||||||
|
rows, err := q.db.Query(ctx, SearchBranchByName, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BranchDetail
|
||||||
|
for rows.Next() {
|
||||||
|
var i BranchDetail
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.ManagerName,
|
||||||
|
&i.ManagerPhoneNumber,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateBranch = `-- name: UpdateBranch :one
|
||||||
|
UPDATE branches
|
||||||
|
SET name = $1,
|
||||||
|
location = $2,
|
||||||
|
branch_manager_id = $3,
|
||||||
|
company_id = $4,
|
||||||
|
is_self_owned = $5
|
||||||
|
WHERE id = $6
|
||||||
|
RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateBranchParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
BranchManagerID int64 `json:"branch_manager_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
IsSelfOwned bool `json:"is_self_owned"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateBranch(ctx context.Context, arg UpdateBranchParams) (Branch, error) {
|
||||||
|
row := q.db.QueryRow(ctx, UpdateBranch,
|
||||||
|
arg.Name,
|
||||||
|
arg.Location,
|
||||||
|
arg.BranchManagerID,
|
||||||
|
arg.CompanyID,
|
||||||
|
arg.IsSelfOwned,
|
||||||
|
arg.ID,
|
||||||
|
)
|
||||||
|
var i Branch
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.WalletID,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
122
gen/db/company.sql.go
Normal file
122
gen/db/company.sql.go
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
// source: company.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CreateCompany = `-- name: CreateCompany :one
|
||||||
|
INSERT INTO companies (
|
||||||
|
name,
|
||||||
|
admin_id,
|
||||||
|
wallet_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
RETURNING id, name, admin_id, wallet_id
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateCompanyParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
AdminID int64 `json:"admin_id"`
|
||||||
|
WalletID int64 `json:"wallet_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Company, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateCompany, arg.Name, arg.AdminID, arg.WalletID)
|
||||||
|
var i Company
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.AdminID,
|
||||||
|
&i.WalletID,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteCompany = `-- name: DeleteCompany :exec
|
||||||
|
DELETE FROM companies
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteCompany(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteCompany, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllCompanies = `-- name: GetAllCompanies :many
|
||||||
|
SELECT id, name, admin_id, wallet_id
|
||||||
|
FROM companies
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllCompanies(ctx context.Context) ([]Company, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllCompanies)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Company
|
||||||
|
for rows.Next() {
|
||||||
|
var i Company
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.AdminID,
|
||||||
|
&i.WalletID,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetCompanyByID = `-- name: GetCompanyByID :one
|
||||||
|
SELECT id, name, admin_id, wallet_id
|
||||||
|
FROM companies
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (Company, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetCompanyByID, id)
|
||||||
|
var i Company
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.AdminID,
|
||||||
|
&i.WalletID,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateCompany = `-- name: UpdateCompany :one
|
||||||
|
UPDATE companies
|
||||||
|
SET name = $1,
|
||||||
|
admin_id = $2
|
||||||
|
WHERE id = $3
|
||||||
|
RETURNING id, name, admin_id, wallet_id
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateCompanyParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
AdminID int64 `json:"admin_id"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (Company, error) {
|
||||||
|
row := q.db.QueryRow(ctx, UpdateCompany, arg.Name, arg.AdminID, arg.ID)
|
||||||
|
var i Company
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.AdminID,
|
||||||
|
&i.WalletID,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
96
gen/db/copyfrom.go
Normal file
96
gen/db/copyfrom.go
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
// source: copyfrom.go
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// iteratorForCreateBetOutcome implements pgx.CopyFromSource.
|
||||||
|
type iteratorForCreateBetOutcome struct {
|
||||||
|
rows []CreateBetOutcomeParams
|
||||||
|
skippedFirstNextCall bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *iteratorForCreateBetOutcome) Next() bool {
|
||||||
|
if len(r.rows) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !r.skippedFirstNextCall {
|
||||||
|
r.skippedFirstNextCall = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
r.rows = r.rows[1:]
|
||||||
|
return len(r.rows) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r iteratorForCreateBetOutcome) Values() ([]interface{}, error) {
|
||||||
|
return []interface{}{
|
||||||
|
r.rows[0].BetID,
|
||||||
|
r.rows[0].EventID,
|
||||||
|
r.rows[0].OddID,
|
||||||
|
r.rows[0].HomeTeamName,
|
||||||
|
r.rows[0].AwayTeamName,
|
||||||
|
r.rows[0].MarketID,
|
||||||
|
r.rows[0].MarketName,
|
||||||
|
r.rows[0].Odd,
|
||||||
|
r.rows[0].OddName,
|
||||||
|
r.rows[0].OddHeader,
|
||||||
|
r.rows[0].OddHandicap,
|
||||||
|
r.rows[0].Expires,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r iteratorForCreateBetOutcome) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateBetOutcome(ctx context.Context, arg []CreateBetOutcomeParams) (int64, error) {
|
||||||
|
return q.db.CopyFrom(ctx, []string{"bet_outcomes"}, []string{"bet_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "odd_header", "odd_handicap", "expires"}, &iteratorForCreateBetOutcome{rows: arg})
|
||||||
|
}
|
||||||
|
|
||||||
|
// iteratorForCreateTicketOutcome implements pgx.CopyFromSource.
|
||||||
|
type iteratorForCreateTicketOutcome struct {
|
||||||
|
rows []CreateTicketOutcomeParams
|
||||||
|
skippedFirstNextCall bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *iteratorForCreateTicketOutcome) Next() bool {
|
||||||
|
if len(r.rows) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !r.skippedFirstNextCall {
|
||||||
|
r.skippedFirstNextCall = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
r.rows = r.rows[1:]
|
||||||
|
return len(r.rows) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r iteratorForCreateTicketOutcome) Values() ([]interface{}, error) {
|
||||||
|
return []interface{}{
|
||||||
|
r.rows[0].TicketID,
|
||||||
|
r.rows[0].EventID,
|
||||||
|
r.rows[0].OddID,
|
||||||
|
r.rows[0].HomeTeamName,
|
||||||
|
r.rows[0].AwayTeamName,
|
||||||
|
r.rows[0].MarketID,
|
||||||
|
r.rows[0].MarketName,
|
||||||
|
r.rows[0].Odd,
|
||||||
|
r.rows[0].OddName,
|
||||||
|
r.rows[0].OddHeader,
|
||||||
|
r.rows[0].OddHandicap,
|
||||||
|
r.rows[0].Expires,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r iteratorForCreateTicketOutcome) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateTicketOutcome(ctx context.Context, arg []CreateTicketOutcomeParams) (int64, error) {
|
||||||
|
return q.db.CopyFrom(ctx, []string{"ticket_outcomes"}, []string{"ticket_id", "event_id", "odd_id", "home_team_name", "away_team_name", "market_id", "market_name", "odd", "odd_name", "odd_header", "odd_handicap", "expires"}, &iteratorForCreateTicketOutcome{rows: arg})
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ type DBTX interface {
|
||||||
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
||||||
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
||||||
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
||||||
|
CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(db DBTX) *Queries {
|
func New(db DBTX) *Queries {
|
||||||
|
|
|
||||||
516
gen/db/events.sql.go
Normal file
516
gen/db/events.sql.go
Normal file
|
|
@ -0,0 +1,516 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
// source: events.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GetAllUpcomingEvents = `-- name: GetAllUpcomingEvents :many
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetAllUpcomingEventsRow struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]GetAllUpcomingEventsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllUpcomingEvents)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetAllUpcomingEventsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetAllUpcomingEventsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.SportID,
|
||||||
|
&i.MatchName,
|
||||||
|
&i.HomeTeam,
|
||||||
|
&i.AwayTeam,
|
||||||
|
&i.HomeTeamID,
|
||||||
|
&i.AwayTeamID,
|
||||||
|
&i.HomeKitImage,
|
||||||
|
&i.AwayKitImage,
|
||||||
|
&i.LeagueID,
|
||||||
|
&i.LeagueName,
|
||||||
|
&i.LeagueCc,
|
||||||
|
&i.StartTime,
|
||||||
|
&i.IsLive,
|
||||||
|
&i.Status,
|
||||||
|
&i.FetchedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetPaginatedUpcomingEvents = `-- name: GetPaginatedUpcomingEvents :many
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
AND (
|
||||||
|
league_id = $3
|
||||||
|
OR $3 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
sport_id = $4
|
||||||
|
OR $4 IS NULL
|
||||||
|
)
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
LIMIT $1 OFFSET $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetPaginatedUpcomingEventsParams struct {
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetPaginatedUpcomingEventsRow struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginatedUpcomingEventsParams) ([]GetPaginatedUpcomingEventsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetPaginatedUpcomingEvents,
|
||||||
|
arg.Limit,
|
||||||
|
arg.Offset,
|
||||||
|
arg.LeagueID,
|
||||||
|
arg.SportID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetPaginatedUpcomingEventsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetPaginatedUpcomingEventsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.SportID,
|
||||||
|
&i.MatchName,
|
||||||
|
&i.HomeTeam,
|
||||||
|
&i.AwayTeam,
|
||||||
|
&i.HomeTeamID,
|
||||||
|
&i.AwayTeamID,
|
||||||
|
&i.HomeKitImage,
|
||||||
|
&i.AwayKitImage,
|
||||||
|
&i.LeagueID,
|
||||||
|
&i.LeagueName,
|
||||||
|
&i.LeagueCc,
|
||||||
|
&i.StartTime,
|
||||||
|
&i.IsLive,
|
||||||
|
&i.Status,
|
||||||
|
&i.FetchedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetTotalEvents = `-- name: GetTotalEvents :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
AND (
|
||||||
|
league_id = $1
|
||||||
|
OR $1 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
sport_id = $2
|
||||||
|
OR $2 IS NULL
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetTotalEventsParams struct {
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetTotalEvents(ctx context.Context, arg GetTotalEventsParams) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetTotalEvents, arg.LeagueID, arg.SportID)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetUpcomingByID = `-- name: GetUpcomingByID :one
|
||||||
|
SELECT id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status,
|
||||||
|
fetched_at
|
||||||
|
FROM events
|
||||||
|
WHERE id = $1
|
||||||
|
AND is_live = false
|
||||||
|
AND status = 'upcoming'
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetUpcomingByIDRow struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetUpcomingByID(ctx context.Context, id string) (GetUpcomingByIDRow, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetUpcomingByID, id)
|
||||||
|
var i GetUpcomingByIDRow
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.SportID,
|
||||||
|
&i.MatchName,
|
||||||
|
&i.HomeTeam,
|
||||||
|
&i.AwayTeam,
|
||||||
|
&i.HomeTeamID,
|
||||||
|
&i.AwayTeamID,
|
||||||
|
&i.HomeKitImage,
|
||||||
|
&i.AwayKitImage,
|
||||||
|
&i.LeagueID,
|
||||||
|
&i.LeagueName,
|
||||||
|
&i.LeagueCc,
|
||||||
|
&i.StartTime,
|
||||||
|
&i.IsLive,
|
||||||
|
&i.Status,
|
||||||
|
&i.FetchedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const InsertEvent = `-- name: InsertEvent :exec
|
||||||
|
INSERT INTO events (
|
||||||
|
id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
score,
|
||||||
|
match_minute,
|
||||||
|
timer_status,
|
||||||
|
added_time,
|
||||||
|
match_period,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15,
|
||||||
|
$16,
|
||||||
|
$17,
|
||||||
|
$18,
|
||||||
|
$19,
|
||||||
|
$20
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
|
match_name = EXCLUDED.match_name,
|
||||||
|
home_team = EXCLUDED.home_team,
|
||||||
|
away_team = EXCLUDED.away_team,
|
||||||
|
home_team_id = EXCLUDED.home_team_id,
|
||||||
|
away_team_id = EXCLUDED.away_team_id,
|
||||||
|
home_kit_image = EXCLUDED.home_kit_image,
|
||||||
|
away_kit_image = EXCLUDED.away_kit_image,
|
||||||
|
league_id = EXCLUDED.league_id,
|
||||||
|
league_name = EXCLUDED.league_name,
|
||||||
|
league_cc = EXCLUDED.league_cc,
|
||||||
|
start_time = EXCLUDED.start_time,
|
||||||
|
score = EXCLUDED.score,
|
||||||
|
match_minute = EXCLUDED.match_minute,
|
||||||
|
timer_status = EXCLUDED.timer_status,
|
||||||
|
added_time = EXCLUDED.added_time,
|
||||||
|
match_period = EXCLUDED.match_period,
|
||||||
|
is_live = EXCLUDED.is_live,
|
||||||
|
status = EXCLUDED.status,
|
||||||
|
fetched_at = now()
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertEventParams struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
Score pgtype.Text `json:"score"`
|
||||||
|
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||||
|
TimerStatus pgtype.Text `json:"timer_status"`
|
||||||
|
AddedTime pgtype.Int4 `json:"added_time"`
|
||||||
|
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||||
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, InsertEvent,
|
||||||
|
arg.ID,
|
||||||
|
arg.SportID,
|
||||||
|
arg.MatchName,
|
||||||
|
arg.HomeTeam,
|
||||||
|
arg.AwayTeam,
|
||||||
|
arg.HomeTeamID,
|
||||||
|
arg.AwayTeamID,
|
||||||
|
arg.HomeKitImage,
|
||||||
|
arg.AwayKitImage,
|
||||||
|
arg.LeagueID,
|
||||||
|
arg.LeagueName,
|
||||||
|
arg.LeagueCc,
|
||||||
|
arg.StartTime,
|
||||||
|
arg.Score,
|
||||||
|
arg.MatchMinute,
|
||||||
|
arg.TimerStatus,
|
||||||
|
arg.AddedTime,
|
||||||
|
arg.MatchPeriod,
|
||||||
|
arg.IsLive,
|
||||||
|
arg.Status,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const InsertUpcomingEvent = `-- name: InsertUpcomingEvent :exec
|
||||||
|
INSERT INTO events (
|
||||||
|
id,
|
||||||
|
sport_id,
|
||||||
|
match_name,
|
||||||
|
home_team,
|
||||||
|
away_team,
|
||||||
|
home_team_id,
|
||||||
|
away_team_id,
|
||||||
|
home_kit_image,
|
||||||
|
away_kit_image,
|
||||||
|
league_id,
|
||||||
|
league_name,
|
||||||
|
league_cc,
|
||||||
|
start_time,
|
||||||
|
is_live,
|
||||||
|
status
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
false,
|
||||||
|
'upcoming'
|
||||||
|
) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET sport_id = EXCLUDED.sport_id,
|
||||||
|
match_name = EXCLUDED.match_name,
|
||||||
|
home_team = EXCLUDED.home_team,
|
||||||
|
away_team = EXCLUDED.away_team,
|
||||||
|
home_team_id = EXCLUDED.home_team_id,
|
||||||
|
away_team_id = EXCLUDED.away_team_id,
|
||||||
|
home_kit_image = EXCLUDED.home_kit_image,
|
||||||
|
away_kit_image = EXCLUDED.away_kit_image,
|
||||||
|
league_id = EXCLUDED.league_id,
|
||||||
|
league_name = EXCLUDED.league_name,
|
||||||
|
league_cc = EXCLUDED.league_cc,
|
||||||
|
start_time = EXCLUDED.start_time,
|
||||||
|
is_live = false,
|
||||||
|
status = 'upcoming',
|
||||||
|
fetched_at = now()
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertUpcomingEventParams struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertUpcomingEvent(ctx context.Context, arg InsertUpcomingEventParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, InsertUpcomingEvent,
|
||||||
|
arg.ID,
|
||||||
|
arg.SportID,
|
||||||
|
arg.MatchName,
|
||||||
|
arg.HomeTeam,
|
||||||
|
arg.AwayTeam,
|
||||||
|
arg.HomeTeamID,
|
||||||
|
arg.AwayTeamID,
|
||||||
|
arg.HomeKitImage,
|
||||||
|
arg.AwayKitImage,
|
||||||
|
arg.LeagueID,
|
||||||
|
arg.LeagueName,
|
||||||
|
arg.LeagueCc,
|
||||||
|
arg.StartTime,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListLiveEvents = `-- name: ListLiveEvents :many
|
||||||
|
SELECT id
|
||||||
|
FROM events
|
||||||
|
WHERE is_live = true
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
|
||||||
|
rows, err := q.db.Query(ctx, ListLiveEvents)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []string
|
||||||
|
for rows.Next() {
|
||||||
|
var id string
|
||||||
|
if err := rows.Scan(&id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, id)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
382
gen/db/models.go
382
gen/db/models.go
|
|
@ -56,57 +56,208 @@ func (ns NullReferralstatus) Value() (driver.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bet struct {
|
type Bet struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Amount int64
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32
|
TotalOdds float32 `json:"total_odds"`
|
||||||
Status int32
|
Status int32 `json:"status"`
|
||||||
FullName string
|
FullName string `json:"full_name"`
|
||||||
PhoneNumber string
|
PhoneNumber string `json:"phone_number"`
|
||||||
BranchID pgtype.Int8
|
BranchID pgtype.Int8 `json:"branch_id"`
|
||||||
UserID pgtype.Int8
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
CashedOut pgtype.Bool
|
CashedOut bool `json:"cashed_out"`
|
||||||
CreatedAt pgtype.Timestamp
|
CashoutID string `json:"cashout_id"`
|
||||||
UpdatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
IsShopBet bool
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
IsShopBet bool `json:"is_shop_bet"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BetOutcome struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
BetID int64 `json:"bet_id"`
|
||||||
|
EventID int64 `json:"event_id"`
|
||||||
|
OddID int64 `json:"odd_id"`
|
||||||
|
HomeTeamName string `json:"home_team_name"`
|
||||||
|
AwayTeamName string `json:"away_team_name"`
|
||||||
|
MarketID int64 `json:"market_id"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
Odd float32 `json:"odd"`
|
||||||
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BetWithOutcome struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
TotalOdds float32 `json:"total_odds"`
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
BranchID pgtype.Int8 `json:"branch_id"`
|
||||||
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
|
CashedOut bool `json:"cashed_out"`
|
||||||
|
CashoutID string `json:"cashout_id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
IsShopBet bool `json:"is_shop_bet"`
|
||||||
|
Outcomes []BetOutcome `json:"outcomes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Branch struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
WalletID int64 `json:"wallet_id"`
|
||||||
|
BranchManagerID int64 `json:"branch_manager_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
IsSelfOwned bool `json:"is_self_owned"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BranchCashier struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
BranchID int64 `json:"branch_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BranchDetail struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
WalletID int64 `json:"wallet_id"`
|
||||||
|
BranchManagerID int64 `json:"branch_manager_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
IsSelfOwned bool `json:"is_self_owned"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
ManagerName interface{} `json:"manager_name"`
|
||||||
|
ManagerPhoneNumber pgtype.Text `json:"manager_phone_number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BranchOperation struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
OperationID int64 `json:"operation_id"`
|
||||||
|
BranchID int64 `json:"branch_id"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Company struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
AdminID int64 `json:"admin_id"`
|
||||||
|
WalletID int64 `json:"wallet_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomerWallet struct {
|
type CustomerWallet struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
CustomerID int64
|
CustomerID int64 `json:"customer_id"`
|
||||||
CompanyID int64
|
CompanyID int64 `json:"company_id"`
|
||||||
RegularWalletID int64
|
RegularWalletID int64 `json:"regular_wallet_id"`
|
||||||
StaticWalletID int64
|
StaticWalletID int64 `json:"static_wallet_id"`
|
||||||
CreatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamp
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID pgtype.Text `json:"sport_id"`
|
||||||
|
MatchName pgtype.Text `json:"match_name"`
|
||||||
|
HomeTeam pgtype.Text `json:"home_team"`
|
||||||
|
AwayTeam pgtype.Text `json:"away_team"`
|
||||||
|
HomeTeamID pgtype.Text `json:"home_team_id"`
|
||||||
|
AwayTeamID pgtype.Text `json:"away_team_id"`
|
||||||
|
HomeKitImage pgtype.Text `json:"home_kit_image"`
|
||||||
|
AwayKitImage pgtype.Text `json:"away_kit_image"`
|
||||||
|
LeagueID pgtype.Text `json:"league_id"`
|
||||||
|
LeagueName pgtype.Text `json:"league_name"`
|
||||||
|
LeagueCc pgtype.Text `json:"league_cc"`
|
||||||
|
StartTime pgtype.Timestamp `json:"start_time"`
|
||||||
|
Score pgtype.Text `json:"score"`
|
||||||
|
MatchMinute pgtype.Int4 `json:"match_minute"`
|
||||||
|
TimerStatus pgtype.Text `json:"timer_status"`
|
||||||
|
AddedTime pgtype.Int4 `json:"added_time"`
|
||||||
|
MatchPeriod pgtype.Int4 `json:"match_period"`
|
||||||
|
IsLive pgtype.Bool `json:"is_live"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
ID string
|
ID string `json:"id"`
|
||||||
RecipientID int64
|
RecipientID int64 `json:"recipient_id"`
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
Level string
|
Level string `json:"level"`
|
||||||
ErrorSeverity pgtype.Text
|
ErrorSeverity pgtype.Text `json:"error_severity"`
|
||||||
Reciever string
|
Reciever string `json:"reciever"`
|
||||||
IsRead bool
|
IsRead bool `json:"is_read"`
|
||||||
DeliveryStatus string
|
DeliveryStatus string `json:"delivery_status"`
|
||||||
DeliveryChannel pgtype.Text
|
DeliveryChannel pgtype.Text `json:"delivery_channel"`
|
||||||
Payload []byte
|
Payload []byte `json:"payload"`
|
||||||
Priority pgtype.Int4
|
Priority pgtype.Int4 `json:"priority"`
|
||||||
Version int32
|
Version int32 `json:"version"`
|
||||||
Timestamp pgtype.Timestamptz
|
Timestamp pgtype.Timestamptz `json:"timestamp"`
|
||||||
Metadata []byte
|
Metadata []byte `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Odd struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
Fi pgtype.Text `json:"fi"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
MarketCategory pgtype.Text `json:"market_category"`
|
||||||
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
|
OddsValue pgtype.Float8 `json:"odds_value"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
RawOdds []byte `json:"raw_odds"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
Source pgtype.Text `json:"source"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Otp struct {
|
type Otp struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
SentTo string
|
SentTo string `json:"sent_to"`
|
||||||
Medium string
|
Medium string `json:"medium"`
|
||||||
OtpFor string
|
OtpFor string `json:"otp_for"`
|
||||||
Otp string
|
Otp string `json:"otp"`
|
||||||
Used bool
|
Used bool `json:"used"`
|
||||||
UsedAt pgtype.Timestamptz
|
UsedAt pgtype.Timestamptz `json:"used_at"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
ExpiresAt pgtype.Timestamptz
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Referral struct {
|
||||||
|
ID int64
|
||||||
|
ReferralCode string
|
||||||
|
ReferrerID string
|
||||||
|
ReferredID pgtype.Text
|
||||||
|
Status Referralstatus
|
||||||
|
RewardAmount pgtype.Numeric
|
||||||
|
CashbackAmount pgtype.Numeric
|
||||||
|
CreatedAt pgtype.Timestamptz
|
||||||
|
UpdatedAt pgtype.Timestamptz
|
||||||
|
ExpiresAt pgtype.Timestamptz
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferralSetting struct {
|
||||||
|
ID int64
|
||||||
|
ReferralRewardAmount pgtype.Numeric
|
||||||
|
CashbackPercentage pgtype.Numeric
|
||||||
|
BetReferralBonusPercentage pgtype.Numeric
|
||||||
|
MaxReferrals int32
|
||||||
|
ExpiresAfterDays int32
|
||||||
|
UpdatedBy string
|
||||||
|
CreatedAt pgtype.Timestamptz
|
||||||
|
UpdatedAt pgtype.Timestamptz
|
||||||
|
Version int32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Referral struct {
|
type Referral struct {
|
||||||
|
|
@ -136,55 +287,88 @@ type ReferralSetting struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshToken struct {
|
type RefreshToken struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
UserID int64
|
UserID int64 `json:"user_id"`
|
||||||
Token string
|
Token string `json:"token"`
|
||||||
ExpiresAt pgtype.Timestamptz
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
Revoked bool
|
Revoked bool `json:"revoked"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SupportedOperation struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ticket struct {
|
type Ticket struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Amount pgtype.Int8
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32
|
TotalOdds float32 `json:"total_odds"`
|
||||||
CreatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamp
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TicketOutcome struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
TicketID int64 `json:"ticket_id"`
|
||||||
|
EventID int64 `json:"event_id"`
|
||||||
|
OddID int64 `json:"odd_id"`
|
||||||
|
HomeTeamName string `json:"home_team_name"`
|
||||||
|
AwayTeamName string `json:"away_team_name"`
|
||||||
|
MarketID int64 `json:"market_id"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
Odd float32 `json:"odd"`
|
||||||
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TicketWithOutcome struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Amount int64 `json:"amount"`
|
||||||
|
TotalOdds float32 `json:"total_odds"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
Outcomes []TicketOutcome `json:"outcomes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Amount int64
|
Amount int64 `json:"amount"`
|
||||||
BranchID int64
|
BranchID int64 `json:"branch_id"`
|
||||||
CashierID int64
|
CashierID int64 `json:"cashier_id"`
|
||||||
BetID int64
|
BetID int64 `json:"bet_id"`
|
||||||
PaymentOption int64
|
Type int64 `json:"type"`
|
||||||
FullName string
|
PaymentOption int64 `json:"payment_option"`
|
||||||
PhoneNumber string
|
FullName string `json:"full_name"`
|
||||||
BankCode string
|
PhoneNumber string `json:"phone_number"`
|
||||||
BeneficiaryName string
|
BankCode string `json:"bank_code"`
|
||||||
AccountName string
|
BeneficiaryName string `json:"beneficiary_name"`
|
||||||
AccountNumber string
|
AccountName string `json:"account_name"`
|
||||||
ReferenceNumber string
|
AccountNumber string `json:"account_number"`
|
||||||
Verified bool
|
ReferenceNumber string `json:"reference_number"`
|
||||||
CreatedAt pgtype.Timestamp
|
Verified bool `json:"verified"`
|
||||||
UpdatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
Password []byte
|
Password []byte `json:"password"`
|
||||||
EmailVerified bool
|
EmailVerified bool `json:"email_verified"`
|
||||||
PhoneVerified bool
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
SuspendedAt pgtype.Timestamptz
|
SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
|
||||||
Suspended bool
|
Suspended bool `json:"suspended"`
|
||||||
ReferralCode pgtype.Text
|
ReferralCode pgtype.Text
|
||||||
ReferredBy pgtype.Text
|
ReferredBy pgtype.Text
|
||||||
}
|
}
|
||||||
|
|
@ -216,24 +400,28 @@ type VirtualGameTransaction struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Wallet struct {
|
type Wallet struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Balance int64
|
Balance int64 `json:"balance"`
|
||||||
IsWithdraw bool
|
IsWithdraw bool `json:"is_withdraw"`
|
||||||
IsBettable bool
|
IsBettable bool `json:"is_bettable"`
|
||||||
UserID int64
|
IsTransferable bool `json:"is_transferable"`
|
||||||
IsActive bool
|
UserID int64 `json:"user_id"`
|
||||||
CreatedAt pgtype.Timestamp
|
IsActive bool `json:"is_active"`
|
||||||
UpdatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
BonusBalance pgtype.Numeric
|
BonusBalance pgtype.Numeric
|
||||||
CashBalance pgtype.Numeric
|
CashBalance pgtype.Numeric
|
||||||
}
|
}
|
||||||
|
|
||||||
type WalletTransfer struct {
|
type WalletTransfer struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Amount int64
|
Amount int64 `json:"amount"`
|
||||||
WalletTransfer string
|
Type string `json:"type"`
|
||||||
WalletID int64
|
ReceiverWalletID int64 `json:"receiver_wallet_id"`
|
||||||
Verified bool
|
SenderWalletID pgtype.Int8 `json:"sender_wallet_id"`
|
||||||
CreatedAt pgtype.Timestamp
|
CashierID pgtype.Int8 `json:"cashier_id"`
|
||||||
UpdatedAt pgtype.Timestamp
|
Verified bool `json:"verified"`
|
||||||
|
PaymentMethod string `json:"payment_method"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,19 +20,19 @@ INSERT INTO notifications (
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateNotificationParams struct {
|
type CreateNotificationParams struct {
|
||||||
ID string
|
ID string `json:"id"`
|
||||||
RecipientID int64
|
RecipientID int64 `json:"recipient_id"`
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
Level string
|
Level string `json:"level"`
|
||||||
ErrorSeverity pgtype.Text
|
ErrorSeverity pgtype.Text `json:"error_severity"`
|
||||||
Reciever string
|
Reciever string `json:"reciever"`
|
||||||
IsRead bool
|
IsRead bool `json:"is_read"`
|
||||||
DeliveryStatus string
|
DeliveryStatus string `json:"delivery_status"`
|
||||||
DeliveryChannel pgtype.Text
|
DeliveryChannel pgtype.Text `json:"delivery_channel"`
|
||||||
Payload []byte
|
Payload []byte `json:"payload"`
|
||||||
Priority pgtype.Int4
|
Priority pgtype.Int4 `json:"priority"`
|
||||||
Timestamp pgtype.Timestamptz
|
Timestamp pgtype.Timestamptz `json:"timestamp"`
|
||||||
Metadata []byte
|
Metadata []byte `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateNotification(ctx context.Context, arg CreateNotificationParams) (Notification, error) {
|
func (q *Queries) CreateNotification(ctx context.Context, arg CreateNotificationParams) (Notification, error) {
|
||||||
|
|
@ -141,9 +141,9 @@ SELECT id, recipient_id, type, level, error_severity, reciever, is_read, deliver
|
||||||
`
|
`
|
||||||
|
|
||||||
type ListNotificationsParams struct {
|
type ListNotificationsParams struct {
|
||||||
RecipientID int64
|
RecipientID int64 `json:"recipient_id"`
|
||||||
Limit int32
|
Limit int32 `json:"limit"`
|
||||||
Offset int32
|
Offset int32 `json:"offset"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) ListNotifications(ctx context.Context, arg ListNotificationsParams) ([]Notification, error) {
|
func (q *Queries) ListNotifications(ctx context.Context, arg ListNotificationsParams) ([]Notification, error) {
|
||||||
|
|
@ -210,10 +210,10 @@ UPDATE notifications SET delivery_status = $2, is_read = $3, metadata = $4 WHERE
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateNotificationStatusParams struct {
|
type UpdateNotificationStatusParams struct {
|
||||||
ID string
|
ID string `json:"id"`
|
||||||
DeliveryStatus string
|
DeliveryStatus string `json:"delivery_status"`
|
||||||
IsRead bool
|
IsRead bool `json:"is_read"`
|
||||||
Metadata []byte
|
Metadata []byte `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateNotificationStatus(ctx context.Context, arg UpdateNotificationStatusParams) (Notification, error) {
|
func (q *Queries) UpdateNotificationStatus(ctx context.Context, arg UpdateNotificationStatusParams) (Notification, error) {
|
||||||
|
|
|
||||||
375
gen/db/odds.sql.go
Normal file
375
gen/db/odds.sql.go
Normal file
|
|
@ -0,0 +1,375 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
// source: odds.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many
|
||||||
|
SELECT event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true
|
||||||
|
AND source = 'b365api'
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetALLPrematchOddsRow struct {
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
Fi pgtype.Text `json:"fi"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
MarketCategory pgtype.Text `json:"market_category"`
|
||||||
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
|
OddsValue pgtype.Float8 `json:"odds_value"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
RawOdds []byte `json:"raw_odds"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
Source pgtype.Text `json:"source"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetALLPrematchOdds(ctx context.Context) ([]GetALLPrematchOddsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetALLPrematchOdds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetALLPrematchOddsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetALLPrematchOddsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.EventID,
|
||||||
|
&i.Fi,
|
||||||
|
&i.MarketType,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.MarketCategory,
|
||||||
|
&i.MarketID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Handicap,
|
||||||
|
&i.OddsValue,
|
||||||
|
&i.Section,
|
||||||
|
&i.Category,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
&i.Source,
|
||||||
|
&i.IsActive,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetPrematchOdds = `-- name: GetPrematchOdds :many
|
||||||
|
SELECT event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true
|
||||||
|
AND source = 'b365api'
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetPrematchOddsRow struct {
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
Fi pgtype.Text `json:"fi"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
MarketCategory pgtype.Text `json:"market_category"`
|
||||||
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
|
OddsValue pgtype.Float8 `json:"odds_value"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
RawOdds []byte `json:"raw_odds"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
Source pgtype.Text `json:"source"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPrematchOdds(ctx context.Context) ([]GetPrematchOddsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetPrematchOdds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetPrematchOddsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetPrematchOddsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.EventID,
|
||||||
|
&i.Fi,
|
||||||
|
&i.MarketType,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.MarketCategory,
|
||||||
|
&i.MarketID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Handicap,
|
||||||
|
&i.OddsValue,
|
||||||
|
&i.Section,
|
||||||
|
&i.Category,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
&i.Source,
|
||||||
|
&i.IsActive,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetPrematchOddsByUpcomingID = `-- name: GetPrematchOddsByUpcomingID :many
|
||||||
|
SELECT o.event_id,
|
||||||
|
o.fi,
|
||||||
|
o.market_type,
|
||||||
|
o.market_name,
|
||||||
|
o.market_category,
|
||||||
|
o.market_id,
|
||||||
|
o.name,
|
||||||
|
o.handicap,
|
||||||
|
o.odds_value,
|
||||||
|
o.section,
|
||||||
|
o.category,
|
||||||
|
o.raw_odds,
|
||||||
|
o.fetched_at,
|
||||||
|
o.source,
|
||||||
|
o.is_active
|
||||||
|
FROM odds o
|
||||||
|
JOIN events e ON o.fi = e.id
|
||||||
|
WHERE e.id = $1
|
||||||
|
AND e.is_live = false
|
||||||
|
AND e.status = 'upcoming'
|
||||||
|
AND o.is_active = true
|
||||||
|
AND o.source = 'b365api'
|
||||||
|
LIMIT $2 OFFSET $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetPrematchOddsByUpcomingIDParams struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetPrematchOddsByUpcomingIDRow struct {
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
Fi pgtype.Text `json:"fi"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
MarketCategory pgtype.Text `json:"market_category"`
|
||||||
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
|
OddsValue pgtype.Float8 `json:"odds_value"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
RawOdds []byte `json:"raw_odds"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
Source pgtype.Text `json:"source"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPrematchOddsByUpcomingID(ctx context.Context, arg GetPrematchOddsByUpcomingIDParams) ([]GetPrematchOddsByUpcomingIDRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetPrematchOddsByUpcomingID, arg.ID, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetPrematchOddsByUpcomingIDRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetPrematchOddsByUpcomingIDRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.EventID,
|
||||||
|
&i.Fi,
|
||||||
|
&i.MarketType,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.MarketCategory,
|
||||||
|
&i.MarketID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Handicap,
|
||||||
|
&i.OddsValue,
|
||||||
|
&i.Section,
|
||||||
|
&i.Category,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
&i.Source,
|
||||||
|
&i.IsActive,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetRawOddsByMarketID = `-- name: GetRawOddsByMarketID :one
|
||||||
|
SELECT id,
|
||||||
|
market_name,
|
||||||
|
handicap,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at
|
||||||
|
FROM odds
|
||||||
|
WHERE market_id = $1
|
||||||
|
AND fi = $2
|
||||||
|
AND is_active = true
|
||||||
|
AND source = 'b365api'
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetRawOddsByMarketIDParams struct {
|
||||||
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
|
Fi pgtype.Text `json:"fi"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetRawOddsByMarketIDRow struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
|
RawOdds []byte `json:"raw_odds"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetRawOddsByMarketID(ctx context.Context, arg GetRawOddsByMarketIDParams) (GetRawOddsByMarketIDRow, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetRawOddsByMarketID, arg.MarketID, arg.Fi)
|
||||||
|
var i GetRawOddsByMarketIDRow
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.Handicap,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
||||||
|
INSERT INTO odds (
|
||||||
|
event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
is_active,
|
||||||
|
source,
|
||||||
|
fetched_at
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
$9,
|
||||||
|
$10,
|
||||||
|
$11,
|
||||||
|
$12,
|
||||||
|
$13,
|
||||||
|
$14,
|
||||||
|
$15
|
||||||
|
) ON CONFLICT (event_id, market_id) DO
|
||||||
|
UPDATE
|
||||||
|
SET odds_value = EXCLUDED.odds_value,
|
||||||
|
raw_odds = EXCLUDED.raw_odds,
|
||||||
|
market_type = EXCLUDED.market_type,
|
||||||
|
market_name = EXCLUDED.market_name,
|
||||||
|
market_category = EXCLUDED.market_category,
|
||||||
|
name = EXCLUDED.name,
|
||||||
|
handicap = EXCLUDED.handicap,
|
||||||
|
fetched_at = EXCLUDED.fetched_at,
|
||||||
|
is_active = EXCLUDED.is_active,
|
||||||
|
source = EXCLUDED.source,
|
||||||
|
fi = EXCLUDED.fi
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertNonLiveOddParams struct {
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
Fi pgtype.Text `json:"fi"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
MarketName pgtype.Text `json:"market_name"`
|
||||||
|
MarketCategory pgtype.Text `json:"market_category"`
|
||||||
|
MarketID pgtype.Text `json:"market_id"`
|
||||||
|
Name pgtype.Text `json:"name"`
|
||||||
|
Handicap pgtype.Text `json:"handicap"`
|
||||||
|
OddsValue pgtype.Float8 `json:"odds_value"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
RawOdds []byte `json:"raw_odds"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
Source pgtype.Text `json:"source"`
|
||||||
|
FetchedAt pgtype.Timestamp `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertNonLiveOdd(ctx context.Context, arg InsertNonLiveOddParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, InsertNonLiveOdd,
|
||||||
|
arg.EventID,
|
||||||
|
arg.Fi,
|
||||||
|
arg.MarketType,
|
||||||
|
arg.MarketName,
|
||||||
|
arg.MarketCategory,
|
||||||
|
arg.MarketID,
|
||||||
|
arg.Name,
|
||||||
|
arg.Handicap,
|
||||||
|
arg.OddsValue,
|
||||||
|
arg.Section,
|
||||||
|
arg.Category,
|
||||||
|
arg.RawOdds,
|
||||||
|
arg.IsActive,
|
||||||
|
arg.Source,
|
||||||
|
arg.FetchedAt,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -17,12 +17,12 @@ VALUES ($1, $2, $3, $4, FALSE, $5, $6)
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateOtpParams struct {
|
type CreateOtpParams struct {
|
||||||
SentTo string
|
SentTo string `json:"sent_to"`
|
||||||
Medium string
|
Medium string `json:"medium"`
|
||||||
OtpFor string
|
OtpFor string `json:"otp_for"`
|
||||||
Otp string
|
Otp string `json:"otp"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
ExpiresAt pgtype.Timestamptz
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateOtp(ctx context.Context, arg CreateOtpParams) error {
|
func (q *Queries) CreateOtp(ctx context.Context, arg CreateOtpParams) error {
|
||||||
|
|
@ -45,9 +45,9 @@ ORDER BY created_at DESC LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetOtpParams struct {
|
type GetOtpParams struct {
|
||||||
SentTo string
|
SentTo string `json:"sent_to"`
|
||||||
OtpFor string
|
OtpFor string `json:"otp_for"`
|
||||||
Medium string
|
Medium string `json:"medium"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetOtp(ctx context.Context, arg GetOtpParams) (Otp, error) {
|
func (q *Queries) GetOtp(ctx context.Context, arg GetOtpParams) (Otp, error) {
|
||||||
|
|
@ -74,8 +74,8 @@ WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type MarkOtpAsUsedParams struct {
|
type MarkOtpAsUsedParams struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
UsedAt pgtype.Timestamptz
|
UsedAt pgtype.Timestamptz `json:"used_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) MarkOtpAsUsed(ctx context.Context, arg MarkOtpAsUsedParams) error {
|
func (q *Queries) MarkOtpAsUsed(ctx context.Context, arg MarkOtpAsUsedParams) error {
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ RETURNING id, amount, total_odds, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateTicketParams struct {
|
type CreateTicketParams struct {
|
||||||
Amount pgtype.Int8
|
Amount int64 `json:"amount"`
|
||||||
TotalOdds float32
|
TotalOdds float32 `json:"total_odds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) {
|
func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) {
|
||||||
|
|
@ -35,8 +35,24 @@ func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Tic
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateTicketOutcomeParams struct {
|
||||||
|
TicketID int64 `json:"ticket_id"`
|
||||||
|
EventID int64 `json:"event_id"`
|
||||||
|
OddID int64 `json:"odd_id"`
|
||||||
|
HomeTeamName string `json:"home_team_name"`
|
||||||
|
AwayTeamName string `json:"away_team_name"`
|
||||||
|
MarketID int64 `json:"market_id"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
Odd float32 `json:"odd"`
|
||||||
|
OddName string `json:"odd_name"`
|
||||||
|
OddHeader string `json:"odd_header"`
|
||||||
|
OddHandicap string `json:"odd_handicap"`
|
||||||
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
|
}
|
||||||
|
|
||||||
const DeleteOldTickets = `-- name: DeleteOldTickets :exec
|
const DeleteOldTickets = `-- name: DeleteOldTickets :exec
|
||||||
Delete from tickets where created_at < now() - interval '1 day'
|
Delete from tickets
|
||||||
|
where created_at < now() - interval '1 day'
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeleteOldTickets(ctx context.Context) error {
|
func (q *Queries) DeleteOldTickets(ctx context.Context) error {
|
||||||
|
|
@ -45,7 +61,8 @@ func (q *Queries) DeleteOldTickets(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeleteTicket = `-- name: DeleteTicket :exec
|
const DeleteTicket = `-- name: DeleteTicket :exec
|
||||||
DELETE FROM tickets WHERE id = $1
|
DELETE FROM tickets
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeleteTicket(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteTicket(ctx context.Context, id int64) error {
|
||||||
|
|
@ -53,25 +70,37 @@ func (q *Queries) DeleteTicket(ctx context.Context, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllTickets = `-- name: GetAllTickets :many
|
const DeleteTicketOutcome = `-- name: DeleteTicketOutcome :exec
|
||||||
SELECT id, amount, total_odds, created_at, updated_at FROM tickets
|
Delete from ticket_outcomes
|
||||||
|
where ticket_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllTickets(ctx context.Context) ([]Ticket, error) {
|
func (q *Queries) DeleteTicketOutcome(ctx context.Context, ticketID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteTicketOutcome, ticketID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllTickets = `-- name: GetAllTickets :many
|
||||||
|
SELECT id, amount, total_odds, created_at, updated_at, outcomes
|
||||||
|
FROM ticket_with_outcomes
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAllTickets(ctx context.Context) ([]TicketWithOutcome, error) {
|
||||||
rows, err := q.db.Query(ctx, GetAllTickets)
|
rows, err := q.db.Query(ctx, GetAllTickets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []Ticket
|
var items []TicketWithOutcome
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i Ticket
|
var i TicketWithOutcome
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.TotalOdds,
|
&i.TotalOdds,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.Outcomes,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -84,18 +113,78 @@ func (q *Queries) GetAllTickets(ctx context.Context) ([]Ticket, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetTicketByID = `-- name: GetTicketByID :one
|
const GetTicketByID = `-- name: GetTicketByID :one
|
||||||
SELECT id, amount, total_odds, created_at, updated_at FROM tickets WHERE id = $1
|
SELECT id, amount, total_odds, created_at, updated_at, outcomes
|
||||||
|
FROM ticket_with_outcomes
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetTicketByID(ctx context.Context, id int64) (Ticket, error) {
|
func (q *Queries) GetTicketByID(ctx context.Context, id int64) (TicketWithOutcome, error) {
|
||||||
row := q.db.QueryRow(ctx, GetTicketByID, id)
|
row := q.db.QueryRow(ctx, GetTicketByID, id)
|
||||||
var i Ticket
|
var i TicketWithOutcome
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.TotalOdds,
|
&i.TotalOdds,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.Outcomes,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetTicketOutcome = `-- name: GetTicketOutcome :many
|
||||||
|
SELECT id, ticket_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires
|
||||||
|
FROM ticket_outcomes
|
||||||
|
WHERE ticket_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTicketOutcome(ctx context.Context, ticketID int64) ([]TicketOutcome, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetTicketOutcome, ticketID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []TicketOutcome
|
||||||
|
for rows.Next() {
|
||||||
|
var i TicketOutcome
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.TicketID,
|
||||||
|
&i.EventID,
|
||||||
|
&i.OddID,
|
||||||
|
&i.HomeTeamName,
|
||||||
|
&i.AwayTeamName,
|
||||||
|
&i.MarketID,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.Odd,
|
||||||
|
&i.OddName,
|
||||||
|
&i.OddHeader,
|
||||||
|
&i.OddHandicap,
|
||||||
|
&i.Status,
|
||||||
|
&i.Expires,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateTicketOutcomeStatus = `-- name: UpdateTicketOutcomeStatus :exec
|
||||||
|
UPDATE ticket_outcomes
|
||||||
|
SET status = $1
|
||||||
|
WHERE id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateTicketOutcomeStatusParams struct {
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateTicketOutcomeStatus(ctx context.Context, arg UpdateTicketOutcomeStatusParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateTicketOutcomeStatus, arg.Status, arg.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const CreateTransaction = `-- name: CreateTransaction :one
|
const CreateTransaction = `-- name: CreateTransaction :one
|
||||||
INSERT INTO transactions (amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at
|
INSERT INTO transactions (amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateTransactionParams struct {
|
type CreateTransactionParams struct {
|
||||||
Amount int64
|
Amount int64 `json:"amount"`
|
||||||
BranchID int64
|
BranchID int64 `json:"branch_id"`
|
||||||
CashierID int64
|
CashierID int64 `json:"cashier_id"`
|
||||||
BetID int64
|
BetID int64 `json:"bet_id"`
|
||||||
PaymentOption int64
|
Type int64 `json:"type"`
|
||||||
FullName string
|
PaymentOption int64 `json:"payment_option"`
|
||||||
PhoneNumber string
|
FullName string `json:"full_name"`
|
||||||
BankCode string
|
PhoneNumber string `json:"phone_number"`
|
||||||
BeneficiaryName string
|
BankCode string `json:"bank_code"`
|
||||||
AccountName string
|
BeneficiaryName string `json:"beneficiary_name"`
|
||||||
AccountNumber string
|
AccountName string `json:"account_name"`
|
||||||
ReferenceNumber string
|
AccountNumber string `json:"account_number"`
|
||||||
|
ReferenceNumber string `json:"reference_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionParams) (Transaction, error) {
|
func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionParams) (Transaction, error) {
|
||||||
|
|
@ -34,6 +35,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa
|
||||||
arg.BranchID,
|
arg.BranchID,
|
||||||
arg.CashierID,
|
arg.CashierID,
|
||||||
arg.BetID,
|
arg.BetID,
|
||||||
|
arg.Type,
|
||||||
arg.PaymentOption,
|
arg.PaymentOption,
|
||||||
arg.FullName,
|
arg.FullName,
|
||||||
arg.PhoneNumber,
|
arg.PhoneNumber,
|
||||||
|
|
@ -50,6 +52,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
&i.CashierID,
|
&i.CashierID,
|
||||||
&i.BetID,
|
&i.BetID,
|
||||||
|
&i.Type,
|
||||||
&i.PaymentOption,
|
&i.PaymentOption,
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
|
|
@ -66,7 +69,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllTransactions = `-- name: GetAllTransactions :many
|
const GetAllTransactions = `-- name: GetAllTransactions :many
|
||||||
SELECT id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions
|
SELECT id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) {
|
func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) {
|
||||||
|
|
@ -84,6 +87,49 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error)
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
&i.CashierID,
|
&i.CashierID,
|
||||||
&i.BetID,
|
&i.BetID,
|
||||||
|
&i.Type,
|
||||||
|
&i.PaymentOption,
|
||||||
|
&i.FullName,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.BankCode,
|
||||||
|
&i.BeneficiaryName,
|
||||||
|
&i.AccountName,
|
||||||
|
&i.AccountNumber,
|
||||||
|
&i.ReferenceNumber,
|
||||||
|
&i.Verified,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetTransactionByBranch = `-- name: GetTransactionByBranch :many
|
||||||
|
SELECT id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE branch_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([]Transaction, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetTransactionByBranch, branchID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Transaction
|
||||||
|
for rows.Next() {
|
||||||
|
var i Transaction
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Amount,
|
||||||
|
&i.BranchID,
|
||||||
|
&i.CashierID,
|
||||||
|
&i.BetID,
|
||||||
|
&i.Type,
|
||||||
&i.PaymentOption,
|
&i.PaymentOption,
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
|
|
@ -107,7 +153,7 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetTransactionByID = `-- name: GetTransactionByID :one
|
const GetTransactionByID = `-- name: GetTransactionByID :one
|
||||||
SELECT id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE id = $1
|
SELECT id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction, error) {
|
func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction, error) {
|
||||||
|
|
@ -119,6 +165,7 @@ func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction
|
||||||
&i.BranchID,
|
&i.BranchID,
|
||||||
&i.CashierID,
|
&i.CashierID,
|
||||||
&i.BetID,
|
&i.BetID,
|
||||||
|
&i.Type,
|
||||||
&i.PaymentOption,
|
&i.PaymentOption,
|
||||||
&i.FullName,
|
&i.FullName,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
|
|
@ -139,8 +186,8 @@ UPDATE transactions SET verified = $2, updated_at = CURRENT_TIMESTAMP WHERE id =
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateTransactionVerifiedParams struct {
|
type UpdateTransactionVerifiedParams struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Verified bool
|
Verified bool `json:"verified"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateTransactionVerified(ctx context.Context, arg UpdateTransactionVerifiedParams) error {
|
func (q *Queries) UpdateTransactionVerified(ctx context.Context, arg UpdateTransactionVerifiedParams) error {
|
||||||
|
|
|
||||||
|
|
@ -7,27 +7,44 @@ package dbgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CreateTransfer = `-- name: CreateTransfer :one
|
const CreateTransfer = `-- name: CreateTransfer :one
|
||||||
INSERT INTO wallet_transfer (amount, wallet_transfer, wallet_id) VALUES ($1, $2, $3) RETURNING id, amount, wallet_transfer, wallet_id, verified, created_at, updated_at
|
INSERT INTO wallet_transfer (amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateTransferParams struct {
|
type CreateTransferParams struct {
|
||||||
Amount int64
|
Amount int64 `json:"amount"`
|
||||||
WalletTransfer string
|
Type string `json:"type"`
|
||||||
WalletID int64
|
ReceiverWalletID int64 `json:"receiver_wallet_id"`
|
||||||
|
SenderWalletID pgtype.Int8 `json:"sender_wallet_id"`
|
||||||
|
CashierID pgtype.Int8 `json:"cashier_id"`
|
||||||
|
Verified bool `json:"verified"`
|
||||||
|
PaymentMethod string `json:"payment_method"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams) (WalletTransfer, error) {
|
func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams) (WalletTransfer, error) {
|
||||||
row := q.db.QueryRow(ctx, CreateTransfer, arg.Amount, arg.WalletTransfer, arg.WalletID)
|
row := q.db.QueryRow(ctx, CreateTransfer,
|
||||||
|
arg.Amount,
|
||||||
|
arg.Type,
|
||||||
|
arg.ReceiverWalletID,
|
||||||
|
arg.SenderWalletID,
|
||||||
|
arg.CashierID,
|
||||||
|
arg.Verified,
|
||||||
|
arg.PaymentMethod,
|
||||||
|
)
|
||||||
var i WalletTransfer
|
var i WalletTransfer
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.WalletTransfer,
|
&i.Type,
|
||||||
&i.WalletID,
|
&i.ReceiverWalletID,
|
||||||
|
&i.SenderWalletID,
|
||||||
|
&i.CashierID,
|
||||||
&i.Verified,
|
&i.Verified,
|
||||||
|
&i.PaymentMethod,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
)
|
)
|
||||||
|
|
@ -35,7 +52,7 @@ func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllTransfers = `-- name: GetAllTransfers :many
|
const GetAllTransfers = `-- name: GetAllTransfers :many
|
||||||
SELECT id, amount, wallet_transfer, wallet_id, verified, created_at, updated_at FROM wallet_transfer
|
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at FROM wallet_transfer
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) {
|
func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) {
|
||||||
|
|
@ -50,9 +67,12 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error)
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.WalletTransfer,
|
&i.Type,
|
||||||
&i.WalletID,
|
&i.ReceiverWalletID,
|
||||||
|
&i.SenderWalletID,
|
||||||
|
&i.CashierID,
|
||||||
&i.Verified,
|
&i.Verified,
|
||||||
|
&i.PaymentMethod,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
@ -67,7 +87,7 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetTransferByID = `-- name: GetTransferByID :one
|
const GetTransferByID = `-- name: GetTransferByID :one
|
||||||
SELECT id, amount, wallet_transfer, wallet_id, verified, created_at, updated_at FROM wallet_transfer WHERE id = $1
|
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at FROM wallet_transfer WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer, error) {
|
func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer, error) {
|
||||||
|
|
@ -76,9 +96,12 @@ func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.WalletTransfer,
|
&i.Type,
|
||||||
&i.WalletID,
|
&i.ReceiverWalletID,
|
||||||
|
&i.SenderWalletID,
|
||||||
|
&i.CashierID,
|
||||||
&i.Verified,
|
&i.Verified,
|
||||||
|
&i.PaymentMethod,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
)
|
)
|
||||||
|
|
@ -86,11 +109,11 @@ func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetTransfersByWallet = `-- name: GetTransfersByWallet :many
|
const GetTransfersByWallet = `-- name: GetTransfersByWallet :many
|
||||||
SELECT id, amount, wallet_transfer, wallet_id, verified, created_at, updated_at FROM wallet_transfer WHERE wallet_id = $1
|
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at FROM wallet_transfer WHERE receiver_wallet_id = $1 OR sender_wallet_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetTransfersByWallet(ctx context.Context, walletID int64) ([]WalletTransfer, error) {
|
func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID int64) ([]WalletTransfer, error) {
|
||||||
rows, err := q.db.Query(ctx, GetTransfersByWallet, walletID)
|
rows, err := q.db.Query(ctx, GetTransfersByWallet, receiverWalletID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -101,9 +124,12 @@ func (q *Queries) GetTransfersByWallet(ctx context.Context, walletID int64) ([]W
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Amount,
|
&i.Amount,
|
||||||
&i.WalletTransfer,
|
&i.Type,
|
||||||
&i.WalletID,
|
&i.ReceiverWalletID,
|
||||||
|
&i.SenderWalletID,
|
||||||
|
&i.CashierID,
|
||||||
&i.Verified,
|
&i.Verified,
|
||||||
|
&i.PaymentMethod,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
@ -122,8 +148,8 @@ UPDATE wallet_transfer SET verified = $1, updated_at = CURRENT_TIMESTAMP WHERE i
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateTransferVerificationParams struct {
|
type UpdateTransferVerificationParams struct {
|
||||||
Verified bool
|
Verified bool `json:"verified"`
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateTransferVerification(ctx context.Context, arg UpdateTransferVerificationParams) error {
|
func (q *Queries) UpdateTransferVerification(ctx context.Context, arg UpdateTransferVerificationParams) error {
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const CheckPhoneEmailExist = `-- name: CheckPhoneEmailExist :one
|
const CheckPhoneEmailExist = `-- name: CheckPhoneEmailExist :one
|
||||||
SELECT
|
SELECT EXISTS (
|
||||||
EXISTS (SELECT 1 FROM users WHERE users.phone_number = $1 AND users.phone_number IS NOT NULL) AS phone_exists,
|
SELECT 1
|
||||||
EXISTS (SELECT 1 FROM users WHERE users.email = $2 AND users.email IS NOT NULL) AS email_exists
|
FROM users
|
||||||
|
WHERE users.phone_number = $1
|
||||||
|
AND users.phone_number IS NOT NULL
|
||||||
|
) AS phone_exists,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM users
|
||||||
|
WHERE users.email = $2
|
||||||
|
AND users.email IS NOT NULL
|
||||||
|
) AS email_exists
|
||||||
`
|
`
|
||||||
|
|
||||||
type CheckPhoneEmailExistParams struct {
|
type CheckPhoneEmailExistParams struct {
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CheckPhoneEmailExistRow struct {
|
type CheckPhoneEmailExistRow struct {
|
||||||
PhoneExists bool
|
PhoneExists bool `json:"phone_exists"`
|
||||||
EmailExists bool
|
EmailExists bool `json:"email_exists"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CheckPhoneEmailExist(ctx context.Context, arg CheckPhoneEmailExistParams) (CheckPhoneEmailExistRow, error) {
|
func (q *Queries) CheckPhoneEmailExist(ctx context.Context, arg CheckPhoneEmailExistParams) (CheckPhoneEmailExistRow, error) {
|
||||||
|
|
@ -35,36 +44,55 @@ func (q *Queries) CheckPhoneEmailExist(ctx context.Context, arg CheckPhoneEmailE
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateUser = `-- name: CreateUser :one
|
const CreateUser = `-- name: CreateUser :one
|
||||||
|
INSERT INTO users (
|
||||||
INSERT INTO users (first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at)
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
password,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||||
RETURNING id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
RETURNING id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateUserParams struct {
|
type CreateUserParams struct {
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
Password []byte
|
Password []byte `json:"password"`
|
||||||
EmailVerified bool
|
EmailVerified bool `json:"email_verified"`
|
||||||
PhoneVerified bool
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateUserRow struct {
|
type CreateUserRow struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
EmailVerified bool
|
EmailVerified bool `json:"email_verified"`
|
||||||
PhoneVerified bool
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) {
|
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) {
|
||||||
|
|
@ -107,21 +135,30 @@ func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllUsers = `-- name: GetAllUsers :many
|
const GetAllUsers = `-- name: GetAllUsers :many
|
||||||
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
FROM users
|
FROM users
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetAllUsersRow struct {
|
type GetAllUsersRow struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
EmailVerified bool
|
EmailVerified bool `json:"email_verified"`
|
||||||
PhoneVerified bool
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetAllUsers(ctx context.Context) ([]GetAllUsersRow, error) {
|
func (q *Queries) GetAllUsers(ctx context.Context) ([]GetAllUsersRow, error) {
|
||||||
|
|
@ -156,22 +193,31 @@ func (q *Queries) GetAllUsers(ctx context.Context) ([]GetAllUsersRow, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetUserByEmail = `-- name: GetUserByEmail :one
|
const GetUserByEmail = `-- name: GetUserByEmail :one
|
||||||
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetUserByEmailRow struct {
|
type GetUserByEmailRow struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
EmailVerified bool
|
EmailVerified bool `json:"email_verified"`
|
||||||
PhoneVerified bool
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetUserByEmail(ctx context.Context, email pgtype.Text) (GetUserByEmailRow, error) {
|
func (q *Queries) GetUserByEmail(ctx context.Context, email pgtype.Text) (GetUserByEmailRow, error) {
|
||||||
|
|
@ -222,22 +268,31 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetUserByPhone = `-- name: GetUserByPhone :one
|
const GetUserByPhone = `-- name: GetUserByPhone :one
|
||||||
SELECT id, first_name, last_name, email, phone_number, role, email_verified, phone_verified, created_at, updated_at
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE phone_number = $1
|
WHERE phone_number = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetUserByPhoneRow struct {
|
type GetUserByPhoneRow struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
EmailVerified bool
|
EmailVerified bool `json:"email_verified"`
|
||||||
PhoneVerified bool
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetUserByPhone(ctx context.Context, phoneNumber pgtype.Text) (GetUserByPhoneRow, error) {
|
func (q *Queries) GetUserByPhone(ctx context.Context, phoneNumber pgtype.Text) (GetUserByPhoneRow, error) {
|
||||||
|
|
@ -258,17 +313,82 @@ func (q *Queries) GetUserByPhone(ctx context.Context, phoneNumber pgtype.Text) (
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SearchUserByNameOrPhone = `-- name: SearchUserByNameOrPhone :many
|
||||||
|
SELECT id,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
email,
|
||||||
|
phone_number,
|
||||||
|
role,
|
||||||
|
email_verified,
|
||||||
|
phone_verified,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM users
|
||||||
|
WHERE first_name ILIKE '%' || $1 || '%'
|
||||||
|
OR last_name ILIKE '%' || $1 || '%'
|
||||||
|
OR phone_number LIKE '%' || $1 || '%'
|
||||||
|
`
|
||||||
|
|
||||||
|
type SearchUserByNameOrPhoneRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Email pgtype.Text `json:"email"`
|
||||||
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
EmailVerified bool `json:"email_verified"`
|
||||||
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SearchUserByNameOrPhone(ctx context.Context, dollar_1 pgtype.Text) ([]SearchUserByNameOrPhoneRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, SearchUserByNameOrPhone, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SearchUserByNameOrPhoneRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i SearchUserByNameOrPhoneRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
|
&i.Email,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.Role,
|
||||||
|
&i.EmailVerified,
|
||||||
|
&i.PhoneVerified,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const UpdatePassword = `-- name: UpdatePassword :exec
|
const UpdatePassword = `-- name: UpdatePassword :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET password = $1, updated_at = $4
|
SET password = $1,
|
||||||
WHERE (email = $2 OR phone_number = $3)
|
updated_at = $4
|
||||||
|
WHERE (
|
||||||
|
email = $2
|
||||||
|
OR phone_number = $3
|
||||||
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdatePasswordParams struct {
|
type UpdatePasswordParams struct {
|
||||||
Password []byte
|
Password []byte `json:"password"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error {
|
func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error {
|
||||||
|
|
@ -283,18 +403,23 @@ func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams)
|
||||||
|
|
||||||
const UpdateUser = `-- name: UpdateUser :exec
|
const UpdateUser = `-- name: UpdateUser :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET first_name = $1, last_name = $2, email = $3, phone_number = $4, role = $5, updated_at = $6
|
SET first_name = $1,
|
||||||
|
last_name = $2,
|
||||||
|
email = $3,
|
||||||
|
phone_number = $4,
|
||||||
|
role = $5,
|
||||||
|
updated_at = $6
|
||||||
WHERE id = $7
|
WHERE id = $7
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateUserParams struct {
|
type UpdateUserParams struct {
|
||||||
FirstName string
|
FirstName string `json:"first_name"`
|
||||||
LastName string
|
LastName string `json:"last_name"`
|
||||||
Email pgtype.Text
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string
|
Role string `json:"role"`
|
||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
|
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const CreateCustomerWallet = `-- name: CreateCustomerWallet :one
|
const CreateCustomerWallet = `-- name: CreateCustomerWallet :one
|
||||||
INSERT INTO customer_wallets (customer_id, company_id, regular_wallet_id, static_wallet_id) VALUES ($1, $2, $3, $4) RETURNING id, customer_id, company_id, regular_wallet_id, static_wallet_id, created_at, updated_at
|
INSERT INTO customer_wallets (
|
||||||
|
customer_id,
|
||||||
|
company_id,
|
||||||
|
regular_wallet_id,
|
||||||
|
static_wallet_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
RETURNING id, customer_id, company_id, regular_wallet_id, static_wallet_id, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateCustomerWalletParams struct {
|
type CreateCustomerWalletParams struct {
|
||||||
CustomerID int64
|
CustomerID int64 `json:"customer_id"`
|
||||||
CompanyID int64
|
CompanyID int64 `json:"company_id"`
|
||||||
RegularWalletID int64
|
RegularWalletID int64 `json:"regular_wallet_id"`
|
||||||
StaticWalletID int64
|
StaticWalletID int64 `json:"static_wallet_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateCustomerWallet(ctx context.Context, arg CreateCustomerWalletParams) (CustomerWallet, error) {
|
func (q *Queries) CreateCustomerWallet(ctx context.Context, arg CreateCustomerWalletParams) (CustomerWallet, error) {
|
||||||
|
|
@ -43,23 +50,37 @@ func (q *Queries) CreateCustomerWallet(ctx context.Context, arg CreateCustomerWa
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateWallet = `-- name: CreateWallet :one
|
const CreateWallet = `-- name: CreateWallet :one
|
||||||
INSERT INTO wallets (is_withdraw, is_bettable, user_id) VALUES ($1, $2, $3) RETURNING id, balance, is_withdraw, is_bettable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance
|
INSERT INTO wallets (
|
||||||
|
is_withdraw,
|
||||||
|
is_bettable,
|
||||||
|
is_transferable,
|
||||||
|
user_id
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
RETURNING id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateWalletParams struct {
|
type CreateWalletParams struct {
|
||||||
IsWithdraw bool
|
IsWithdraw bool `json:"is_withdraw"`
|
||||||
IsBettable bool
|
IsBettable bool `json:"is_bettable"`
|
||||||
UserID int64
|
IsTransferable bool `json:"is_transferable"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wallet, error) {
|
func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wallet, error) {
|
||||||
row := q.db.QueryRow(ctx, CreateWallet, arg.IsWithdraw, arg.IsBettable, arg.UserID)
|
row := q.db.QueryRow(ctx, CreateWallet,
|
||||||
|
arg.IsWithdraw,
|
||||||
|
arg.IsBettable,
|
||||||
|
arg.IsTransferable,
|
||||||
|
arg.UserID,
|
||||||
|
)
|
||||||
var i Wallet
|
var i Wallet
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsWithdraw,
|
&i.IsWithdraw,
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
|
|
@ -70,8 +91,68 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetAllBranchWallets = `-- name: GetAllBranchWallets :many
|
||||||
|
SELECT wallets.id,
|
||||||
|
wallets.balance,
|
||||||
|
wallets.is_active,
|
||||||
|
wallets.updated_at,
|
||||||
|
wallets.created_at,
|
||||||
|
branches.name,
|
||||||
|
branches.location,
|
||||||
|
branches.branch_manager_id,
|
||||||
|
branches.company_id,
|
||||||
|
branches.is_self_owned
|
||||||
|
FROM branches
|
||||||
|
JOIN wallets ON branches.wallet_id = wallets.id
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetAllBranchWalletsRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Balance int64 `json:"balance"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
BranchManagerID int64 `json:"branch_manager_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
IsSelfOwned bool `json:"is_self_owned"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAllBranchWallets(ctx context.Context) ([]GetAllBranchWalletsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllBranchWallets)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetAllBranchWalletsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetAllBranchWalletsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Balance,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.Name,
|
||||||
|
&i.Location,
|
||||||
|
&i.BranchManagerID,
|
||||||
|
&i.CompanyID,
|
||||||
|
&i.IsSelfOwned,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const GetAllWallets = `-- name: GetAllWallets :many
|
const GetAllWallets = `-- name: GetAllWallets :many
|
||||||
SELECT id, balance, is_withdraw, is_bettable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance FROM wallets
|
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance
|
||||||
|
FROM wallets
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
|
func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
|
||||||
|
|
@ -88,6 +169,7 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsWithdraw,
|
&i.IsWithdraw,
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
|
|
@ -106,8 +188,7 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetCustomerWallet = `-- name: GetCustomerWallet :one
|
const GetCustomerWallet = `-- name: GetCustomerWallet :one
|
||||||
SELECT
|
SELECT cw.id,
|
||||||
cw.id,
|
|
||||||
cw.customer_id,
|
cw.customer_id,
|
||||||
cw.company_id,
|
cw.company_id,
|
||||||
rw.id AS regular_id,
|
rw.id AS regular_id,
|
||||||
|
|
@ -118,27 +199,28 @@ SELECT
|
||||||
sw.updated_at as static_updated_at,
|
sw.updated_at as static_updated_at,
|
||||||
cw.created_at
|
cw.created_at
|
||||||
FROM customer_wallets cw
|
FROM customer_wallets cw
|
||||||
JOIN wallets rw ON cw.regular_wallet_id = rw.id
|
JOIN wallets rw ON cw.regular_wallet_id = rw.id
|
||||||
JOIN wallets sw ON cw.static_wallet_id = sw.id
|
JOIN wallets sw ON cw.static_wallet_id = sw.id
|
||||||
WHERE cw.customer_id = $1 AND cw.company_id = $2
|
WHERE cw.customer_id = $1
|
||||||
|
AND cw.company_id = $2
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetCustomerWalletParams struct {
|
type GetCustomerWalletParams struct {
|
||||||
CustomerID int64
|
CustomerID int64 `json:"customer_id"`
|
||||||
CompanyID int64
|
CompanyID int64 `json:"company_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetCustomerWalletRow struct {
|
type GetCustomerWalletRow struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
CustomerID int64
|
CustomerID int64 `json:"customer_id"`
|
||||||
CompanyID int64
|
CompanyID int64 `json:"company_id"`
|
||||||
RegularID int64
|
RegularID int64 `json:"regular_id"`
|
||||||
RegularBalance int64
|
RegularBalance int64 `json:"regular_balance"`
|
||||||
StaticID int64
|
StaticID int64 `json:"static_id"`
|
||||||
StaticBalance int64
|
StaticBalance int64 `json:"static_balance"`
|
||||||
RegularUpdatedAt pgtype.Timestamp
|
RegularUpdatedAt pgtype.Timestamp `json:"regular_updated_at"`
|
||||||
StaticUpdatedAt pgtype.Timestamp
|
StaticUpdatedAt pgtype.Timestamp `json:"static_updated_at"`
|
||||||
CreatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetCustomerWallet(ctx context.Context, arg GetCustomerWalletParams) (GetCustomerWalletRow, error) {
|
func (q *Queries) GetCustomerWallet(ctx context.Context, arg GetCustomerWalletParams) (GetCustomerWalletRow, error) {
|
||||||
|
|
@ -160,7 +242,9 @@ func (q *Queries) GetCustomerWallet(ctx context.Context, arg GetCustomerWalletPa
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetWalletByID = `-- name: GetWalletByID :one
|
const GetWalletByID = `-- name: GetWalletByID :one
|
||||||
SELECT id, balance, is_withdraw, is_bettable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance FROM wallets WHERE id = $1
|
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance
|
||||||
|
FROM wallets
|
||||||
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
|
func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
|
||||||
|
|
@ -171,6 +255,7 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsWithdraw,
|
&i.IsWithdraw,
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
|
|
@ -182,7 +267,9 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetWalletByUserID = `-- name: GetWalletByUserID :many
|
const GetWalletByUserID = `-- name: GetWalletByUserID :many
|
||||||
SELECT id, balance, is_withdraw, is_bettable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance FROM wallets WHERE user_id = $1
|
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, bonus_balance, cash_balance
|
||||||
|
FROM wallets
|
||||||
|
WHERE user_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet, error) {
|
func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet, error) {
|
||||||
|
|
@ -199,6 +286,7 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
|
||||||
&i.Balance,
|
&i.Balance,
|
||||||
&i.IsWithdraw,
|
&i.IsWithdraw,
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
|
|
@ -217,12 +305,15 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateBalance = `-- name: UpdateBalance :exec
|
const UpdateBalance = `-- name: UpdateBalance :exec
|
||||||
UPDATE wallets SET balance = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2
|
UPDATE wallets
|
||||||
|
SET balance = $1,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $2
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateBalanceParams struct {
|
type UpdateBalanceParams struct {
|
||||||
Balance int64
|
Balance int64 `json:"balance"`
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateBalance(ctx context.Context, arg UpdateBalanceParams) error {
|
func (q *Queries) UpdateBalance(ctx context.Context, arg UpdateBalanceParams) error {
|
||||||
|
|
@ -231,12 +322,15 @@ func (q *Queries) UpdateBalance(ctx context.Context, arg UpdateBalanceParams) er
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateWalletActive = `-- name: UpdateWalletActive :exec
|
const UpdateWalletActive = `-- name: UpdateWalletActive :exec
|
||||||
UPDATE wallets SET is_active = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2
|
UPDATE wallets
|
||||||
|
SET is_active = $1,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $2
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateWalletActiveParams struct {
|
type UpdateWalletActiveParams struct {
|
||||||
IsActive bool
|
IsActive bool `json:"is_active"`
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateWalletActive(ctx context.Context, arg UpdateWalletActiveParams) error {
|
func (q *Queries) UpdateWalletActive(ctx context.Context, arg UpdateWalletActiveParams) error {
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -11,6 +11,7 @@ require (
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/jackc/pgx/v5 v5.7.4
|
github.com/jackc/pgx/v5 v5.7.4
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/swaggo/fiber-swagger v1.3.0
|
github.com/swaggo/fiber-swagger v1.3.0
|
||||||
github.com/swaggo/swag v1.16.4
|
github.com/swaggo/swag v1.16.4
|
||||||
golang.org/x/crypto v0.36.0
|
golang.org/x/crypto v0.36.0
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -109,6 +109,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ var (
|
||||||
ErrInvalidLevel = errors.New("invalid log level")
|
ErrInvalidLevel = errors.New("invalid log level")
|
||||||
ErrInvalidEnv = errors.New("env not set or invalid")
|
ErrInvalidEnv = errors.New("env not set or invalid")
|
||||||
ErrInvalidSMSAPIKey = errors.New("SMS API key is invalid")
|
ErrInvalidSMSAPIKey = errors.New("SMS API key is invalid")
|
||||||
|
ErrMissingBetToken = errors.New("missing BET365_TOKEN in .env")
|
||||||
ErrInvalidPopOKClientID = errors.New("PopOK client ID is invalid")
|
ErrInvalidPopOKClientID = errors.New("PopOK client ID is invalid")
|
||||||
ErrInvalidPopOKSecretKey = errors.New("PopOK secret key is invalid")
|
ErrInvalidPopOKSecretKey = errors.New("PopOK secret key is invalid")
|
||||||
ErrInvalidPopOKBaseURL = errors.New("PopOK base URL is invalid")
|
ErrInvalidPopOKBaseURL = errors.New("PopOK base URL is invalid")
|
||||||
|
|
@ -39,6 +40,7 @@ type Config struct {
|
||||||
AFRO_SMS_SENDER_NAME string
|
AFRO_SMS_SENDER_NAME string
|
||||||
AFRO_SMS_RECEIVER_PHONE_NUMBER string
|
AFRO_SMS_RECEIVER_PHONE_NUMBER string
|
||||||
ADRO_SMS_HOST_URL string
|
ADRO_SMS_HOST_URL string
|
||||||
|
Bet365Token string
|
||||||
PopOK domain.PopOKConfig
|
PopOK domain.PopOKConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,5 +159,10 @@ func (c *Config) loadEnv() error {
|
||||||
BaseURL: popOKBaseURL,
|
BaseURL: popOKBaseURL,
|
||||||
CallbackURL: popOKCallbackURL,
|
CallbackURL: popOKCallbackURL,
|
||||||
}
|
}
|
||||||
|
betToken := os.Getenv("BET365_TOKEN")
|
||||||
|
if betToken == "" {
|
||||||
|
return ErrMissingBetToken
|
||||||
|
}
|
||||||
|
c.Bet365Token = betToken
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
internal/domain/bank.go
Normal file
1
internal/domain/bank.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package domain
|
||||||
|
|
@ -1,44 +1,81 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
type BetStatus int
|
import (
|
||||||
|
"time"
|
||||||
const (
|
|
||||||
BET_STATUS_PENDING BetStatus = iota
|
|
||||||
BET_STATUS_WIN
|
|
||||||
BET_STATUS_LOSS
|
|
||||||
BET_STATUS_ERROR
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type BetOutcome struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
BetID int64 `json:"bet_id" example:"1"`
|
||||||
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
|
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
|
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
|
Status OutcomeStatus `json:"status" example:"1"`
|
||||||
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBetOutcome struct {
|
||||||
|
BetID int64 `json:"bet_id" example:"1"`
|
||||||
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
|
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
|
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
|
}
|
||||||
|
|
||||||
// If it is a ShopBet then UserID will be the cashier
|
// If it is a ShopBet then UserID will be the cashier
|
||||||
// If it is a DigitalBet then UserID will be the user and the branchID will be 0 or nil
|
// If it is a DigitalBet then UserID will be the user and the branchID will be 0 or nil
|
||||||
type Bet struct {
|
type Bet struct {
|
||||||
ID int64
|
ID int64
|
||||||
Outcomes []Outcome
|
|
||||||
Amount Currency
|
Amount Currency
|
||||||
TotalOdds float32
|
TotalOdds float32
|
||||||
Status BetStatus
|
Status OutcomeStatus
|
||||||
FullName string
|
FullName string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
BranchID ValidInt64 // Can Be Nullable
|
BranchID ValidInt64 // Can Be Nullable
|
||||||
UserID ValidInt64 // Can Be Nullable
|
UserID ValidInt64 // Can Be Nullable
|
||||||
IsShopBet bool
|
IsShopBet bool
|
||||||
CashedOut bool
|
CashedOut bool
|
||||||
|
CashoutID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateBet struct {
|
type GetBet struct {
|
||||||
Outcomes []int64
|
ID int64
|
||||||
Amount Currency
|
Amount Currency
|
||||||
TotalOdds float32
|
TotalOdds float32
|
||||||
Status BetStatus
|
Status OutcomeStatus
|
||||||
FullName string
|
FullName string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
BranchID ValidInt64 // Can Be Nullable
|
BranchID ValidInt64 // Can Be Nullable
|
||||||
UserID ValidInt64 // Can Be Nullable
|
UserID ValidInt64 // Can Be Nullable
|
||||||
IsShopBet bool
|
IsShopBet bool
|
||||||
|
CashedOut bool
|
||||||
|
CashoutID string
|
||||||
|
Outcomes []BetOutcome
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BetStatus) String() string {
|
type CreateBet struct {
|
||||||
return []string{"Pending", "Win", "Loss", "Error"}[b]
|
Amount Currency
|
||||||
|
TotalOdds float32
|
||||||
|
Status OutcomeStatus
|
||||||
|
FullName string
|
||||||
|
PhoneNumber string
|
||||||
|
BranchID ValidInt64 // Can Be Nullable
|
||||||
|
UserID ValidInt64 // Can Be Nullable
|
||||||
|
IsShopBet bool
|
||||||
|
CashoutID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// func isBetStatusValid()
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,61 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
type Branch struct {
|
type Branch struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string
|
Name string
|
||||||
Location string
|
Location string
|
||||||
WalletID int64
|
WalletID int64
|
||||||
BranchManagerID int64
|
BranchManagerID int64
|
||||||
IsSelfOwned bool
|
CompanyID int64
|
||||||
IsSupportingSportBook bool
|
IsSelfOwned bool
|
||||||
IsSupportingVirtual bool
|
|
||||||
IsSupportingGameZone bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BranchDetail struct {
|
||||||
|
ID int64
|
||||||
|
Name string
|
||||||
|
Location string
|
||||||
|
WalletID int64
|
||||||
|
BranchManagerID int64
|
||||||
|
CompanyID int64
|
||||||
|
IsSelfOwned bool
|
||||||
|
ManagerName string
|
||||||
|
ManagerPhoneNumber string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SupportedOperation struct {
|
||||||
|
ID int64
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BranchOperation struct {
|
||||||
|
ID int64
|
||||||
|
OperationName string
|
||||||
|
OperationDescription string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBranch struct {
|
||||||
|
Name string
|
||||||
|
Location string
|
||||||
|
WalletID int64
|
||||||
|
BranchManagerID int64
|
||||||
|
CompanyID int64
|
||||||
|
IsSelfOwned bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateBranch struct {
|
||||||
|
Name string
|
||||||
|
Location string
|
||||||
|
BranchManagerID int64
|
||||||
|
CompanyID int64
|
||||||
|
IsSelfOwned bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateSupportedOperation struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
type CreateBranchOperation struct {
|
||||||
|
BranchID int64
|
||||||
|
OperationID int64
|
||||||
|
}
|
||||||
|
|
|
||||||
1
internal/domain/chapa.go
Normal file
1
internal/domain/chapa.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package domain
|
||||||
|
|
@ -35,5 +35,17 @@ func (m Currency) String() string {
|
||||||
x := float32(m)
|
x := float32(m)
|
||||||
x = x / 100
|
x = x / 100
|
||||||
return fmt.Sprintf("$%.2f", x)
|
return fmt.Sprintf("$%.2f", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutcomeStatus int
|
||||||
|
|
||||||
|
const (
|
||||||
|
OUTCOME_STATUS_PENDING OutcomeStatus = iota
|
||||||
|
OUTCOME_STATUS_WIN
|
||||||
|
OUTCOME_STATUS_LOSS
|
||||||
|
OUTCOME_STATUS_ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b OutcomeStatus) String() string {
|
||||||
|
return []string{"Pending", "Win", "Loss", "Error"}[b]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
internal/domain/company.go
Normal file
21
internal/domain/company.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
type CreateCompany struct {
|
||||||
|
Name string
|
||||||
|
AdminID int64
|
||||||
|
WalletID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateCompany struct {
|
||||||
|
Name string
|
||||||
|
AdminID int64
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,41 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
type Event struct {}
|
import "time"
|
||||||
|
|
||||||
type Outcome struct {}
|
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
ID string
|
||||||
|
SportID string
|
||||||
|
MatchName string
|
||||||
|
HomeTeam string
|
||||||
|
AwayTeam string
|
||||||
|
HomeTeamID string
|
||||||
|
AwayTeamID string
|
||||||
|
HomeKitImage string
|
||||||
|
AwayKitImage string
|
||||||
|
LeagueID string
|
||||||
|
LeagueName string
|
||||||
|
LeagueCC string
|
||||||
|
StartTime string
|
||||||
|
Score string
|
||||||
|
MatchMinute int
|
||||||
|
TimerStatus string
|
||||||
|
AddedTime int
|
||||||
|
MatchPeriod int
|
||||||
|
IsLive bool
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
type UpcomingEvent struct {
|
||||||
|
ID string // Event ID
|
||||||
|
SportID string // Sport ID
|
||||||
|
MatchName string // Match or event name
|
||||||
|
HomeTeam string // Home team name (if available)
|
||||||
|
AwayTeam string // Away team name (can be empty/null)
|
||||||
|
HomeTeamID string // Home team ID
|
||||||
|
AwayTeamID string // Away team ID (can be empty/null)
|
||||||
|
HomeKitImage string // Kit or image for home team (optional)
|
||||||
|
AwayKitImage string // Kit or image for away team (optional)
|
||||||
|
LeagueID string // League ID
|
||||||
|
LeagueName string // League name
|
||||||
|
LeagueCC string // League country code
|
||||||
|
StartTime time.Time // Converted from "time" field in UNIX format
|
||||||
|
}
|
||||||
47
internal/domain/odds.go
Normal file
47
internal/domain/odds.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RawMessage interface{}
|
||||||
|
|
||||||
|
type Market struct {
|
||||||
|
EventID string
|
||||||
|
FI string
|
||||||
|
MarketCategory string
|
||||||
|
MarketType string
|
||||||
|
MarketName string
|
||||||
|
MarketID string
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Odds []json.RawMessage
|
||||||
|
Name string
|
||||||
|
Handicap string
|
||||||
|
OddsVal float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Odd struct {
|
||||||
|
EventID string `json:"event_id"`
|
||||||
|
Fi string `json:"fi"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
MarketCategory string `json:"market_category"`
|
||||||
|
MarketID string `json:"market_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Handicap string `json:"handicap"`
|
||||||
|
OddsValue float64 `json:"odds_value"`
|
||||||
|
Section string `json:"section"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
RawOdds []RawMessage `json:"raw_odds"`
|
||||||
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
type RawOddsByMarketID struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
Handicap string `json:"handicap"`
|
||||||
|
RawOdds []RawMessage `json:"raw_odds"`
|
||||||
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,54 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TicketOutcome struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
TicketID int64 `json:"ticket_id" example:"1"`
|
||||||
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
|
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
|
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
|
Status OutcomeStatus `json:"status" example:"1"`
|
||||||
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTicketOutcome struct {
|
||||||
|
TicketID int64 `json:"ticket_id" example:"1"`
|
||||||
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
|
HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
|
AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
|
MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
|
Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
OddName string `json:"odd_name" example:"1"`
|
||||||
|
OddHeader string `json:"odd_header" example:"1"`
|
||||||
|
OddHandicap string `json:"odd_handicap" example:"1"`
|
||||||
|
Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
|
}
|
||||||
|
|
||||||
// ID will serve as the fast code since this doesn't need to be secure
|
// ID will serve as the fast code since this doesn't need to be secure
|
||||||
type Ticket struct {
|
type Ticket struct {
|
||||||
ID int64
|
ID int64
|
||||||
Outcomes []Outcome
|
|
||||||
Amount Currency
|
Amount Currency
|
||||||
TotalOdds float32
|
TotalOdds float32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetTicket struct {
|
||||||
|
ID int64
|
||||||
|
Amount Currency
|
||||||
|
TotalOdds float32
|
||||||
|
Outcomes []TicketOutcome
|
||||||
|
}
|
||||||
|
|
||||||
type CreateTicket struct {
|
type CreateTicket struct {
|
||||||
Outcomes []int64
|
|
||||||
Amount Currency
|
Amount Currency
|
||||||
TotalOdds float32
|
TotalOdds float32
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
type TransactionType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TRANSACTION_CASHOUT TransactionType = iota
|
||||||
|
TRANSACTION_DEPOSIT
|
||||||
|
)
|
||||||
|
|
||||||
type PaymentOption int64
|
type PaymentOption int64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -9,12 +16,15 @@ const (
|
||||||
BANK
|
BANK
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Transaction only represents when the user cashes out a bet in the shop
|
||||||
|
// It probably would be better to call it a CashOut or ShopWithdrawal
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
ID int64
|
ID int64
|
||||||
Amount Currency
|
Amount Currency
|
||||||
BranchID int64
|
BranchID int64
|
||||||
CashierID int64
|
CashierID int64
|
||||||
BetID int64
|
BetID int64
|
||||||
|
Type TransactionType
|
||||||
PaymentOption PaymentOption
|
PaymentOption PaymentOption
|
||||||
FullName string
|
FullName string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
|
|
@ -32,6 +42,7 @@ type CreateTransaction struct {
|
||||||
BranchID int64
|
BranchID int64
|
||||||
CashierID int64
|
CashierID int64
|
||||||
BetID int64
|
BetID int64
|
||||||
|
Type TransactionType
|
||||||
PaymentOption PaymentOption
|
PaymentOption PaymentOption
|
||||||
FullName string
|
FullName string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,48 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type TransferType string
|
type TransferType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DEPOSIT TransferType = "deposit"
|
DEPOSIT TransferType = "deposit"
|
||||||
WITHDRAW TransferType = "withdraw"
|
WITHDRAW TransferType = "withdraw"
|
||||||
|
WALLET TransferType = "wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PaymentMethod string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TRANSFER_CASH PaymentMethod = "cash"
|
||||||
|
TRANSFER_BANK PaymentMethod = "bank"
|
||||||
|
TRANSFER_CHAPA PaymentMethod = "chapa"
|
||||||
|
TRANSFER_ARIFPAY PaymentMethod = "arifpay"
|
||||||
|
TRANSFER_SANTIMPAY PaymentMethod = "santimpay"
|
||||||
|
TRANSFER_ADDISPAY PaymentMethod = "addispay"
|
||||||
|
TRANSFER_OTHER PaymentMethod = "other"
|
||||||
|
)
|
||||||
|
|
||||||
|
// There is always a receiving wallet id
|
||||||
|
// There is a sender wallet id only if wallet transfer type
|
||||||
type Transfer struct {
|
type Transfer struct {
|
||||||
ID int64
|
ID int64
|
||||||
Amount Currency
|
Amount Currency
|
||||||
Verified bool
|
Verified bool
|
||||||
WalletID int64
|
Type TransferType
|
||||||
Type TransferType
|
PaymentMethod PaymentMethod
|
||||||
|
ReceiverWalletID int64
|
||||||
|
SenderWalletID ValidInt64
|
||||||
|
CashierID ValidInt64
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTransfer struct {
|
type CreateTransfer struct {
|
||||||
Amount Currency
|
Amount Currency
|
||||||
Verified bool
|
Verified bool
|
||||||
WalletID int64
|
ReceiverWalletID int64
|
||||||
Type TransferType
|
SenderWalletID ValidInt64
|
||||||
|
CashierID ValidInt64
|
||||||
|
Type TransferType
|
||||||
|
PaymentMethod PaymentMethod
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ type User struct {
|
||||||
//
|
//
|
||||||
SuspendedAt time.Time
|
SuspendedAt time.Time
|
||||||
Suspended bool
|
Suspended bool
|
||||||
|
//
|
||||||
|
BranchID int64
|
||||||
}
|
}
|
||||||
type RegisterUserReq struct {
|
type RegisterUserReq struct {
|
||||||
FirstName string
|
FirstName string
|
||||||
|
|
@ -33,11 +35,19 @@ type RegisterUserReq struct {
|
||||||
Email string
|
Email string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
Password string
|
Password string
|
||||||
//Role string
|
Role string
|
||||||
Otp string
|
Otp string
|
||||||
ReferralCode string `json:"referral_code"`
|
ReferralCode string `json:"referral_code"`
|
||||||
OtpMedium OtpMedium
|
OtpMedium OtpMedium
|
||||||
}
|
}
|
||||||
|
type CreateUserReq struct {
|
||||||
|
FirstName string
|
||||||
|
LastName string
|
||||||
|
Email string
|
||||||
|
PhoneNumber string
|
||||||
|
Password string
|
||||||
|
Role string
|
||||||
|
}
|
||||||
type ResetPasswordReq struct {
|
type ResetPasswordReq struct {
|
||||||
Email string
|
Email string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
|
|
@ -46,6 +56,7 @@ type ResetPasswordReq struct {
|
||||||
OtpMedium OtpMedium
|
OtpMedium OtpMedium
|
||||||
}
|
}
|
||||||
type UpdateUserReq struct {
|
type UpdateUserReq struct {
|
||||||
|
UserId int64
|
||||||
FirstName ValidString
|
FirstName ValidString
|
||||||
LastName ValidString
|
LastName ValidString
|
||||||
Suspended ValidBool
|
Suspended ValidBool
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,23 @@ package domain
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Wallet struct {
|
type Wallet struct {
|
||||||
ID int64
|
ID int64
|
||||||
Balance Currency
|
Balance Currency
|
||||||
IsWithdraw bool
|
IsWithdraw bool
|
||||||
IsBettable bool
|
IsBettable bool
|
||||||
IsActive bool
|
IsTransferable bool
|
||||||
UserID int64
|
IsActive bool
|
||||||
UpdatedAt time.Time
|
UserID int64
|
||||||
CreatedAt time.Time
|
UpdatedAt time.Time
|
||||||
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomerWallet struct {
|
type CustomerWallet struct {
|
||||||
ID int64
|
ID int64
|
||||||
RegularID int64
|
RegularID int64
|
||||||
StaticID int64
|
StaticID int64
|
||||||
CustomerID int64
|
CustomerID int64
|
||||||
CompanyID int64
|
CompanyID int64
|
||||||
}
|
}
|
||||||
type GetCustomerWallet struct {
|
type GetCustomerWallet struct {
|
||||||
ID int64
|
ID int64
|
||||||
|
|
@ -33,10 +34,24 @@ type GetCustomerWallet struct {
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BranchWallet struct {
|
||||||
|
ID int64
|
||||||
|
Balance Currency
|
||||||
|
IsActive bool
|
||||||
|
Name string
|
||||||
|
Location string
|
||||||
|
BranchManagerID int64
|
||||||
|
CompanyID int64
|
||||||
|
IsSelfOwned bool
|
||||||
|
UpdatedAt time.Time
|
||||||
|
CreatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
type CreateWallet struct {
|
type CreateWallet struct {
|
||||||
IsWithdraw bool
|
IsWithdraw bool
|
||||||
IsBettable bool
|
IsBettable bool
|
||||||
UserID int64
|
IsTransferable bool
|
||||||
|
UserID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateCustomerWallet struct {
|
type CreateCustomerWallet struct {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
// "fmt"
|
||||||
|
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
|
@ -13,7 +14,7 @@ func convertDBBet(bet dbgen.Bet) domain.Bet {
|
||||||
ID: bet.ID,
|
ID: bet.ID,
|
||||||
Amount: domain.Currency(bet.Amount),
|
Amount: domain.Currency(bet.Amount),
|
||||||
TotalOdds: bet.TotalOdds,
|
TotalOdds: bet.TotalOdds,
|
||||||
Status: domain.BetStatus(bet.Status),
|
Status: domain.OutcomeStatus(bet.Status),
|
||||||
FullName: bet.FullName,
|
FullName: bet.FullName,
|
||||||
PhoneNumber: bet.PhoneNumber,
|
PhoneNumber: bet.PhoneNumber,
|
||||||
BranchID: domain.ValidInt64{
|
BranchID: domain.ValidInt64{
|
||||||
|
|
@ -25,6 +26,71 @@ func convertDBBet(bet dbgen.Bet) domain.Bet {
|
||||||
Valid: bet.UserID.Valid,
|
Valid: bet.UserID.Valid,
|
||||||
},
|
},
|
||||||
IsShopBet: bet.IsShopBet,
|
IsShopBet: bet.IsShopBet,
|
||||||
|
CashedOut: bet.CashedOut,
|
||||||
|
CashoutID: bet.CashoutID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDBBetOutcomes(bet dbgen.BetWithOutcome) domain.GetBet {
|
||||||
|
var outcomes []domain.BetOutcome = make([]domain.BetOutcome, 0, len(bet.Outcomes))
|
||||||
|
|
||||||
|
for _, outcome := range bet.Outcomes {
|
||||||
|
outcomes = append(outcomes, domain.BetOutcome{
|
||||||
|
ID: outcome.ID,
|
||||||
|
BetID: outcome.BetID,
|
||||||
|
EventID: outcome.EventID,
|
||||||
|
OddID: outcome.OddID,
|
||||||
|
HomeTeamName: outcome.HomeTeamName,
|
||||||
|
AwayTeamName: outcome.AwayTeamName,
|
||||||
|
MarketID: outcome.MarketID,
|
||||||
|
MarketName: outcome.MarketName,
|
||||||
|
Odd: outcome.Odd,
|
||||||
|
OddName: outcome.OddName,
|
||||||
|
OddHeader: outcome.OddHeader,
|
||||||
|
OddHandicap: outcome.OddHandicap,
|
||||||
|
Status: domain.OutcomeStatus(outcome.Status),
|
||||||
|
Expires: outcome.Expires.Time,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return domain.GetBet{
|
||||||
|
ID: bet.ID,
|
||||||
|
Amount: domain.Currency(bet.Amount),
|
||||||
|
TotalOdds: bet.TotalOdds,
|
||||||
|
Status: domain.OutcomeStatus(bet.Status),
|
||||||
|
FullName: bet.FullName,
|
||||||
|
PhoneNumber: bet.PhoneNumber,
|
||||||
|
BranchID: domain.ValidInt64{
|
||||||
|
Value: bet.BranchID.Int64,
|
||||||
|
Valid: bet.BranchID.Valid,
|
||||||
|
},
|
||||||
|
UserID: domain.ValidInt64{
|
||||||
|
Value: bet.UserID.Int64,
|
||||||
|
Valid: bet.UserID.Valid,
|
||||||
|
},
|
||||||
|
IsShopBet: bet.IsShopBet,
|
||||||
|
CashedOut: bet.CashedOut,
|
||||||
|
CashoutID: bet.CashoutID,
|
||||||
|
Outcomes: outcomes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDBCreateBetOutcome(betOutcome domain.CreateBetOutcome) dbgen.CreateBetOutcomeParams {
|
||||||
|
return dbgen.CreateBetOutcomeParams{
|
||||||
|
BetID: betOutcome.BetID,
|
||||||
|
EventID: betOutcome.EventID,
|
||||||
|
OddID: betOutcome.OddID,
|
||||||
|
HomeTeamName: betOutcome.HomeTeamName,
|
||||||
|
AwayTeamName: betOutcome.AwayTeamName,
|
||||||
|
MarketID: betOutcome.MarketID,
|
||||||
|
MarketName: betOutcome.MarketName,
|
||||||
|
Odd: betOutcome.Odd,
|
||||||
|
OddName: betOutcome.OddName,
|
||||||
|
OddHeader: betOutcome.OddHeader,
|
||||||
|
OddHandicap: betOutcome.OddHandicap,
|
||||||
|
Expires: pgtype.Timestamp{
|
||||||
|
Time: betOutcome.Expires,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,11 +110,11 @@ func convertCreateBet(bet domain.CreateBet) dbgen.CreateBetParams {
|
||||||
Valid: bet.UserID.Valid,
|
Valid: bet.UserID.Valid,
|
||||||
},
|
},
|
||||||
IsShopBet: bet.IsShopBet,
|
IsShopBet: bet.IsShopBet,
|
||||||
|
CashoutID: bet.CashoutID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
|
func (s *Store) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
|
||||||
|
|
||||||
newBet, err := s.queries.CreateBet(ctx, convertCreateBet(bet))
|
newBet, err := s.queries.CreateBet(ctx, convertCreateBet(bet))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Bet{}, err
|
return domain.Bet{}, err
|
||||||
|
|
@ -57,25 +123,68 @@ func (s *Store) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.Bet, error) {
|
func (s *Store) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error) {
|
||||||
bet, err := s.queries.GetBetByID(ctx, id)
|
var dbParams []dbgen.CreateBetOutcomeParams = make([]dbgen.CreateBetOutcomeParams, 0, len(outcomes))
|
||||||
|
|
||||||
|
for _, outcome := range outcomes {
|
||||||
|
dbParams = append(dbParams, convertDBCreateBetOutcome(outcome))
|
||||||
|
}
|
||||||
|
rows, err := s.queries.CreateBetOutcome(ctx, dbParams)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Bet{}, err
|
return rows, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertDBBet(bet), nil
|
return rows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetAllBets(ctx context.Context) ([]domain.Bet, error) {
|
func (s *Store) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
|
||||||
|
bet, err := s.queries.GetBetByID(ctx, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.GetBet{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertDBBetOutcomes(bet), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) {
|
||||||
|
bet, err := s.queries.GetBetByCashoutID(ctx, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.GetBet{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertDBBetOutcomes(bet), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllBets(ctx context.Context) ([]domain.GetBet, error) {
|
||||||
bets, err := s.queries.GetAllBets(ctx)
|
bets, err := s.queries.GetAllBets(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
|
||||||
|
for _, bet := range bets {
|
||||||
|
result = append(result, convertDBBetOutcomes(bet))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error) {
|
||||||
|
bets, err := s.queries.GetBetByBranchID(ctx, pgtype.Int8{
|
||||||
|
Int64: BranchID,
|
||||||
|
Valid: true,
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []domain.Bet = make([]domain.Bet, len(bets))
|
var result []domain.GetBet = make([]domain.GetBet, 0, len(bets))
|
||||||
for _, bet := range bets {
|
for _, bet := range bets {
|
||||||
result = append(result, convertDBBet(bet))
|
result = append(result, convertDBBetOutcomes(bet))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
@ -83,10 +192,24 @@ func (s *Store) GetAllBets(ctx context.Context) ([]domain.Bet, error) {
|
||||||
|
|
||||||
func (s *Store) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error {
|
func (s *Store) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error {
|
||||||
err := s.queries.UpdateCashOut(ctx, dbgen.UpdateCashOutParams{
|
err := s.queries.UpdateCashOut(ctx, dbgen.UpdateCashOutParams{
|
||||||
ID: id,
|
ID: id,
|
||||||
CashedOut: pgtype.Bool{
|
CashedOut: cashedOut,
|
||||||
Bool: cashedOut,
|
})
|
||||||
},
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
err := s.queries.UpdateStatus(ctx, dbgen.UpdateStatusParams{
|
||||||
|
ID: id,
|
||||||
|
Status: int32(status),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
err := s.queries.UpdateBetOutcomeStatus(ctx, dbgen.UpdateBetOutcomeStatusParams{
|
||||||
|
Status: int32(status),
|
||||||
|
ID: id,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
224
internal/repository/branch.go
Normal file
224
internal/repository/branch.go
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertCreateBranch(branch domain.CreateBranch) dbgen.CreateBranchParams {
|
||||||
|
return dbgen.CreateBranchParams{
|
||||||
|
Name: branch.Name,
|
||||||
|
Location: branch.Location,
|
||||||
|
WalletID: branch.WalletID,
|
||||||
|
BranchManagerID: branch.BranchManagerID,
|
||||||
|
CompanyID: branch.CompanyID,
|
||||||
|
IsSelfOwned: branch.IsSelfOwned,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDBBranchDetail(dbBranch dbgen.BranchDetail) domain.BranchDetail {
|
||||||
|
return domain.BranchDetail{
|
||||||
|
ID: dbBranch.ID,
|
||||||
|
Name: dbBranch.Name,
|
||||||
|
Location: dbBranch.Location,
|
||||||
|
WalletID: dbBranch.WalletID,
|
||||||
|
BranchManagerID: dbBranch.BranchManagerID,
|
||||||
|
CompanyID: dbBranch.CompanyID,
|
||||||
|
IsSelfOwned: dbBranch.IsSelfOwned,
|
||||||
|
ManagerName: dbBranch.ManagerName.(string),
|
||||||
|
ManagerPhoneNumber: dbBranch.ManagerPhoneNumber.String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDBBranch(dbBranch dbgen.Branch) domain.Branch {
|
||||||
|
return domain.Branch{
|
||||||
|
ID: dbBranch.ID,
|
||||||
|
Name: dbBranch.Name,
|
||||||
|
Location: dbBranch.Location,
|
||||||
|
WalletID: dbBranch.WalletID,
|
||||||
|
BranchManagerID: dbBranch.BranchManagerID,
|
||||||
|
CompanyID: dbBranch.CompanyID,
|
||||||
|
IsSelfOwned: dbBranch.IsSelfOwned,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error) {
|
||||||
|
|
||||||
|
dbBranch, err := s.queries.CreateBranch(ctx, convertCreateBranch(branch))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.Branch{}, err
|
||||||
|
}
|
||||||
|
return convertDBBranch(dbBranch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error) {
|
||||||
|
dbBranch, err := s.queries.GetBranchByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return domain.BranchDetail{}, err
|
||||||
|
}
|
||||||
|
return convertDBBranchDetail(dbBranch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]domain.BranchDetail, error) {
|
||||||
|
dbBranches, err := s.queries.GetBranchByManagerID(ctx, branchManagerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var branches []domain.BranchDetail = make([]domain.BranchDetail, 0, len(dbBranches))
|
||||||
|
for _, dbBranch := range dbBranches {
|
||||||
|
branches = append(branches, convertDBBranchDetail(dbBranch))
|
||||||
|
}
|
||||||
|
return branches, nil
|
||||||
|
}
|
||||||
|
func (s *Store) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error) {
|
||||||
|
dbBranches, err := s.queries.GetBranchByCompanyID(ctx, companyID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var branches []domain.BranchDetail = make([]domain.BranchDetail, 0, len(dbBranches))
|
||||||
|
for _, dbBranch := range dbBranches {
|
||||||
|
branches = append(branches, convertDBBranchDetail(dbBranch))
|
||||||
|
}
|
||||||
|
return branches, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error) {
|
||||||
|
dbBranches, err := s.queries.GetAllBranches(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var branches []domain.BranchDetail = make([]domain.BranchDetail, 0, len(dbBranches))
|
||||||
|
for _, dbBranch := range dbBranches {
|
||||||
|
branches = append(branches, convertDBBranchDetail(dbBranch))
|
||||||
|
}
|
||||||
|
return branches, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error) {
|
||||||
|
dbBranches, err := s.queries.SearchBranchByName(ctx, pgtype.Text{String: name, Valid: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var branches []domain.BranchDetail = make([]domain.BranchDetail, 0, len(dbBranches))
|
||||||
|
for _, dbBranch := range dbBranches {
|
||||||
|
branches = append(branches, convertDBBranchDetail(dbBranch))
|
||||||
|
}
|
||||||
|
return branches, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error) {
|
||||||
|
dbBranch, err := s.queries.UpdateBranch(ctx, dbgen.UpdateBranchParams{
|
||||||
|
ID: id,
|
||||||
|
Name: branch.Name,
|
||||||
|
Location: branch.Location,
|
||||||
|
BranchManagerID: branch.BranchManagerID,
|
||||||
|
IsSelfOwned: branch.IsSelfOwned,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Branch{}, err
|
||||||
|
}
|
||||||
|
return convertDBBranch(dbBranch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteBranch(ctx context.Context, id int64) error {
|
||||||
|
return s.queries.DeleteBranch(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch Operations
|
||||||
|
|
||||||
|
func (s *Store) CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error {
|
||||||
|
_, err := s.queries.CreateBranchOperation(ctx, dbgen.CreateBranchOperationParams{
|
||||||
|
BranchID: branchOperation.BranchID,
|
||||||
|
OperationID: branchOperation.OperationID,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) CreateSupportedOperation(ctx context.Context, supportedOperation domain.CreateSupportedOperation) (domain.SupportedOperation, error) {
|
||||||
|
dbSupportedOperation, err := s.queries.CreateSupportedOperation(ctx, dbgen.CreateSupportedOperationParams{
|
||||||
|
Name: supportedOperation.Name,
|
||||||
|
Description: supportedOperation.Description,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.SupportedOperation{}, err
|
||||||
|
}
|
||||||
|
return domain.SupportedOperation{
|
||||||
|
ID: dbSupportedOperation.ID,
|
||||||
|
Name: dbSupportedOperation.Name,
|
||||||
|
Description: dbSupportedOperation.Description,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) CreateBranchCashier(ctx context.Context, branchID int64, userID int64) error {
|
||||||
|
_, err := s.queries.CreateBranchCashier(ctx, dbgen.CreateBranchCashierParams{
|
||||||
|
UserID: userID,
|
||||||
|
BranchID: branchID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error) {
|
||||||
|
dbOperations, err := s.queries.GetAllSupportedOperations(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var operations []domain.SupportedOperation = make([]domain.SupportedOperation, 0, len(dbOperations))
|
||||||
|
for _, dbOperation := range dbOperations {
|
||||||
|
operations = append(operations, domain.SupportedOperation{
|
||||||
|
ID: dbOperation.ID,
|
||||||
|
Name: dbOperation.Name,
|
||||||
|
Description: dbOperation.Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return operations, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error) {
|
||||||
|
dbBranchOperations, err := s.queries.GetBranchOperations(ctx, branchID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var branchOperations []domain.BranchOperation = make([]domain.BranchOperation, 0, len(dbBranchOperations))
|
||||||
|
for _, dbBranchOperation := range dbBranchOperations {
|
||||||
|
branchOperations = append(branchOperations, domain.BranchOperation{
|
||||||
|
ID: dbBranchOperation.ID,
|
||||||
|
OperationName: dbBranchOperation.Name,
|
||||||
|
OperationDescription: dbBranchOperation.Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return branchOperations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error) {
|
||||||
|
branch, err := s.queries.GetBranchByCashier(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Branch{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertDBBranch(branch), err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (s *Store) DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error {
|
||||||
|
err := s.queries.DeleteBranchOperation(ctx, dbgen.DeleteBranchOperationParams{
|
||||||
|
BranchID: branchID,
|
||||||
|
OperationID: operationID,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteBranchCashier(ctx context.Context, userID int64) error {
|
||||||
|
return s.queries.DeleteBranchCashier(ctx, userID)
|
||||||
|
|
||||||
|
}
|
||||||
74
internal/repository/company.go
Normal file
74
internal/repository/company.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) {
|
||||||
|
dbCompany, err := s.queries.CreateCompany(ctx, convertCreateCompany(company))
|
||||||
|
if err != nil {
|
||||||
|
return domain.Company{}, err
|
||||||
|
}
|
||||||
|
return convertDBCompany(dbCompany), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllCompanies(ctx context.Context) ([]domain.Company, error) {
|
||||||
|
dbCompanies, err := s.queries.GetAllCompanies(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var companies []domain.Company = make([]domain.Company, 0, len(dbCompanies))
|
||||||
|
for _, dbCompany := range dbCompanies {
|
||||||
|
companies = append(companies, convertDBCompany(dbCompany))
|
||||||
|
}
|
||||||
|
|
||||||
|
return companies, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.Company, error) {
|
||||||
|
dbCompany, err := s.queries.GetCompanyByID(ctx, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.Company{}, err
|
||||||
|
}
|
||||||
|
return convertDBCompany(dbCompany), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateCompany(ctx context.Context, id int64, company domain.UpdateCompany) (domain.Company, error) {
|
||||||
|
dbCompany, err := s.queries.UpdateCompany(ctx, dbgen.UpdateCompanyParams{
|
||||||
|
ID: id,
|
||||||
|
Name: company.Name,
|
||||||
|
AdminID: company.AdminID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.Company{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertDBCompany(dbCompany), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteCompany(ctx context.Context, id int64) error {
|
||||||
|
return s.queries.DeleteCompany(ctx, id)
|
||||||
|
}
|
||||||
165
internal/repository/event.go
Normal file
165
internal/repository/event.go
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
|
||||||
|
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
|
||||||
|
parsedTime, err := time.Parse(time.RFC3339, e.StartTime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.queries.InsertEvent(ctx, dbgen.InsertEventParams{
|
||||||
|
ID: e.ID,
|
||||||
|
SportID: pgtype.Text{String: e.SportID, Valid: true},
|
||||||
|
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
|
||||||
|
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
|
||||||
|
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
|
||||||
|
HomeTeamID: pgtype.Text{String: e.HomeTeamID, Valid: true},
|
||||||
|
AwayTeamID: pgtype.Text{String: e.AwayTeamID, Valid: true},
|
||||||
|
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
|
||||||
|
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
|
||||||
|
LeagueID: pgtype.Text{String: e.LeagueID, Valid: true},
|
||||||
|
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
|
||||||
|
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
|
||||||
|
StartTime: pgtype.Timestamp{Time: parsedTime, Valid: true},
|
||||||
|
Score: pgtype.Text{String: e.Score, Valid: true},
|
||||||
|
MatchMinute: pgtype.Int4{Int32: int32(e.MatchMinute), Valid: true},
|
||||||
|
TimerStatus: pgtype.Text{String: e.TimerStatus, Valid: true},
|
||||||
|
AddedTime: pgtype.Int4{Int32: int32(e.AddedTime), Valid: true},
|
||||||
|
MatchPeriod: pgtype.Int4{Int32: int32(e.MatchPeriod), Valid: true},
|
||||||
|
IsLive: pgtype.Bool{Bool: e.IsLive, Valid: true},
|
||||||
|
Status: pgtype.Text{String: e.Status, Valid: true},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
|
||||||
|
return s.queries.InsertUpcomingEvent(ctx, dbgen.InsertUpcomingEventParams{
|
||||||
|
ID: e.ID,
|
||||||
|
SportID: pgtype.Text{String: e.SportID, Valid: true},
|
||||||
|
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
|
||||||
|
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
|
||||||
|
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
|
||||||
|
HomeTeamID: pgtype.Text{String: e.HomeTeamID, Valid: true},
|
||||||
|
AwayTeamID: pgtype.Text{String: e.AwayTeamID, Valid: true},
|
||||||
|
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
|
||||||
|
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
|
||||||
|
LeagueID: pgtype.Text{String: e.LeagueID, Valid: true},
|
||||||
|
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
|
||||||
|
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
|
||||||
|
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
|
||||||
|
return s.queries.ListLiveEvents(ctx)
|
||||||
|
}
|
||||||
|
func (s *Store) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
|
||||||
|
events, err := s.queries.GetAllUpcomingEvents(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
upcomingEvents := make([]domain.UpcomingEvent, len(events))
|
||||||
|
for i, e := range events {
|
||||||
|
upcomingEvents[i] = domain.UpcomingEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
SportID: e.SportID.String,
|
||||||
|
MatchName: e.MatchName.String,
|
||||||
|
HomeTeam: e.HomeTeam.String,
|
||||||
|
AwayTeam: e.AwayTeam.String,
|
||||||
|
HomeTeamID: e.HomeTeamID.String,
|
||||||
|
AwayTeamID: e.AwayTeamID.String,
|
||||||
|
HomeKitImage: e.HomeKitImage.String,
|
||||||
|
AwayKitImage: e.AwayKitImage.String,
|
||||||
|
LeagueID: e.LeagueID.String,
|
||||||
|
LeagueName: e.LeagueName.String,
|
||||||
|
LeagueCC: e.LeagueCc.String,
|
||||||
|
StartTime: e.StartTime.Time.UTC(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upcomingEvents, nil
|
||||||
|
}
|
||||||
|
func (s *Store) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32, leagueID domain.ValidString, sportID domain.ValidString) ([]domain.UpcomingEvent, int64, error) {
|
||||||
|
events, err := s.queries.GetPaginatedUpcomingEvents(ctx, dbgen.GetPaginatedUpcomingEventsParams{
|
||||||
|
LeagueID: pgtype.Text{
|
||||||
|
String: leagueID.Value,
|
||||||
|
Valid: leagueID.Valid,
|
||||||
|
},
|
||||||
|
SportID: pgtype.Text{
|
||||||
|
String: sportID.Value,
|
||||||
|
Valid: sportID.Valid,
|
||||||
|
},
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset * limit,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
upcomingEvents := make([]domain.UpcomingEvent, len(events))
|
||||||
|
for i, e := range events {
|
||||||
|
upcomingEvents[i] = domain.UpcomingEvent{
|
||||||
|
ID: e.ID,
|
||||||
|
SportID: e.SportID.String,
|
||||||
|
MatchName: e.MatchName.String,
|
||||||
|
HomeTeam: e.HomeTeam.String,
|
||||||
|
AwayTeam: e.AwayTeam.String,
|
||||||
|
HomeTeamID: e.HomeTeamID.String,
|
||||||
|
AwayTeamID: e.AwayTeamID.String,
|
||||||
|
HomeKitImage: e.HomeKitImage.String,
|
||||||
|
AwayKitImage: e.AwayKitImage.String,
|
||||||
|
LeagueID: e.LeagueID.String,
|
||||||
|
LeagueName: e.LeagueName.String,
|
||||||
|
LeagueCC: e.LeagueCc.String,
|
||||||
|
StartTime: e.StartTime.Time.UTC(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalCount, err := s.queries.GetTotalEvents(ctx, dbgen.GetTotalEventsParams{
|
||||||
|
LeagueID: pgtype.Text{
|
||||||
|
String: leagueID.Value,
|
||||||
|
Valid: leagueID.Valid,
|
||||||
|
},
|
||||||
|
SportID: pgtype.Text{
|
||||||
|
String: sportID.Value,
|
||||||
|
Valid: sportID.Valid,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfPages := math.Ceil(float64(totalCount) / float64(limit))
|
||||||
|
return upcomingEvents, int64(numberOfPages), nil
|
||||||
|
}
|
||||||
|
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
|
event, err := s.queries.GetUpcomingByID(ctx, ID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.UpcomingEvent{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.UpcomingEvent{
|
||||||
|
ID: event.ID,
|
||||||
|
SportID: event.SportID.String,
|
||||||
|
MatchName: event.MatchName.String,
|
||||||
|
HomeTeam: event.HomeTeam.String,
|
||||||
|
AwayTeam: event.AwayTeam.String,
|
||||||
|
HomeTeamID: event.HomeTeamID.String,
|
||||||
|
AwayTeamID: event.AwayTeamID.String,
|
||||||
|
HomeKitImage: event.HomeKitImage.String,
|
||||||
|
AwayKitImage: event.AwayKitImage.String,
|
||||||
|
LeagueID: event.LeagueID.String,
|
||||||
|
LeagueName: event.LeagueName.String,
|
||||||
|
LeagueCC: event.LeagueCc.String,
|
||||||
|
StartTime: event.StartTime.Time.UTC(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
249
internal/repository/odds.go
Normal file
249
internal/repository/odds.go
Normal file
|
|
@ -0,0 +1,249 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
||||||
|
if len(m.Odds) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, raw := range m.Odds {
|
||||||
|
var item map[string]interface{}
|
||||||
|
if err := json.Unmarshal(raw, &item); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := getString(item["name"])
|
||||||
|
handicap := getString(item["handicap"])
|
||||||
|
oddsVal := getFloat(item["odds"])
|
||||||
|
|
||||||
|
rawOddsBytes, _ := json.Marshal(m.Odds)
|
||||||
|
|
||||||
|
params := dbgen.InsertNonLiveOddParams{
|
||||||
|
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
||||||
|
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
|
||||||
|
MarketType: m.MarketType,
|
||||||
|
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
|
||||||
|
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
|
||||||
|
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
|
||||||
|
Name: pgtype.Text{String: name, Valid: name != ""},
|
||||||
|
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
|
||||||
|
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
|
||||||
|
Section: m.MarketCategory,
|
||||||
|
Category: pgtype.Text{Valid: false},
|
||||||
|
RawOdds: rawOddsBytes,
|
||||||
|
IsActive: pgtype.Bool{Bool: true, Valid: true},
|
||||||
|
Source: pgtype.Text{String: "b365api", Valid: true},
|
||||||
|
FetchedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.queries.InsertNonLiveOdd(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
_ = writeFailedMarketLog(m, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFailedMarketLog(m domain.Market, err error) error {
|
||||||
|
logDir := "logs"
|
||||||
|
logFile := logDir + "/failed_markets.log"
|
||||||
|
|
||||||
|
if mkErr := os.MkdirAll(logDir, 0755); mkErr != nil {
|
||||||
|
return mkErr
|
||||||
|
}
|
||||||
|
|
||||||
|
f, fileErr := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if fileErr != nil {
|
||||||
|
return fileErr
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
entry := struct {
|
||||||
|
Time string `json:"time"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Record domain.Market `json:"record"`
|
||||||
|
}{
|
||||||
|
Time: time.Now().Format(time.RFC3339),
|
||||||
|
Error: err.Error(),
|
||||||
|
Record: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, _ := json.MarshalIndent(entry, "", " ")
|
||||||
|
_, writeErr := f.WriteString(string(jsonData) + "\n\n")
|
||||||
|
return writeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func getString(v interface{}) string {
|
||||||
|
if s, ok := v.(string); ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFloat(v interface{}) float64 {
|
||||||
|
if s, ok := v.(string); ok {
|
||||||
|
f, err := strconv.ParseFloat(s, 64)
|
||||||
|
if err == nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
||||||
|
odds, err := s.queries.GetPrematchOdds(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
domainOdds := make([]domain.Odd, len(odds))
|
||||||
|
for i, odd := range odds {
|
||||||
|
domainOdds[i] = domain.Odd{
|
||||||
|
EventID: odd.EventID.String,
|
||||||
|
Fi: odd.Fi.String,
|
||||||
|
MarketType: odd.MarketType,
|
||||||
|
MarketName: odd.MarketName.String,
|
||||||
|
MarketCategory: odd.MarketCategory.String,
|
||||||
|
MarketID: odd.MarketID.String,
|
||||||
|
Name: odd.Name.String,
|
||||||
|
Handicap: odd.Handicap.String,
|
||||||
|
OddsValue: odd.OddsValue.Float64,
|
||||||
|
Section: odd.Section,
|
||||||
|
Category: odd.Category.String,
|
||||||
|
RawOdds: func() []domain.RawMessage {
|
||||||
|
var rawOdds []domain.RawMessage
|
||||||
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
||||||
|
rawOdds = nil
|
||||||
|
}
|
||||||
|
return rawOdds
|
||||||
|
}(),
|
||||||
|
FetchedAt: odd.FetchedAt.Time,
|
||||||
|
Source: odd.Source.String,
|
||||||
|
IsActive: odd.IsActive.Bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainOdds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
|
||||||
|
rows, err := s.queries.GetALLPrematchOdds(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
domainOdds := make([]domain.Odd, len(rows))
|
||||||
|
for i, row := range rows {
|
||||||
|
domainOdds[i] = domain.Odd{
|
||||||
|
// ID: int64(row.ID),
|
||||||
|
EventID: row.EventID.String,
|
||||||
|
Fi: row.Fi.String,
|
||||||
|
MarketType: row.MarketType,
|
||||||
|
MarketName: row.MarketName.String,
|
||||||
|
MarketCategory: row.MarketCategory.String,
|
||||||
|
MarketID: row.MarketID.String,
|
||||||
|
Name: row.Name.String,
|
||||||
|
Handicap: row.Handicap.String,
|
||||||
|
OddsValue: row.OddsValue.Float64,
|
||||||
|
Section: row.Section,
|
||||||
|
Category: row.Category.String,
|
||||||
|
RawOdds: func() []domain.RawMessage {
|
||||||
|
var rawOdds []domain.RawMessage
|
||||||
|
if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil {
|
||||||
|
rawOdds = nil
|
||||||
|
}
|
||||||
|
return rawOdds
|
||||||
|
}(),
|
||||||
|
FetchedAt: row.FetchedAt.Time,
|
||||||
|
Source: row.Source.String,
|
||||||
|
IsActive: row.IsActive.Bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainOdds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetRawOddsByMarketID(ctx context.Context, rawOddsID string, upcomingID string) (domain.RawOddsByMarketID, error) {
|
||||||
|
params := dbgen.GetRawOddsByMarketIDParams{
|
||||||
|
MarketID: pgtype.Text{String: rawOddsID, Valid: true},
|
||||||
|
Fi: pgtype.Text{String: upcomingID, Valid: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := s.queries.GetRawOddsByMarketID(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return domain.RawOddsByMarketID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawOdds []json.RawMessage
|
||||||
|
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
|
||||||
|
return domain.RawOddsByMarketID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.RawOddsByMarketID{
|
||||||
|
ID: int64(odds.ID),
|
||||||
|
MarketName: odds.MarketName.String,
|
||||||
|
Handicap: odds.Handicap.String,
|
||||||
|
RawOdds: func() []domain.RawMessage {
|
||||||
|
converted := make([]domain.RawMessage, len(rawOdds))
|
||||||
|
for i, r := range rawOdds {
|
||||||
|
converted[i] = domain.RawMessage(r)
|
||||||
|
}
|
||||||
|
return converted
|
||||||
|
}(),
|
||||||
|
FetchedAt: odds.FetchedAt.Time,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
||||||
|
params := dbgen.GetPrematchOddsByUpcomingIDParams{
|
||||||
|
ID: upcomingID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := s.queries.GetPrematchOddsByUpcomingID(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the results to domain.Odd
|
||||||
|
domainOdds := make([]domain.Odd, len(odds))
|
||||||
|
for i, odd := range odds {
|
||||||
|
var rawOdds []domain.RawMessage
|
||||||
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
||||||
|
rawOdds = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
domainOdds[i] = domain.Odd{
|
||||||
|
EventID: odd.EventID.String,
|
||||||
|
Fi: odd.Fi.String,
|
||||||
|
MarketType: odd.MarketType,
|
||||||
|
MarketName: odd.MarketName.String,
|
||||||
|
MarketCategory: odd.MarketCategory.String,
|
||||||
|
MarketID: odd.MarketID.String,
|
||||||
|
Name: odd.Name.String,
|
||||||
|
Handicap: odd.Handicap.String,
|
||||||
|
OddsValue: odd.OddsValue.Float64,
|
||||||
|
Section: odd.Section,
|
||||||
|
Category: odd.Category.String,
|
||||||
|
RawOdds: rawOdds,
|
||||||
|
FetchedAt: odd.FetchedAt.Time,
|
||||||
|
Source: odd.Source.String,
|
||||||
|
IsActive: odd.IsActive.Bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainOdds, nil
|
||||||
|
}
|
||||||
|
|
@ -11,16 +11,64 @@ import (
|
||||||
func convertDBTicket(ticket dbgen.Ticket) domain.Ticket {
|
func convertDBTicket(ticket dbgen.Ticket) domain.Ticket {
|
||||||
return domain.Ticket{
|
return domain.Ticket{
|
||||||
ID: ticket.ID,
|
ID: ticket.ID,
|
||||||
Amount: domain.Currency(ticket.Amount.Int64),
|
Amount: domain.Currency(ticket.Amount),
|
||||||
TotalOdds: ticket.TotalOdds,
|
TotalOdds: ticket.TotalOdds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertDBTicketOutcomes(ticket dbgen.TicketWithOutcome) domain.GetTicket {
|
||||||
|
|
||||||
|
var outcomes []domain.TicketOutcome = make([]domain.TicketOutcome, 0, len(ticket.Outcomes))
|
||||||
|
|
||||||
|
for _, outcome := range ticket.Outcomes {
|
||||||
|
outcomes = append(outcomes, domain.TicketOutcome{
|
||||||
|
ID: outcome.ID,
|
||||||
|
TicketID: outcome.TicketID,
|
||||||
|
EventID: outcome.EventID,
|
||||||
|
OddID: outcome.OddID,
|
||||||
|
HomeTeamName: outcome.HomeTeamName,
|
||||||
|
AwayTeamName: outcome.AwayTeamName,
|
||||||
|
MarketID: outcome.MarketID,
|
||||||
|
MarketName: outcome.MarketName,
|
||||||
|
Odd: outcome.Odd,
|
||||||
|
OddName: outcome.OddName,
|
||||||
|
OddHeader: outcome.OddHeader,
|
||||||
|
OddHandicap: outcome.OddHandicap,
|
||||||
|
Status: domain.OutcomeStatus(outcome.Status),
|
||||||
|
Expires: outcome.Expires.Time,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return domain.GetTicket{
|
||||||
|
ID: ticket.ID,
|
||||||
|
Amount: domain.Currency(ticket.Amount),
|
||||||
|
TotalOdds: ticket.TotalOdds,
|
||||||
|
Outcomes: outcomes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDBCreateTicketOutcome(ticketOutcome domain.CreateTicketOutcome) dbgen.CreateTicketOutcomeParams {
|
||||||
|
return dbgen.CreateTicketOutcomeParams{
|
||||||
|
TicketID: ticketOutcome.TicketID,
|
||||||
|
EventID: ticketOutcome.EventID,
|
||||||
|
OddID: ticketOutcome.OddID,
|
||||||
|
HomeTeamName: ticketOutcome.HomeTeamName,
|
||||||
|
AwayTeamName: ticketOutcome.AwayTeamName,
|
||||||
|
MarketID: ticketOutcome.MarketID,
|
||||||
|
MarketName: ticketOutcome.MarketName,
|
||||||
|
Odd: ticketOutcome.Odd,
|
||||||
|
OddName: ticketOutcome.OddName,
|
||||||
|
OddHeader: ticketOutcome.OddHeader,
|
||||||
|
OddHandicap: ticketOutcome.OddHandicap,
|
||||||
|
Expires: pgtype.Timestamp{
|
||||||
|
Time: ticketOutcome.Expires,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func convertCreateTicket(ticket domain.CreateTicket) dbgen.CreateTicketParams {
|
func convertCreateTicket(ticket domain.CreateTicket) dbgen.CreateTicketParams {
|
||||||
return dbgen.CreateTicketParams{
|
return dbgen.CreateTicketParams{
|
||||||
Amount: pgtype.Int8{
|
Amount: int64(ticket.Amount),
|
||||||
Int64: int64(ticket.Amount),
|
|
||||||
},
|
|
||||||
TotalOdds: ticket.TotalOdds,
|
TotalOdds: ticket.TotalOdds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -35,30 +83,54 @@ func (s *Store) CreateTicket(ctx context.Context, ticket domain.CreateTicket) (d
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) {
|
func (s *Store) CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error) {
|
||||||
ticket, err := s.queries.GetTicketByID(ctx, id)
|
|
||||||
if err != nil {
|
var dbParams []dbgen.CreateTicketOutcomeParams = make([]dbgen.CreateTicketOutcomeParams, 0, len(outcomes))
|
||||||
return domain.Ticket{}, err
|
for _, outcome := range outcomes {
|
||||||
|
dbParams = append(dbParams, convertDBCreateTicketOutcome(outcome))
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertDBTicket(ticket), nil
|
rows, err := s.queries.CreateTicketOutcome(ctx, dbParams)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return rows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetAllTickets(ctx context.Context) ([]domain.Ticket, error) {
|
func (s *Store) GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error) {
|
||||||
tickets, err := s.queries.GetAllTickets(ctx)
|
ticket, err := s.queries.GetTicketByID(ctx, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.GetTicket{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertDBTicketOutcomes(ticket), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error) {
|
||||||
|
tickets, err := s.queries.GetAllTickets(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []domain.Ticket = make([]domain.Ticket, len(tickets))
|
var result []domain.GetTicket = make([]domain.GetTicket, 0, len(tickets))
|
||||||
for _, ticket := range tickets {
|
for _, ticket := range tickets {
|
||||||
result = append(result, convertDBTicket(ticket))
|
result = append(result, convertDBTicketOutcomes(ticket))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
err := s.queries.UpdateTicketOutcomeStatus(ctx, dbgen.UpdateTicketOutcomeStatusParams{
|
||||||
|
Status: int32(status),
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) DeleteOldTickets(ctx context.Context) error {
|
func (s *Store) DeleteOldTickets(ctx context.Context) error {
|
||||||
return s.queries.DeleteOldTickets(ctx)
|
return s.queries.DeleteOldTickets(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ func convertDBTransaction(transaction dbgen.Transaction) domain.Transaction {
|
||||||
BranchID: transaction.BranchID,
|
BranchID: transaction.BranchID,
|
||||||
CashierID: transaction.CashierID,
|
CashierID: transaction.CashierID,
|
||||||
BetID: transaction.BetID,
|
BetID: transaction.BetID,
|
||||||
|
Type: domain.TransactionType(transaction.Type),
|
||||||
PaymentOption: domain.PaymentOption(transaction.PaymentOption),
|
PaymentOption: domain.PaymentOption(transaction.PaymentOption),
|
||||||
FullName: transaction.FullName,
|
FullName: transaction.FullName,
|
||||||
PhoneNumber: transaction.PhoneNumber,
|
PhoneNumber: transaction.PhoneNumber,
|
||||||
|
|
@ -30,6 +31,7 @@ func convertCreateTransaction(transaction domain.CreateTransaction) dbgen.Create
|
||||||
BranchID: transaction.BranchID,
|
BranchID: transaction.BranchID,
|
||||||
CashierID: transaction.CashierID,
|
CashierID: transaction.CashierID,
|
||||||
BetID: transaction.BetID,
|
BetID: transaction.BetID,
|
||||||
|
Type: int64(transaction.Type),
|
||||||
PaymentOption: int64(transaction.PaymentOption),
|
PaymentOption: int64(transaction.PaymentOption),
|
||||||
FullName: transaction.FullName,
|
FullName: transaction.FullName,
|
||||||
PhoneNumber: transaction.PhoneNumber,
|
PhoneNumber: transaction.PhoneNumber,
|
||||||
|
|
@ -66,7 +68,20 @@ func (s *Store) GetAllTransactions(ctx context.Context) ([]domain.Transaction, e
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []domain.Transaction = make([]domain.Transaction, len(transaction))
|
var result []domain.Transaction = make([]domain.Transaction, 0, len(transaction))
|
||||||
|
for _, ticket := range transaction {
|
||||||
|
result = append(result, convertDBTransaction(ticket))
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
func (s *Store) GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error) {
|
||||||
|
transaction, err := s.queries.GetTransactionByBranch(ctx, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []domain.Transaction = make([]domain.Transaction, 0, len(transaction))
|
||||||
for _, ticket := range transaction {
|
for _, ticket := range transaction {
|
||||||
result = append(result, convertDBTransaction(ticket))
|
result = append(result, convertDBTransaction(ticket))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,77 +1,96 @@
|
||||||
package repository
|
package repository
|
||||||
|
|
||||||
// import (
|
import (
|
||||||
// "context"
|
"context"
|
||||||
|
|
||||||
// dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
// "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
// )
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
// func convertDBTransaction(transaction dbgen.Transaction) domain.Transaction {
|
func convertDBTransfer(transfer dbgen.WalletTransfer) domain.Transfer {
|
||||||
// return domain.Transaction{
|
return domain.Transfer{
|
||||||
// ID: transaction.ID,
|
ID: transfer.ID,
|
||||||
// Amount: domain.Currency(transaction.Amount),
|
Amount: domain.Currency(transfer.Amount),
|
||||||
// Type: domain.TransactionType(transaction.TransactionType),
|
Type: domain.TransferType(transfer.Type),
|
||||||
// Verified: transaction.Verified,
|
Verified: transfer.Verified,
|
||||||
// WalletID: transaction.WalletID,
|
ReceiverWalletID: transfer.ReceiverWalletID,
|
||||||
// }
|
SenderWalletID: domain.ValidInt64{
|
||||||
// }
|
Value: transfer.SenderWalletID.Int64,
|
||||||
|
Valid: transfer.SenderWalletID.Valid,
|
||||||
|
},
|
||||||
|
CashierID: domain.ValidInt64{
|
||||||
|
Value: transfer.CashierID.Int64,
|
||||||
|
Valid: transfer.CashierID.Valid,
|
||||||
|
},
|
||||||
|
PaymentMethod: domain.PaymentMethod(transfer.PaymentMethod),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// func convertCreateTransaction(transaction domain.CreateTransaction) dbgen.CreateTransactionParams {
|
func convertCreateTransfer(transfer domain.CreateTransfer) dbgen.CreateTransferParams {
|
||||||
// return dbgen.CreateTransactionParams{
|
return dbgen.CreateTransferParams{
|
||||||
// Amount: int64(transaction.Amount),
|
Amount: int64(transfer.Amount),
|
||||||
// TransactionType: string(transaction.Type),
|
Type: string(transfer.Type),
|
||||||
// WalletID: transaction.WalletID,
|
ReceiverWalletID: transfer.ReceiverWalletID,
|
||||||
// }
|
SenderWalletID: pgtype.Int8{
|
||||||
// }
|
Int64: transfer.SenderWalletID.Value,
|
||||||
|
Valid: transfer.SenderWalletID.Valid,
|
||||||
|
},
|
||||||
|
CashierID: pgtype.Int8{
|
||||||
|
Int64: transfer.CashierID.Value,
|
||||||
|
Valid: transfer.CashierID.Valid,
|
||||||
|
},
|
||||||
|
PaymentMethod: string(transfer.PaymentMethod),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// func (s *Store) CreateTransaction(ctx context.Context, transaction domain.CreateTransaction) (domain.Transaction, error) {
|
func (s *Store) CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
||||||
// newTransaction, err := s.queries.CreateTransaction(ctx, convertCreateTransaction(transaction))
|
newTransfer, err := s.queries.CreateTransfer(ctx, convertCreateTransfer(transfer))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return domain.Transaction{}, err
|
return domain.Transfer{}, err
|
||||||
// }
|
}
|
||||||
// return convertDBTransaction(newTransaction), nil
|
return convertDBTransfer(newTransfer), nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func (s *Store) GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) {
|
func (s *Store) GetAllTransfers(ctx context.Context) ([]domain.Transfer, error) {
|
||||||
// transactions, err := s.queries.GetAllTransactions(ctx)
|
transfers, err := s.queries.GetAllTransfers(ctx)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return nil, err
|
return nil, err
|
||||||
// }
|
}
|
||||||
// var result []domain.Transaction = make([]domain.Transaction, len(transactions))
|
var result []domain.Transfer = make([]domain.Transfer, 0, len(transfers))
|
||||||
|
|
||||||
// for _, transaction := range transactions {
|
for _, transfer := range transfers {
|
||||||
// result = append(result, convertDBTransaction(transaction))
|
result = append(result, convertDBTransfer(transfer))
|
||||||
// }
|
}
|
||||||
// return result, nil
|
return result, nil
|
||||||
// }
|
}
|
||||||
// func (s *Store) GetTransactionsByWallet(ctx context.Context, walletID int64) ([]domain.Transaction, error) {
|
func (s *Store) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error) {
|
||||||
// transactions, err := s.queries.GetTransactionsByWallet(ctx, walletID)
|
transfers, err := s.queries.GetTransfersByWallet(ctx, walletID)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return nil, err
|
return nil, err
|
||||||
// }
|
}
|
||||||
|
|
||||||
// var result []domain.Transaction = make([]domain.Transaction, len(transactions))
|
var result []domain.Transfer = make([]domain.Transfer, 0, len(transfers))
|
||||||
|
|
||||||
// for _, transaction := range transactions {
|
for _, transfer := range transfers {
|
||||||
// result = append(result, convertDBTransaction(transaction))
|
result = append(result, convertDBTransfer(transfer))
|
||||||
// }
|
}
|
||||||
// return result, nil
|
return result, nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func (s *Store) GetTransactionByID(ctx context.Context, id int64) (domain.Transaction, error) {
|
func (s *Store) GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error) {
|
||||||
// transaction, err := s.queries.GetTransactionByID(ctx, id)
|
transfer, err := s.queries.GetTransferByID(ctx, id)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return domain.Transaction{}, nil
|
return domain.Transfer{}, nil
|
||||||
// }
|
}
|
||||||
// return convertDBTransaction(transaction), nil
|
return convertDBTransfer(transfer), nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func (s *Store) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error {
|
func (s *Store) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error {
|
||||||
// err := s.queries.UpdateTransferVerification(ctx, dbgen.UpdateTransferVerificationParams{
|
err := s.queries.UpdateTransferVerification(ctx, dbgen.UpdateTransferVerificationParams{
|
||||||
// ID: id,
|
ID: id,
|
||||||
// Verified: verified,
|
Verified: verified,
|
||||||
// })
|
})
|
||||||
|
|
||||||
// return err
|
return err
|
||||||
// }
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -82,7 +83,7 @@ func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
func (s *Store) GetAllUsers(ctx context.Context) ([]domain.User, error) {
|
func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.User, error) {
|
||||||
users, err := s.queries.GetAllUsers(ctx)
|
users, err := s.queries.GetAllUsers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -100,6 +101,68 @@ func (s *Store) GetAllUsers(ctx context.Context) ([]domain.User, error) {
|
||||||
}
|
}
|
||||||
return userList, nil
|
return userList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.User, error) {
|
||||||
|
users, err := s.queries.GetAllCashiers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userList := make([]domain.User, len(users))
|
||||||
|
for i, user := range users {
|
||||||
|
userList[i] = domain.User{
|
||||||
|
ID: user.ID,
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: user.Email.String,
|
||||||
|
PhoneNumber: user.PhoneNumber.String,
|
||||||
|
Role: domain.Role(user.Role),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) {
|
||||||
|
users, err := s.queries.GetCashiersByBranch(ctx, branchID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userList := make([]domain.User, len(users))
|
||||||
|
for i, user := range users {
|
||||||
|
userList[i] = domain.User{
|
||||||
|
ID: user.ID,
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: user.Email.String,
|
||||||
|
PhoneNumber: user.PhoneNumber.String,
|
||||||
|
Role: domain.Role(user.Role),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SearchUserByNameOrPhone(ctx context.Context, searchString string) ([]domain.User, error) {
|
||||||
|
users, err := s.queries.SearchUserByNameOrPhone(ctx, pgtype.Text{
|
||||||
|
String: searchString,
|
||||||
|
Valid: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userList := make([]domain.User, 0, len(users))
|
||||||
|
for _, user := range users {
|
||||||
|
userList = append(userList, domain.User{
|
||||||
|
ID: user.ID,
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: user.Email.String,
|
||||||
|
PhoneNumber: user.PhoneNumber.String,
|
||||||
|
Role: domain.Role(user.Role),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return userList, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
func (s *Store) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
||||||
err := s.queries.UpdateUser(ctx, dbgen.UpdateUserParams{
|
err := s.queries.UpdateUser(ctx, dbgen.UpdateUserParams{
|
||||||
// ID: user.ID,
|
// ID: user.ID,
|
||||||
|
|
@ -209,3 +272,40 @@ func (s *Store) UpdatePassword(ctx context.Context, identifier string, password
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (s *Store) CreateUserWithoutOtp(ctx context.Context, user domain.User) (domain.User, error) {
|
||||||
|
userRes, err := s.queries.CreateUser(ctx, dbgen.CreateUserParams{
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: pgtype.Text{
|
||||||
|
String: user.Email,
|
||||||
|
Valid: user.Email != "",
|
||||||
|
},
|
||||||
|
PhoneNumber: pgtype.Text{
|
||||||
|
String: user.PhoneNumber,
|
||||||
|
Valid: user.PhoneNumber != "",
|
||||||
|
},
|
||||||
|
Password: user.Password,
|
||||||
|
Role: string(user.Role),
|
||||||
|
EmailVerified: user.EmailVerified,
|
||||||
|
PhoneVerified: user.PhoneVerified,
|
||||||
|
CreatedAt: pgtype.Timestamptz{
|
||||||
|
Time: time.Now(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
UpdatedAt: pgtype.Timestamptz{
|
||||||
|
Time: time.Now(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.User{}, err
|
||||||
|
}
|
||||||
|
return domain.User{
|
||||||
|
ID: userRes.ID,
|
||||||
|
FirstName: userRes.FirstName,
|
||||||
|
LastName: userRes.LastName,
|
||||||
|
Email: userRes.Email.String,
|
||||||
|
PhoneNumber: userRes.PhoneNumber.String,
|
||||||
|
Role: domain.Role(userRes.Role),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,24 @@ import (
|
||||||
|
|
||||||
func convertDBWallet(wallet dbgen.Wallet) domain.Wallet {
|
func convertDBWallet(wallet dbgen.Wallet) domain.Wallet {
|
||||||
return domain.Wallet{
|
return domain.Wallet{
|
||||||
ID: wallet.ID,
|
ID: wallet.ID,
|
||||||
Balance: domain.Currency(wallet.Balance),
|
Balance: domain.Currency(wallet.Balance),
|
||||||
IsWithdraw: wallet.IsWithdraw,
|
IsWithdraw: wallet.IsWithdraw,
|
||||||
IsBettable: wallet.IsBettable,
|
IsBettable: wallet.IsBettable,
|
||||||
IsActive: wallet.IsActive,
|
IsTransferable: wallet.IsTransferable,
|
||||||
UserID: wallet.UserID,
|
IsActive: wallet.IsActive,
|
||||||
UpdatedAt: wallet.UpdatedAt.Time,
|
UserID: wallet.UserID,
|
||||||
CreatedAt: wallet.CreatedAt.Time,
|
UpdatedAt: wallet.UpdatedAt.Time,
|
||||||
|
CreatedAt: wallet.CreatedAt.Time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertCreateWallet(wallet domain.CreateWallet) dbgen.CreateWalletParams {
|
func convertCreateWallet(wallet domain.CreateWallet) dbgen.CreateWalletParams {
|
||||||
return dbgen.CreateWalletParams{
|
return dbgen.CreateWalletParams{
|
||||||
IsWithdraw: wallet.IsWithdraw,
|
IsWithdraw: wallet.IsWithdraw,
|
||||||
IsBettable: wallet.IsBettable,
|
IsBettable: wallet.IsBettable,
|
||||||
UserID: wallet.UserID,
|
IsTransferable: wallet.IsTransferable,
|
||||||
|
UserID: wallet.UserID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +95,7 @@ func (s *Store) GetAllWallets(ctx context.Context) ([]domain.Wallet, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []domain.Wallet = make([]domain.Wallet, len(wallets))
|
var result []domain.Wallet = make([]domain.Wallet, 0, len(wallets))
|
||||||
|
|
||||||
for _, wallet := range wallets {
|
for _, wallet := range wallets {
|
||||||
result = append(result, convertDBWallet(wallet))
|
result = append(result, convertDBWallet(wallet))
|
||||||
|
|
@ -107,7 +109,7 @@ func (s *Store) GetWalletsByUser(ctx context.Context, userID int64) ([]domain.Wa
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []domain.Wallet = make([]domain.Wallet, len(wallets))
|
var result []domain.Wallet = make([]domain.Wallet, 0, len(wallets))
|
||||||
|
|
||||||
for _, wallet := range wallets {
|
for _, wallet := range wallets {
|
||||||
result = append(result, convertDBWallet(wallet))
|
result = append(result, convertDBWallet(wallet))
|
||||||
|
|
@ -127,6 +129,31 @@ func (s *Store) GetCustomerWallet(ctx context.Context, customerID int64, company
|
||||||
return convertDBGetCustomerWallet(customerWallet), nil
|
return convertDBGetCustomerWallet(customerWallet), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error) {
|
||||||
|
wallets, err := s.queries.GetAllBranchWallets(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []domain.BranchWallet = make([]domain.BranchWallet, 0, len(wallets))
|
||||||
|
|
||||||
|
for _, wallet := range wallets {
|
||||||
|
result = append(result, domain.BranchWallet{
|
||||||
|
ID: wallet.ID,
|
||||||
|
Balance: domain.Currency(wallet.Balance),
|
||||||
|
IsActive: wallet.IsActive,
|
||||||
|
UpdatedAt: wallet.UpdatedAt.Time,
|
||||||
|
CreatedAt: wallet.CreatedAt.Time,
|
||||||
|
Name: wallet.Name,
|
||||||
|
Location: wallet.Location,
|
||||||
|
BranchManagerID: wallet.BranchManagerID,
|
||||||
|
CompanyID: wallet.CompanyID,
|
||||||
|
IsSelfOwned: wallet.IsSelfOwned,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
func (s *Store) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
||||||
err := s.queries.UpdateBalance(ctx, dbgen.UpdateBalanceParams{
|
err := s.queries.UpdateBalance(ctx, dbgen.UpdateBalanceParams{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,10 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginSuccess struct {
|
type LoginSuccess struct {
|
||||||
UserId int64
|
UserId int64
|
||||||
Role domain.Role
|
Role domain.Role
|
||||||
RfToken string
|
RfToken string
|
||||||
|
BranchId int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Login(ctx context.Context, email, phone string, password string) (LoginSuccess, error) {
|
func (s *Service) Login(ctx context.Context, email, phone string, password string) (LoginSuccess, error) {
|
||||||
|
|
@ -48,40 +49,38 @@ func (s *Service) Login(ctx context.Context, email, phone string, password strin
|
||||||
return LoginSuccess{}, err
|
return LoginSuccess{}, err
|
||||||
}
|
}
|
||||||
return LoginSuccess{
|
return LoginSuccess{
|
||||||
UserId: user.ID,
|
UserId: user.ID,
|
||||||
Role: user.Role,
|
Role: user.Role,
|
||||||
RfToken: refreshToken,
|
RfToken: refreshToken,
|
||||||
|
BranchId: user.BranchID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) RefreshToken(ctx context.Context, refToken string) (string, error) {
|
func (s *Service) RefreshToken(ctx context.Context, refToken string) error {
|
||||||
|
|
||||||
token, err := s.tokenStore.GetRefreshToken(ctx, refToken)
|
token, err := s.tokenStore.GetRefreshToken(ctx, refToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
if token.Revoked {
|
if token.Revoked {
|
||||||
return "", ErrRefreshTokenNotFound
|
return ErrRefreshTokenNotFound
|
||||||
}
|
}
|
||||||
if token.ExpiresAt.Before(time.Now()) {
|
if token.ExpiresAt.Before(time.Now()) {
|
||||||
return "", ErrExpiredToken
|
return ErrExpiredToken
|
||||||
}
|
}
|
||||||
|
|
||||||
newRefToken, err := generateRefreshToken()
|
// newRefToken, err := generateRefreshToken()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return "", err
|
// return "", err
|
||||||
}
|
// }
|
||||||
|
|
||||||
err = s.tokenStore.CreateRefreshToken(ctx, domain.RefreshToken{
|
// err = s.tokenStore.CreateRefreshToken(ctx, domain.RefreshToken{
|
||||||
Token: newRefToken,
|
// Token: newRefToken,
|
||||||
UserID: token.UserID,
|
// UserID: token.UserID,
|
||||||
CreatedAt: time.Now(),
|
// CreatedAt: time.Now(),
|
||||||
ExpiresAt: time.Now().Add(time.Duration(s.RefreshExpiry) * time.Second),
|
// ExpiresAt: time.Now().Add(time.Duration(s.RefreshExpiry) * time.Second),
|
||||||
})
|
// })
|
||||||
if err != nil {
|
return nil
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return newRefToken, nil
|
|
||||||
}
|
}
|
||||||
func (s *Service) Logout(ctx context.Context, refToken string) error {
|
func (s *Service) Logout(ctx context.Context, refToken string) error {
|
||||||
token, err := s.tokenStore.GetRefreshToken(ctx, refToken)
|
token, err := s.tokenStore.GetRefreshToken(ctx, refToken)
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,13 @@ import (
|
||||||
|
|
||||||
type BetStore interface {
|
type BetStore interface {
|
||||||
CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error)
|
CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error)
|
||||||
GetBetByID(ctx context.Context, id int64) (domain.Bet, error)
|
CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error)
|
||||||
GetAllBets(ctx context.Context) ([]domain.Bet, error)
|
GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error)
|
||||||
|
GetBetByID(ctx context.Context, id int64) (domain.GetBet, error)
|
||||||
|
GetAllBets(ctx context.Context) ([]domain.GetBet, error)
|
||||||
|
GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error)
|
||||||
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
|
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
|
||||||
|
UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||||
|
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||||
DeleteBet(ctx context.Context, id int64) error
|
DeleteBet(ctx context.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,40 @@ func NewService(betStore BetStore) *Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
|
func (s *Service) CreateBet(ctx context.Context, bet domain.CreateBet) (domain.Bet, error) {
|
||||||
|
|
||||||
return s.betStore.CreateBet(ctx, bet)
|
return s.betStore.CreateBet(ctx, bet)
|
||||||
}
|
}
|
||||||
func (s *Service) GetBetByID(ctx context.Context, id int64) (domain.Bet, error) {
|
|
||||||
|
func (s *Service) CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error) {
|
||||||
|
return s.betStore.CreateBetOutcome(ctx, outcomes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) {
|
||||||
return s.betStore.GetBetByID(ctx, id)
|
return s.betStore.GetBetByID(ctx, id)
|
||||||
}
|
}
|
||||||
func (s *Service) GetAllBets(ctx context.Context) ([]domain.Bet, error) {
|
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) ([]domain.GetBet, error) {
|
||||||
return s.betStore.GetAllBets(ctx)
|
return s.betStore.GetAllBets(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetBetByBranchID(ctx context.Context, branchID int64) ([]domain.GetBet, error) {
|
||||||
|
return s.betStore.GetBetByBranchID(ctx, branchID)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error {
|
func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error {
|
||||||
return s.betStore.UpdateCashOut(ctx, id, cashedOut)
|
return s.betStore.UpdateCashOut(ctx, id, cashedOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
return s.betStore.UpdateStatus(ctx, id, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
return s.betStore.UpdateBetOutcomeStatus(ctx, id, status)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
|
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
|
||||||
return s.betStore.DeleteBet(ctx, id)
|
return s.betStore.DeleteBet(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
internal/services/branch/port.go
Normal file
26
internal/services/branch/port.go
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
package branch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BranchStore interface {
|
||||||
|
CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error)
|
||||||
|
GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error)
|
||||||
|
GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]domain.BranchDetail, error)
|
||||||
|
GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error)
|
||||||
|
GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error)
|
||||||
|
SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error)
|
||||||
|
UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error)
|
||||||
|
DeleteBranch(ctx context.Context, id int64) error
|
||||||
|
CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error
|
||||||
|
CreateSupportedOperation(ctx context.Context, supportedOperation domain.CreateSupportedOperation) (domain.SupportedOperation, error)
|
||||||
|
GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error)
|
||||||
|
GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error)
|
||||||
|
DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error
|
||||||
|
CreateBranchCashier(ctx context.Context, branchID int64, userID int64) error
|
||||||
|
GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error)
|
||||||
|
DeleteBranchCashier(ctx context.Context, userID int64) error
|
||||||
|
}
|
||||||
72
internal/services/branch/service.go
Normal file
72
internal/services/branch/service.go
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
package branch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
branchStore BranchStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(branchStore BranchStore) *Service {
|
||||||
|
return &Service{
|
||||||
|
branchStore: branchStore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error) {
|
||||||
|
return s.branchStore.CreateBranch(ctx, branch)
|
||||||
|
}
|
||||||
|
func (s *Service) CreateSupportedOperation(ctx context.Context, supportedOperation domain.CreateSupportedOperation) (domain.SupportedOperation, error) {
|
||||||
|
return s.branchStore.CreateSupportedOperation(ctx, supportedOperation)
|
||||||
|
}
|
||||||
|
func (s *Service) CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error {
|
||||||
|
return s.branchStore.CreateBranchOperation(ctx, branchOperation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateBranchCashier(ctx context.Context, branchID int64, userID int64) error {
|
||||||
|
return s.branchStore.CreateBranchCashier(ctx, branchID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error) {
|
||||||
|
return s.branchStore.GetBranchByID(ctx, id)
|
||||||
|
}
|
||||||
|
func (s *Service) GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]domain.BranchDetail, error) {
|
||||||
|
return s.branchStore.GetBranchByManagerID(ctx, branchManagerID)
|
||||||
|
}
|
||||||
|
func (s *Service) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error) {
|
||||||
|
return s.branchStore.GetBranchByCompanyID(ctx, companyID)
|
||||||
|
}
|
||||||
|
func (s *Service) GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error) {
|
||||||
|
return s.branchStore.GetBranchOperations(ctx, branchID)
|
||||||
|
}
|
||||||
|
func (s *Service) GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error) {
|
||||||
|
return s.branchStore.GetAllBranches(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error) {
|
||||||
|
return s.branchStore.GetBranchByCashier(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllSupportedOperations(ctx context.Context) ([]domain.SupportedOperation, error) {
|
||||||
|
return s.branchStore.GetAllSupportedOperations(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error) {
|
||||||
|
return s.branchStore.SearchBranchByName(ctx, name)
|
||||||
|
}
|
||||||
|
func (s *Service) UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error) {
|
||||||
|
return s.branchStore.UpdateBranch(ctx, id, branch)
|
||||||
|
}
|
||||||
|
func (s *Service) DeleteBranch(ctx context.Context, id int64) error {
|
||||||
|
return s.branchStore.DeleteBranch(ctx, id)
|
||||||
|
}
|
||||||
|
func (s *Service) DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error {
|
||||||
|
return s.branchStore.DeleteBranchOperation(ctx, branchID, operationID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteBranchCashier(ctx context.Context, userID int64) error {
|
||||||
|
return s.branchStore.DeleteBranchCashier(ctx, userID)
|
||||||
|
}
|
||||||
15
internal/services/company/port.go
Normal file
15
internal/services/company/port.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package company
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CompanyStore interface {
|
||||||
|
CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error)
|
||||||
|
GetAllCompanies(ctx context.Context) ([]domain.Company, error)
|
||||||
|
GetCompanyByID(ctx context.Context, id int64) (domain.Company, error)
|
||||||
|
UpdateCompany(ctx context.Context, id int64, company domain.UpdateCompany) (domain.Company, error)
|
||||||
|
DeleteCompany(ctx context.Context, id int64) error
|
||||||
|
}
|
||||||
35
internal/services/company/service.go
Normal file
35
internal/services/company/service.go
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
package company
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
companyStore CompanyStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(companyStore CompanyStore) *Service {
|
||||||
|
return &Service{
|
||||||
|
companyStore: companyStore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) {
|
||||||
|
return s.companyStore.CreateCompany(ctx, company)
|
||||||
|
}
|
||||||
|
func (s *Service) GetAllCompanies(ctx context.Context) ([]domain.Company, error) {
|
||||||
|
return s.companyStore.GetAllCompanies(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCompanyByID(ctx context.Context, id int64) (domain.Company, error) {
|
||||||
|
return s.companyStore.GetCompanyByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateCompany(ctx context.Context, id int64, company domain.UpdateCompany) (domain.Company, error) {
|
||||||
|
return s.companyStore.UpdateCompany(ctx, id, company)
|
||||||
|
}
|
||||||
|
func (s *Service) DeleteCompany(ctx context.Context, id int64) error {
|
||||||
|
return s.companyStore.DeleteCompany(ctx, id)
|
||||||
|
}
|
||||||
15
internal/services/event/port.go
Normal file
15
internal/services/event/port.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package event
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
FetchLiveEvents(ctx context.Context) error
|
||||||
|
FetchUpcomingEvents(ctx context.Context) error
|
||||||
|
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||||
|
GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32, leagueID domain.ValidString, sportID domain.ValidString) ([]domain.UpcomingEvent, int64, error)
|
||||||
|
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
||||||
|
}
|
||||||
187
internal/services/event/service.go
Normal file
187
internal/services/event/service.go
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
package event
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
|
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
)
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
token string
|
||||||
|
store *repository.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(token string, store *repository.Store) Service {
|
||||||
|
return &service{
|
||||||
|
token: token,
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) FetchLiveEvents(ctx context.Context) error {
|
||||||
|
sportIDs := []int{1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4, 83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90, 95, 110, 107, 151, 162, 148}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
for _, sportID := range sportIDs {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(sportID int) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/inplay?sport_id=%d&token=%s", sportID, s.token)
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf(" Failed request for sport_id=%d: %v\n", sportID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Success int `json:"success"`
|
||||||
|
Results [][]map[string]interface{} `json:"results"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||||
|
fmt.Printf(" Decode failed for sport_id=%d\nRaw: %s\n", sportID, string(body))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, group := range data.Results {
|
||||||
|
for _, ev := range group {
|
||||||
|
if getString(ev["type"]) != "EV" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
event := domain.Event{
|
||||||
|
ID: getString(ev["ID"]),
|
||||||
|
SportID: fmt.Sprintf("%d", sportID),
|
||||||
|
MatchName: getString(ev["NA"]),
|
||||||
|
Score: getString(ev["SS"]),
|
||||||
|
MatchMinute: getInt(ev["TM"]),
|
||||||
|
TimerStatus: getString(ev["TT"]),
|
||||||
|
HomeTeamID: getString(ev["HT"]),
|
||||||
|
AwayTeamID: getString(ev["AT"]),
|
||||||
|
HomeKitImage: getString(ev["K1"]),
|
||||||
|
AwayKitImage: getString(ev["K2"]),
|
||||||
|
LeagueName: getString(ev["CT"]),
|
||||||
|
LeagueID: getString(ev["C2"]),
|
||||||
|
LeagueCC: getString(ev["CB"]),
|
||||||
|
StartTime: time.Now().UTC().Format(time.RFC3339),
|
||||||
|
IsLive: true,
|
||||||
|
Status: "live",
|
||||||
|
MatchPeriod: getInt(ev["MD"]),
|
||||||
|
AddedTime: getInt(ev["TA"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.store.SaveEvent(ctx, event); err != nil {
|
||||||
|
fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(sportID)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
fmt.Println("All live events fetched and stored.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
|
sportIDs := []int{1}
|
||||||
|
for _, sportID := range sportIDs {
|
||||||
|
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
var data struct {
|
||||||
|
Success int `json:"success"`
|
||||||
|
Results []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID string `json:"sport_id"`
|
||||||
|
Time string `json:"time"`
|
||||||
|
League struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"league"`
|
||||||
|
Home struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"home"`
|
||||||
|
Away *struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"away"`
|
||||||
|
} `json:"results"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ev := range data.Results {
|
||||||
|
startUnix, _ := strconv.ParseInt(ev.Time, 10, 64)
|
||||||
|
event := domain.UpcomingEvent{
|
||||||
|
ID: ev.ID,
|
||||||
|
SportID: ev.SportID,
|
||||||
|
MatchName: ev.Home.Name,
|
||||||
|
HomeTeam: ev.Home.Name,
|
||||||
|
AwayTeam: "", // handle nil safely
|
||||||
|
HomeTeamID: ev.Home.ID,
|
||||||
|
AwayTeamID: "",
|
||||||
|
HomeKitImage: "",
|
||||||
|
AwayKitImage: "",
|
||||||
|
LeagueID: ev.League.ID,
|
||||||
|
LeagueName: ev.League.Name,
|
||||||
|
LeagueCC: "",
|
||||||
|
StartTime: time.Unix(startUnix, 0).UTC(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if ev.Away != nil {
|
||||||
|
event.AwayTeam = ev.Away.Name
|
||||||
|
event.AwayTeamID = ev.Away.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = s.store.SaveUpcomingEvent(ctx, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getString(v interface{}) string {
|
||||||
|
if str, ok := v.(string); ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInt(v interface{}) int {
|
||||||
|
if f, ok := v.(float64); ok {
|
||||||
|
return int(f)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) {
|
||||||
|
return s.store.GetAllUpcomingEvents(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32, leagueID domain.ValidString, sportID domain.ValidString) ([]domain.UpcomingEvent, int64, error) {
|
||||||
|
return s.store.GetPaginatedUpcomingEvents(ctx, limit, offset, leagueID, sportID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
|
return s.store.GetUpcomingEventByID(ctx, ID)
|
||||||
|
}
|
||||||
14
internal/services/odds/port.go
Normal file
14
internal/services/odds/port.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package odds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
FetchNonLiveOdds(ctx context.Context) error
|
||||||
|
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
||||||
|
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
|
||||||
|
GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error)
|
||||||
|
}
|
||||||
133
internal/services/odds/service.go
Normal file
133
internal/services/odds/service.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
package odds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceImpl struct {
|
||||||
|
token string
|
||||||
|
store *repository.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(token string, store *repository.Store) *ServiceImpl {
|
||||||
|
return &ServiceImpl{token: token, store: store}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
||||||
|
eventIDs, err := s.store.GetAllUpcomingEvents(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Failed to fetch upcoming event IDs: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range eventIDs {
|
||||||
|
eventID := event.ID
|
||||||
|
prematchURL := "https://api.b365api.com/v3/bet365/prematch?token=" + s.token + "&FI=" + eventID
|
||||||
|
log.Printf("📡 Fetching prematch odds for event ID: %s", eventID)
|
||||||
|
resp, err := http.Get(prematchURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Failed to fetch prematch odds for event %s: %v", eventID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
var oddsData struct {
|
||||||
|
Success int `json:"success"`
|
||||||
|
Results []struct {
|
||||||
|
EventID string `json:"event_id"`
|
||||||
|
FI string `json:"FI"`
|
||||||
|
Main OddsSection `json:"main"`
|
||||||
|
} `json:"results"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
||||||
|
log.Printf("❌ Invalid prematch data for event %s", eventID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result := oddsData.Results[0]
|
||||||
|
finalID := result.EventID
|
||||||
|
if finalID == "" {
|
||||||
|
finalID = result.FI
|
||||||
|
}
|
||||||
|
if finalID == "" {
|
||||||
|
log.Printf("⚠️ Skipping event %s with no valid ID", eventID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) {
|
||||||
|
if len(section.Sp) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedAtUnix, _ := strconv.ParseInt(section.UpdatedAt, 10, 64)
|
||||||
|
updatedAt := time.Unix(updatedAtUnix, 0)
|
||||||
|
|
||||||
|
for marketType, market := range section.Sp {
|
||||||
|
if len(market.Odds) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
marketRecord := domain.Market{
|
||||||
|
EventID: eventID,
|
||||||
|
FI: fi,
|
||||||
|
MarketCategory: sectionName,
|
||||||
|
MarketType: marketType,
|
||||||
|
MarketName: market.Name,
|
||||||
|
MarketID: market.ID,
|
||||||
|
UpdatedAt: updatedAt,
|
||||||
|
Odds: market.Odds,
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = s.store.SaveNonLiveMarket(ctx, marketRecord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type OddsMarket struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Odds []json.RawMessage `json:"odds"`
|
||||||
|
Header string `json:"header,omitempty"`
|
||||||
|
Handicap string `json:"handicap,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OddsSection struct {
|
||||||
|
UpdatedAt string `json:"updated_at"`
|
||||||
|
Sp map[string]OddsMarket `json:"sp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
||||||
|
return s.store.GetPrematchOdds(ctx, eventID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
|
||||||
|
return s.store.GetALLPrematchOdds(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.RawOddsByMarketID, error) {
|
||||||
|
rows, err := s.store.GetRawOddsByMarketID(ctx, marketID, upcomingID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.RawOddsByMarketID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) GetPrematchOddsByUpcomingID(ctx context.Context, upcomingID string, limit, offset int32) ([]domain.Odd, error) {
|
||||||
|
return s.store.GetPrematchOddsByUpcomingID(ctx, upcomingID, limit, offset)
|
||||||
|
}
|
||||||
|
|
@ -8,8 +8,10 @@ import (
|
||||||
|
|
||||||
type TicketStore interface {
|
type TicketStore interface {
|
||||||
CreateTicket(ctx context.Context, ticket domain.CreateTicket) (domain.Ticket, error)
|
CreateTicket(ctx context.Context, ticket domain.CreateTicket) (domain.Ticket, error)
|
||||||
GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error)
|
CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error)
|
||||||
GetAllTickets(ctx context.Context) ([]domain.Ticket, error)
|
GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error)
|
||||||
|
GetAllTickets(ctx context.Context) ([]domain.GetTicket, error)
|
||||||
|
UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||||
DeleteOldTickets(ctx context.Context) error
|
DeleteOldTickets(ctx context.Context) error
|
||||||
DeleteTicket(ctx context.Context, id int64) error
|
DeleteTicket(ctx context.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,21 @@ func NewService(ticketStore TicketStore) *Service {
|
||||||
func (s *Service) CreateTicket(ctx context.Context, ticket domain.CreateTicket) (domain.Ticket, error) {
|
func (s *Service) CreateTicket(ctx context.Context, ticket domain.CreateTicket) (domain.Ticket, error) {
|
||||||
return s.ticketStore.CreateTicket(ctx, ticket)
|
return s.ticketStore.CreateTicket(ctx, ticket)
|
||||||
}
|
}
|
||||||
func (s *Service) GetTicketByID(ctx context.Context, id int64) (domain.Ticket, error) {
|
|
||||||
|
func (s *Service) CreateTicketOutcome(ctx context.Context, outcomes []domain.CreateTicketOutcome) (int64, error) {
|
||||||
|
return s.ticketStore.CreateTicketOutcome(ctx, outcomes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetTicketByID(ctx context.Context, id int64) (domain.GetTicket, error) {
|
||||||
return s.ticketStore.GetTicketByID(ctx, id)
|
return s.ticketStore.GetTicketByID(ctx, id)
|
||||||
}
|
}
|
||||||
func (s *Service) GetAllTickets(ctx context.Context) ([]domain.Ticket, error) {
|
func (s *Service) GetAllTickets(ctx context.Context) ([]domain.GetTicket, error) {
|
||||||
return s.ticketStore.GetAllTickets(ctx)
|
return s.ticketStore.GetAllTickets(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateTicketOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error {
|
||||||
|
return s.ticketStore.UpdateTicketOutcomeStatus(ctx, id, status)
|
||||||
|
}
|
||||||
func (s *Service) DeleteTicket(ctx context.Context, id int64) error {
|
func (s *Service) DeleteTicket(ctx context.Context, id int64) error {
|
||||||
return s.ticketStore.DeleteTicket(ctx, id)
|
return s.ticketStore.DeleteTicket(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,6 @@ type TransactionStore interface {
|
||||||
CreateTransaction(ctx context.Context, transaction domain.CreateTransaction) (domain.Transaction, error)
|
CreateTransaction(ctx context.Context, transaction domain.CreateTransaction) (domain.Transaction, error)
|
||||||
GetTransactionByID(ctx context.Context, id int64) (domain.Transaction, error)
|
GetTransactionByID(ctx context.Context, id int64) (domain.Transaction, error)
|
||||||
GetAllTransactions(ctx context.Context) ([]domain.Transaction, error)
|
GetAllTransactions(ctx context.Context) ([]domain.Transaction, error)
|
||||||
|
GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error)
|
||||||
UpdateTransactionVerified(ctx context.Context, id int64, verified bool) error
|
UpdateTransactionVerified(ctx context.Context, id int64, verified bool) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,9 @@ func (s *Service) GetTransactionByID(ctx context.Context, id int64) (domain.Tran
|
||||||
func (s *Service) GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) {
|
func (s *Service) GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) {
|
||||||
return s.transactionStore.GetAllTransactions(ctx)
|
return s.transactionStore.GetAllTransactions(ctx)
|
||||||
}
|
}
|
||||||
|
func (s *Service) GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error) {
|
||||||
|
return s.transactionStore.GetTransactionByBranch(ctx, id)
|
||||||
|
}
|
||||||
func (s *Service) UpdateTransactionVerified(ctx context.Context, id int64, verified bool) error {
|
func (s *Service) UpdateTransactionVerified(ctx context.Context, id int64, verified bool) error {
|
||||||
|
|
||||||
return s.transactionStore.UpdateTransactionVerified(ctx, id, verified)
|
return s.transactionStore.UpdateTransactionVerified(ctx, id, verified)
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package transfer
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package transfer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TransferStore interface {
|
|
||||||
CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error)
|
|
||||||
GetAllTransfers(ctx context.Context) ([]domain.Transfer, error)
|
|
||||||
GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error)
|
|
||||||
GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error)
|
|
||||||
UpdateTransferVerification(ctx context.Context, id int64, verified bool) error
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
package transfer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
transferStore TransferStore
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(transferStore TransferStore) *Service {
|
|
||||||
return &Service{
|
|
||||||
transferStore: transferStore,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
|
||||||
return s.transferStore.CreateTransfer(ctx, transfer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetAllTransfers(ctx context.Context) ([]domain.Transfer, error) {
|
|
||||||
return s.transferStore.GetAllTransfers(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error) {
|
|
||||||
return s.transferStore.GetTransferByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error {
|
|
||||||
return s.transferStore.UpdateTransferVerification(ctx, id, verified)
|
|
||||||
}
|
|
||||||
74
internal/services/user/direct.go
Normal file
74
internal/services/user/direct.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateUser(ctx context.Context, User domain.CreateUserReq) (domain.User, error) {
|
||||||
|
// Create User
|
||||||
|
// creator, err := s.userStore.GetUserByID(ctx, createrUserId)
|
||||||
|
// if err != nil {
|
||||||
|
// return domain.User{}, err
|
||||||
|
// }
|
||||||
|
// if creator.Role != domain.RoleAdmin {
|
||||||
|
// User.BranchID = creator.BranchID
|
||||||
|
// User.Role = string(domain.RoleCashier)
|
||||||
|
// } else {
|
||||||
|
// User.BranchID = branchId
|
||||||
|
// User.Role = string(domain.RoleBranchManager)
|
||||||
|
// }
|
||||||
|
hashedPassword, err := hashPassword(User.Password)
|
||||||
|
if err != nil {
|
||||||
|
return domain.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.userStore.CreateUserWithoutOtp(ctx, domain.User{
|
||||||
|
FirstName: User.FirstName,
|
||||||
|
LastName: User.LastName,
|
||||||
|
Email: User.Email,
|
||||||
|
PhoneNumber: User.PhoneNumber,
|
||||||
|
Password: hashedPassword,
|
||||||
|
Role: domain.Role(User.Role),
|
||||||
|
EmailVerified: true,
|
||||||
|
PhoneVerified: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteUser(ctx context.Context, id int64) error {
|
||||||
|
// Delete User
|
||||||
|
return s.userStore.DeleteUser(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
Role string
|
||||||
|
BranchId ValidBranchId
|
||||||
|
Page int
|
||||||
|
PageSize int
|
||||||
|
}
|
||||||
|
type ValidRole struct {
|
||||||
|
Value domain.Role
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
type ValidBranchId struct {
|
||||||
|
Value int64
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, error) {
|
||||||
|
// Get all Users
|
||||||
|
return s.userStore.GetAllUsers(ctx, filter)
|
||||||
|
}
|
||||||
|
func (s *Service) GetUserById(ctx context.Context, id int64) (domain.User, error) {
|
||||||
|
|
||||||
|
return s.userStore.GetUserByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) {
|
||||||
|
return s.userStore.GetCashiersByBranch(ctx, branchID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.User, error) {
|
||||||
|
return s.userStore.GetAllCashiers(ctx)
|
||||||
|
}
|
||||||
|
|
@ -8,14 +8,17 @@ import (
|
||||||
|
|
||||||
type UserStore interface {
|
type UserStore interface {
|
||||||
CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error)
|
CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error)
|
||||||
|
CreateUserWithoutOtp(ctx context.Context, user domain.User) (domain.User, error)
|
||||||
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||||
GetAllUsers(ctx context.Context) ([]domain.User, error)
|
GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, error)
|
||||||
|
GetAllCashiers(ctx context.Context) ([]domain.User, error)
|
||||||
|
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
|
||||||
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
||||||
DeleteUser(ctx context.Context, id int64) error
|
DeleteUser(ctx context.Context, id int64) error
|
||||||
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error)
|
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error)
|
||||||
GetUserByEmail(ctx context.Context, email string) (domain.User, error)
|
GetUserByEmail(ctx context.Context, email string) (domain.User, error)
|
||||||
GetUserByPhone(ctx context.Context, phoneNum string) (domain.User, error)
|
GetUserByPhone(ctx context.Context, phoneNum string) (domain.User, error)
|
||||||
//
|
SearchUserByNameOrPhone(ctx context.Context, searchString string) ([]domain.User, error)
|
||||||
UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64) error // identifier verified email or phone
|
UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64) error // identifier verified email or phone
|
||||||
}
|
}
|
||||||
type SmsGateway interface {
|
type SmsGateway interface {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterU
|
||||||
Email: registerReq.Email,
|
Email: registerReq.Email,
|
||||||
PhoneNumber: registerReq.PhoneNumber,
|
PhoneNumber: registerReq.PhoneNumber,
|
||||||
Password: hashedPassword,
|
Password: hashedPassword,
|
||||||
Role: "user",
|
Role: domain.RoleCustomer,
|
||||||
EmailVerified: registerReq.OtpMedium == domain.OtpMediumEmail,
|
EmailVerified: registerReq.OtpMedium == domain.OtpMediumEmail,
|
||||||
PhoneVerified: registerReq.OtpMedium == domain.OtpMediumSms,
|
PhoneVerified: registerReq.OtpMedium == domain.OtpMediumSms,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,14 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func (s *Service) SearchUserByNameOrPhone(ctx context.Context, searchString string) ([]domain.User, error) {
|
||||||
|
// Search user
|
||||||
|
return s.userStore.SearchUserByNameOrPhone(ctx, searchString)
|
||||||
|
|
||||||
|
}
|
||||||
func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
||||||
// update user
|
// update user
|
||||||
return s.userStore.UpdateUser(ctx, user)
|
return s.userStore.UpdateUser(ctx, user)
|
||||||
|
|
|
||||||
1
internal/services/wallet/chapa.go
Normal file
1
internal/services/wallet/chapa.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package wallet
|
||||||
|
|
@ -13,6 +13,15 @@ type WalletStore interface {
|
||||||
GetAllWallets(ctx context.Context) ([]domain.Wallet, error)
|
GetAllWallets(ctx context.Context) ([]domain.Wallet, error)
|
||||||
GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error)
|
GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error)
|
||||||
GetCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.GetCustomerWallet, error)
|
GetCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.GetCustomerWallet, error)
|
||||||
|
GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error)
|
||||||
UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error
|
UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error
|
||||||
UpdateWalletActive(ctx context.Context, id int64, isActive bool) error
|
UpdateWalletActive(ctx context.Context, id int64, isActive bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TransferStore interface {
|
||||||
|
CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error)
|
||||||
|
GetAllTransfers(ctx context.Context) ([]domain.Transfer, error)
|
||||||
|
GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error)
|
||||||
|
GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error)
|
||||||
|
UpdateTransferVerification(ctx context.Context, id int64, verified bool) error
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,102 +1,13 @@
|
||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
walletStore WalletStore
|
walletStore WalletStore
|
||||||
|
transferStore TransferStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(walletStore WalletStore) *Service {
|
func NewService(walletStore WalletStore, transferStore TransferStore) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
walletStore: walletStore,
|
walletStore: walletStore,
|
||||||
|
transferStore: transferStore,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
ErrBalanceInsufficient = errors.New("wallet balance is insufficient")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Service) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
|
|
||||||
return s.walletStore.CreateWallet(ctx, wallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.CustomerWallet, error) {
|
|
||||||
|
|
||||||
regularWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
|
|
||||||
IsWithdraw: true,
|
|
||||||
IsBettable: true,
|
|
||||||
UserID: customerID,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return domain.CustomerWallet{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
staticWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
|
|
||||||
IsWithdraw: false,
|
|
||||||
IsBettable: true,
|
|
||||||
UserID: customerID,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return domain.CustomerWallet{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.walletStore.CreateCustomerWallet(ctx, domain.CreateCustomerWallet{
|
|
||||||
CustomerID: customerID,
|
|
||||||
CompanyID: companyID,
|
|
||||||
RegularWalletID: regularWallet.ID,
|
|
||||||
StaticWalletID: staticWallet.ID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetWalletByID(ctx context.Context, id int64) (domain.Wallet, error) {
|
|
||||||
return s.walletStore.GetWalletByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetAllWallets(ctx context.Context) ([]domain.Wallet, error) {
|
|
||||||
return s.walletStore.GetAllWallets(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error) {
|
|
||||||
return s.walletStore.GetWalletsByUser(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.GetCustomerWallet, error) {
|
|
||||||
return s.walletStore.GetCustomerWallet(ctx, customerID, companyID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
|
||||||
return s.walletStore.UpdateBalance(ctx, id, balance)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Add(ctx context.Context, id int64, amount domain.Currency) error {
|
|
||||||
wallet, err := s.GetWalletByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Deduct(ctx context.Context, id int64, amount domain.Currency) error {
|
|
||||||
wallet, err := s.GetWalletByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if wallet.Balance < amount {
|
|
||||||
return ErrBalanceInsufficient
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateWalletActive(ctx context.Context, id int64, isActive bool) error {
|
|
||||||
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
119
internal/services/wallet/transfer.go
Normal file
119
internal/services/wallet/transfer.go
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
package wallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrWalletNotTransferable = errors.New("wallet is not transferable")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
||||||
|
return s.transferStore.CreateTransfer(ctx, transfer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllTransfers(ctx context.Context) ([]domain.Transfer, error) {
|
||||||
|
return s.transferStore.GetAllTransfers(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error) {
|
||||||
|
return s.transferStore.GetTransferByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error) {
|
||||||
|
return s.transferStore.GetTransfersByWallet(ctx, walletID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error {
|
||||||
|
return s.transferStore.UpdateTransferVerification(ctx, id, verified)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) RefillWallet(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
||||||
|
receiverWallet, err := s.GetWalletByID(ctx, transfer.ReceiverWalletID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to receiver
|
||||||
|
err = s.walletStore.UpdateBalance(ctx, receiverWallet.ID, receiverWallet.Balance+transfer.Amount)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the transfer so that if there is a mistake, it can be reverted
|
||||||
|
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
||||||
|
CashierID: transfer.CashierID,
|
||||||
|
ReceiverWalletID: receiverWallet.ID,
|
||||||
|
Amount: transfer.Amount,
|
||||||
|
Type: domain.DEPOSIT,
|
||||||
|
PaymentMethod: transfer.PaymentMethod,
|
||||||
|
Verified: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newTransfer, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiverID int64, amount domain.Currency, paymentMethod domain.PaymentMethod, cashierID domain.ValidInt64) (domain.Transfer, error) {
|
||||||
|
|
||||||
|
senderWallet, err := s.GetWalletByID(ctx, senderID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if senderWallet.IsTransferable {
|
||||||
|
return domain.Transfer{}, ErrWalletNotTransferable
|
||||||
|
}
|
||||||
|
|
||||||
|
receiverWallet, err := s.GetWalletByID(ctx, receiverID)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if receiverWallet.IsTransferable {
|
||||||
|
return domain.Transfer{}, ErrWalletNotTransferable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduct from sender
|
||||||
|
if senderWallet.Balance < amount {
|
||||||
|
return domain.Transfer{}, ErrBalanceInsufficient
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.walletStore.UpdateBalance(ctx, senderID, senderWallet.Balance-amount)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to receiver
|
||||||
|
err = s.walletStore.UpdateBalance(ctx, receiverID, receiverWallet.Balance+amount)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the transfer so that if there is a mistake, it can be reverted
|
||||||
|
transfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
||||||
|
SenderWalletID: domain.ValidInt64{
|
||||||
|
Value: senderID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
CashierID: cashierID,
|
||||||
|
ReceiverWalletID: receiverID,
|
||||||
|
Amount: amount,
|
||||||
|
Type: domain.WALLET,
|
||||||
|
PaymentMethod: paymentMethod,
|
||||||
|
Verified: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return transfer, nil
|
||||||
|
}
|
||||||
98
internal/services/wallet/wallet.go
Normal file
98
internal/services/wallet/wallet.go
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
package wallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrBalanceInsufficient = errors.New("wallet balance is insufficient")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
|
||||||
|
return s.walletStore.CreateWallet(ctx, wallet)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.CustomerWallet, error) {
|
||||||
|
|
||||||
|
regularWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
|
||||||
|
IsWithdraw: true,
|
||||||
|
IsBettable: true,
|
||||||
|
UserID: customerID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.CustomerWallet{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
staticWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
|
||||||
|
IsWithdraw: false,
|
||||||
|
IsBettable: true,
|
||||||
|
UserID: customerID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.CustomerWallet{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.walletStore.CreateCustomerWallet(ctx, domain.CreateCustomerWallet{
|
||||||
|
CustomerID: customerID,
|
||||||
|
CompanyID: companyID,
|
||||||
|
RegularWalletID: regularWallet.ID,
|
||||||
|
StaticWalletID: staticWallet.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetWalletByID(ctx context.Context, id int64) (domain.Wallet, error) {
|
||||||
|
return s.walletStore.GetWalletByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllWallets(ctx context.Context) ([]domain.Wallet, error) {
|
||||||
|
return s.walletStore.GetAllWallets(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error) {
|
||||||
|
return s.walletStore.GetWalletsByUser(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCustomerWallet(ctx context.Context, customerID int64, companyID int64) (domain.GetCustomerWallet, error) {
|
||||||
|
return s.walletStore.GetCustomerWallet(ctx, customerID, companyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error) {
|
||||||
|
return s.walletStore.GetAllBranchWallets(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
||||||
|
return s.walletStore.UpdateBalance(ctx, id, balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) AddToWallet(ctx context.Context, id int64, amount domain.Currency) error {
|
||||||
|
wallet, err := s.GetWalletByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.Currency) error {
|
||||||
|
wallet, err := s.GetWalletByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if wallet.Balance < amount {
|
||||||
|
return ErrBalanceInsufficient
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func (s *Service) UpdateWalletActive(ctx context.Context, id int64, isActive bool) error {
|
||||||
|
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,10 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/company"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
|
|
@ -18,6 +22,7 @@ import (
|
||||||
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
|
|
@ -33,9 +38,13 @@ type App struct {
|
||||||
walletSvc *wallet.Service
|
walletSvc *wallet.Service
|
||||||
transactionSvc *transaction.Service
|
transactionSvc *transaction.Service
|
||||||
ticketSvc *ticket.Service
|
ticketSvc *ticket.Service
|
||||||
|
branchSvc *branch.Service
|
||||||
|
companySvc *company.Service
|
||||||
validator *customvalidator.CustomValidator
|
validator *customvalidator.CustomValidator
|
||||||
JwtConfig jwtutil.JwtConfig
|
JwtConfig jwtutil.JwtConfig
|
||||||
Logger *slog.Logger
|
Logger *slog.Logger
|
||||||
|
prematchSvc *odds.ServiceImpl
|
||||||
|
eventSvc event.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApp(
|
func NewApp(
|
||||||
|
|
@ -48,7 +57,11 @@ func NewApp(
|
||||||
betSvc *bet.Service,
|
betSvc *bet.Service,
|
||||||
walletSvc *wallet.Service,
|
walletSvc *wallet.Service,
|
||||||
transactionSvc *transaction.Service,
|
transactionSvc *transaction.Service,
|
||||||
|
branchSvc *branch.Service,
|
||||||
|
companySvc *company.Service,
|
||||||
notidicationStore notificationservice.NotificationStore,
|
notidicationStore notificationservice.NotificationStore,
|
||||||
|
prematchSvc *odds.ServiceImpl,
|
||||||
|
eventSvc event.Service,
|
||||||
referralSvc referralservice.ReferralStore,
|
referralSvc referralservice.ReferralStore,
|
||||||
virtualGameSvc virtualgameservice.VirtualGameService,
|
virtualGameSvc virtualgameservice.VirtualGameService,
|
||||||
) *App {
|
) *App {
|
||||||
|
|
@ -58,6 +71,14 @@ func NewApp(
|
||||||
JSONEncoder: sonic.Marshal,
|
JSONEncoder: sonic.Marshal,
|
||||||
JSONDecoder: sonic.Unmarshal,
|
JSONDecoder: sonic.Unmarshal,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.Use(cors.New(cors.Config{
|
||||||
|
AllowOrigins: "*", // Specify your frontend's origin
|
||||||
|
AllowMethods: "GET,POST,PUT,DELETE,OPTIONS", // Specify the allowed HTTP methods
|
||||||
|
AllowHeaders: "Content-Type,Authorization,platform", // Specify the allowed headers
|
||||||
|
// AllowCredentials: true,
|
||||||
|
}))
|
||||||
|
|
||||||
s := &App{
|
s := &App{
|
||||||
fiber: app,
|
fiber: app,
|
||||||
port: port,
|
port: port,
|
||||||
|
|
@ -70,9 +91,13 @@ func NewApp(
|
||||||
betSvc: betSvc,
|
betSvc: betSvc,
|
||||||
walletSvc: walletSvc,
|
walletSvc: walletSvc,
|
||||||
transactionSvc: transactionSvc,
|
transactionSvc: transactionSvc,
|
||||||
|
branchSvc: branchSvc,
|
||||||
|
companySvc: companySvc,
|
||||||
NotidicationStore: notidicationStore,
|
NotidicationStore: notidicationStore,
|
||||||
referralSvc: referralSvc,
|
referralSvc: referralSvc,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
prematchSvc: prematchSvc,
|
||||||
|
eventSvc: eventSvc,
|
||||||
virtualGameSvc: virtualGameSvc,
|
virtualGameSvc: virtualGameSvc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
58
internal/web_server/cron.go
Normal file
58
internal/web_server/cron.go
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package httpserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.Service) {
|
||||||
|
c := cron.New(cron.WithSeconds())
|
||||||
|
|
||||||
|
schedule := []struct {
|
||||||
|
spec string
|
||||||
|
task func()
|
||||||
|
}{
|
||||||
|
|
||||||
|
// {
|
||||||
|
// spec: "0 0 * * * *", // Every hour
|
||||||
|
// task: func() {
|
||||||
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
|
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||||
|
// task: func() {
|
||||||
|
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
||||||
|
// log.Printf("FetchLiveEvents error: %v", err)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// spec: "0 */15 * * * *", // Every 15 minutes
|
||||||
|
// task: func() {
|
||||||
|
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
|
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, job := range schedule {
|
||||||
|
job.task()
|
||||||
|
fmt.Printf("here at")
|
||||||
|
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||||
|
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Start()
|
||||||
|
log.Println("Cron jobs started for event and odds services")
|
||||||
|
}
|
||||||
|
|
@ -3,12 +3,14 @@ package handlers
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
||||||
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// LoginCustomer godoc
|
// LoginCustomer godoc
|
||||||
// @Summary Login customer
|
// @Summary Login customer
|
||||||
// @Description Login customer
|
// @Description Login customer
|
||||||
|
|
@ -30,6 +32,7 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
type loginCustomerRes struct {
|
type loginCustomerRes struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
Role string `json:"role"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var req loginCustomerReq
|
var req loginCustomerReq
|
||||||
|
|
@ -54,7 +57,7 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, err := jwtutil.CreateJwt(successRes.UserId, successRes.Role, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
accessToken, err := jwtutil.CreateJwt(successRes.UserId, successRes.Role, successRes.BranchId, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Failed to create access token", "userID", successRes.UserId, "error", err)
|
h.logger.Error("Failed to create access token", "userID", successRes.UserId, "error", err)
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to generate access token")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to generate access token")
|
||||||
|
|
@ -63,10 +66,12 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
res := loginCustomerRes{
|
res := loginCustomerRes{
|
||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
RefreshToken: successRes.RfToken,
|
RefreshToken: successRes.RfToken,
|
||||||
|
Role: string(successRes.Role),
|
||||||
}
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Login successful", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Login successful", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// RefreshToken godoc
|
// RefreshToken godoc
|
||||||
// @Summary Refresh token
|
// @Summary Refresh token
|
||||||
// @Description Refresh token
|
// @Description Refresh token
|
||||||
|
|
@ -99,7 +104,10 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
rf, err := h.authSvc.RefreshToken(c.Context(), req.RefreshToken)
|
userId := c.Locals("user_id").(int64)
|
||||||
|
role := c.Locals("role").(string)
|
||||||
|
branchId := c.Locals("branch_id").(int64)
|
||||||
|
err := authSvc.RefreshToken(c.Context(), req.RefreshToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Info("Refresh token attempt failed", "refreshToken", req.RefreshToken, "error", err)
|
h.logger.Info("Refresh token attempt failed", "refreshToken", req.RefreshToken, "error", err)
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -114,7 +122,7 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assuming the refreshed token includes userID and role info; adjust if needed
|
// Assuming the refreshed token includes userID and role info; adjust if needed
|
||||||
accessToken, err := jwtutil.CreateJwt(0, "", h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
accessToken, err := jwtutil.CreateJwt(userId, domain.Role(role), branchId, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Failed to create new access token", "error", err)
|
h.logger.Error("Failed to create new access token", "error", err)
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to generate access token")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to generate access token")
|
||||||
|
|
@ -122,7 +130,7 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error {
|
||||||
|
|
||||||
res := loginCustomerRes{
|
res := loginCustomerRes{
|
||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
RefreshToken: rf,
|
RefreshToken: req.RefreshToken,
|
||||||
}
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Refresh successful", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Refresh successful", res, nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,93 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CreateBetOutcomeReq struct {
|
||||||
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBetReq struct {
|
||||||
|
Outcomes []CreateBetOutcomeReq `json:"outcomes"`
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||||
|
Status domain.OutcomeStatus `json:"status" example:"1"`
|
||||||
|
FullName string `json:"full_name" example:"John"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBetRes struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||||
|
Status domain.OutcomeStatus `json:"status" example:"1"`
|
||||||
|
FullName string `json:"full_name" example:"John"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
BranchID int64 `json:"branch_id" example:"2"`
|
||||||
|
UserID int64 `json:"user_id" example:"2"`
|
||||||
|
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||||
|
CreatedNumber int64 `json:"created_number" example:"2"`
|
||||||
|
CashedID string `json:"cashed_id" example:"21234"`
|
||||||
|
}
|
||||||
type BetRes struct {
|
type BetRes struct {
|
||||||
ID int64 `json:"id" example:"1"`
|
ID int64 `json:"id" example:"1"`
|
||||||
Outcomes []domain.Outcome `json:"outcomes"`
|
Outcomes []domain.BetOutcome `json:"outcomes"`
|
||||||
Amount float32 `json:"amount" example:"100.0"`
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||||
Status domain.BetStatus `json:"status" example:"1"`
|
Status domain.OutcomeStatus `json:"status" example:"1"`
|
||||||
FullName string `json:"full_name" example:"John"`
|
FullName string `json:"full_name" example:"John"`
|
||||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
BranchID int64 `json:"branch_id" example:"2"`
|
BranchID int64 `json:"branch_id" example:"2"`
|
||||||
UserID int64 `json:"user_id" example:"2"`
|
UserID int64 `json:"user_id" example:"2"`
|
||||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
||||||
|
CashedOut bool `json:"cashed_out" example:"false"`
|
||||||
|
CashedID string `json:"cashed_id" example:"21234"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCreateBet(bet domain.Bet, createdNumber int64) CreateBetRes {
|
||||||
|
return CreateBetRes{
|
||||||
|
ID: bet.ID,
|
||||||
|
Amount: bet.Amount.Float64(),
|
||||||
|
TotalOdds: bet.TotalOdds,
|
||||||
|
Status: bet.Status,
|
||||||
|
FullName: bet.FullName,
|
||||||
|
PhoneNumber: bet.PhoneNumber,
|
||||||
|
BranchID: bet.BranchID.Value,
|
||||||
|
UserID: bet.UserID.Value,
|
||||||
|
CreatedNumber: createdNumber,
|
||||||
|
CashedID: bet.CashoutID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertBet(bet domain.GetBet) BetRes {
|
||||||
|
return BetRes{
|
||||||
|
ID: bet.ID,
|
||||||
|
Amount: bet.Amount.Float64(),
|
||||||
|
TotalOdds: bet.TotalOdds,
|
||||||
|
Status: bet.Status,
|
||||||
|
FullName: bet.FullName,
|
||||||
|
PhoneNumber: bet.PhoneNumber,
|
||||||
|
BranchID: bet.BranchID.Value,
|
||||||
|
UserID: bet.UserID.Value,
|
||||||
|
Outcomes: bet.Outcomes,
|
||||||
|
IsShopBet: bet.IsShopBet,
|
||||||
|
CashedOut: bet.CashedOut,
|
||||||
|
CashedID: bet.CashoutID,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBet godoc
|
// CreateBet godoc
|
||||||
|
|
@ -33,15 +102,9 @@ type BetRes struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /bet [post]
|
// @Router /bet [post]
|
||||||
func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
||||||
type CreateBetReq struct {
|
|
||||||
Outcomes []int64 `json:"outcomes" validate:"required" example:"[1, 2, 3]"`
|
// Get user_id from middleware
|
||||||
Amount float32 `json:"amount" validate:"required" example:"100.0"`
|
userID := c.Locals("user_id").(int64)
|
||||||
TotalOdds float32 `json:"total_odds" validate:"required" example:"4.22"`
|
|
||||||
Status domain.BetStatus `json:"status" validate:"required" example:"1"`
|
|
||||||
FullName string `json:"full_name" example:"John"`
|
|
||||||
PhoneNumber string `json:"phone_number" validate:"required" example:"1234567890"`
|
|
||||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var req CreateBetReq
|
var req CreateBetReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
@ -49,50 +112,165 @@ func (h *Handler) CreateBet(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
}
|
}
|
||||||
|
|
||||||
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
valErrs, ok := h.validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check the token, find the role, and get the branch ID from there
|
// Validating user by role
|
||||||
isShopBet := true
|
// Differentiating between offline and online bets
|
||||||
branchID := int64(1)
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
var userID int64
|
cashoutUUID := uuid.New()
|
||||||
|
var bet domain.Bet
|
||||||
|
if user.Role == domain.RoleCashier {
|
||||||
|
|
||||||
// TODO: Validate Outcomes Here and make sure they didn't expire
|
// Get the branch from the branch ID
|
||||||
|
branch, err := h.branchSvc.GetBranchByCashier(c.Context(), user.ID)
|
||||||
bet, err := h.betSvc.CreateBet(c.Context(), domain.CreateBet{
|
if err != nil {
|
||||||
Outcomes: req.Outcomes,
|
h.logger.Error("CreateBetReq failed, branch id invalid")
|
||||||
Amount: domain.Currency(req.Amount),
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
TotalOdds: req.TotalOdds,
|
|
||||||
Status: req.Status,
|
|
||||||
FullName: req.FullName,
|
|
||||||
PhoneNumber: req.PhoneNumber,
|
|
||||||
BranchID: domain.ValidInt64{
|
|
||||||
Value: branchID,
|
|
||||||
Valid: isShopBet,
|
|
||||||
},
|
|
||||||
UserID: domain.ValidInt64{
|
|
||||||
Value: userID,
|
|
||||||
Valid: !isShopBet,
|
|
||||||
},
|
|
||||||
IsShopBet: req.IsShopBet,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
h.logger.Error("Failed to create bet", "error", err)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create bet")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Reduce amount from the branch wallet (assuming walletSvc integration)
|
|
||||||
// This would typically be done here or in the bet service
|
|
||||||
|
|
||||||
if !req.IsShopBet && req.PhoneNumber != "" {
|
|
||||||
if err := h.referralSvc.ProcessBetReferral(c.Context(), req.PhoneNumber, float64(req.Amount)); err != nil {
|
|
||||||
h.logger.Warn("Failed to process bet referral", "phone", req.PhoneNumber, "amount", req.Amount, "error", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deduct a percentage of the amount
|
||||||
|
// TODO move to service layer
|
||||||
|
var deductedAmount = req.Amount / 10
|
||||||
|
err = h.walletSvc.DeductFromWallet(c.Context(), branch.WalletID, domain.ToCurrency(deductedAmount))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("CreateBetReq failed, unable to deduct from WalletID")
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
bet, err = h.betSvc.CreateBet(c.Context(), domain.CreateBet{
|
||||||
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
|
TotalOdds: req.TotalOdds,
|
||||||
|
Status: req.Status,
|
||||||
|
FullName: req.FullName,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
|
||||||
|
BranchID: domain.ValidInt64{
|
||||||
|
Value: branch.ID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
UserID: domain.ValidInt64{
|
||||||
|
Value: userID,
|
||||||
|
Valid: false,
|
||||||
|
},
|
||||||
|
IsShopBet: req.IsShopBet,
|
||||||
|
CashoutID: cashoutUUID.String(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// TODO if user is customer, get id from the token then get the wallet id from there and reduce the amount
|
||||||
|
bet, err = h.betSvc.CreateBet(c.Context(), domain.CreateBet{
|
||||||
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
|
TotalOdds: req.TotalOdds,
|
||||||
|
Status: req.Status,
|
||||||
|
FullName: req.FullName,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
|
||||||
|
BranchID: domain.ValidInt64{
|
||||||
|
Value: 0,
|
||||||
|
Valid: false,
|
||||||
|
},
|
||||||
|
UserID: domain.ValidInt64{
|
||||||
|
Value: userID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
IsShopBet: req.IsShopBet,
|
||||||
|
CashoutID: cashoutUUID.String(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
res := convertBet(bet)
|
if err != nil {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Bet created successfully", res, nil)
|
h.logger.Error("CreateBetReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||||
|
// Validation for creating tickets
|
||||||
|
if len(req.Outcomes) > 30 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||||
|
}
|
||||||
|
var outcomes []domain.CreateBetOutcome = make([]domain.CreateBetOutcome, 0, len(req.Outcomes))
|
||||||
|
for _, outcome := range req.Outcomes {
|
||||||
|
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||||
|
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||||
|
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||||
|
event, err := h.eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking to make sure the event hasn't already started
|
||||||
|
currentTime := time.Now()
|
||||||
|
if event.StartTime.Before(currentTime) {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := h.oddSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||||
|
}
|
||||||
|
type rawOddType struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Odds string
|
||||||
|
Header string
|
||||||
|
Handicap string
|
||||||
|
}
|
||||||
|
var selectedOdd rawOddType
|
||||||
|
var isOddFound bool = false
|
||||||
|
for _, raw := range odds.RawOdds {
|
||||||
|
var rawOdd rawOddType
|
||||||
|
rawBytes, err := json.Marshal(raw)
|
||||||
|
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to unmarshal raw odd:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rawOdd.ID == oddIDStr {
|
||||||
|
selectedOdd = rawOdd
|
||||||
|
isOddFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isOddFound {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||||
|
|
||||||
|
outcomes = append(outcomes, domain.CreateBetOutcome{
|
||||||
|
BetID: bet.ID,
|
||||||
|
EventID: outcome.EventID,
|
||||||
|
OddID: outcome.OddID,
|
||||||
|
MarketID: outcome.MarketID,
|
||||||
|
HomeTeamName: event.HomeTeam,
|
||||||
|
AwayTeamName: event.AwayTeam,
|
||||||
|
MarketName: odds.MarketName,
|
||||||
|
Odd: float32(parsedOdd),
|
||||||
|
OddName: selectedOdd.Name,
|
||||||
|
OddHeader: selectedOdd.Header,
|
||||||
|
OddHandicap: selectedOdd.Handicap,
|
||||||
|
Expires: event.StartTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := h.betSvc.CreateBetOutcome(c.Context(), outcomes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("CreateBetReq failed to create outcomes", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertCreateBet(bet, rows)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Bet Created", res, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllBet godoc
|
// GetAllBet godoc
|
||||||
|
|
@ -132,19 +310,6 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /bet/{id} [get]
|
// @Router /bet/{id} [get]
|
||||||
func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
||||||
type BetRes struct {
|
|
||||||
ID int64 `json:"id" example:"1"`
|
|
||||||
Outcomes []domain.Outcome `json:"outcomes"`
|
|
||||||
Amount float32 `json:"amount" example:"100.0"`
|
|
||||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
|
||||||
Status domain.BetStatus `json:"status" example:"1"`
|
|
||||||
FullName string `json:"full_name" example:"John"`
|
|
||||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
|
||||||
BranchID int64 `json:"branch_id" example:"2"`
|
|
||||||
UserID int64 `json:"user_id" example:"2"`
|
|
||||||
IsShopBet bool `json:"is_shop_bet" example:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
betID := c.Params("id")
|
betID := c.Params("id")
|
||||||
id, err := strconv.ParseInt(betID, 10, 64)
|
id, err := strconv.ParseInt(betID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -159,7 +324,47 @@ func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
res := convertBet(bet)
|
res := convertBet(bet)
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil)
|
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} BetRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /bet/cashout/{id} [get]
|
||||||
|
func GetBetByCashoutID(logger *slog.Logger, betSvc *bet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
cashoutID := c.Params("id")
|
||||||
|
// id, err := strconv.ParseInt(cashoutID, 10, 64)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Error("Invalid cashout ID", "cashoutID", cashoutID, "error", err)
|
||||||
|
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashout ID", err, nil)
|
||||||
|
// }
|
||||||
|
|
||||||
|
bet, err := betSvc.GetBetByCashoutID(c.Context(), cashoutID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get bet by ID", "cashoutID", cashoutID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bet", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertBet(bet)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateCashOutReq struct {
|
||||||
|
CashedOut bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCashOut godoc
|
// UpdateCashOut godoc
|
||||||
|
|
@ -189,7 +394,7 @@ func (h *Handler) UpdateCashOut(c *fiber.Ctx) error {
|
||||||
var req UpdateCashOutReq
|
var req UpdateCashOutReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.logger.Error("Failed to parse UpdateCashOut request", "error", err)
|
h.logger.Error("Failed to parse UpdateCashOut request", "error", err)
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request body", err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||||
|
|
@ -232,18 +437,3 @@ func (h *Handler) DeleteBet(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Bet removed successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Bet removed successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertBet(bet domain.Bet) BetRes {
|
|
||||||
return BetRes{
|
|
||||||
ID: bet.ID,
|
|
||||||
Outcomes: bet.Outcomes,
|
|
||||||
Amount: bet.Amount.Float64(),
|
|
||||||
TotalOdds: bet.TotalOdds,
|
|
||||||
Status: bet.Status,
|
|
||||||
FullName: bet.FullName,
|
|
||||||
PhoneNumber: bet.PhoneNumber,
|
|
||||||
BranchID: bet.BranchID.Value,
|
|
||||||
UserID: bet.UserID.Value,
|
|
||||||
IsShopBet: bet.IsShopBet,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
664
internal/web_server/handlers/branch_handler.go
Normal file
664
internal/web_server/handlers/branch_handler.go
Normal file
|
|
@ -0,0 +1,664 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateBranchReq struct {
|
||||||
|
Name string `json:"name" example:"4-kilo Branch"`
|
||||||
|
Location string `json:"location" example:"Addis Ababa"`
|
||||||
|
BranchManagerID int64 `json:"branch_manager_id" example:"1"`
|
||||||
|
CompanyID int64 `json:"company_id" example:"1"`
|
||||||
|
IsSelfOwned bool `json:"is_self_owned" example:"false"`
|
||||||
|
Operations []int64 `json:"operations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch [post]
|
||||||
|
func CreateBranch(logger *slog.Logger, branchSvc *branch.Service, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
// Check if user is either branch manager / super main
|
||||||
|
// role := string(c.Locals("role").(domain.Role))
|
||||||
|
|
||||||
|
// if role != string(domain.RoleAdmin) && role != string(domain.RoleSuperAdmin) && role != string(domain.RoleBranchManager) {
|
||||||
|
// logger.Error("Unauthorized access", "role", role)
|
||||||
|
// return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||||
|
// }
|
||||||
|
|
||||||
|
var req CreateBranchReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateBranchReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Branch Wallet
|
||||||
|
newWallet, err := walletSvc.CreateWallet(c.Context(), domain.CreateWallet{
|
||||||
|
IsWithdraw: false,
|
||||||
|
IsBettable: true,
|
||||||
|
IsTransferable: true,
|
||||||
|
UserID: req.BranchManagerID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Create Branch Wallet failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create branch wallet", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := branchSvc.CreateBranch(c.Context(), domain.CreateBranch{
|
||||||
|
Name: req.Name,
|
||||||
|
Location: req.Location,
|
||||||
|
WalletID: newWallet.ID,
|
||||||
|
BranchManagerID: req.BranchManagerID,
|
||||||
|
CompanyID: req.CompanyID,
|
||||||
|
IsSelfOwned: req.IsSelfOwned,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateBranchReq failed", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, operation := range req.Operations {
|
||||||
|
err := branchSvc.CreateBranchOperation(c.Context(), domain.CreateBranchOperation{
|
||||||
|
BranchID: branch.ID,
|
||||||
|
OperationID: operation,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
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",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertBranch(branch)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusCreated, "Branch Created", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSupportedOperation godoc
|
||||||
|
// @Summary Create a supported operation
|
||||||
|
// @Description Creates a supported operation
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param createSupportedOperation body CreateSupportedOperationReq true "Creates supported operation"
|
||||||
|
// @Success 200 {object} SupportedOperationRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /supportedOperation [post]
|
||||||
|
func CreateSupportedOperation(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req CreateSupportedOperationReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateSupportedOperationReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
operation, err := branchSvc.CreateSupportedOperation(c.Context(), domain.CreateSupportedOperation{
|
||||||
|
Name: req.Name,
|
||||||
|
Description: req.Description,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateSupportedOperationReq failed", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res := SupportedOperationRes{
|
||||||
|
Name: operation.Name,
|
||||||
|
Description: operation.Description,
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Operation Created", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBranchOperation godoc
|
||||||
|
// @Summary Create a operation
|
||||||
|
// @Description Creates a operation
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param createBranchOperation body CreateBranchOperationReq true "Creates operation"
|
||||||
|
// @Success 200 {object} BranchOperationRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /operation [post]
|
||||||
|
func CreateBranchOperation(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req CreateBranchOperationReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateBranchOperationReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := branchSvc.CreateBranchOperation(c.Context(), domain.CreateBranchOperation{
|
||||||
|
BranchID: req.BranchID,
|
||||||
|
OperationID: req.OperationID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateBranchOperationReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Operation Created", nil, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBranchByID godoc
|
||||||
|
// @Summary Gets branch by id
|
||||||
|
// @Description Gets a single branch by id
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Success 200 {object} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id} [get]
|
||||||
|
func GetBranchByID(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := branchSvc.GetBranchByID(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get branch by ID", "branchID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertBranchDetail(branch)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch retrieved successfully", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBranchByManagerID godoc
|
||||||
|
// @Summary Gets branches by manager id
|
||||||
|
// @Description Gets a branches by manager id
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {array} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /manager/{id}/branch [get]
|
||||||
|
func GetBranchByManagerID(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(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 {
|
||||||
|
logger.Error("Invalid user ID", "userID", userID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid user ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branches, err := branchSvc.GetBranchByManagerID(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get branches", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil)
|
||||||
|
}
|
||||||
|
var result []BranchDetailRes = make([]BranchDetailRes, 0, len(branches))
|
||||||
|
for _, branch := range branches {
|
||||||
|
result = append(result, convertBranchDetail(branch))
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branches for Branch Manager retrieved", result, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBranchByCompanyID godoc
|
||||||
|
// @Summary Gets branches by company id
|
||||||
|
// @Description Gets branches by company id
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Company ID"
|
||||||
|
// @Success 200 {array} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /company/{id}/branch [get]
|
||||||
|
func GetBranchByCompanyID(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(companyID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid company ID", "companyID", companyID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branches, err := branchSvc.GetBranchByCompanyID(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get branches", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []BranchDetailRes = make([]BranchDetailRes, 0, len(branches))
|
||||||
|
for _, branch := range branches {
|
||||||
|
result = append(result, convertBranchDetail(branch))
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branches for Company retrieved", result, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllBranches godoc
|
||||||
|
// @Summary Gets all branches
|
||||||
|
// @Description Gets all branches
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch [get]
|
||||||
|
func GetAllBranches(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
// TODO: Limit the get all branches to only the companies for branch manager and cashiers
|
||||||
|
branches, err := branchSvc.GetAllBranches(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get branches", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []BranchDetailRes = make([]BranchDetailRes, 0, len(branches))
|
||||||
|
for _, branch := range branches {
|
||||||
|
result = append(result, convertBranchDetail(branch))
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branches for Company retrieved", result, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchBranch godoc
|
||||||
|
// @Summary Search branches
|
||||||
|
// @Description Search branches by name or location
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param q query string true "Search query"
|
||||||
|
// @Success 200 {array} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /search/branch [get]
|
||||||
|
func SearchBranch(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
// Get search query from request
|
||||||
|
searchQuery := c.Query("q")
|
||||||
|
if searchQuery == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Search query is required", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the service to search for branches
|
||||||
|
branches, err := branchSvc.SearchBranchByName(c.Context(), searchQuery)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to search branches", "query", searchQuery, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to search branches", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert branches to response format
|
||||||
|
var result []BranchDetailRes
|
||||||
|
for _, branch := range branches {
|
||||||
|
result = append(result, convertBranchDetail(branch))
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branches retrieved successfully", result, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllSupportedOperations godoc
|
||||||
|
// @Summary Gets all supported operations
|
||||||
|
// @Description Gets all supported operations
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /supportedOperation [get]
|
||||||
|
func GetAllSupportedOperations(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
operations, err := branchSvc.GetAllSupportedOperations(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get operations", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get operations", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []SupportedOperationRes = make([]SupportedOperationRes, 0, len(operations))
|
||||||
|
for _, operation := range operations {
|
||||||
|
result = append(result, SupportedOperationRes{
|
||||||
|
ID: operation.ID,
|
||||||
|
Name: operation.Name,
|
||||||
|
Description: operation.Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "SupportedOperations for Company retrieved", result, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBranchOperations godoc
|
||||||
|
// @Summary Gets branch operations
|
||||||
|
// @Description Gets branch operations
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Success 200 {array} BranchOperationRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id}/operation [get]
|
||||||
|
func GetBranchOperations(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
operations, err := branchSvc.GetBranchOperations(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get operation by ID", "branchID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve operation", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []BranchOperationRes = make([]BranchOperationRes, 0, len(operations))
|
||||||
|
|
||||||
|
for _, branch := range operations {
|
||||||
|
result = append(result, BranchOperationRes{
|
||||||
|
Name: branch.OperationName,
|
||||||
|
Description: branch.OperationDescription,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Operations retrieved successfully", result, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBetByBranchID godoc
|
||||||
|
// @Summary Gets bets by its branch id
|
||||||
|
// @Description Gets bets by its branch id
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} BetRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id}/bets [get]
|
||||||
|
func GetBetByBranchID(logger *slog.Logger, betSvc *bet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
bets, err := betSvc.GetBetByBranchID(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get bets", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve bets", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []BetRes = make([]BetRes, 0, len(bets))
|
||||||
|
for _, bet := range bets {
|
||||||
|
res = append(res, convertBet(bet))
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Bets Retrieved", res, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateBranch godoc
|
||||||
|
// @Summary Updates a branch
|
||||||
|
// @Description Updates a branch
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Param updateBranch body CreateBranchReq true "Update Branch"
|
||||||
|
// @Success 200 {object} BranchRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id} [put]
|
||||||
|
func UpdateBranch(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var req CreateBranchReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateBranchReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := branchSvc.UpdateBranch(c.Context(), id, domain.UpdateBranch{
|
||||||
|
Name: req.Name,
|
||||||
|
Location: req.Location,
|
||||||
|
BranchManagerID: req.BranchManagerID,
|
||||||
|
CompanyID: req.CompanyID,
|
||||||
|
IsSelfOwned: req.IsSelfOwned,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to update branch", "branchID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update branch", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertBranch(branch)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Updated", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBranch godoc
|
||||||
|
// @Summary Delete the branch
|
||||||
|
// @Description Delete the branch
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID""
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id} [delete]
|
||||||
|
func DeleteBranch(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid Branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = branchSvc.DeleteBranch(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to delete by ID", "Branch ID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Branch", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch removed successfully", nil, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBranchOperation godoc
|
||||||
|
// @Summary Delete the branch operation
|
||||||
|
// @Description Delete the branch operation
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Param opID path int true "Branch Operation ID"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /branch/{id}/operation/{opID} [delete]
|
||||||
|
func DeleteBranchOperation(logger *slog.Logger, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
branchID := c.Params("id")
|
||||||
|
opID := c.Params("opID")
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid Branch ID", "branchID", branchID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Branch ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
operationID, err := strconv.ParseInt(opID, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid Operation ID", "operationID", opID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Operation ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = branchSvc.DeleteBranchOperation(c.Context(), id, operationID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to delete operation", "Branch ID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Operation", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Operation removed successfully", nil, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
208
internal/web_server/handlers/cashier.go
Normal file
208
internal/web_server/handlers/cashier.go
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateCashierReq struct {
|
||||||
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
Password string `json:"password" example:"password123"`
|
||||||
|
BranchID int64 `json:"branch_id" example:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCashier godoc
|
||||||
|
// @Summary Create cashier
|
||||||
|
// @Description Create cashier
|
||||||
|
// @Tags cashier
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param cashier body CreateCashierReq true "Create cashier"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /cashiers [post]
|
||||||
|
func CreateCashier(logger *slog.Logger, userSvc *user.Service, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
var req CreateCashierReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("RegisterUser failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
userRequest := domain.CreateUserReq{
|
||||||
|
FirstName: req.FirstName,
|
||||||
|
LastName: req.LastName,
|
||||||
|
Email: req.Email,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
Password: req.Password,
|
||||||
|
Role: string(domain.RoleCashier),
|
||||||
|
}
|
||||||
|
newUser, err := userSvc.CreateUser(c.Context(), userRequest)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateCashier failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = branchSvc.CreateBranchCashier(c.Context(), req.BranchID, newUser.ID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateCashier failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil)
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Cashier created successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetCashierRes struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Role domain.Role `json:"role"`
|
||||||
|
EmailVerified bool `json:"email_verified"`
|
||||||
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
|
Suspended bool `json:"suspended"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllCashiers godoc
|
||||||
|
// @Summary Get all cashiers
|
||||||
|
// @Description Get all cashiers
|
||||||
|
// @Tags cashier
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "Page number"
|
||||||
|
// @Param page_size query int false "Page size"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /cashiers [get]
|
||||||
|
func GetAllCashiers(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
// branchId := int64(12) //c.Locals("branch_id").(int64)
|
||||||
|
// filter := user.Filter{
|
||||||
|
// Role: string(domain.RoleCashier),
|
||||||
|
// BranchId: user.ValidBranchId{
|
||||||
|
// Value: branchId,
|
||||||
|
// Valid: true,
|
||||||
|
// },
|
||||||
|
// Page: c.QueryInt("page", 1),
|
||||||
|
// PageSize: c.QueryInt("page_size", 10),
|
||||||
|
// }
|
||||||
|
// valErrs, ok := validator.Validate(c, filter)
|
||||||
|
// if !ok {
|
||||||
|
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
// }
|
||||||
|
|
||||||
|
cashiers, err := userSvc.GetAllCashiers(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("GetAllCashiers failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []GetCashierRes
|
||||||
|
|
||||||
|
for _, cashier := range cashiers {
|
||||||
|
result = append(result, GetCashierRes{
|
||||||
|
ID: cashier.ID,
|
||||||
|
FirstName: cashier.FirstName,
|
||||||
|
LastName: cashier.LastName,
|
||||||
|
Email: cashier.Email,
|
||||||
|
PhoneNumber: cashier.PhoneNumber,
|
||||||
|
Role: cashier.Role,
|
||||||
|
EmailVerified: cashier.EmailVerified,
|
||||||
|
PhoneVerified: cashier.PhoneVerified,
|
||||||
|
CreatedAt: cashier.CreatedAt,
|
||||||
|
UpdatedAt: cashier.UpdatedAt,
|
||||||
|
SuspendedAt: cashier.SuspendedAt,
|
||||||
|
Suspended: cashier.Suspended,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", result, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type updateUserReq struct {
|
||||||
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
|
Suspended bool `json:"suspended" example:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateCashier godoc
|
||||||
|
// @Summary Update cashier
|
||||||
|
// @Description Update cashier
|
||||||
|
// @Tags cashier
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param cashier body updateUserReq true "Update cashier"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /cashiers/{id} [put]
|
||||||
|
func UpdateCashier(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req updateUserReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("UpdateCashier failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
cashierIdStr := c.Params("id")
|
||||||
|
cashierId, err := strconv.ParseInt(cashierIdStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("UpdateCashier failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil)
|
||||||
|
}
|
||||||
|
err = userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
|
UserId: cashierId,
|
||||||
|
FirstName: domain.ValidString{
|
||||||
|
Value: req.FirstName,
|
||||||
|
Valid: req.FirstName != "",
|
||||||
|
},
|
||||||
|
LastName: domain.ValidString{
|
||||||
|
Value: req.LastName,
|
||||||
|
Valid: req.LastName != "",
|
||||||
|
},
|
||||||
|
Suspended: domain.ValidBool{
|
||||||
|
Value: req.Suspended,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("UpdateCashier failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update cashier", nil, nil)
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Cashier updated successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
229
internal/web_server/handlers/company_handler.go
Normal file
229
internal/web_server/handlers/company_handler.go
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/company"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateCompanyReq struct {
|
||||||
|
Name string `json:"name" example:"CompanyName"`
|
||||||
|
AdminID int64 `json:"admin_id" 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCompany(company domain.Company) CompanyRes {
|
||||||
|
return CompanyRes{
|
||||||
|
ID: company.ID,
|
||||||
|
Name: company.Name,
|
||||||
|
AdminID: company.AdminID,
|
||||||
|
WalletID: company.WalletID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /company [post]
|
||||||
|
func CreateCompany(logger *slog.Logger, companySvc *company.Service, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req CreateCompanyReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateCompanyReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
// Create Branch Wallet
|
||||||
|
newWallet, err := walletSvc.CreateWallet(c.Context(), domain.CreateWallet{
|
||||||
|
IsWithdraw: false,
|
||||||
|
IsBettable: true,
|
||||||
|
IsTransferable: true,
|
||||||
|
UserID: req.AdminID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Create Company Wallet failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create company wallet", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := companySvc.CreateCompany(c.Context(), domain.CreateCompany{
|
||||||
|
Name: req.Name,
|
||||||
|
AdminID: req.AdminID,
|
||||||
|
WalletID: newWallet.ID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateCompanyReq failed", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertCompany(company)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusCreated, "Company Created", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllCompanies godoc
|
||||||
|
// @Summary Gets all companies
|
||||||
|
// @Description Gets all companies
|
||||||
|
// @Tags company
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} CompanyRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /company [get]
|
||||||
|
func GetAllCompanies(logger *slog.Logger, companySvc *company.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
companies, err := companySvc.GetAllCompanies(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get companies", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get companies", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []CompanyRes = make([]CompanyRes, 0, len(companies))
|
||||||
|
|
||||||
|
for _, company := range companies {
|
||||||
|
result = append(result, convertCompany(company))
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCompanyByID godoc
|
||||||
|
// @Summary Gets company by id
|
||||||
|
// @Description Gets a single company by id
|
||||||
|
// @Tags company
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Company ID"
|
||||||
|
// @Success 200 {object} CompanyRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /company/{id} [get]
|
||||||
|
func GetCompanyByID(logger *slog.Logger, companySvc *company.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(companyID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid company ID", "companyID", companyID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := companySvc.GetCompanyByID(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get company by ID", "companyID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to company branch", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertCompany(company)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateCompany godoc
|
||||||
|
// @Summary Updates a company
|
||||||
|
// @Description Updates a company
|
||||||
|
// @Tags company
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Company ID"
|
||||||
|
// @Param updateCompany body CreateCompanyReq true "Update Company"
|
||||||
|
// @Success 200 {object} CompanyRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /company/{id} [put]
|
||||||
|
func UpdateCompany(logger *slog.Logger, companySvc *company.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(companyID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid company ID", "companyID", companyID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var req CreateCompanyReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateCompanyReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := companySvc.UpdateCompany(c.Context(), id, domain.UpdateCompany{
|
||||||
|
Name: req.Name,
|
||||||
|
AdminID: req.AdminID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to update company", "companyID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update company", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertCompany(company)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Company Updated", res, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCompany godoc
|
||||||
|
// @Summary Delete the company
|
||||||
|
// @Description Delete the company
|
||||||
|
// @Tags company
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Company ID""
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /company/{id} [delete]
|
||||||
|
func DeleteCompany(logger *slog.Logger, companySvc *company.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(companyID, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid Company ID", "companyID", companyID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Company ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = companySvc.DeleteCompany(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to delete by ID", "Company ID", id, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Company", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Company removed successfully", nil, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
156
internal/web_server/handlers/manager.go
Normal file
156
internal/web_server/handlers/manager.go
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateManagerReq struct {
|
||||||
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
Password string `json:"password" example:"password123"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateManagers godoc
|
||||||
|
// @Summary Create Managers
|
||||||
|
// @Description Create Managers
|
||||||
|
// @Tags manager
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param manger body CreateManagerReq true "Create manager"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /managers [post]
|
||||||
|
func CreateManager(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req CreateManagerReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("RegisterUser failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
user := domain.CreateUserReq{
|
||||||
|
FirstName: req.FirstName,
|
||||||
|
LastName: req.LastName,
|
||||||
|
Email: req.Email,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
Password: req.Password,
|
||||||
|
Role: string(domain.RoleBranchManager),
|
||||||
|
}
|
||||||
|
_, err := userSvc.CreateUser(c.Context(), user)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateManagers failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create Managers", nil, nil)
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Managers created successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllManagers godoc
|
||||||
|
// @Summary Get all Managers
|
||||||
|
// @Description Get all Managers
|
||||||
|
// @Tags manager
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "Page number"
|
||||||
|
// @Param page_size query int false "Page size"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /managers [get]
|
||||||
|
func GetAllManagers(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
filter := user.Filter{
|
||||||
|
Role: string(domain.RoleBranchManager),
|
||||||
|
BranchId: user.ValidBranchId{
|
||||||
|
Value: int64(c.QueryInt("branch_id")),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
Page: c.QueryInt("page", 1),
|
||||||
|
PageSize: c.QueryInt("page_size", 10),
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, filter)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
Managers, err := userSvc.GetAllUsers(c.Context(), filter)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("GetAllManagers failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Managers", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Managers retrieved successfully", Managers, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateManagers godoc
|
||||||
|
// @Summary Update Managers
|
||||||
|
// @Description Update Managers
|
||||||
|
// @Tags Managers
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Managers body updateUserReq true "Update Managers"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /managers/{id} [put]
|
||||||
|
func UPdateManagers(logger *slog.Logger, userSvc *user.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req updateUserReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("UpdateManagers failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
ManagersIdStr := c.Params("id")
|
||||||
|
ManagersId, err := strconv.ParseInt(ManagersIdStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("UpdateManagers failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Managers ID", nil, nil)
|
||||||
|
}
|
||||||
|
err = userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
|
UserId: ManagersId,
|
||||||
|
FirstName: domain.ValidString{
|
||||||
|
Value: req.FirstName,
|
||||||
|
Valid: req.FirstName != "",
|
||||||
|
},
|
||||||
|
LastName: domain.ValidString{
|
||||||
|
Value: req.LastName,
|
||||||
|
Valid: req.LastName != "",
|
||||||
|
},
|
||||||
|
Suspended: domain.ValidBool{
|
||||||
|
Value: req.Suspended,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("UpdateManagers failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update Managers", nil, nil)
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Managers updated successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
195
internal/web_server/handlers/prematch.go
Normal file
195
internal/web_server/handlers/prematch.go
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetPrematchOdds godoc
|
||||||
|
// @Summary Retrieve prematch odds for an event
|
||||||
|
// @Description Retrieve prematch odds for a specific event by event ID
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param event_id path string true "Event ID"
|
||||||
|
// @Success 200 {array} domain.Odd
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds/{event_id} [get]
|
||||||
|
func GetPrematchOdds(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
eventID := c.Params("event_id")
|
||||||
|
if eventID == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing event_id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := prematchSvc.GetPrematchOdds(c.Context(), eventID)
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve odds", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetALLPrematchOdds
|
||||||
|
// @Summary Retrieve all prematch odds
|
||||||
|
// @Description Retrieve all prematch odds from the database
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.Odd
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds [get]
|
||||||
|
func GetALLPrematchOdds(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
odds, err := prematchSvc.GetALLPrematchOdds(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all prematch odds", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All prematch odds retrieved successfully", odds, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRawOddsByMarketID
|
||||||
|
// @Summary Retrieve raw odds by Market ID
|
||||||
|
// @Description Retrieve raw odds records using a Market ID
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param upcoming_id path string true "Upcoming ID"
|
||||||
|
// @Param market_id path string true "Market ID"
|
||||||
|
// @Success 200 {array} domain.RawOddsByMarketID
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds/upcoming/{upcoming_id}/market/{market_id} [get]
|
||||||
|
func GetRawOddsByMarketID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if upcomingID == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawOdds, err := prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed to fetch raw odds", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Raw odds retrieved successfully", rawOdds, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Retrieve all upcoming events
|
||||||
|
// @Description Retrieve all upcoming events from the database
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "Page number"
|
||||||
|
// @Param page_size query int false "Page size"
|
||||||
|
// @Param league_id query string false "League ID Filter"
|
||||||
|
// @Param sport_id query string false "Sport ID Filter"
|
||||||
|
// @Success 200 {array} domain.UpcomingEvent
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/events [get]
|
||||||
|
func GetAllUpcomingEvents(logger *slog.Logger, eventSvc event.Service) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
page := c.QueryInt("page", 1)
|
||||||
|
pageSize := c.QueryInt("page_size", 10)
|
||||||
|
leagueIDQuery := c.Query("league_id")
|
||||||
|
sportIDQuery := c.Query("sport_id")
|
||||||
|
|
||||||
|
leagueID := domain.ValidString{
|
||||||
|
Value: leagueIDQuery,
|
||||||
|
Valid: leagueIDQuery != "",
|
||||||
|
}
|
||||||
|
sportID := domain.ValidString{
|
||||||
|
Value: sportIDQuery,
|
||||||
|
Valid: sportIDQuery != "",
|
||||||
|
}
|
||||||
|
|
||||||
|
events, total, err := eventSvc.GetPaginatedUpcomingEvents(c.Context(), int32(pageSize), int32(page)-1, leagueID, sportID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all upcoming events", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", events, nil, page, int(total))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Retrieve an upcoming by ID
|
||||||
|
// @Description Retrieve an upcoming event by ID
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "ID"
|
||||||
|
// @Success 200 {object} domain.UpcomingEvent
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/events/{id} [get]
|
||||||
|
func GetUpcomingEventByID(logger *slog.Logger, eventSvc event.Service) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
if id == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
event, err := eventSvc.GetUpcomingEventByID(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve upcoming event", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", event, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Retrieve prematch odds by upcoming ID (FI)
|
||||||
|
// @Description Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
|
||||||
|
// @Param limit query int false "Number of results to return (default: 10)"
|
||||||
|
// @Param offset query int false "Number of results to skip (default: 0)"
|
||||||
|
// @Success 200 {array} domain.Odd
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds/upcoming/{upcoming_id} [get]
|
||||||
|
func GetPrematchOddsByUpcomingID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
upcomingID := c.Params("upcoming_id")
|
||||||
|
if upcomingID == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing upcoming_id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
odds, err := prematchSvc.GetPrematchOddsByUpcomingID(c.Context(), upcomingID, int32(limit), int32(offset))
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve prematch odds", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,42 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CreateTicketOutcomeReq struct {
|
||||||
|
// TicketID int64 `json:"ticket_id" example:"1"`
|
||||||
|
EventID int64 `json:"event_id" example:"1"`
|
||||||
|
OddID int64 `json:"odd_id" example:"1"`
|
||||||
|
MarketID int64 `json:"market_id" example:"1"`
|
||||||
|
// HomeTeamName string `json:"home_team_name" example:"Manchester"`
|
||||||
|
// AwayTeamName string `json:"away_team_name" example:"Liverpool"`
|
||||||
|
// MarketName string `json:"market_name" example:"Fulltime Result"`
|
||||||
|
// Odd float32 `json:"odd" example:"1.5"`
|
||||||
|
// OddName string `json:"odd_name" example:"1"`
|
||||||
|
// Expires time.Time `json:"expires" example:"2025-04-08T12:00:00Z"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTicketReq struct {
|
||||||
|
Outcomes []CreateTicketOutcomeReq `json:"outcomes"`
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||||
|
}
|
||||||
|
type CreateTicketRes struct {
|
||||||
|
FastCode int64 `json:"fast_code" example:"1234"`
|
||||||
|
CreatedNumber int64 `json:"created_number" example:"3"`
|
||||||
|
}
|
||||||
|
type TicketRes struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
Outcomes []domain.TicketOutcome `json:"outcomes"`
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||||
|
}
|
||||||
|
|
||||||
// CreateTicket godoc
|
// CreateTicket godoc
|
||||||
// @Summary Create a temporary ticket
|
// @Summary Create a temporary ticket
|
||||||
// @Description Creates a temporary ticket
|
// @Description Creates a temporary ticket
|
||||||
|
|
@ -40,22 +70,106 @@ func (h *Handler) CreateTicket(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Validate Outcomes Here and make sure they didn't expire
|
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||||
|
// Validation for creating tickets
|
||||||
|
if len(req.Outcomes) > 30 {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||||
|
}
|
||||||
|
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
||||||
|
for _, outcome := range req.Outcomes {
|
||||||
|
eventIDStr := strconv.FormatInt(outcome.EventID, 10)
|
||||||
|
marketIDStr := strconv.FormatInt(outcome.MarketID, 10)
|
||||||
|
oddIDStr := strconv.FormatInt(outcome.OddID, 10)
|
||||||
|
event, err := eventSvc.GetUpcomingEventByID(c.Context(), eventIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid event id", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
ticket, err := h.ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
// Checking to make sure the event hasn't already started
|
||||||
Outcomes: req.Outcomes,
|
currentTime := time.Now()
|
||||||
Amount: domain.Currency(req.Amount),
|
if event.StartTime.Before(currentTime) {
|
||||||
TotalOdds: req.TotalOdds,
|
return response.WriteJSON(c, fiber.StatusBadRequest, "The event has already expired", nil, nil)
|
||||||
})
|
}
|
||||||
if err != nil {
|
|
||||||
h.logger.Error("Failed to create ticket", "error", err)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create ticket")
|
|
||||||
}
|
|
||||||
|
|
||||||
res := CreateTicketRes{
|
odds, err := oddSvc.GetRawOddsByMarketID(c.Context(), marketIDStr, eventIDStr)
|
||||||
FastCode: ticket.ID,
|
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid market id", err, nil)
|
||||||
|
}
|
||||||
|
type rawOddType struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Odds string
|
||||||
|
Header string
|
||||||
|
Handicap string
|
||||||
|
}
|
||||||
|
var selectedOdd rawOddType
|
||||||
|
var isOddFound bool = false
|
||||||
|
for _, raw := range odds.RawOdds {
|
||||||
|
var rawOdd rawOddType
|
||||||
|
rawBytes, err := json.Marshal(raw)
|
||||||
|
err = json.Unmarshal(rawBytes, &rawOdd)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to unmarshal raw odd:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rawOdd.ID == oddIDStr {
|
||||||
|
selectedOdd = rawOdd
|
||||||
|
isOddFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isOddFound {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid odd id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
|
||||||
|
|
||||||
|
outcomes = append(outcomes, domain.CreateTicketOutcome{
|
||||||
|
EventID: outcome.EventID,
|
||||||
|
OddID: outcome.OddID,
|
||||||
|
MarketID: outcome.MarketID,
|
||||||
|
HomeTeamName: event.HomeTeam,
|
||||||
|
AwayTeamName: event.AwayTeam,
|
||||||
|
MarketName: odds.MarketName,
|
||||||
|
Odd: float32(parsedOdd),
|
||||||
|
OddName: selectedOdd.Name,
|
||||||
|
OddHeader: selectedOdd.Header,
|
||||||
|
OddHandicap: selectedOdd.Handicap,
|
||||||
|
Expires: event.StartTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket, err := ticketSvc.CreateTicket(c.Context(), domain.CreateTicket{
|
||||||
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
|
TotalOdds: req.TotalOdds,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateTicketReq failed", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the ticket id now that it has fetched from the database
|
||||||
|
for index := range outcomes {
|
||||||
|
outcomes[index].TicketID = ticket.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := ticketSvc.CreateTicketOutcome(c.Context(), outcomes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateTicketReq failed to create outcomes", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res := CreateTicketRes{
|
||||||
|
FastCode: ticket.ID,
|
||||||
|
CreatedNumber: rows,
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Ticket Created", res, nil)
|
||||||
}
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Ticket created successfully", res, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTicketByID godoc
|
// GetTicketByID godoc
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type TransactionRes struct {
|
type TransactionRes struct {
|
||||||
ID int64 `json:"id" example:"1"`
|
ID int64 `json:"id" example:"1"`
|
||||||
Amount float32 `json:"amount" example:"100.0"`
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
BranchID int64 `json:"branch_id" example:"1"`
|
BranchID int64 `json:"branch_id" example:"1"`
|
||||||
CashierID int64 `json:"cashier_id" example:"1"`
|
CashierID int64 `json:"cashier_id" example:"1"`
|
||||||
BetID int64 `json:"bet_id" example:"1"`
|
BetID int64 `json:"bet_id" example:"1"`
|
||||||
|
Type int64 `json:"type" example:"1"`
|
||||||
PaymentOption domain.PaymentOption `json:"payment_option" example:"1"`
|
PaymentOption domain.PaymentOption `json:"payment_option" example:"1"`
|
||||||
FullName string `json:"full_name" example:"John Smith"`
|
FullName string `json:"full_name" example:"John Smith"`
|
||||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||||
|
|
@ -27,19 +27,18 @@ type TransactionRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTransactionReq struct {
|
type CreateTransactionReq struct {
|
||||||
Amount float32 `json:"amount" example:"100.0"`
|
CashoutID string `json:"cashout_id" example:"191212"`
|
||||||
BranchID int64 `json:"branch_id" example:"1"`
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
CashierID int64 `json:"cashier_id" example:"1"`
|
BetID int64 `json:"bet_id" example:"1"`
|
||||||
BetID int64 `json:"bet_id" example:"1"`
|
Type int64 `json:"type" example:"1"`
|
||||||
PaymentOption domain.PaymentOption `json:"payment_option" example:"1"`
|
PaymentOption domain.PaymentOption `json:"payment_option" example:"1"`
|
||||||
FullName string `json:"full_name" example:"John Smith"`
|
FullName string `json:"full_name" example:"John Smith"`
|
||||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||||
// Payment Details for bank
|
BankCode string `json:"bank_code"`
|
||||||
BankCode string `json:"bank_code"`
|
BeneficiaryName string `json:"beneficiary_name"`
|
||||||
BeneficiaryName string `json:"beneficiary_name"`
|
AccountName string `json:"account_name"`
|
||||||
AccountName string `json:"account_name"`
|
AccountNumber string `json:"account_number"`
|
||||||
AccountNumber string `json:"account_number"`
|
ReferenceNumber string `json:"reference_number"`
|
||||||
ReferenceNumber string `json:"reference_number"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertTransaction(transaction domain.Transaction) TransactionRes {
|
func convertTransaction(transaction domain.Transaction) TransactionRes {
|
||||||
|
|
@ -49,6 +48,7 @@ func convertTransaction(transaction domain.Transaction) TransactionRes {
|
||||||
BranchID: transaction.BranchID,
|
BranchID: transaction.BranchID,
|
||||||
CashierID: transaction.CashierID,
|
CashierID: transaction.CashierID,
|
||||||
BetID: transaction.BetID,
|
BetID: transaction.BetID,
|
||||||
|
Type: int64(transaction.Type),
|
||||||
PaymentOption: transaction.PaymentOption,
|
PaymentOption: transaction.PaymentOption,
|
||||||
FullName: transaction.FullName,
|
FullName: transaction.FullName,
|
||||||
PhoneNumber: transaction.PhoneNumber,
|
PhoneNumber: transaction.PhoneNumber,
|
||||||
|
|
@ -72,57 +72,75 @@ func convertTransaction(transaction domain.Transaction) TransactionRes {
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /transaction [post]
|
// @Router /transaction [post]
|
||||||
// Update transaction handler to include deposit bonus
|
|
||||||
func (h *Handler) CreateTransaction(c *fiber.Ctx) error {
|
func (h *Handler) CreateTransaction(c *fiber.Ctx) error {
|
||||||
type CreateTransactionReq struct {
|
userID := c.Locals("user_id").(int64)
|
||||||
Amount float32 `json:"amount" validate:"required" example:"100.0"`
|
user, err := userSvc.GetUserByID(c.Context(), userID)
|
||||||
BranchID int64 `json:"branch_id" example:"1"`
|
|
||||||
CashierID int64 `json:"cashier_id" example:"1"`
|
|
||||||
BetID int64 `json:"bet_id" example:"1"`
|
|
||||||
PaymentOption domain.PaymentOption `json:"payment_option" validate:"required" example:"1"`
|
|
||||||
FullName string `json:"full_name" example:"John Smith"`
|
|
||||||
PhoneNumber string `json:"phone_number" validate:"required" example:"0911111111"`
|
|
||||||
BankCode string `json:"bank_code"`
|
|
||||||
BeneficiaryName string `json:"beneficiary_name"`
|
|
||||||
AccountName string `json:"account_name"`
|
|
||||||
AccountNumber string `json:"account_number"`
|
|
||||||
ReferenceNumber string `json:"reference_number"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var req CreateTransactionReq
|
if user.Role == domain.RoleCustomer {
|
||||||
if err := c.BodyParser(&req); err != nil {
|
logger.Error("CreateTransactionReq failed")
|
||||||
h.logger.Error("CreateTransaction failed to parse request", "error", err)
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
"error": "unauthorized access",
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
// TODO: Add validation to make sure that the bet hasn't already been cashed out by someone else
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
var branchID int64
|
||||||
}
|
if user.Role == domain.RoleAdmin || user.Role == domain.RoleBranchManager || user.Role == domain.RoleSuperAdmin {
|
||||||
|
branch, err := branchSvc.GetBranchByID(c.Context(), 1)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateTransactionReq no branches")
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "This user type doesn't have branches", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
isDeposit := req.PaymentOption == domain.BANK
|
branchID = branch.ID
|
||||||
|
|
||||||
transaction, err := h.transactionSvc.CreateTransaction(c.Context(), domain.CreateTransaction{
|
} else {
|
||||||
Amount: domain.Currency(req.Amount),
|
branch, err := branchSvc.GetBranchByCashier(c.Context(), user.ID)
|
||||||
BranchID: req.BranchID,
|
if err != nil {
|
||||||
CashierID: req.CashierID,
|
logger.Error("CreateTransactionReq failed, branch id invalid")
|
||||||
BetID: req.BetID,
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID invalid", err, nil)
|
||||||
PaymentOption: req.PaymentOption,
|
}
|
||||||
FullName: req.FullName,
|
branchID = branch.ID
|
||||||
PhoneNumber: req.PhoneNumber,
|
}
|
||||||
BankCode: req.BankCode,
|
|
||||||
BeneficiaryName: req.BeneficiaryName,
|
|
||||||
AccountName: req.AccountName,
|
|
||||||
AccountNumber: req.AccountNumber,
|
|
||||||
ReferenceNumber: req.ReferenceNumber,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
h.logger.Error("CreateTransaction failed", "error", err)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create transaction")
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDeposit {
|
var req CreateTransactionReq
|
||||||
if err := h.referralSvc.ProcessDepositBonus(c.Context(), req.PhoneNumber, float64(req.Amount)); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.logger.Warn("Failed to process deposit bonus", "phone", req.PhoneNumber, "amount", req.Amount, "error", err)
|
h.logger.Error("CreateTransaction failed to parse request", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
logger.Error("CreateTransactionReq failed v", "error", valErrs)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction, err := transactionSvc.CreateTransaction(c.Context(), domain.CreateTransaction{
|
||||||
|
BranchID: branchID,
|
||||||
|
CashierID: userID,
|
||||||
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
|
BetID: req.BetID,
|
||||||
|
Type: domain.TransactionType(req.Type),
|
||||||
|
PaymentOption: domain.PaymentOption(req.PaymentOption),
|
||||||
|
FullName: req.FullName,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
BankCode: req.BankCode,
|
||||||
|
BeneficiaryName: req.BeneficiaryName,
|
||||||
|
AccountName: req.AccountName,
|
||||||
|
AccountNumber: req.AccountNumber,
|
||||||
|
ReferenceNumber: req.ReferenceNumber,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateTransactionReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = betSvc.UpdateCashOut(c.Context(), req.BetID, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("CreateTransactionReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,18 +159,47 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /transaction [get]
|
// @Router /transaction [get]
|
||||||
func (h *Handler) GetAllTransactions(c *fiber.Ctx) error {
|
func (h *Handler) GetAllTransactions(c *fiber.Ctx) error {
|
||||||
transactions, err := h.transactionSvc.GetAllTransactions(c.Context())
|
// Get user_id from middleware
|
||||||
if err != nil {
|
userID := c.Locals("user_id").(int64)
|
||||||
h.logger.Error("Failed to get transactions", "error", err)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transactions")
|
// Fetch user details
|
||||||
}
|
user, err := userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to fetch user details", "user_id", userID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve user details", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var transactions []domain.Transaction
|
||||||
|
|
||||||
|
// Check user role and fetch transactions accordingly
|
||||||
|
switch user.Role {
|
||||||
|
case domain.RoleSuperAdmin:
|
||||||
|
// Admin can fetch all transactions
|
||||||
|
transactions, err = transactionSvc.GetAllTransactions(c.Context())
|
||||||
|
case domain.RoleAdmin:
|
||||||
|
// Admin can fetch all transactions
|
||||||
|
transactions, err = transactionSvc.GetAllTransactions(c.Context())
|
||||||
|
case domain.RoleBranchManager, domain.RoleCashier:
|
||||||
|
// Branch Manager or Cashier can fetch transactions for their branch
|
||||||
|
// transactions, err = transactionSvc.GetTransactionByBranch(c.Context(), user.BranchID)
|
||||||
|
transactions, err = transactionSvc.GetAllTransactions(c.Context())
|
||||||
|
default:
|
||||||
|
// Unauthorized role
|
||||||
|
return response.WriteJSON(c, fiber.StatusForbidden, "Unauthorized", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get transactions", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transactions", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
res := make([]TransactionRes, len(transactions))
|
res := make([]TransactionRes, len(transactions))
|
||||||
for i, transaction := range transactions {
|
for i, transaction := range transactions {
|
||||||
res[i] = convertTransaction(transaction)
|
res[i] = convertTransaction(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "All transactions retrieved", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Transactions retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionByID godoc
|
// GetTransactionByID godoc
|
||||||
|
|
@ -208,11 +255,11 @@ func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
var req UpdateTransactionVerifiedReq
|
var req UpdateTransactionVerifiedReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
|
logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
|
|
||||||
245
internal/web_server/handlers/transfer_handler.go
Normal file
245
internal/web_server/handlers/transfer_handler.go
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransferWalletRes struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
Verified bool `json:"verified" example:"true"`
|
||||||
|
Type string `json:"type" example:"transfer"`
|
||||||
|
PaymentMethod string `json:"payment_method" example:"bank"`
|
||||||
|
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
|
||||||
|
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
||||||
|
CashierID *int64 `json:"cashier_id" example:"789"`
|
||||||
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:30:00Z"`
|
||||||
|
}
|
||||||
|
type RefillRes struct {
|
||||||
|
ID int64 `json:"id" example:"1"`
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
Verified bool `json:"verified" example:"true"`
|
||||||
|
Type string `json:"type" example:"transfer"`
|
||||||
|
PaymentMethod string `json:"payment_method" example:"bank"`
|
||||||
|
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
|
||||||
|
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
||||||
|
CashierID *int64 `json:"cashier_id" example:"789"`
|
||||||
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:30:00Z"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTransfer(transfer domain.Transfer) TransferWalletRes {
|
||||||
|
var senderWalletID *int64
|
||||||
|
if transfer.SenderWalletID.Valid {
|
||||||
|
senderWalletID = &transfer.SenderWalletID.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
var cashierID *int64
|
||||||
|
if transfer.CashierID.Valid {
|
||||||
|
cashierID = &transfer.CashierID.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return TransferWalletRes{
|
||||||
|
ID: transfer.ID,
|
||||||
|
Amount: transfer.Amount.Float64(),
|
||||||
|
Verified: transfer.Verified,
|
||||||
|
Type: string(transfer.Type),
|
||||||
|
PaymentMethod: string(transfer.PaymentMethod),
|
||||||
|
ReceiverWalletID: transfer.ReceiverWalletID,
|
||||||
|
SenderWalletID: senderWalletID,
|
||||||
|
CashierID: cashierID,
|
||||||
|
CreatedAt: transfer.CreatedAt,
|
||||||
|
UpdatedAt: transfer.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTransferReq struct {
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
PaymentMethod string `json:"payment_method" example:"cash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateRefillReq struct {
|
||||||
|
Amount float32 `json:"amount" example:"100.0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransfersByWallet godoc
|
||||||
|
// @Summary Get transfer by wallet
|
||||||
|
// @Description Get transfer by wallet
|
||||||
|
// @Tags transfer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param transferToWallet body CreateTransferReq true "Create Transfer"
|
||||||
|
// @Success 200 {object} TransferWalletRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /transfer/wallet/{id} [get]
|
||||||
|
func GetTransfersByWallet(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
walletID := c.Params("id")
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(walletID, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid wallet ID", "walletID", walletID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
transfers, err := walletSvc.GetTransfersByWallet(c.Context(), int64(id))
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get transfers by wallet", "walletID", walletID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transfers", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var transferResponses []TransferWalletRes
|
||||||
|
for _, transfer := range transfers {
|
||||||
|
transferResponses = append(transferResponses, convertTransfer(transfer))
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Transfers retrieved successfully", transferResponses, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransferToWallet godoc
|
||||||
|
// @Summary Create a transfer to wallet
|
||||||
|
// @Description Create a transfer to wallet
|
||||||
|
// @Tags transfer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param transferToWallet body CreateTransferReq true "Create Transfer"
|
||||||
|
// @Success 200 {object} TransferWalletRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /transfer/wallet/:id [post]
|
||||||
|
func TransferToWallet(logger *slog.Logger, walletSvc *wallet.Service, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
receiverIDString := c.Params("id")
|
||||||
|
|
||||||
|
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
||||||
|
}
|
||||||
|
// Get sender ID from the cashier
|
||||||
|
userID := c.Locals("user_id").(int64)
|
||||||
|
role := string(c.Locals("role").(domain.Role))
|
||||||
|
|
||||||
|
var senderID int64
|
||||||
|
|
||||||
|
if role == string(domain.RoleCustomer) {
|
||||||
|
logger.Error("Unauthorized access", "userID", userID, "role", role)
|
||||||
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||||
|
} else if role == string(domain.RoleBranchManager) || role == string(domain.RoleAdmin) || role == string(domain.RoleSuperAdmin) {
|
||||||
|
// TODO Add a way for admins to reference branch wallet
|
||||||
|
senderID = 0
|
||||||
|
logger.Error("Will", "userID", userID, "role", role)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Unauthorized access", nil, nil)
|
||||||
|
} else {
|
||||||
|
cashierBranch, err := branchSvc.GetBranchByCashier(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to get branch", "user ID", userID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier branch", err, nil)
|
||||||
|
}
|
||||||
|
senderID = cashierBranch.WalletID
|
||||||
|
}
|
||||||
|
|
||||||
|
var req CreateTransferReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateTransferReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer, err := walletSvc.TransferToWallet(c.Context(), senderID, receiverID, domain.ToCurrency(req.Amount), domain.PaymentMethod(req.PaymentMethod), domain.ValidInt64{Value: userID, Valid: true})
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Transfer Failed", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertTransfer(transfer)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefillWallet godoc
|
||||||
|
// @Summary Refill wallet
|
||||||
|
// @Description Super Admin route to refill a wallet
|
||||||
|
// @Tags transfer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param refillWallet body CreateTransferReq true "Create Transfer"
|
||||||
|
// @Success 200 {object} TransferWalletRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /transfer/refill/:id [post]
|
||||||
|
func RefillWallet(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
receiverIDString := c.Params("id")
|
||||||
|
|
||||||
|
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
||||||
|
}
|
||||||
|
// Get sender ID from the cashier
|
||||||
|
userID := c.Locals("user_id").(int64)
|
||||||
|
role := string(c.Locals("role").(domain.Role))
|
||||||
|
|
||||||
|
if role != string(domain.RoleSuperAdmin) {
|
||||||
|
logger.Error("Unauthorized access", "userID", userID, "role", role)
|
||||||
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var req CreateRefillReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("CreateRefillReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer, err := walletSvc.RefillWallet(c.Context(), domain.CreateTransfer{
|
||||||
|
Amount: domain.ToCurrency(req.Amount),
|
||||||
|
PaymentMethod: domain.TRANSFER_BANK,
|
||||||
|
ReceiverWalletID: receiverID,
|
||||||
|
CashierID: domain.ValidInt64{
|
||||||
|
Value: userID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
Type: domain.TransferType("deposit"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := convertTransfer(transfer)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -356,3 +356,61 @@ func getMedium(email, phoneNumber string) (domain.OtpMedium, error) {
|
||||||
}
|
}
|
||||||
return "", errors.New("both email and phone number are empty")
|
return "", errors.New("both email and phone number are empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SearchUserByNameOrPhoneReq struct {
|
||||||
|
SearchString string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchUserByNameOrPhone godoc
|
||||||
|
// @Summary Search for user using name or phone
|
||||||
|
// @Description Search for user using name or phone
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param searchUserByNameOrPhone body SearchUserByNameOrPhoneReq true "Search for using his name or phone"
|
||||||
|
// @Success 200 {object} UserProfileRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /user/search [post]
|
||||||
|
func SearchUserByNameOrPhone(logger *slog.Logger, userSvc *user.Service,
|
||||||
|
validator *customvalidator.CustomValidator) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var req SearchUserByNameOrPhoneReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
logger.Error("SearchUserByNameOrPhone failed", "error", err)
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Invalid request",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
valErrs, ok := validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
users, err := userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("SearchUserByNameOrPhone failed", "error", err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var res []UserProfileRes = make([]UserProfileRes, 0, len(users))
|
||||||
|
for _, user := range users {
|
||||||
|
res = append(res, UserProfileRes{
|
||||||
|
ID: user.ID,
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: user.Email,
|
||||||
|
PhoneNumber: user.PhoneNumber,
|
||||||
|
Role: user.Role,
|
||||||
|
EmailVerified: user.EmailVerified,
|
||||||
|
PhoneVerified: user.PhoneVerified,
|
||||||
|
CreatedAt: user.CreatedAt,
|
||||||
|
UpdatedAt: user.UpdatedAt,
|
||||||
|
SuspendedAt: user.SuspendedAt,
|
||||||
|
Suspended: user.Suspended,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Search Successful", res, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user