game list
This commit is contained in:
commit
b1a97bc31b
|
|
@ -121,7 +121,7 @@ func main() {
|
||||||
companySvc := company.NewService(store)
|
companySvc := company.NewService(store)
|
||||||
leagueSvc := league.New(store)
|
leagueSvc := league.New(store)
|
||||||
betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, logger, domain.MongoDBLogger)
|
betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, logger, domain.MongoDBLogger)
|
||||||
resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc)
|
resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc)
|
||||||
referalRepo := repository.NewReferralRepository(store)
|
referalRepo := repository.NewReferralRepository(store)
|
||||||
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
vitualGameRepo := repository.NewVirtualGameRepository(store)
|
||||||
recommendationRepo := repository.NewRecommendationRepository(store)
|
recommendationRepo := repository.NewRecommendationRepository(store)
|
||||||
|
|
|
||||||
17
db.sql
Normal file
17
db.sql
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
psql (16.8)
|
||||||
|
Type "help" for help.
|
||||||
|
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
gh=#
|
||||||
|
|
@ -250,10 +250,12 @@ CREATE TABLE companies (
|
||||||
CREATE TABLE leagues (
|
CREATE TABLE leagues (
|
||||||
id BIGINT PRIMARY KEY,
|
id BIGINT PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
img TEXT,
|
||||||
country_code TEXT,
|
country_code TEXT,
|
||||||
bet365_id INT,
|
bet365_id INT,
|
||||||
sport_id INT NOT NULL,
|
sport_id INT NOT NULL,
|
||||||
is_active BOOLEAN DEFAULT true
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
is_featured BOOLEAN DEFAULT false
|
||||||
);
|
);
|
||||||
CREATE TABLE teams (
|
CREATE TABLE teams (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
|
|
@ -275,7 +277,6 @@ FROM companies
|
||||||
JOIN wallets ON wallets.id = companies.wallet_id
|
JOIN wallets ON wallets.id = companies.wallet_id
|
||||||
JOIN users ON users.id = companies.admin_id;
|
JOIN users ON users.id = companies.admin_id;
|
||||||
;
|
;
|
||||||
|
|
||||||
CREATE VIEW branch_details AS
|
CREATE VIEW branch_details AS
|
||||||
SELECT branches.*,
|
SELECT branches.*,
|
||||||
CONCAT(users.first_name, ' ', users.last_name) AS manager_name,
|
CONCAT(users.first_name, ' ', users.last_name) AS manager_name,
|
||||||
|
|
@ -302,41 +303,40 @@ FROM tickets
|
||||||
LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id
|
LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id
|
||||||
GROUP BY tickets.id;
|
GROUP BY tickets.id;
|
||||||
-- Foreign Keys
|
-- Foreign Keys
|
||||||
|
|
||||||
ALTER TABLE users
|
ALTER TABLE users
|
||||||
ADD CONSTRAINT unique_email UNIQUE (email),
|
ADD CONSTRAINT unique_email UNIQUE (email),
|
||||||
ADD CONSTRAINT unique_phone_number UNIQUE (phone_number);
|
ADD CONSTRAINT unique_phone_number UNIQUE (phone_number);
|
||||||
ALTER TABLE refresh_tokens
|
ALTER TABLE refresh_tokens
|
||||||
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id);
|
ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id);
|
||||||
ALTER TABLE bets
|
ALTER TABLE bets
|
||||||
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id),
|
ADD CONSTRAINT fk_bets_users FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
ADD CONSTRAINT fk_bets_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
|
ADD CONSTRAINT fk_bets_branches FOREIGN KEY (branch_id) REFERENCES branches(id);
|
||||||
ALTER TABLE wallets
|
ALTER TABLE wallets
|
||||||
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id),
|
ADD CONSTRAINT fk_wallets_users FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
ADD COLUMN currency VARCHAR(3) NOT NULL DEFAULT 'ETB';
|
ADD COLUMN currency VARCHAR(3) NOT NULL DEFAULT 'ETB';
|
||||||
ALTER TABLE customer_wallets
|
ALTER TABLE customer_wallets
|
||||||
ADD CONSTRAINT fk_customer_wallets_customers FOREIGN KEY (customer_id) REFERENCES users(id),
|
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_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);
|
ADD CONSTRAINT fk_customer_wallets_static_wallet FOREIGN KEY (static_wallet_id) REFERENCES wallets(id);
|
||||||
ALTER TABLE wallet_transfer
|
ALTER TABLE wallet_transfer
|
||||||
ADD CONSTRAINT fk_wallet_transfer_receiver_wallet FOREIGN KEY (receiver_wallet_id) REFERENCES wallets(id),
|
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_sender_wallet FOREIGN KEY (sender_wallet_id) REFERENCES wallets(id),
|
||||||
ADD CONSTRAINT fk_wallet_transfer_cashier FOREIGN KEY (cashier_id) REFERENCES users(id);
|
ADD CONSTRAINT fk_wallet_transfer_cashier FOREIGN KEY (cashier_id) REFERENCES users(id);
|
||||||
ALTER TABLE transactions
|
ALTER TABLE transactions
|
||||||
ADD CONSTRAINT fk_transactions_branches FOREIGN KEY (branch_id) REFERENCES branches(id),
|
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_cashiers FOREIGN KEY (cashier_id) REFERENCES users(id),
|
||||||
ADD CONSTRAINT fk_transactions_bets FOREIGN KEY (bet_id) REFERENCES bets(id);
|
ADD CONSTRAINT fk_transactions_bets FOREIGN KEY (bet_id) REFERENCES bets(id);
|
||||||
ALTER TABLE branches
|
ALTER TABLE branches
|
||||||
ADD CONSTRAINT fk_branches_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id),
|
ADD CONSTRAINT fk_branches_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id),
|
||||||
ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id);
|
ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id);
|
||||||
ALTER TABLE branch_operations
|
ALTER TABLE branch_operations
|
||||||
ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id) ON DELETE CASCADE,
|
ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id) ON DELETE CASCADE,
|
||||||
ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
||||||
ALTER TABLE branch_cashiers
|
ALTER TABLE branch_cashiers
|
||||||
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
||||||
ALTER TABLE companies
|
ALTER TABLE companies
|
||||||
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
|
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
|
||||||
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE;
|
||||||
----------------------------------------------seed data-------------------------------------------------------------
|
----------------------------------------------seed data-------------------------------------------------------------
|
||||||
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
|
-------------------------------------- DO NOT USE IN PRODUCTION-------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ CREATE TABLE user_game_interactions (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
user_id BIGINT NOT NULL REFERENCES users(id),
|
user_id BIGINT NOT NULL REFERENCES users(id),
|
||||||
game_id BIGINT NOT NULL REFERENCES virtual_games(id),
|
game_id BIGINT NOT NULL REFERENCES virtual_games(id),
|
||||||
interaction_type VARCHAR(50) NOT NULL, -- 'view', 'play', 'bet', 'favorite'
|
interaction_type VARCHAR(50) NOT NULL,
|
||||||
amount DECIMAL(15,2),
|
-- 'view', 'play', 'bet', 'favorite'
|
||||||
|
amount DECIMAL(15, 2),
|
||||||
duration_seconds INTEGER,
|
duration_seconds INTEGER,
|
||||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_user_game_interactions_user ON user_game_interactions(user_id);
|
CREATE INDEX idx_user_game_interactions_user ON user_game_interactions(user_id);
|
||||||
CREATE INDEX idx_user_game_interactions_game ON user_game_interactions(game_id);
|
CREATE INDEX idx_user_game_interactions_game ON user_game_interactions(game_id);
|
||||||
|
|
@ -49,16 +49,20 @@ VALUES (
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM bet_with_outcomes
|
FROM bet_with_outcomes
|
||||||
wHERE (
|
wHERE (
|
||||||
branch_id = $1
|
branch_id = sqlc.narg('branch_id')
|
||||||
OR $1 IS NULL
|
OR sqlc.narg('branch_id') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
company_id = $2
|
company_id = sqlc.narg('company_id')
|
||||||
OR $2 IS NULL
|
OR sqlc.narg('company_id') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
user_id = $3
|
user_id = sqlc.narg('user_id')
|
||||||
OR $3 IS NULL
|
OR sqlc.narg('user_id') IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
is_shop_bet = sqlc.narg('is_shop_bet')
|
||||||
|
OR sqlc.narg('is_shop_bet') IS NULL
|
||||||
);
|
);
|
||||||
-- name: GetBetByID :one
|
-- name: GetBetByID :one
|
||||||
SELECT *
|
SELECT *
|
||||||
|
|
@ -99,6 +103,11 @@ UPDATE bet_outcomes
|
||||||
SET status = $1
|
SET status = $1
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
-- name: UpdateBetOutcomeStatusForEvent :many
|
||||||
|
UPDATE bet_outcomes
|
||||||
|
SEt status = $1
|
||||||
|
WHERE event_id = $2
|
||||||
|
RETURNING *;
|
||||||
-- name: UpdateStatus :exec
|
-- name: UpdateStatus :exec
|
||||||
UPDATE bets
|
UPDATE bets
|
||||||
SET status = $1,
|
SET status = $1,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,15 @@ VALUES ($1, $2)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
-- name: GetAllBranches :many
|
-- name: GetAllBranches :many
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM branch_details;
|
FROM branch_details
|
||||||
|
WHERE (
|
||||||
|
company_id = sqlc.narg('company_id')
|
||||||
|
OR sqlc.narg('company_id') IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
is_active = sqlc.narg('is_active')
|
||||||
|
OR sqlc.narg('is_active') IS NULL
|
||||||
|
);
|
||||||
-- name: GetBranchByID :one
|
-- name: GetBranchByID :one
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,16 @@ INSERT INTO leagues (
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
sport_id,
|
sport_id,
|
||||||
is_active
|
is_active,
|
||||||
|
is_featured
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO
|
VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (id) DO
|
||||||
UPDATE
|
UPDATE
|
||||||
SET name = EXCLUDED.name,
|
SET name = EXCLUDED.name,
|
||||||
country_code = EXCLUDED.country_code,
|
country_code = EXCLUDED.country_code,
|
||||||
bet365_id = EXCLUDED.bet365_id,
|
bet365_id = EXCLUDED.bet365_id,
|
||||||
is_active = EXCLUDED.is_active,
|
is_active = EXCLUDED.is_active,
|
||||||
|
is_featured = EXCLUDED.is_featured,
|
||||||
sport_id = EXCLUDED.sport_id;
|
sport_id = EXCLUDED.sport_id;
|
||||||
-- name: GetAllLeagues :many
|
-- name: GetAllLeagues :many
|
||||||
SELECT id,
|
SELECT id,
|
||||||
|
|
@ -20,6 +22,7 @@ SELECT id,
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
is_active,
|
is_active,
|
||||||
|
is_featured,
|
||||||
sport_id
|
sport_id
|
||||||
FROM leagues
|
FROM leagues
|
||||||
WHERE (
|
WHERE (
|
||||||
|
|
@ -34,7 +37,21 @@ WHERE (
|
||||||
is_active = sqlc.narg('is_active')
|
is_active = sqlc.narg('is_active')
|
||||||
OR sqlc.narg('is_active') IS NULL
|
OR sqlc.narg('is_active') IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
is_featured = sqlc.narg('is_featured')
|
||||||
|
OR sqlc.narg('is_featured') IS NULL
|
||||||
|
)
|
||||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||||
|
-- name: GetFeaturedLeagues :many
|
||||||
|
SELECT id,
|
||||||
|
name,
|
||||||
|
country_code,
|
||||||
|
bet365_id,
|
||||||
|
is_active,
|
||||||
|
is_featured,
|
||||||
|
sport_id
|
||||||
|
FROM leagues
|
||||||
|
WHERE is_featured = true;
|
||||||
-- name: CheckLeagueSupport :one
|
-- name: CheckLeagueSupport :one
|
||||||
SELECT EXISTS(
|
SELECT EXISTS(
|
||||||
SELECT 1
|
SELECT 1
|
||||||
|
|
@ -48,6 +65,7 @@ SET name = COALESCE(sqlc.narg('name'), name),
|
||||||
country_code = COALESCE(sqlc.narg('country_code'), country_code),
|
country_code = COALESCE(sqlc.narg('country_code'), country_code),
|
||||||
bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id),
|
bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id),
|
||||||
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
||||||
|
is_featured = COALESCE(sqlc.narg('is_featured'), is_featured),
|
||||||
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
|
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
-- name: UpdateLeagueByBet365ID :exec
|
-- name: UpdateLeagueByBet365ID :exec
|
||||||
|
|
@ -56,6 +74,7 @@ SET name = COALESCE(sqlc.narg('name'), name),
|
||||||
id = COALESCE(sqlc.narg('id'), id),
|
id = COALESCE(sqlc.narg('id'), id),
|
||||||
country_code = COALESCE(sqlc.narg('country_code'), country_code),
|
country_code = COALESCE(sqlc.narg('country_code'), country_code),
|
||||||
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
is_active = COALESCE(sqlc.narg('is_active'), is_active),
|
||||||
|
is_featured = COALESCE(sqlc.narg('is_featured'), is_featured),
|
||||||
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
|
sport_id = COALESCE(sqlc.narg('sport_id'), sport_id)
|
||||||
WHERE bet365_id = $1;
|
WHERE bet365_id = $1;
|
||||||
-- name: SetLeagueActive :exec
|
-- name: SetLeagueActive :exec
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: auth.sql
|
// source: auth.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: bet.sql
|
// source: bet.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -129,16 +129,26 @@ wHERE (
|
||||||
user_id = $3
|
user_id = $3
|
||||||
OR $3 IS NULL
|
OR $3 IS NULL
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
is_shop_bet = $4
|
||||||
|
OR $4 IS NULL
|
||||||
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetAllBetsParams struct {
|
type GetAllBetsParams struct {
|
||||||
BranchID pgtype.Int8 `json:"branch_id"`
|
BranchID pgtype.Int8 `json:"branch_id"`
|
||||||
CompanyID pgtype.Int8 `json:"company_id"`
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
UserID pgtype.Int8 `json:"user_id"`
|
UserID pgtype.Int8 `json:"user_id"`
|
||||||
|
IsShopBet pgtype.Bool `json:"is_shop_bet"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWithOutcome, error) {
|
func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWithOutcome, error) {
|
||||||
rows, err := q.db.Query(ctx, GetAllBets, arg.BranchID, arg.CompanyID, arg.UserID)
|
rows, err := q.db.Query(ctx, GetAllBets,
|
||||||
|
arg.BranchID,
|
||||||
|
arg.CompanyID,
|
||||||
|
arg.UserID,
|
||||||
|
arg.IsShopBet,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -458,6 +468,54 @@ func (q *Queries) UpdateBetOutcomeStatus(ctx context.Context, arg UpdateBetOutco
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateBetOutcomeStatusForEvent = `-- name: UpdateBetOutcomeStatusForEvent :many
|
||||||
|
UPDATE bet_outcomes
|
||||||
|
SEt status = $1
|
||||||
|
WHERE event_id = $2
|
||||||
|
RETURNING id, bet_id, sport_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateBetOutcomeStatusForEventParams struct {
|
||||||
|
Status int32 `json:"status"`
|
||||||
|
EventID int64 `json:"event_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateBetOutcomeStatusForEvent(ctx context.Context, arg UpdateBetOutcomeStatusForEventParams) ([]BetOutcome, error) {
|
||||||
|
rows, err := q.db.Query(ctx, UpdateBetOutcomeStatusForEvent, arg.Status, arg.EventID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []BetOutcome
|
||||||
|
for rows.Next() {
|
||||||
|
var i BetOutcome
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.BetID,
|
||||||
|
&i.SportID,
|
||||||
|
&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 UpdateCashOut = `-- name: UpdateCashOut :exec
|
const UpdateCashOut = `-- name: UpdateCashOut :exec
|
||||||
UPDATE bets
|
UPDATE bets
|
||||||
SET cashed_out = $2,
|
SET cashed_out = $2,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: branch.sql
|
// source: branch.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -157,10 +157,23 @@ func (q *Queries) DeleteBranchOperation(ctx context.Context, arg DeleteBranchOpe
|
||||||
const GetAllBranches = `-- name: GetAllBranches :many
|
const GetAllBranches = `-- name: GetAllBranches :many
|
||||||
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
|
||||||
FROM branch_details
|
FROM branch_details
|
||||||
|
WHERE (
|
||||||
|
company_id = $1
|
||||||
|
OR $1 IS NULL
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
is_active = $2
|
||||||
|
OR $2 IS NULL
|
||||||
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllBranches(ctx context.Context) ([]BranchDetail, error) {
|
type GetAllBranchesParams struct {
|
||||||
rows, err := q.db.Query(ctx, GetAllBranches)
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAllBranches(ctx context.Context, arg GetAllBranchesParams) ([]BranchDetail, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllBranches, arg.CompanyID, arg.IsActive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: cashier.sql
|
// source: cashier.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: company.sql
|
// source: company.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: copyfrom.go
|
// source: copyfrom.go
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: events.sql
|
// source: events.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: leagues.sql
|
// source: leagues.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
@ -33,6 +33,7 @@ SELECT id,
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
is_active,
|
is_active,
|
||||||
|
is_featured,
|
||||||
sport_id
|
sport_id
|
||||||
FROM leagues
|
FROM leagues
|
||||||
WHERE (
|
WHERE (
|
||||||
|
|
@ -47,13 +48,18 @@ WHERE (
|
||||||
is_active = $3
|
is_active = $3
|
||||||
OR $3 IS NULL
|
OR $3 IS NULL
|
||||||
)
|
)
|
||||||
LIMIT $5 OFFSET $4
|
AND (
|
||||||
|
is_featured = $4
|
||||||
|
OR $4 IS NULL
|
||||||
|
)
|
||||||
|
LIMIT $6 OFFSET $5
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetAllLeaguesParams struct {
|
type GetAllLeaguesParams struct {
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
SportID pgtype.Int4 `json:"sport_id"`
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
Offset pgtype.Int4 `json:"offset"`
|
Offset pgtype.Int4 `json:"offset"`
|
||||||
Limit pgtype.Int4 `json:"limit"`
|
Limit pgtype.Int4 `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +70,7 @@ type GetAllLeaguesRow struct {
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
SportID int32 `json:"sport_id"`
|
SportID int32 `json:"sport_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,6 +79,7 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
|
||||||
arg.CountryCode,
|
arg.CountryCode,
|
||||||
arg.SportID,
|
arg.SportID,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.IsFeatured,
|
||||||
arg.Offset,
|
arg.Offset,
|
||||||
arg.Limit,
|
arg.Limit,
|
||||||
)
|
)
|
||||||
|
|
@ -88,6 +96,57 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
|
||||||
&i.CountryCode,
|
&i.CountryCode,
|
||||||
&i.Bet365ID,
|
&i.Bet365ID,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
|
&i.IsFeatured,
|
||||||
|
&i.SportID,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetFeaturedLeagues = `-- name: GetFeaturedLeagues :many
|
||||||
|
SELECT id,
|
||||||
|
name,
|
||||||
|
country_code,
|
||||||
|
bet365_id,
|
||||||
|
is_active,
|
||||||
|
is_featured,
|
||||||
|
sport_id
|
||||||
|
FROM leagues
|
||||||
|
WHERE is_featured = true
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetFeaturedLeaguesRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
|
SportID int32 `json:"sport_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetFeaturedLeagues(ctx context.Context) ([]GetFeaturedLeaguesRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetFeaturedLeagues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetFeaturedLeaguesRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetFeaturedLeaguesRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.CountryCode,
|
||||||
|
&i.Bet365ID,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.IsFeatured,
|
||||||
&i.SportID,
|
&i.SportID,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -107,14 +166,16 @@ INSERT INTO leagues (
|
||||||
country_code,
|
country_code,
|
||||||
bet365_id,
|
bet365_id,
|
||||||
sport_id,
|
sport_id,
|
||||||
is_active
|
is_active,
|
||||||
|
is_featured
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO
|
VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (id) DO
|
||||||
UPDATE
|
UPDATE
|
||||||
SET name = EXCLUDED.name,
|
SET name = EXCLUDED.name,
|
||||||
country_code = EXCLUDED.country_code,
|
country_code = EXCLUDED.country_code,
|
||||||
bet365_id = EXCLUDED.bet365_id,
|
bet365_id = EXCLUDED.bet365_id,
|
||||||
is_active = EXCLUDED.is_active,
|
is_active = EXCLUDED.is_active,
|
||||||
|
is_featured = EXCLUDED.is_featured,
|
||||||
sport_id = EXCLUDED.sport_id
|
sport_id = EXCLUDED.sport_id
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -125,6 +186,7 @@ type InsertLeagueParams struct {
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
SportID int32 `json:"sport_id"`
|
SportID int32 `json:"sport_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) error {
|
func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) error {
|
||||||
|
|
@ -135,6 +197,7 @@ func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) erro
|
||||||
arg.Bet365ID,
|
arg.Bet365ID,
|
||||||
arg.SportID,
|
arg.SportID,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.IsFeatured,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -161,7 +224,8 @@ SET name = COALESCE($2, name),
|
||||||
country_code = COALESCE($3, country_code),
|
country_code = COALESCE($3, country_code),
|
||||||
bet365_id = COALESCE($4, bet365_id),
|
bet365_id = COALESCE($4, bet365_id),
|
||||||
is_active = COALESCE($5, is_active),
|
is_active = COALESCE($5, is_active),
|
||||||
sport_id = COALESCE($6, sport_id)
|
is_featured = COALESCE($6, is_featured),
|
||||||
|
sport_id = COALESCE($7, sport_id)
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -171,6 +235,7 @@ type UpdateLeagueParams struct {
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
SportID pgtype.Int4 `json:"sport_id"`
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,6 +246,7 @@ func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) erro
|
||||||
arg.CountryCode,
|
arg.CountryCode,
|
||||||
arg.Bet365ID,
|
arg.Bet365ID,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.IsFeatured,
|
||||||
arg.SportID,
|
arg.SportID,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
|
|
@ -192,7 +258,8 @@ SET name = COALESCE($2, name),
|
||||||
id = COALESCE($3, id),
|
id = COALESCE($3, id),
|
||||||
country_code = COALESCE($4, country_code),
|
country_code = COALESCE($4, country_code),
|
||||||
is_active = COALESCE($5, is_active),
|
is_active = COALESCE($5, is_active),
|
||||||
sport_id = COALESCE($6, sport_id)
|
is_featured = COALESCE($6, is_featured),
|
||||||
|
sport_id = COALESCE($7, sport_id)
|
||||||
WHERE bet365_id = $1
|
WHERE bet365_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -202,6 +269,7 @@ type UpdateLeagueByBet365IDParams struct {
|
||||||
ID pgtype.Int8 `json:"id"`
|
ID pgtype.Int8 `json:"id"`
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
SportID pgtype.Int4 `json:"sport_id"`
|
SportID pgtype.Int4 `json:"sport_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,6 +280,7 @@ func (q *Queries) UpdateLeagueByBet365ID(ctx context.Context, arg UpdateLeagueBy
|
||||||
arg.ID,
|
arg.ID,
|
||||||
arg.CountryCode,
|
arg.CountryCode,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.IsFeatured,
|
||||||
arg.SportID,
|
arg.SportID,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
||||||
|
|
@ -218,10 +218,12 @@ type ExchangeRate struct {
|
||||||
type League struct {
|
type League struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Img pgtype.Text `json:"img"`
|
||||||
CountryCode pgtype.Text `json:"country_code"`
|
CountryCode pgtype.Text `json:"country_code"`
|
||||||
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
Bet365ID pgtype.Int4 `json:"bet365_id"`
|
||||||
SportID int32 `json:"sport_id"`
|
SportID int32 `json:"sport_id"`
|
||||||
IsActive pgtype.Bool `json:"is_active"`
|
IsActive pgtype.Bool `json:"is_active"`
|
||||||
|
IsFeatured pgtype.Bool `json:"is_featured"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: monitor.sql
|
// source: monitor.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: notification.sql
|
// source: notification.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: odds.sql
|
// source: odds.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: otp.sql
|
// source: otp.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: referal.sql
|
// source: referal.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: result.sql
|
// source: result.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: ticket.sql
|
// source: ticket.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: transactions.sql
|
// source: transactions.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: transfer.sql
|
// source: transfer.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: user.sql
|
// source: user.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: virtual_games.sql
|
// source: virtual_games.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.29.0
|
// sqlc v1.28.0
|
||||||
// source: wallet.sql
|
// source: wallet.sql
|
||||||
|
|
||||||
package dbgen
|
package dbgen
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ type BetFilter struct {
|
||||||
BranchID ValidInt64 // Can Be Nullable
|
BranchID ValidInt64 // Can Be Nullable
|
||||||
CompanyID ValidInt64 // Can Be Nullable
|
CompanyID ValidInt64 // Can Be Nullable
|
||||||
UserID ValidInt64 // Can Be Nullable
|
UserID ValidInt64 // Can Be Nullable
|
||||||
|
IsShopBet ValidBool
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetBet struct {
|
type GetBet struct {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@ type Branch struct {
|
||||||
IsSelfOwned bool
|
IsSelfOwned bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BranchFilter struct {
|
||||||
|
CompanyID ValidInt64
|
||||||
|
IsSuspended ValidBool
|
||||||
|
}
|
||||||
|
|
||||||
type BranchDetail struct {
|
type BranchDetail struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string
|
Name string
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ type League struct {
|
||||||
Bet365ID int32 `json:"bet365_id" example:"1121"`
|
Bet365ID int32 `json:"bet365_id" example:"1121"`
|
||||||
IsActive bool `json:"is_active" example:"false"`
|
IsActive bool `json:"is_active" example:"false"`
|
||||||
SportID int32 `json:"sport_id" example:"1"`
|
SportID int32 `json:"sport_id" example:"1"`
|
||||||
|
IsFeatured bool `json:"is_featured" example:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateLeague struct {
|
type UpdateLeague struct {
|
||||||
|
|
@ -15,6 +16,7 @@ type UpdateLeague struct {
|
||||||
CountryCode ValidString `json:"cc" example:"uk"`
|
CountryCode ValidString `json:"cc" example:"uk"`
|
||||||
Bet365ID ValidInt32 `json:"bet365_id" example:"1121"`
|
Bet365ID ValidInt32 `json:"bet365_id" example:"1121"`
|
||||||
IsActive ValidBool `json:"is_active" example:"false"`
|
IsActive ValidBool `json:"is_active" example:"false"`
|
||||||
|
IsFeatured ValidBool `json:"is_featured" example:"false"`
|
||||||
SportID ValidInt32 `json:"sport_id" example:"1"`
|
SportID ValidInt32 `json:"sport_id" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,6 +24,69 @@ type LeagueFilter struct {
|
||||||
CountryCode ValidString
|
CountryCode ValidString
|
||||||
SportID ValidInt32
|
SportID ValidInt32
|
||||||
IsActive ValidBool
|
IsActive ValidBool
|
||||||
|
IsFeatured ValidBool
|
||||||
Limit ValidInt64
|
Limit ValidInt64
|
||||||
Offset ValidInt64
|
Offset ValidInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// These leagues are automatically featured when the league is created
|
||||||
|
var FeaturedLeagues = []int64{
|
||||||
|
// Football
|
||||||
|
10044469, // Ethiopian Premier League
|
||||||
|
10041282, //Premier League
|
||||||
|
10083364, //La Liga
|
||||||
|
10041095, //German Bundesliga
|
||||||
|
10041100, //Ligue 1
|
||||||
|
10041809, //UEFA Champions League
|
||||||
|
10041957, //UEFA Europa League
|
||||||
|
10079560, //UEFA Conference League
|
||||||
|
10050282, //UEFA Nations League
|
||||||
|
10044685, //FIFA Club World Cup
|
||||||
|
10050346, //UEFA Super Cup
|
||||||
|
10081269, //CONCACAF Champions Cup
|
||||||
|
10070189, //CONCACAF Gold Cup
|
||||||
|
|
||||||
|
10067913, //Europe - World Cup Qualifying
|
||||||
|
10040162, //Asia - World Cup Qualifying
|
||||||
|
10067624, //South America - World Cup Qualifying
|
||||||
|
10073057, //North & Central America - World Cup Qualifying
|
||||||
|
|
||||||
|
10037075, //International Match
|
||||||
|
10077480, //Women’s International
|
||||||
|
10037109, //Europe Friendlies
|
||||||
|
10068837, //Euro U21
|
||||||
|
|
||||||
|
10041315, //Italian Serie A
|
||||||
|
10036538, //Spain Segunda
|
||||||
|
10047168, // US MLS
|
||||||
|
|
||||||
|
10043156, //England FA Cup
|
||||||
|
10042103, //France Cup
|
||||||
|
10041088, //Premier League 2
|
||||||
|
10084250, //Turkiye Super League
|
||||||
|
10041187, //Kenya Super League
|
||||||
|
10041391, //Netherlands Eredivisie
|
||||||
|
|
||||||
|
// Basketball
|
||||||
|
10041830, //NBA
|
||||||
|
10049984, //WNBA
|
||||||
|
10037165, //German Bundesliga
|
||||||
|
10036608, //Italian Lega 1
|
||||||
|
10040795, //EuroLeague
|
||||||
|
10041534, //Basketball Africa League
|
||||||
|
|
||||||
|
// Ice Hockey
|
||||||
|
10037477, //NHL
|
||||||
|
10037447, //AHL
|
||||||
|
10069385, //IIHF World Championship
|
||||||
|
|
||||||
|
// AMERICAN FOOTBALL
|
||||||
|
10037219, //NFL
|
||||||
|
|
||||||
|
// BASEBALL
|
||||||
|
10037485, // MLB
|
||||||
|
|
||||||
|
// VOLLEYBALL
|
||||||
|
10069666, //FIVB Nations League
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ type DeliveryChannel string
|
||||||
const (
|
const (
|
||||||
NotificationTypeCashOutSuccess NotificationType = "cash_out_success"
|
NotificationTypeCashOutSuccess NotificationType = "cash_out_success"
|
||||||
NotificationTypeDepositSuccess NotificationType = "deposit_success"
|
NotificationTypeDepositSuccess NotificationType = "deposit_success"
|
||||||
|
NotificationTypeWithdrawSuccess NotificationType = "withdraw_success"
|
||||||
NotificationTypeBetPlaced NotificationType = "bet_placed"
|
NotificationTypeBetPlaced NotificationType = "bet_placed"
|
||||||
NotificationTypeDailyReport NotificationType = "daily_report"
|
NotificationTypeDailyReport NotificationType = "daily_report"
|
||||||
NotificationTypeHighLossOnBet NotificationType = "high_loss_on_bet"
|
NotificationTypeHighLossOnBet NotificationType = "high_loss_on_bet"
|
||||||
|
|
@ -23,10 +24,12 @@ const (
|
||||||
NotificationTypeSignUpWelcome NotificationType = "signup_welcome"
|
NotificationTypeSignUpWelcome NotificationType = "signup_welcome"
|
||||||
NotificationTypeOTPSent NotificationType = "otp_sent"
|
NotificationTypeOTPSent NotificationType = "otp_sent"
|
||||||
NOTIFICATION_TYPE_WALLET NotificationType = "wallet_threshold"
|
NOTIFICATION_TYPE_WALLET NotificationType = "wallet_threshold"
|
||||||
NOTIFICATION_TYPE_TRANSFER NotificationType = "transfer_failed"
|
NOTIFICATION_TYPE_TRANSFER_FAIL NotificationType = "transfer_failed"
|
||||||
|
NOTIFICATION_TYPE_TRANSFER_SUCCESS NotificationType = "transfer_success"
|
||||||
NOTIFICATION_TYPE_ADMIN_ALERT NotificationType = "admin_alert"
|
NOTIFICATION_TYPE_ADMIN_ALERT NotificationType = "admin_alert"
|
||||||
NOTIFICATION_RECEIVER_ADMIN NotificationRecieverSide = "admin"
|
NOTIFICATION_TYPE_BET_RESULT NotificationType = "bet_result"
|
||||||
|
|
||||||
|
NOTIFICATION_RECEIVER_ADMIN NotificationRecieverSide = "admin"
|
||||||
NotificationRecieverSideAdmin NotificationRecieverSide = "admin"
|
NotificationRecieverSideAdmin NotificationRecieverSide = "admin"
|
||||||
NotificationRecieverSideCustomer NotificationRecieverSide = "customer"
|
NotificationRecieverSideCustomer NotificationRecieverSide = "customer"
|
||||||
NotificationRecieverSideCashier NotificationRecieverSide = "cashier"
|
NotificationRecieverSideCashier NotificationRecieverSide = "cashier"
|
||||||
|
|
@ -91,3 +94,18 @@ func FromJSON(data []byte) (*Notification, error) {
|
||||||
}
|
}
|
||||||
return &n, nil
|
return &n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReceiverFromRole(role Role) NotificationRecieverSide {
|
||||||
|
|
||||||
|
if role == RoleAdmin {
|
||||||
|
return NotificationRecieverSideAdmin
|
||||||
|
} else if role == RoleCashier {
|
||||||
|
return NotificationRecieverSideCashier
|
||||||
|
} else if role == RoleBranchManager {
|
||||||
|
return NotificationRecieverSideBranchManager
|
||||||
|
} else if role == RoleCustomer {
|
||||||
|
return NotificationRecieverSideCustomer
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@ const (
|
||||||
|
|
||||||
type PaymentMethod string
|
type PaymentMethod string
|
||||||
|
|
||||||
|
// Info on why the wallet was modified
|
||||||
|
// If its internal system modification then, its always direct
|
||||||
const (
|
const (
|
||||||
|
TRANSFER_DIRECT PaymentMethod = "direct"
|
||||||
TRANSFER_CASH PaymentMethod = "cash"
|
TRANSFER_CASH PaymentMethod = "cash"
|
||||||
TRANSFER_BANK PaymentMethod = "bank"
|
TRANSFER_BANK PaymentMethod = "bank"
|
||||||
TRANSFER_CHAPA PaymentMethod = "chapa"
|
TRANSFER_CHAPA PaymentMethod = "chapa"
|
||||||
|
|
@ -22,16 +25,21 @@ const (
|
||||||
TRANSFER_OTHER PaymentMethod = "other"
|
TRANSFER_OTHER PaymentMethod = "other"
|
||||||
)
|
)
|
||||||
|
|
||||||
// There is always a receiving wallet id
|
// Info for the payment providers
|
||||||
// There is a sender wallet id only if wallet transfer type
|
type PaymentDetails struct {
|
||||||
|
ReferenceNumber ValidString
|
||||||
|
BankNumber ValidString
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Transfer is logged for every modification of ALL wallets and wallet types
|
||||||
type Transfer struct {
|
type Transfer struct {
|
||||||
ID int64
|
ID int64
|
||||||
Amount Currency
|
Amount Currency
|
||||||
Verified bool
|
Verified bool
|
||||||
Type TransferType
|
Type TransferType
|
||||||
PaymentMethod PaymentMethod
|
PaymentMethod PaymentMethod
|
||||||
ReceiverWalletID int64
|
ReceiverWalletID ValidInt64
|
||||||
SenderWalletID int64
|
SenderWalletID ValidInt64
|
||||||
ReferenceNumber string
|
ReferenceNumber string
|
||||||
Status string
|
Status string
|
||||||
CashierID ValidInt64
|
CashierID ValidInt64
|
||||||
|
|
@ -44,8 +52,8 @@ type CreateTransfer struct {
|
||||||
Verified bool
|
Verified bool
|
||||||
ReferenceNumber string
|
ReferenceNumber string
|
||||||
Status string
|
Status string
|
||||||
ReceiverWalletID int64
|
ReceiverWalletID ValidInt64
|
||||||
SenderWalletID int64
|
SenderWalletID ValidInt64
|
||||||
CashierID ValidInt64
|
CashierID ValidInt64
|
||||||
Type TransferType
|
Type TransferType
|
||||||
PaymentMethod PaymentMethod
|
PaymentMethod PaymentMethod
|
||||||
|
|
|
||||||
|
|
@ -58,3 +58,11 @@ type CreateCustomerWallet struct {
|
||||||
RegularWalletID int64
|
RegularWalletID int64
|
||||||
StaticWalletID int64
|
StaticWalletID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WalletType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CustomerWalletType WalletType = "customer_wallet"
|
||||||
|
BranchWalletType WalletType = "branch_wallet"
|
||||||
|
CompanyWalletType WalletType = "company_wallet"
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,10 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma
|
||||||
Int64: filter.UserID.Value,
|
Int64: filter.UserID.Value,
|
||||||
Valid: filter.UserID.Valid,
|
Valid: filter.UserID.Valid,
|
||||||
},
|
},
|
||||||
|
IsShopBet: pgtype.Bool{
|
||||||
|
Bool: filter.IsShopBet.Value,
|
||||||
|
Valid: filter.IsShopBet.Valid,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
domain.MongoDBLogger.Error("failed to get all bets",
|
domain.MongoDBLogger.Error("failed to get all bets",
|
||||||
|
|
@ -360,6 +364,28 @@ func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status dom
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) {
|
||||||
|
outcomes, err := s.queries.UpdateBetOutcomeStatusForEvent(ctx, dbgen.UpdateBetOutcomeStatusForEventParams{
|
||||||
|
EventID: eventID,
|
||||||
|
Status: int32(status),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Error("failed to update bet outcome status for event",
|
||||||
|
zap.Int64("eventID", eventID),
|
||||||
|
zap.Int32("status", int32(status)),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes))
|
||||||
|
for _, outcome := range outcomes {
|
||||||
|
result = append(result, convertDBBetOutcomes(outcome))
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
|
||||||
return s.queries.DeleteBet(ctx, id)
|
return s.queries.DeleteBet(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,13 @@ func (s *Store) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]do
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error) {
|
func (s *Store) GetAllBranches(ctx context.Context, filter domain.BranchFilter) ([]domain.BranchDetail, error) {
|
||||||
dbBranches, err := s.queries.GetAllBranches(ctx)
|
dbBranches, err := s.queries.GetAllBranches(ctx, dbgen.GetAllBranchesParams{
|
||||||
|
CompanyID: pgtype.Int8{
|
||||||
|
Int64: filter.CompanyID.Value,
|
||||||
|
Valid: filter.CompanyID.Valid,
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ func (s *Store) SaveLeague(ctx context.Context, l domain.League) error {
|
||||||
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
CountryCode: pgtype.Text{String: l.CountryCode, Valid: true},
|
||||||
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
Bet365ID: pgtype.Int4{Int32: l.Bet365ID, Valid: true},
|
||||||
IsActive: pgtype.Bool{Bool: l.IsActive, Valid: true},
|
IsActive: pgtype.Bool{Bool: l.IsActive, Valid: true},
|
||||||
|
IsFeatured: pgtype.Bool{Bool: l.IsFeatured, Valid: true},
|
||||||
SportID: l.SportID,
|
SportID: l.SportID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -33,6 +34,10 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) (
|
||||||
Bool: filter.IsActive.Value,
|
Bool: filter.IsActive.Value,
|
||||||
Valid: filter.IsActive.Valid,
|
Valid: filter.IsActive.Valid,
|
||||||
},
|
},
|
||||||
|
IsFeatured: pgtype.Bool{
|
||||||
|
Bool: filter.IsFeatured.Value,
|
||||||
|
Valid: filter.IsFeatured.Valid,
|
||||||
|
},
|
||||||
Limit: pgtype.Int4{
|
Limit: pgtype.Int4{
|
||||||
Int32: int32(filter.Limit.Value),
|
Int32: int32(filter.Limit.Value),
|
||||||
Valid: filter.Limit.Valid,
|
Valid: filter.Limit.Valid,
|
||||||
|
|
@ -54,6 +59,29 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) (
|
||||||
CountryCode: league.CountryCode.String,
|
CountryCode: league.CountryCode.String,
|
||||||
Bet365ID: league.Bet365ID.Int32,
|
Bet365ID: league.Bet365ID.Int32,
|
||||||
IsActive: league.IsActive.Bool,
|
IsActive: league.IsActive.Bool,
|
||||||
|
IsFeatured: league.IsFeatured.Bool,
|
||||||
|
SportID: league.SportID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leagues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) {
|
||||||
|
l, err := s.queries.GetFeaturedLeagues(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
leagues := make([]domain.League, len(l))
|
||||||
|
for i, league := range l {
|
||||||
|
leagues[i] = domain.League{
|
||||||
|
ID: league.ID,
|
||||||
|
Name: league.Name,
|
||||||
|
CountryCode: league.CountryCode.String,
|
||||||
|
Bet365ID: league.Bet365ID.Int32,
|
||||||
|
IsActive: league.IsActive.Bool,
|
||||||
|
|
||||||
SportID: league.SportID,
|
SportID: league.SportID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +121,10 @@ func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) er
|
||||||
Bool: league.IsActive.Value,
|
Bool: league.IsActive.Value,
|
||||||
Valid: league.IsActive.Valid,
|
Valid: league.IsActive.Valid,
|
||||||
},
|
},
|
||||||
|
IsFeatured: pgtype.Bool{
|
||||||
|
Bool: league.IsFeatured.Value,
|
||||||
|
Valid: league.IsActive.Valid,
|
||||||
|
},
|
||||||
SportID: pgtype.Int4{
|
SportID: pgtype.Int4{
|
||||||
Int32: league.SportID.Value,
|
Int32: league.SportID.Value,
|
||||||
Valid: league.SportID.Valid,
|
Valid: league.SportID.Valid,
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,14 @@ func convertDBTransfer(transfer dbgen.WalletTransfer) domain.Transfer {
|
||||||
Amount: domain.Currency(transfer.Amount.Int64),
|
Amount: domain.Currency(transfer.Amount.Int64),
|
||||||
Type: domain.TransferType(transfer.Type.String),
|
Type: domain.TransferType(transfer.Type.String),
|
||||||
Verified: transfer.Verified.Bool,
|
Verified: transfer.Verified.Bool,
|
||||||
ReceiverWalletID: transfer.ReceiverWalletID.Int64,
|
ReceiverWalletID: domain.ValidInt64{
|
||||||
SenderWalletID: transfer.SenderWalletID.Int64,
|
Value: transfer.ReceiverWalletID.Int64,
|
||||||
|
Valid: transfer.ReceiverWalletID.Valid,
|
||||||
|
},
|
||||||
|
SenderWalletID: domain.ValidInt64{
|
||||||
|
Value: transfer.SenderWalletID.Int64,
|
||||||
|
Valid: transfer.SenderWalletID.Valid,
|
||||||
|
},
|
||||||
CashierID: domain.ValidInt64{
|
CashierID: domain.ValidInt64{
|
||||||
Value: transfer.CashierID.Int64,
|
Value: transfer.CashierID.Int64,
|
||||||
Valid: transfer.CashierID.Valid,
|
Valid: transfer.CashierID.Valid,
|
||||||
|
|
@ -29,12 +35,12 @@ func convertCreateTransfer(transfer domain.CreateTransfer) dbgen.CreateTransferP
|
||||||
Amount: pgtype.Int8{Int64: int64(transfer.Amount), Valid: true},
|
Amount: pgtype.Int8{Int64: int64(transfer.Amount), Valid: true},
|
||||||
Type: pgtype.Text{String: string(transfer.Type), Valid: true},
|
Type: pgtype.Text{String: string(transfer.Type), Valid: true},
|
||||||
ReceiverWalletID: pgtype.Int8{
|
ReceiverWalletID: pgtype.Int8{
|
||||||
Int64: transfer.ReceiverWalletID,
|
Int64: transfer.ReceiverWalletID.Value,
|
||||||
Valid: true,
|
Valid: transfer.ReceiverWalletID.Valid,
|
||||||
},
|
},
|
||||||
SenderWalletID: pgtype.Int8{
|
SenderWalletID: pgtype.Int8{
|
||||||
Int64: transfer.SenderWalletID,
|
Int64: transfer.SenderWalletID.Value,
|
||||||
Valid: true,
|
Valid: transfer.SenderWalletID.Valid,
|
||||||
},
|
},
|
||||||
CashierID: pgtype.Int8{
|
CashierID: pgtype.Int8{
|
||||||
Int64: transfer.CashierID.Value,
|
Int64: transfer.CashierID.Value,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ type BetStore interface {
|
||||||
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
|
UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
|
||||||
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
|
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
|
||||||
|
UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error)
|
||||||
DeleteBet(ctx context.Context, id int64) error
|
DeleteBet(ctx context.Context, id int64) error
|
||||||
|
|
||||||
GetBetSummary(ctx context.Context, filter domain.ReportFilter) (
|
GetBetSummary(ctx context.Context, filter domain.ReportFilter) (
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,11 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
||||||
}
|
}
|
||||||
|
|
||||||
deductedAmount := req.Amount / 10
|
deductedAmount := req.Amount / 10
|
||||||
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
_, err = s.walletSvc.DeductFromWallet(ctx,
|
||||||
|
branch.WalletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{
|
||||||
|
Value: userID,
|
||||||
|
Valid: true,
|
||||||
|
}, domain.TRANSFER_DIRECT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to deduct from wallet",
|
s.mongoLogger.Error("failed to deduct from wallet",
|
||||||
zap.Int64("wallet_id", branch.WalletID),
|
zap.Int64("wallet_id", branch.WalletID),
|
||||||
|
|
@ -297,7 +301,10 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
||||||
}
|
}
|
||||||
|
|
||||||
deductedAmount := req.Amount / 10
|
deductedAmount := req.Amount / 10
|
||||||
err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount))
|
_, err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{
|
||||||
|
Value: userID,
|
||||||
|
Valid: true,
|
||||||
|
}, domain.TRANSFER_DIRECT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("wallet deduction failed",
|
s.mongoLogger.Error("wallet deduction failed",
|
||||||
zap.Int64("wallet_id", branch.WalletID),
|
zap.Int64("wallet_id", branch.WalletID),
|
||||||
|
|
@ -323,7 +330,8 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
||||||
}
|
}
|
||||||
|
|
||||||
userWallet := wallets[0]
|
userWallet := wallets[0]
|
||||||
err = s.walletSvc.DeductFromWallet(ctx, userWallet.ID, domain.ToCurrency(req.Amount))
|
_, err = s.walletSvc.DeductFromWallet(ctx, userWallet.ID,
|
||||||
|
domain.ToCurrency(req.Amount), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("wallet deduction failed for customer",
|
s.mongoLogger.Error("wallet deduction failed for customer",
|
||||||
zap.Int64("wallet_id", userWallet.ID),
|
zap.Int64("wallet_id", userWallet.ID),
|
||||||
|
|
@ -704,7 +712,8 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
|
||||||
amount = bet.Amount
|
amount = bet.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount)
|
_, err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.mongoLogger.Error("failed to add winnings to wallet",
|
s.mongoLogger.Error("failed to add winnings to wallet",
|
||||||
zap.Int64("wallet_id", customerWallet.RegularID),
|
zap.Int64("wallet_id", customerWallet.RegularID),
|
||||||
|
|
@ -810,6 +819,19 @@ func (s *Service) UpdateBetOutcomeStatus(ctx context.Context, id int64, status d
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) {
|
||||||
|
outcomes, err := s.betStore.UpdateBetOutcomeStatusForEvent(ctx, eventID, status)
|
||||||
|
if err != nil {
|
||||||
|
s.mongoLogger.Error("failed to update bet outcome status",
|
||||||
|
zap.Int64("eventID", eventID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return outcomes, nil
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ type BranchStore interface {
|
||||||
GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error)
|
GetBranchByID(ctx context.Context, id int64) (domain.BranchDetail, error)
|
||||||
GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]domain.BranchDetail, error)
|
GetBranchByManagerID(ctx context.Context, branchManagerID int64) ([]domain.BranchDetail, error)
|
||||||
GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error)
|
GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error)
|
||||||
GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error)
|
GetAllBranches(ctx context.Context, filter domain.BranchFilter) ([]domain.BranchDetail, error)
|
||||||
SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error)
|
SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error)
|
||||||
UpdateBranch(ctx context.Context, branch domain.UpdateBranch) (domain.Branch, error)
|
UpdateBranch(ctx context.Context, branch domain.UpdateBranch) (domain.Branch, error)
|
||||||
DeleteBranch(ctx context.Context, id int64) error
|
DeleteBranch(ctx context.Context, id int64) error
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package branch
|
package branch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -42,8 +42,8 @@ func (s *Service) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]
|
||||||
func (s *Service) GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error) {
|
func (s *Service) GetBranchOperations(ctx context.Context, branchID int64) ([]domain.BranchOperation, error) {
|
||||||
return s.branchStore.GetBranchOperations(ctx, branchID)
|
return s.branchStore.GetBranchOperations(ctx, branchID)
|
||||||
}
|
}
|
||||||
func (s *Service) GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error) {
|
func (s *Service) GetAllBranches(ctx context.Context, filter domain.BranchFilter) ([]domain.BranchDetail, error) {
|
||||||
return s.branchStore.GetAllBranches(ctx)
|
return s.branchStore.GetAllBranches(ctx, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error) {
|
func (s *Service) GetBranchByCashier(ctx context.Context, userID int64) (domain.Branch, error) {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,10 @@ func (s *Service) InitiateDeposit(ctx context.Context, userID int64, amount doma
|
||||||
PaymentMethod: domain.TRANSFER_CHAPA,
|
PaymentMethod: domain.TRANSFER_CHAPA,
|
||||||
ReferenceNumber: reference,
|
ReferenceNumber: reference,
|
||||||
// ReceiverWalletID: 1,
|
// ReceiverWalletID: 1,
|
||||||
SenderWalletID: senderWallet.ID,
|
SenderWalletID: domain.ValidInt64{
|
||||||
|
Value: senderWallet.ID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
Verified: false,
|
Verified: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,8 +155,10 @@ func (s *Service) InitiateWithdrawal(ctx context.Context, userID int64, req doma
|
||||||
createTransfer := domain.CreateTransfer{
|
createTransfer := domain.CreateTransfer{
|
||||||
Amount: domain.Currency(amount),
|
Amount: domain.Currency(amount),
|
||||||
Type: domain.WITHDRAW,
|
Type: domain.WITHDRAW,
|
||||||
ReceiverWalletID: 1,
|
SenderWalletID: domain.ValidInt64{
|
||||||
SenderWalletID: withdrawWallet.ID,
|
Value: withdrawWallet.ID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
Status: string(domain.PaymentStatusPending),
|
Status: string(domain.PaymentStatusPending),
|
||||||
Verified: false,
|
Verified: false,
|
||||||
ReferenceNumber: reference,
|
ReferenceNumber: reference,
|
||||||
|
|
@ -215,6 +220,11 @@ func (s *Service) ManualVerifTransaction(ctx context.Context, txRef string) (*do
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// just making sure that the sender id is valid
|
||||||
|
if !transfer.SenderWalletID.Valid {
|
||||||
|
return nil, fmt.Errorf("sender wallet id is invalid: %v \n", transfer.SenderWalletID)
|
||||||
|
}
|
||||||
|
|
||||||
// If not verified or not found, verify with Chapa
|
// If not verified or not found, verify with Chapa
|
||||||
verification, err := s.chapaClient.VerifyPayment(ctx, txRef)
|
verification, err := s.chapaClient.VerifyPayment(ctx, txRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -229,7 +239,7 @@ func (s *Service) ManualVerifTransaction(ctx context.Context, txRef string) (*do
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credit user's wallet
|
// Credit user's wallet
|
||||||
err = s.walletStore.UpdateBalance(ctx, transfer.SenderWalletID, transfer.Amount)
|
err = s.walletStore.UpdateBalance(ctx, transfer.SenderWalletID.Value, transfer.Amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to update wallet balance: %w", err)
|
return nil, fmt.Errorf("failed to update wallet balance: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +281,11 @@ func (s *Service) HandleVerifyDepositWebhook(ctx context.Context, transfer domai
|
||||||
|
|
||||||
// If payment is completed, credit user's wallet
|
// If payment is completed, credit user's wallet
|
||||||
if transfer.Status == string(domain.PaymentStatusCompleted) {
|
if transfer.Status == string(domain.PaymentStatusCompleted) {
|
||||||
if err := s.walletStore.AddToWallet(ctx, payment.SenderWalletID, payment.Amount); err != nil {
|
if _, err := s.walletStore.AddToWallet(ctx, payment.SenderWalletID.Value, payment.Amount, domain.ValidInt64{}, domain.TRANSFER_CHAPA, domain.PaymentDetails{
|
||||||
|
ReferenceNumber: domain.ValidString{
|
||||||
|
Value: transfer.Reference,
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
return fmt.Errorf("failed to credit user wallet: %w", err)
|
return fmt.Errorf("failed to credit user wallet: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +322,7 @@ func (s *Service) HandleVerifyWithdrawWebhook(ctx context.Context, payment domai
|
||||||
|
|
||||||
// If payment is completed, credit user's wallet
|
// If payment is completed, credit user's wallet
|
||||||
if payment.Status == string(domain.PaymentStatusFailed) {
|
if payment.Status == string(domain.PaymentStatusFailed) {
|
||||||
if err := s.walletStore.AddToWallet(ctx, transfer.SenderWalletID, transfer.Amount); err != nil {
|
if _, err := s.walletStore.AddToWallet(ctx, transfer.SenderWalletID.Value, transfer.Amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil {
|
||||||
return fmt.Errorf("failed to credit user wallet: %w", err)
|
return fmt.Errorf("failed to credit user wallet: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -202,8 +203,10 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, source string) {
|
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, source string) {
|
||||||
sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91}
|
// sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91}
|
||||||
|
sportIDs := []int{1}
|
||||||
// TODO: Add the league skipping again when we have dynamic leagues
|
// TODO: Add the league skipping again when we have dynamic leagues
|
||||||
|
|
||||||
// b, err := os.OpenFile("logs/skipped_leagues.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
// b, err := os.OpenFile("logs/skipped_leagues.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Printf("❌ Failed to open leagues file %v", err)
|
// log.Printf("❌ Failed to open leagues file %v", err)
|
||||||
|
|
@ -212,7 +215,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
||||||
for sportIndex, sportID := range sportIDs {
|
for sportIndex, sportID := range sportIDs {
|
||||||
var totalPages int = 1
|
var totalPages int = 1
|
||||||
var page int = 0
|
var page int = 0
|
||||||
var limit int = 200
|
var limit int = 1
|
||||||
var count int = 0
|
var count int = 0
|
||||||
log.Printf("Sport ID %d", sportID)
|
log.Printf("Sport ID %d", sportID)
|
||||||
for page <= totalPages {
|
for page <= totalPages {
|
||||||
|
|
@ -252,10 +255,12 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
|
||||||
// doesn't make sense to save and check back to back, but for now it can be here
|
// doesn't make sense to save and check back to back, but for now it can be here
|
||||||
// no this its fine to keep it here
|
// no this its fine to keep it here
|
||||||
// but change the league id to bet365 id later
|
// but change the league id to bet365 id later
|
||||||
|
//Automatically feature the league if its in the list
|
||||||
err = s.store.SaveLeague(ctx, domain.League{
|
err = s.store.SaveLeague(ctx, domain.League{
|
||||||
ID: leagueID,
|
ID: leagueID,
|
||||||
Name: ev.League.Name,
|
Name: ev.League.Name,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
|
IsFeatured: slices.Contains(domain.FeaturedLeagues, leagueID),
|
||||||
SportID: convertInt32(ev.SportID),
|
SportID: convertInt32(ev.SportID),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
type Service interface {
|
type Service interface {
|
||||||
SaveLeague(ctx context.Context, l domain.League) error
|
SaveLeague(ctx context.Context, l domain.League) error
|
||||||
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error)
|
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.League, error)
|
||||||
|
GetFeaturedLeagues(ctx context.Context) ([]domain.League, error)
|
||||||
SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error
|
SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error
|
||||||
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error
|
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ func (s *service) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter)
|
||||||
return s.store.GetAllLeagues(ctx, filter)
|
return s.store.GetAllLeagues(ctx, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) GetFeaturedLeagues(ctx context.Context) ([]domain.League, error) {
|
||||||
|
return s.store.GetFeaturedLeagues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error {
|
func (s *service) SetLeagueActive(ctx context.Context, leagueId int64, isActive bool) error {
|
||||||
return s.store.SetLeagueActive(ctx, leagueId, isActive)
|
return s.store.SetLeagueActive(ctx, leagueId, isActive)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
|
||||||
|
|
||||||
walletID := wallets[0].ID
|
walletID := wallets[0].ID
|
||||||
currentBonus := float64(wallets[0].Balance)
|
currentBonus := float64(wallets[0].Balance)
|
||||||
err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(int64((currentBonus+referral.RewardAmount)*100)))
|
_, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBonus+referral.RewardAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to add referral reward to wallet", "walletID", walletID, "referrerID", referrerID, "error", err)
|
s.logger.Error("Failed to add referral reward to wallet", "walletID", walletID, "referrerID", referrerID, "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -162,7 +162,7 @@ func (s *Service) ProcessDepositBonus(ctx context.Context, userPhone string, amo
|
||||||
walletID := wallets[0].ID
|
walletID := wallets[0].ID
|
||||||
bonus := amount * (settings.CashbackPercentage / 100)
|
bonus := amount * (settings.CashbackPercentage / 100)
|
||||||
currentBonus := float64(wallets[0].Balance)
|
currentBonus := float64(wallets[0].Balance)
|
||||||
err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(int64((currentBonus+bonus)*100)))
|
_, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBonus+bonus)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to add deposit bonus to wallet", "walletID", walletID, "userID", userID, "bonus", bonus, "error", err)
|
s.logger.Error("Failed to add deposit bonus to wallet", "walletID", walletID, "userID", userID, "bonus", bonus, "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -216,7 +216,7 @@ func (s *Service) ProcessBetReferral(ctx context.Context, userPhone string, betA
|
||||||
|
|
||||||
walletID := wallets[0].ID
|
walletID := wallets[0].ID
|
||||||
currentBalance := float64(wallets[0].Balance)
|
currentBalance := float64(wallets[0].Balance)
|
||||||
err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(int64((currentBalance+bonus)*100)))
|
_, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBalance+bonus)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referrerID, "bonus", bonus, "error", err)
|
s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referrerID, "bonus", bonus, "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -17,6 +16,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
|
||||||
|
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,9 +29,10 @@ type Service struct {
|
||||||
oddSvc odds.ServiceImpl
|
oddSvc odds.ServiceImpl
|
||||||
eventSvc event.Service
|
eventSvc event.Service
|
||||||
leagueSvc league.Service
|
leagueSvc league.Service
|
||||||
|
notificationSvc *notificationservice.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger, betSvc bet.Service, oddSvc odds.ServiceImpl, eventSvc event.Service, leagueSvc league.Service) *Service {
|
func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger, betSvc bet.Service, oddSvc odds.ServiceImpl, eventSvc event.Service, leagueSvc league.Service, notificationSvc *notificationservice.Service) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
|
|
@ -41,6 +42,7 @@ func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger,
|
||||||
oddSvc: oddSvc,
|
oddSvc: oddSvc,
|
||||||
eventSvc: eventSvc,
|
eventSvc: eventSvc,
|
||||||
leagueSvc: leagueSvc,
|
leagueSvc: leagueSvc,
|
||||||
|
notificationSvc: notificationSvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,6 +50,127 @@ var (
|
||||||
ErrEventIsNotActive = fmt.Errorf("event has been cancelled or postponed")
|
ErrEventIsNotActive = fmt.Errorf("event has been cancelled or postponed")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s *Service) UpdateResultForOutcomes(ctx context.Context, eventID int64, resultRes json.RawMessage, sportID int64) error {
|
||||||
|
// TODO: Optimize this since there could be many outcomes with the same event_id and market_id that could be updated the same time
|
||||||
|
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get pending bet outcomes", "error", err)
|
||||||
|
return fmt.Errorf("failed to get pending bet outcomes for event %d: %w", eventID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(outcomes) == 0 {
|
||||||
|
s.logger.Info("No bets have been placed on event", "event", eventID)
|
||||||
|
}
|
||||||
|
// if len(outcomes) == 0 {
|
||||||
|
// fmt.Printf("🕛 No bets have been placed on event %v (%d/%d) \n", eventID, i+1, len(events))
|
||||||
|
// } else {
|
||||||
|
// fmt.Printf("✅ %d bets have been placed on event %v (%d/%d) \n", len(outcomes), event.ID, i+1, len(events))
|
||||||
|
// }
|
||||||
|
|
||||||
|
for _, outcome := range outcomes {
|
||||||
|
if outcome.Expires.After(time.Now()) {
|
||||||
|
s.logger.Warn("Outcome is not expired yet", "event_id", outcome.EventID, "outcome_id", outcome.ID)
|
||||||
|
return fmt.Errorf("Outcome has not expired yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
parseResult, err := s.parseResult(ctx, resultRes, outcome, sportID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to parse result", "event_id", outcome.EventID, "outcome_id", outcome.ID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, parseResult.Status)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if outcome.Status == domain.OUTCOME_STATUS_ERROR || outcome.Status == domain.OUTCOME_STATUS_PENDING {
|
||||||
|
s.logger.Error("Outcome is pending or error", "event_id", outcome.EventID, "outcome_id", outcome.ID)
|
||||||
|
return fmt.Errorf("Error while updating outcome")
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := s.betSvc.CheckBetOutcomeForBet(ctx, outcome.BetID)
|
||||||
|
if err != nil {
|
||||||
|
if err != bet.ErrOutcomesNotCompleted {
|
||||||
|
s.logger.Error("Failed to check bet outcome for bet", "event_id", outcome.EventID, "error", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.logger.Info("Updating bet status", "bet_id", outcome.BetID, "status", status.String())
|
||||||
|
err = s.betSvc.UpdateStatus(ctx, outcome.BetID, status)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) RefundAllOutcomes(ctx context.Context, eventID int64) error {
|
||||||
|
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get pending bet outcomes", "error", err)
|
||||||
|
return fmt.Errorf("failed to get pending bet outcomes for event %d: %w", eventID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(outcomes) == 0 {
|
||||||
|
s.logger.Info("No bets have been placed on event", "event", eventID)
|
||||||
|
}
|
||||||
|
|
||||||
|
outcomes, err = s.betSvc.UpdateBetOutcomeStatusForEvent(ctx, eventID, domain.OUTCOME_STATUS_VOID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to update all outcomes for event")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all the unique bet_ids and how many outcomes have this bet_id
|
||||||
|
betIDSet := make(map[int64]int64)
|
||||||
|
for _, outcome := range outcomes {
|
||||||
|
betIDSet[outcome.BetID] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for betID := range betIDSet {
|
||||||
|
status, err := s.betSvc.CheckBetOutcomeForBet(ctx, betID)
|
||||||
|
if err != nil {
|
||||||
|
if err != bet.ErrOutcomesNotCompleted {
|
||||||
|
s.logger.Error("Failed to check bet outcome for bet", "event_id", eventID, "error", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.betSvc.UpdateStatus(ctx, betID, status)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to update bet status", "event id", eventID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
// for _, outcome := range outcomes {
|
||||||
|
// outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, domain.OUTCOME_STATUS_VOID)
|
||||||
|
// if err != nil {
|
||||||
|
// s.logger.Error("Failed to refund all outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Check if all the bet outcomes have been set to refund for
|
||||||
|
// status, err := s.betSvc.CheckBetOutcomeForBet(ctx, outcome.BetID)
|
||||||
|
// if err != nil {
|
||||||
|
// if err != bet.ErrOutcomesNotCompleted {
|
||||||
|
// s.logger.Error("Failed to check bet outcome for bet", "event_id", outcome.EventID, "error", err)
|
||||||
|
// }
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// err = s.betSvc.UpdateStatus(ctx, outcome.BetID, domain.OUTCOME_STATUS_VOID)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
// TODO: Optimize this because there could be many bet outcomes for the same odd
|
// TODO: Optimize this because there could be many bet outcomes for the same odd
|
||||||
// Take market id and match result as param and update all the bet outcomes at the same time
|
// Take market id and match result as param and update all the bet outcomes at the same time
|
||||||
|
|
@ -58,29 +181,15 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
fmt.Printf("⚠️ Expired Events: %d \n", len(events))
|
fmt.Printf("⚠️ Expired Events: %d \n", len(events))
|
||||||
removed := 0
|
removed := 0
|
||||||
errs := make([]error, 0, len(events))
|
|
||||||
for i, event := range events {
|
for _, event := range events {
|
||||||
|
|
||||||
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse event id")
|
s.logger.Error("Failed to parse", "eventID", event.ID, "err", err)
|
||||||
errs = append(errs, fmt.Errorf("failed to parse event id %s: %w", event.ID, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to get pending bet outcomes", "error", err)
|
|
||||||
errs = append(errs, fmt.Errorf("failed to get pending bet outcomes for event %d: %w", eventID, err))
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(outcomes) == 0 {
|
|
||||||
fmt.Printf("🕛 No bets have been placed on event %v (%d/%d) \n", event.ID, i+1, len(events))
|
|
||||||
} else {
|
|
||||||
fmt.Printf("✅ %d bets have been placed on event %v (%d/%d) \n", len(outcomes), event.ID, i+1, len(events))
|
|
||||||
}
|
|
||||||
|
|
||||||
isDeleted := true
|
|
||||||
result, err := s.fetchResult(ctx, eventID)
|
result, err := s.fetchResult(ctx, eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrEventIsNotActive {
|
if err == ErrEventIsNotActive {
|
||||||
|
|
@ -108,78 +217,41 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Figure out what to do with the events that have been cancelled or postponed, etc...
|
// TODO: Figure out what to do with the events that have been cancelled or postponed, etc...
|
||||||
if timeStatusParsed != int64(domain.TIME_STATUS_ENDED) {
|
// if timeStatusParsed != int64(domain.TIME_STATUS_ENDED) {
|
||||||
s.logger.Warn("Event is not ended yet", "event_id", eventID, "time_status", commonResp.TimeStatus)
|
// s.logger.Warn("Event is not ended yet", "event_id", eventID, "time_status", commonResp.TimeStatus)
|
||||||
fmt.Printf("⚠️ Event %v is not ended yet (%d/%d) \n", event.ID, i+1, len(events))
|
// fmt.Printf("⚠️ Event %v is not ended yet (%d/%d) \n", event.ID, i+1, len(events))
|
||||||
isDeleted = false
|
// isDeleted = false
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// notification := &domain.Notification{
|
||||||
|
// RecipientID: recipientID,
|
||||||
|
// Type: domain.NOTIFICATION_TYPE_WALLET,
|
||||||
|
// Level: domain.NotificationLevelWarning,
|
||||||
|
// Reciever: domain.NotificationRecieverSideAdmin,
|
||||||
|
// DeliveryChannel: domain.DeliveryChannelInApp,
|
||||||
|
// Payload: domain.NotificationPayload{
|
||||||
|
// Headline: "Wallet Threshold Alert",
|
||||||
|
// Message: message,
|
||||||
|
// },
|
||||||
|
// Priority: 2, // Medium priority
|
||||||
|
// }
|
||||||
|
|
||||||
|
switch timeStatusParsed {
|
||||||
|
case int64(domain.TIME_STATUS_NOT_STARTED), int64(domain.TIME_STATUS_IN_PLAY):
|
||||||
continue
|
continue
|
||||||
}
|
|
||||||
|
|
||||||
for j, outcome := range outcomes {
|
case int64(domain.TIME_STATUS_TO_BE_FIXED):
|
||||||
fmt.Printf("⚙️ Processing 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
s.logger.Warn("Event needs to be rescheduled or corrected", "event_id", eventID)
|
||||||
outcome.MarketName,
|
// Admin users will be able to review the events
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
|
||||||
j+1, len(outcomes))
|
|
||||||
|
|
||||||
if outcome.Expires.After(time.Now()) {
|
case int64(domain.TIME_STATUS_ENDED), int64(domain.TIME_STATUS_WALKOVER), int64(domain.TIME_STATUS_DECIDED_BY_FA):
|
||||||
isDeleted = false
|
err = s.UpdateResultForOutcomes(ctx, eventID, result.Results[0], sportID)
|
||||||
s.logger.Warn("Outcome is not expired yet", "event_id", event.ID, "outcome_id", outcome.ID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
parseResult, err := s.parseResult(ctx, result.Results[0], outcome, sportID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
isDeleted = false
|
s.logger.Error("Error while updating result for event", "event_id", eventID)
|
||||||
s.logger.Error("Failed to parse result", "event_id", outcome.EventID, "outcome_id", outcome.ID, "error", err)
|
|
||||||
errs = append(errs, fmt.Errorf("failed to parse result for event %d: %w", outcome.EventID, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, parseResult.Status)
|
|
||||||
if err != nil {
|
|
||||||
isDeleted = false
|
|
||||||
s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if outcome.Status == domain.OUTCOME_STATUS_ERROR || outcome.Status == domain.OUTCOME_STATUS_PENDING {
|
|
||||||
fmt.Printf("❌ Error while updating 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
|
||||||
outcome.MarketName,
|
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
|
||||||
j+1, len(outcomes))
|
|
||||||
|
|
||||||
s.logger.Error("Outcome is pending or error", "event_id", outcome.EventID, "outcome_id", outcome.ID)
|
|
||||||
isDeleted = false
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("✅ Successfully updated 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
s.logger.Info("Removing Event", "eventID", event.ID)
|
||||||
outcome.MarketName,
|
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
|
||||||
j+1, len(outcomes))
|
|
||||||
|
|
||||||
status, err := s.betSvc.CheckBetOutcomeForBet(ctx, outcome.BetID)
|
|
||||||
if err != nil {
|
|
||||||
if err != bet.ErrOutcomesNotCompleted {
|
|
||||||
s.logger.Error("Failed to check bet outcome for bet", "event_id", outcome.EventID, "error", err)
|
|
||||||
}
|
|
||||||
isDeleted = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Printf("🧾 Updating bet %v - event %v (%d/%d) to %v\n", outcome.BetID, event.ID, j+1, len(outcomes), status.String())
|
|
||||||
err = s.betSvc.UpdateStatus(ctx, outcome.BetID, status)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
|
|
||||||
isDeleted = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Printf("✅ Successfully updated 🎫 Bet %v - event %v(%v) (%d/%d) \n",
|
|
||||||
outcome.BetID,
|
|
||||||
event.HomeTeam+" "+event.AwayTeam, event.ID,
|
|
||||||
j+1, len(outcomes))
|
|
||||||
|
|
||||||
}
|
|
||||||
if isDeleted {
|
|
||||||
removed += 1
|
|
||||||
fmt.Printf("⚠️ Removing Event %v \n", event.ID)
|
|
||||||
err = s.repo.DeleteEvent(ctx, event.ID)
|
err = s.repo.DeleteEvent(ctx, event.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to remove event", "event_id", event.ID, "error", err)
|
s.logger.Error("Failed to remove event", "event_id", event.ID, "error", err)
|
||||||
|
|
@ -190,17 +262,91 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
||||||
s.logger.Error("Failed to remove odds for event", "event_id", event.ID, "error", err)
|
s.logger.Error("Failed to remove odds for event", "event_id", event.ID, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
removed += 1
|
||||||
|
case int64(domain.TIME_STATUS_ABANDONED), int64(domain.TIME_STATUS_CANCELLED), int64(domain.TIME_STATUS_REMOVED):
|
||||||
|
s.logger.Info("Event abandoned/cancelled/removed", "event_id", eventID, "status", timeStatusParsed)
|
||||||
|
err = s.RefundAllOutcomes(ctx, eventID)
|
||||||
|
|
||||||
|
s.logger.Info("Removing Event", "eventID", event.ID)
|
||||||
|
err = s.repo.DeleteEvent(ctx, event.ID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to remove event", "event_id", event.ID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.repo.DeleteOddsForEvent(ctx, event.ID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to remove odds for event", "event_id", event.ID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
removed += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for j, outcome := range outcomes {
|
||||||
|
|
||||||
|
// fmt.Printf("⚙️ Processing 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
||||||
|
// outcome.MarketName,
|
||||||
|
// event.HomeTeam+" "+event.AwayTeam, event.ID,
|
||||||
|
// j+1, len(outcomes))
|
||||||
|
|
||||||
|
// if outcome.Expires.After(time.Now()) {
|
||||||
|
// isDeleted = false
|
||||||
|
// s.logger.Warn("Outcome is not expired yet", "event_id", event.ID, "outcome_id", outcome.ID)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// parseResult, err := s.parseResult(ctx, result.Results[0], outcome, sportID)
|
||||||
|
// if err != nil {
|
||||||
|
// isDeleted = false
|
||||||
|
// s.logger.Error("Failed to parse result", "event_id", outcome.EventID, "outcome_id", outcome.ID, "error", err)
|
||||||
|
// errs = append(errs, fmt.Errorf("failed to parse result for event %d: %w", outcome.EventID, err))
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, parseResult.Status)
|
||||||
|
// if err != nil {
|
||||||
|
// isDeleted = false
|
||||||
|
// s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// if outcome.Status == domain.OUTCOME_STATUS_ERROR || outcome.Status == domain.OUTCOME_STATUS_PENDING {
|
||||||
|
// fmt.Printf("❌ Error while updating 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
||||||
|
// outcome.MarketName,
|
||||||
|
// event.HomeTeam+" "+event.AwayTeam, event.ID,
|
||||||
|
// j+1, len(outcomes))
|
||||||
|
|
||||||
|
// s.logger.Error("Outcome is pending or error", "event_id", outcome.EventID, "outcome_id", outcome.ID)
|
||||||
|
// isDeleted = false
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fmt.Printf("✅ Successfully updated 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
|
||||||
|
// outcome.MarketName,
|
||||||
|
// event.HomeTeam+" "+event.AwayTeam, event.ID,
|
||||||
|
// j+1, len(outcomes))
|
||||||
|
|
||||||
|
// status, err := s.betSvc.CheckBetOutcomeForBet(ctx, outcome.BetID)
|
||||||
|
// if err != nil {
|
||||||
|
// if err != bet.ErrOutcomesNotCompleted {
|
||||||
|
// s.logger.Error("Failed to check bet outcome for bet", "event_id", outcome.EventID, "error", err)
|
||||||
|
// }
|
||||||
|
// isDeleted = false
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fmt.Printf("🧾 Updating bet %v - event %v (%d/%d) to %v\n", outcome.BetID, event.ID, j+1, len(outcomes), status.String())
|
||||||
|
// err = s.betSvc.UpdateStatus(ctx, outcome.BetID, status)
|
||||||
|
// if err != nil {
|
||||||
|
// s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
|
||||||
|
// isDeleted = false
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// fmt.Printf("✅ Successfully updated 🎫 Bet %v - event %v(%v) (%d/%d) \n",
|
||||||
|
// outcome.BetID,
|
||||||
|
// event.HomeTeam+" "+event.AwayTeam, event.ID,
|
||||||
|
// j+1, len(outcomes))
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
fmt.Printf("🗑️ Removed Events: %d \n", removed)
|
s.logger.Info("Total Number of Removed Events", "count", removed)
|
||||||
if len(errs) > 0 {
|
|
||||||
s.logger.Error("Errors occurred while processing results", "errors", errs)
|
|
||||||
for _, err := range errs {
|
|
||||||
fmt.Println("Error:", err)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("errors occurred while processing results: %v", errs)
|
|
||||||
}
|
|
||||||
s.logger.Info("Successfully processed results", "removed_events", removed, "total_events", len(events))
|
s.logger.Info("Successfully processed results", "removed_events", removed, "total_events", len(events))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -211,10 +357,9 @@ func (s *Service) CheckAndUpdateExpiredEvents(ctx context.Context) (int64, error
|
||||||
s.logger.Error("Failed to fetch events")
|
s.logger.Error("Failed to fetch events")
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
fmt.Printf("⚠️ Expired Events: %d \n", len(events))
|
|
||||||
updated := 0
|
updated := 0
|
||||||
for i, event := range events {
|
for _, event := range events {
|
||||||
fmt.Printf("⚙️ Processing event %v (%d/%d) \n", event.ID, i+1, len(events))
|
// fmt.Printf("⚙️ Processing event %v (%d/%d) \n", event.ID, i+1, len(events))
|
||||||
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to parse event id")
|
s.logger.Error("Failed to parse event id")
|
||||||
|
|
@ -232,7 +377,6 @@ func (s *Service) CheckAndUpdateExpiredEvents(ctx context.Context) (int64, error
|
||||||
}
|
}
|
||||||
if result.Success != 1 || len(result.Results) == 0 {
|
if result.Success != 1 || len(result.Results) == 0 {
|
||||||
s.logger.Error("Invalid API response", "event_id", eventID)
|
s.logger.Error("Invalid API response", "event_id", eventID)
|
||||||
fmt.Printf("⚠️ Invalid API response for event %v \n", result)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,12 +426,13 @@ func (s *Service) CheckAndUpdateExpiredEvents(ctx context.Context) (int64, error
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
updated++
|
updated++
|
||||||
fmt.Printf("✅ Successfully updated event %v to %v (%d/%d) \n", event.ID, eventStatus, i+1, len(events))
|
// fmt.Printf("✅ Successfully updated event %v to %v (%d/%d) \n", event.ID, eventStatus, i+1, len(events))
|
||||||
|
s.logger.Info("Updated Event Status", "event ID", event.ID, "status", eventStatus)
|
||||||
// Update the league because the league country code is only found on the result response
|
// Update the league because the league country code is only found on the result response
|
||||||
leagueID, err := strconv.ParseInt(commonResp.League.ID, 10, 64)
|
leagueID, err := strconv.ParseInt(commonResp.League.ID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("❌ Invalid league id, leagueID %v", commonResp.League.ID)
|
// log.Printf("❌ Invalid league id, leagueID %v", commonResp.League.ID)
|
||||||
|
s.logger.Error("Invalid League ID", "leagueID", commonResp.League.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -304,12 +449,11 @@ func (s *Service) CheckAndUpdateExpiredEvents(ctx context.Context) (int64, error
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("❌ Error Updating League %v", commonResp.League.Name)
|
s.logger.Error("Error Updating League", "League Name", commonResp.League.Name, "err", err)
|
||||||
log.Printf("err:%v", err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("✅ Updated League %v with country code %v \n", leagueID, commonResp.League.CC)
|
// fmt.Printf("✅ Updated League %v with country code %v \n", leagueID, commonResp.League.CC)
|
||||||
|
s.logger.Info("Updated League with country code", "leagueID", leagueID, "code", commonResp.League.CC)
|
||||||
}
|
}
|
||||||
|
|
||||||
if updated == 0 {
|
if updated == 0 {
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ func (s *AleaPlayService) processTransaction(ctx context.Context, tx *domain.Vir
|
||||||
}
|
}
|
||||||
tx.WalletID = wallets[0].ID
|
tx.WalletID = wallets[0].ID
|
||||||
|
|
||||||
if err := s.walletSvc.AddToWallet(ctx, tx.WalletID, domain.Currency(tx.Amount)); err != nil {
|
if _, err := s.walletSvc.AddToWallet(ctx, tx.WalletID, domain.Currency(tx.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil {
|
||||||
return fmt.Errorf("wallet update failed: %w", err)
|
return fmt.Errorf("wallet update failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ func (s *service) HandleCallback(ctx context.Context, callback *domain.PopOKCall
|
||||||
return errors.New("unknown transaction type")
|
return errors.New("unknown transaction type")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(amount))
|
_, err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update wallet", "walletID", walletID, "userID", session.UserID, "amount", amount, "error", err)
|
s.logger.Error("Failed to update wallet", "walletID", walletID, "userID", session.UserID, "amount", amount, "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -202,7 +202,7 @@ func (s *service) ProcessBet(ctx context.Context, req *domain.PopOKBetRequest) (
|
||||||
return &domain.PopOKBetResponse{}, fmt.Errorf("Failed to read user wallets")
|
return &domain.PopOKBetResponse{}, fmt.Errorf("Failed to read user wallets")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.walletSvc.DeductFromWallet(ctx, claims.UserID, domain.Currency(amountCents)); err != nil {
|
if _, err := s.walletSvc.DeductFromWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT); err != nil {
|
||||||
return nil, fmt.Errorf("insufficient balance")
|
return nil, fmt.Errorf("insufficient balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@ func (s *service) ProcessWin(ctx context.Context, req *domain.PopOKWinRequest) (
|
||||||
|
|
||||||
// 4. Credit to wallet
|
// 4. Credit to wallet
|
||||||
|
|
||||||
if err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents)); err != nil {
|
if _, err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil {
|
||||||
s.logger.Error("Failed to credit wallet", "userID", claims.UserID, "error", err)
|
s.logger.Error("Failed to credit wallet", "userID", claims.UserID, "error", err)
|
||||||
return nil, fmt.Errorf("wallet credit failed")
|
return nil, fmt.Errorf("wallet credit failed")
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +334,7 @@ func (s *service) ProcessCancel(ctx context.Context, req *domain.PopOKCancelRequ
|
||||||
// 5. Refund the bet amount (absolute value since bet amount is negative)
|
// 5. Refund the bet amount (absolute value since bet amount is negative)
|
||||||
refundAmount := -originalBet.Amount
|
refundAmount := -originalBet.Amount
|
||||||
|
|
||||||
if err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(refundAmount)); err != nil {
|
if _, err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(refundAmount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil {
|
||||||
s.logger.Error("Failed to refund bet", "userID", claims.UserID, "error", err)
|
s.logger.Error("Failed to refund bet", "userID", claims.UserID, "error", err)
|
||||||
return nil, fmt.Errorf("refund failed")
|
return nil, fmt.Errorf("refund failed")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,85 +14,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
func (s *Service) CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
||||||
senderWallet, err := s.walletStore.GetWalletByID(ctx, transfer.SenderWalletID)
|
// This is just a transfer log when
|
||||||
receiverWallet, err := s.walletStore.GetWalletByID(ctx, transfer.ReceiverWalletID)
|
|
||||||
if err != nil {
|
|
||||||
return domain.Transfer{}, fmt.Errorf("failed to get sender wallet: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if wallet has sufficient balance
|
|
||||||
if senderWallet.Balance < transfer.Amount || senderWallet.Balance == 0 {
|
|
||||||
// Send notification to customer
|
|
||||||
customerNotification := &domain.Notification{
|
|
||||||
RecipientID: receiverWallet.UserID,
|
|
||||||
Type: domain.NOTIFICATION_TYPE_TRANSFER,
|
|
||||||
Level: domain.NotificationLevelError,
|
|
||||||
Reciever: domain.NotificationRecieverSideCustomer,
|
|
||||||
DeliveryChannel: domain.DeliveryChannelInApp,
|
|
||||||
Payload: domain.NotificationPayload{
|
|
||||||
Headline: "Service Temporarily Unavailable",
|
|
||||||
Message: "Our payment system is currently under maintenance. Please try again later.",
|
|
||||||
},
|
|
||||||
Priority: 2,
|
|
||||||
Metadata: []byte(fmt.Sprintf(`{
|
|
||||||
"transfer_amount": %d,
|
|
||||||
"current_balance": %d,
|
|
||||||
"wallet_id": %d,
|
|
||||||
"notification_type": "customer_facing"
|
|
||||||
}`, transfer.Amount, senderWallet.Balance, transfer.SenderWalletID)),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send notification to admin team
|
|
||||||
adminNotification := &domain.Notification{
|
|
||||||
RecipientID: senderWallet.UserID,
|
|
||||||
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
|
||||||
Level: domain.NotificationLevelError,
|
|
||||||
Reciever: domain.NotificationRecieverSideAdmin,
|
|
||||||
DeliveryChannel: domain.DeliveryChannelEmail, // Or any preferred admin channel
|
|
||||||
Payload: domain.NotificationPayload{
|
|
||||||
Headline: "CREDIT WARNING: System Running Out of Funds",
|
|
||||||
Message: fmt.Sprintf(
|
|
||||||
"Wallet ID %d has insufficient balance for transfer. Current balance: %.2f, Attempted transfer: %.2f",
|
|
||||||
transfer.SenderWalletID,
|
|
||||||
float64(senderWallet.Balance)/100,
|
|
||||||
float64(transfer.Amount)/100,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
Priority: 1, // High priority for admin alerts
|
|
||||||
Metadata: fmt.Appendf(nil, `{
|
|
||||||
"wallet_id": %d,
|
|
||||||
"balance": %d,
|
|
||||||
"required_amount": %d,
|
|
||||||
"notification_type": "admin_alert"
|
|
||||||
}`, transfer.SenderWalletID, senderWallet.Balance, transfer.Amount),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send both notifications
|
|
||||||
if err := s.notificationStore.SendNotification(ctx, customerNotification); err != nil {
|
|
||||||
s.logger.Error("failed to send customer notification",
|
|
||||||
"user_id", "",
|
|
||||||
"error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get admin recipients and send to all
|
|
||||||
adminRecipients, err := s.notificationStore.ListRecipientIDs(ctx, domain.NotificationRecieverSideAdmin)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("failed to get admin recipients", "error", err)
|
|
||||||
} else {
|
|
||||||
for _, adminID := range adminRecipients {
|
|
||||||
adminNotification.RecipientID = adminID
|
|
||||||
if err := s.notificationStore.SendNotification(ctx, adminNotification); err != nil {
|
|
||||||
s.logger.Error("failed to send admin notification",
|
|
||||||
"admin_id", adminID,
|
|
||||||
"error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Transfer{}, ErrInsufficientBalance
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proceed with transfer if balance is sufficient
|
|
||||||
return s.transferStore.CreateTransfer(ctx, transfer)
|
return s.transferStore.CreateTransfer(ctx, transfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,43 +42,10 @@ func (s *Service) UpdateTransferStatus(ctx context.Context, id int64, status str
|
||||||
return s.transferStore.UpdateTransferStatus(ctx, id, status)
|
return s.transferStore.UpdateTransferStatus(ctx, id, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiverID int64,
|
||||||
senderWallet, err := s.GetWalletByID(ctx, transfer.SenderWalletID)
|
amount domain.Currency, paymentMethod domain.PaymentMethod,
|
||||||
if err != nil {
|
cashierID domain.ValidInt64) (domain.Transfer, error) {
|
||||||
return domain.Transfer{}, err
|
|
||||||
} else if senderWallet.Balance < transfer.Amount {
|
|
||||||
return domain.Transfer{}, ErrInsufficientBalance
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
senderWallet, err := s.GetWalletByID(ctx, senderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -195,10 +84,16 @@ func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the transfer so that if there is a mistake, it can be reverted
|
// Log the transfer so that if there is a mistake, it can be reverted
|
||||||
transfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
transfer, err := s.CreateTransfer(ctx, domain.CreateTransfer{
|
||||||
SenderWalletID: senderID,
|
SenderWalletID: domain.ValidInt64{
|
||||||
|
Value: senderID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
ReceiverWalletID: domain.ValidInt64{
|
||||||
|
Value: receiverID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
CashierID: cashierID,
|
CashierID: cashierID,
|
||||||
ReceiverWalletID: receiverID,
|
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
Type: domain.WALLET,
|
Type: domain.WALLET,
|
||||||
PaymentMethod: paymentMethod,
|
PaymentMethod: paymentMethod,
|
||||||
|
|
@ -210,3 +105,66 @@ func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiver
|
||||||
|
|
||||||
return transfer, nil
|
return transfer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendTransferNotification(ctx context.Context, senderWallet domain.Wallet, receiverWallet domain.Wallet,
|
||||||
|
senderRole domain.Role, receiverRole domain.Role, amount domain.Currency) error {
|
||||||
|
// Send notification to sender (this could be any role) that money was transferred
|
||||||
|
senderWalletReceiverSide := domain.ReceiverFromRole(senderRole)
|
||||||
|
|
||||||
|
senderNotify := &domain.Notification{
|
||||||
|
RecipientID: senderWallet.UserID,
|
||||||
|
Type: domain.NOTIFICATION_TYPE_TRANSFER_SUCCESS,
|
||||||
|
Level: domain.NotificationLevelSuccess,
|
||||||
|
Reciever: senderWalletReceiverSide,
|
||||||
|
DeliveryChannel: domain.DeliveryChannelInApp,
|
||||||
|
Payload: domain.NotificationPayload{
|
||||||
|
Headline: "Wallet has been deducted",
|
||||||
|
Message: fmt.Sprintf(`ETB %d has been transferred from your wallet`),
|
||||||
|
},
|
||||||
|
Priority: 2,
|
||||||
|
Metadata: []byte(fmt.Sprintf(`{
|
||||||
|
"transfer_amount": %d,
|
||||||
|
"current_balance": %d,
|
||||||
|
"wallet_id": %d,
|
||||||
|
"notification_type": "customer_facing"
|
||||||
|
}`, amount, senderWallet.Balance, senderWallet.ID)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sender notifications
|
||||||
|
if err := s.notificationStore.SendNotification(ctx, senderNotify); err != nil {
|
||||||
|
s.logger.Error("failed to send sender notification",
|
||||||
|
"user_id", "",
|
||||||
|
"error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
receiverWalletReceiverSide := domain.ReceiverFromRole(receiverRole)
|
||||||
|
|
||||||
|
receiverNotify := &domain.Notification{
|
||||||
|
RecipientID: receiverWallet.UserID,
|
||||||
|
Type: domain.NOTIFICATION_TYPE_TRANSFER_SUCCESS,
|
||||||
|
Level: domain.NotificationLevelSuccess,
|
||||||
|
Reciever: receiverWalletReceiverSide,
|
||||||
|
DeliveryChannel: domain.DeliveryChannelInApp,
|
||||||
|
Payload: domain.NotificationPayload{
|
||||||
|
Headline: "Wallet has been credited",
|
||||||
|
Message: fmt.Sprintf(`ETB %d has been transferred to your wallet`),
|
||||||
|
},
|
||||||
|
Priority: 2,
|
||||||
|
Metadata: []byte(fmt.Sprintf(`{
|
||||||
|
"transfer_amount": %d,
|
||||||
|
"current_balance": %d,
|
||||||
|
"wallet_id": %d,
|
||||||
|
"notification_type": "customer_facing"
|
||||||
|
}`, amount, receiverWallet.Balance, receiverWallet.ID)),
|
||||||
|
}
|
||||||
|
// Sender notifications
|
||||||
|
if err := s.notificationStore.SendNotification(ctx, receiverNotify); err != nil {
|
||||||
|
s.logger.Error("failed to send sender notification",
|
||||||
|
"user_id", "",
|
||||||
|
"error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package wallet
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
@ -68,28 +69,152 @@ func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Cu
|
||||||
return s.walletStore.UpdateBalance(ctx, id, balance)
|
return s.walletStore.UpdateBalance(ctx, id, balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) AddToWallet(ctx context.Context, id int64, amount domain.Currency) error {
|
func (s *Service) AddToWallet(
|
||||||
|
ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, paymentDetails domain. PaymentDetails) (domain.Transfer, error) {
|
||||||
wallet, err := s.GetWalletByID(ctx, id)
|
wallet, err := s.GetWalletByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return domain.Transfer{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the transfer here for reference
|
||||||
|
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
||||||
|
Amount: amount,
|
||||||
|
Verified: true,
|
||||||
|
ReceiverWalletID: domain.ValidInt64{
|
||||||
|
Value: wallet.ID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
CashierID: cashierID,
|
||||||
|
PaymentMethod: paymentMethod,
|
||||||
|
Type: domain.DEPOSIT,
|
||||||
|
ReferenceNumber: paymentDetails.ReferenceNumber.Value,
|
||||||
|
})
|
||||||
|
|
||||||
|
return newTransfer, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.Currency) error {
|
func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.Currency, walletType domain.WalletType, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod) (domain.Transfer, error) {
|
||||||
wallet, err := s.GetWalletByID(ctx, id)
|
wallet, err := s.GetWalletByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return domain.Transfer{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if wallet.Balance < amount {
|
if wallet.Balance < amount {
|
||||||
return ErrBalanceInsufficient
|
// Send Wallet low to admin
|
||||||
|
if walletType == domain.CompanyWalletType || walletType == domain.BranchWalletType {
|
||||||
|
s.SendAdminWalletLowNotification(ctx, wallet, amount)
|
||||||
|
}
|
||||||
|
return domain.Transfer{}, ErrBalanceInsufficient
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.walletStore.UpdateBalance(ctx, id, wallet.Balance-amount)
|
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance-amount)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return domain.Transfer{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the transfer here for reference
|
||||||
|
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
||||||
|
Amount: amount,
|
||||||
|
Verified: true,
|
||||||
|
SenderWalletID: domain.ValidInt64{
|
||||||
|
Value: wallet.ID,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
CashierID: cashierID,
|
||||||
|
PaymentMethod: paymentMethod,
|
||||||
|
Type: domain.WITHDRAW,
|
||||||
|
ReferenceNumber: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
return newTransfer, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Directly Refilling wallet without
|
||||||
|
// 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
|
||||||
|
// senderWallet, err := s.GetWalletByID(ctx, transfer.SenderWalletID)
|
||||||
|
// if err != nil {
|
||||||
|
// return domain.Transfer{}, err
|
||||||
|
// } else if senderWallet.Balance < transfer.Amount {
|
||||||
|
// return domain.Transfer{}, ErrInsufficientBalance
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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: transfer.ReceiverWalletID,
|
||||||
|
// Amount: transfer.Amount,
|
||||||
|
// Type: domain.DEPOSIT,
|
||||||
|
// PaymentMethod: transfer.PaymentMethod,
|
||||||
|
// Verified: true,
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// return domain.Transfer{}, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return newTransfer, nil
|
||||||
|
// }
|
||||||
|
|
||||||
func (s *Service) UpdateWalletActive(ctx context.Context, id int64, isActive bool) error {
|
func (s *Service) UpdateWalletActive(ctx context.Context, id int64, isActive bool) error {
|
||||||
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWallet domain.Wallet, amount domain.Currency) error {
|
||||||
|
// Send notification to admin team
|
||||||
|
adminNotification := &domain.Notification{
|
||||||
|
RecipientID: adminWallet.UserID,
|
||||||
|
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
||||||
|
Level: domain.NotificationLevelError,
|
||||||
|
Reciever: domain.NotificationRecieverSideAdmin,
|
||||||
|
DeliveryChannel: domain.DeliveryChannelEmail, // Or any preferred admin channel
|
||||||
|
Payload: domain.NotificationPayload{
|
||||||
|
Headline: "CREDIT WARNING: System Running Out of Funds",
|
||||||
|
Message: fmt.Sprintf(
|
||||||
|
"Wallet ID %d has insufficient balance for transfer. Current balance: %.2f, Attempted transfer: %.2f",
|
||||||
|
adminWallet.ID,
|
||||||
|
adminWallet.Balance.Float32(),
|
||||||
|
amount.Float32(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Priority: 1, // High priority for admin alerts
|
||||||
|
Metadata: fmt.Appendf(nil, `{
|
||||||
|
"wallet_id": %d,
|
||||||
|
"balance": %d,
|
||||||
|
"required_amount": %d,
|
||||||
|
"notification_type": "admin_alert"
|
||||||
|
}`, adminWallet.ID, adminWallet.Balance, amount),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get admin recipients and send to all
|
||||||
|
adminRecipients, err := s.notificationStore.ListRecipientIDs(ctx, domain.NotificationRecieverSideAdmin)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("failed to get admin recipients", "error", err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
for _, adminID := range adminRecipients {
|
||||||
|
adminNotification.RecipientID = adminID
|
||||||
|
if err := s.notificationStore.SendNotification(ctx, adminNotification); err != nil {
|
||||||
|
s.logger.Error("failed to send admin notification",
|
||||||
|
"admin_id", adminID,
|
||||||
|
"error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,22 +46,22 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
spec string
|
spec string
|
||||||
task func()
|
task func()
|
||||||
}{
|
}{
|
||||||
{
|
// {
|
||||||
spec: "0 0 * * * *", // Every 1 hour
|
// spec: "0 0 * * * *", // Every 1 hour
|
||||||
task: func() {
|
// task: func() {
|
||||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
log.Printf("FetchUpcomingEvents error: %v", err)
|
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
spec: "0 0 * * * *", // Every 15 minutes
|
// spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
|
||||||
task: func() {
|
// task: func() {
|
||||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
log.Printf("FetchNonLiveOdds error: %v", err)
|
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
spec: "0 */5 * * * *", // Every 5 Minutes
|
spec: "0 */5 * * * *", // Every 5 Minutes
|
||||||
task: func() {
|
task: func() {
|
||||||
|
|
@ -89,7 +89,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
// job.task()
|
job.task()
|
||||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,14 @@ type loginCustomerRes struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /auth/login [post]
|
// @Router /auth/login [post]
|
||||||
func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
|
|
||||||
var req loginCustomerReq
|
var req loginCustomerReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.logger.Error("Failed to parse LoginCustomer request", "error", err)
|
h.logger.Error("Failed to parse LoginCustomer request", "error", err)
|
||||||
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 {
|
if _, ok := h.validator.Validate(c, req); !ok {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Request")
|
||||||
}
|
}
|
||||||
|
|
||||||
successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password)
|
successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -24,7 +23,6 @@ import (
|
||||||
// @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 {
|
||||||
fmt.Printf("Calling leagues")
|
|
||||||
// Get user_id from middleware
|
// Get user_id from middleware
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
role := c.Locals("role").(domain.Role)
|
role := c.Locals("role").(domain.Role)
|
||||||
|
|
@ -160,12 +158,29 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /bet [get]
|
// @Router /bet [get]
|
||||||
func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
// role := c.Locals("role").(domain.Role)
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
branchID := c.Locals("branch_id").(domain.ValidInt64)
|
branchID := c.Locals("branch_id").(domain.ValidInt64)
|
||||||
|
|
||||||
|
var isShopBet domain.ValidBool
|
||||||
|
isShopBetQuery := c.Query("is_shop")
|
||||||
|
|
||||||
|
|
||||||
|
if isShopBetQuery != "" {
|
||||||
|
isShopBetParse, err := strconv.ParseBool(isShopBetQuery)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_shop_bet")
|
||||||
|
}
|
||||||
|
isShopBet = domain.ValidBool{
|
||||||
|
Value: isShopBetParse,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{
|
bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{
|
||||||
BranchID: branchID,
|
BranchID: branchID,
|
||||||
CompanyID: companyID,
|
CompanyID: companyID,
|
||||||
|
IsShopBet: isShopBet,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Failed to get bets", "error", err)
|
h.logger.Error("Failed to get bets", "error", err)
|
||||||
|
|
|
||||||
|
|
@ -382,8 +382,23 @@ func (h *Handler) GetBranchByCompanyID(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /branch [get]
|
// @Router /branch [get]
|
||||||
func (h *Handler) GetAllBranches(c *fiber.Ctx) error {
|
func (h *Handler) GetAllBranches(c *fiber.Ctx) error {
|
||||||
// TODO: Limit the get all branches to only the companies for branch manager and cashiers
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
branches, err := h.branchSvc.GetAllBranches(c.Context())
|
isActiveParam := c.Params("is_active")
|
||||||
|
isActiveValid := isActiveParam != ""
|
||||||
|
isActive, err := strconv.ParseBool(isActiveParam)
|
||||||
|
|
||||||
|
if isActiveValid && err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid is_active param", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
branches, err := h.branchSvc.GetAllBranches(c.Context(),
|
||||||
|
domain.BranchFilter{
|
||||||
|
CompanyID: companyID,
|
||||||
|
IsSuspended: domain.ValidBool{
|
||||||
|
Value: isActive,
|
||||||
|
Valid: isActiveValid,
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Failed to get branches", "error", err)
|
h.logger.Error("Failed to get branches", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get branches", err, nil)
|
||||||
|
|
|
||||||
|
|
@ -106,3 +106,32 @@ func (h *Handler) SetLeagueActive(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) SetLeagueAsFeatured(c *fiber.Ctx) error {
|
||||||
|
fmt.Printf("Set Active Leagues")
|
||||||
|
leagueIdStr := c.Params("id")
|
||||||
|
if leagueIdStr == "" {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "Missing league id", nil, nil)
|
||||||
|
}
|
||||||
|
leagueId, err := strconv.Atoi(leagueIdStr)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteJSON(c, fiber.StatusBadRequest, "invalid league id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var req SetLeagueActiveReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.logger.Error("SetLeagueReq failed", "error", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to parse request", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := h.validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.leagueSvc.SetLeagueActive(c.Context(), int64(leagueId), req.IsActive); err != nil {
|
||||||
|
response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update league", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
||||||
role := c.Locals("role").(domain.Role)
|
role := c.Locals("role").(domain.Role)
|
||||||
companyId := c.Locals("company_id").(domain.ValidInt64)
|
companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
|
||||||
|
// Checking to make sure that admin user has a company id in the token
|
||||||
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
|
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
|
||||||
}
|
}
|
||||||
|
|
@ -182,32 +183,38 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /managers/{id} [get]
|
// @Router /managers/{id} [get]
|
||||||
func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
|
func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
|
||||||
// branchId := int64(12) //c.Locals("branch_id").(int64)
|
role := c.Locals("role").(domain.Role)
|
||||||
// filter := user.Filter{
|
companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||||
// Role: string(domain.RoleUser),
|
requestUserID := c.Locals("user_id").(int64)
|
||||||
// BranchId: user.ValidBranchId{
|
|
||||||
// Value: branchId,
|
// Only Super Admin / Admin / Branch Manager can view this route
|
||||||
// Valid: true,
|
if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager {
|
||||||
// },
|
return fiber.NewError(fiber.StatusUnauthorized, "Role Unauthorized")
|
||||||
// Page: c.QueryInt("page", 1),
|
}
|
||||||
// PageSize: c.QueryInt("page_size", 10),
|
|
||||||
// }
|
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
||||||
// valErrs, ok := validator.Validate(c, filter)
|
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
|
||||||
// if !ok {
|
}
|
||||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
|
||||||
// }
|
|
||||||
|
|
||||||
userIDstr := c.Params("id")
|
userIDstr := c.Params("id")
|
||||||
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("failed to fetch user using UserID", "error", err)
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid managers ID")
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid managers ID", nil, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Get User By ID failed", "error", err)
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers")
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get managers", nil, nil)
|
}
|
||||||
|
|
||||||
|
// A Branch Manager can only fetch his own branch info
|
||||||
|
if role == domain.RoleBranchManager && user.ID != requestUserID {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "User Access Not Allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that only admin from company can view this route
|
||||||
|
if role != domain.RoleSuperAdmin && user.CompanyID.Value != companyId.Value {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Only company user can view manager info")
|
||||||
}
|
}
|
||||||
|
|
||||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
||||||
|
|
@ -259,7 +266,9 @@ type updateManagerReq struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /managers/{id} [put]
|
// @Router /managers/{id} [put]
|
||||||
func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
|
func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
|
||||||
|
|
||||||
var req updateManagerReq
|
var req updateManagerReq
|
||||||
|
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.logger.Error("UpdateManagers failed", "error", err)
|
h.logger.Error("UpdateManagers failed", "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,8 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
|
rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to fetch raw odds: %v market_id:%v upcomingID:%v\n", err, marketID, upcomingID)
|
// fmt.Printf("Failed to fetch raw odds: %v market_id:%v upcomingID:%v\n", err, marketID, upcomingID)
|
||||||
h.logger.Error("failed to fetch raw odds", "error", err)
|
h.logger.Error("Failed to get raw odds by market ID", "marketID", marketID, "upcomingID", upcomingID, "error", err)
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,6 +172,62 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TopLeaguesRes struct {
|
||||||
|
Leagues []TopLeague `json:"leagues"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TopLeague struct {
|
||||||
|
LeagueID int64 `json:"league_id"`
|
||||||
|
LeagueName string `json:"league_name"`
|
||||||
|
Events []domain.UpcomingEvent `json:"events"`
|
||||||
|
// Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Retrieve all top leagues
|
||||||
|
// @Description Retrieve all top leagues
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.UpcomingEvent
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /top-leagues [get]
|
||||||
|
func (h *Handler) GetTopLeagues(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
leagues, err := h.leagueSvc.GetFeaturedLeagues(c.Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Error while fetching top leagues", "err", err)
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get featured leagues", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var topLeague []TopLeague = make([]TopLeague, 0, len(leagues))
|
||||||
|
for _, league := range leagues {
|
||||||
|
events, _, err := h.eventSvc.GetPaginatedUpcomingEvents(
|
||||||
|
c.Context(), domain.EventFilter{
|
||||||
|
LeagueID: domain.ValidInt32{
|
||||||
|
Value: int32(league.ID),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error while fetching events for top league %v \n", league.ID)
|
||||||
|
h.logger.Error("Error while fetching events for top league", "League ID", league.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
topLeague = append(topLeague, TopLeague{
|
||||||
|
LeagueID: league.ID,
|
||||||
|
LeagueName: league.Name,
|
||||||
|
Events: events,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res := TopLeaguesRes{
|
||||||
|
Leagues: topLeague,
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All top leagues events retrieved successfully", res, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Retrieve an upcoming by ID
|
// @Summary Retrieve an upcoming by ID
|
||||||
// @Description Retrieve an upcoming event by ID
|
// @Description Retrieve an upcoming event by ID
|
||||||
// @Tags prematch
|
// @Tags prematch
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ type TransferWalletRes struct {
|
||||||
Verified bool `json:"verified" example:"true"`
|
Verified bool `json:"verified" example:"true"`
|
||||||
Type string `json:"type" example:"transfer"`
|
Type string `json:"type" example:"transfer"`
|
||||||
PaymentMethod string `json:"payment_method" example:"bank"`
|
PaymentMethod string `json:"payment_method" example:"bank"`
|
||||||
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
|
ReceiverWalletID *int64 `json:"receiver_wallet_id" example:"1"`
|
||||||
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
||||||
CashierID *int64 `json:"cashier_id" example:"789"`
|
CashierID *int64 `json:"cashier_id" example:"789"`
|
||||||
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
||||||
|
|
@ -27,7 +27,7 @@ type RefillRes struct {
|
||||||
Verified bool `json:"verified" example:"true"`
|
Verified bool `json:"verified" example:"true"`
|
||||||
Type string `json:"type" example:"transfer"`
|
Type string `json:"type" example:"transfer"`
|
||||||
PaymentMethod string `json:"payment_method" example:"bank"`
|
PaymentMethod string `json:"payment_method" example:"bank"`
|
||||||
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
|
ReceiverWalletID *int64 `json:"receiver_wallet_id" example:"1"`
|
||||||
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
||||||
CashierID *int64 `json:"cashier_id" example:"789"`
|
CashierID *int64 `json:"cashier_id" example:"789"`
|
||||||
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
||||||
|
|
@ -35,13 +35,20 @@ type RefillRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertTransfer(transfer domain.Transfer) TransferWalletRes {
|
func convertTransfer(transfer domain.Transfer) TransferWalletRes {
|
||||||
var senderWalletID *int64
|
|
||||||
senderWalletID = &transfer.SenderWalletID
|
|
||||||
|
|
||||||
var cashierID *int64
|
var cashierID *int64
|
||||||
if transfer.CashierID.Valid {
|
if transfer.CashierID.Valid {
|
||||||
cashierID = &transfer.CashierID.Value
|
cashierID = &transfer.CashierID.Value
|
||||||
}
|
}
|
||||||
|
var receiverID *int64
|
||||||
|
if transfer.ReceiverWalletID.Valid {
|
||||||
|
receiverID = &transfer.ReceiverWalletID.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
var senderId *int64
|
||||||
|
if transfer.SenderWalletID.Valid {
|
||||||
|
senderId = &transfer.SenderWalletID.Value
|
||||||
|
}
|
||||||
|
|
||||||
return TransferWalletRes{
|
return TransferWalletRes{
|
||||||
ID: transfer.ID,
|
ID: transfer.ID,
|
||||||
|
|
@ -49,8 +56,8 @@ func convertTransfer(transfer domain.Transfer) TransferWalletRes {
|
||||||
Verified: transfer.Verified,
|
Verified: transfer.Verified,
|
||||||
Type: string(transfer.Type),
|
Type: string(transfer.Type),
|
||||||
PaymentMethod: string(transfer.PaymentMethod),
|
PaymentMethod: string(transfer.PaymentMethod),
|
||||||
ReceiverWalletID: transfer.ReceiverWalletID,
|
ReceiverWalletID: receiverID,
|
||||||
SenderWalletID: senderWalletID,
|
SenderWalletID: senderId,
|
||||||
CashierID: cashierID,
|
CashierID: cashierID,
|
||||||
CreatedAt: transfer.CreatedAt,
|
CreatedAt: transfer.CreatedAt,
|
||||||
UpdatedAt: transfer.UpdatedAt,
|
UpdatedAt: transfer.UpdatedAt,
|
||||||
|
|
@ -126,16 +133,16 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
// Get sender ID from the cashier
|
// Get sender ID from the cashier
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
role := string(c.Locals("role").(domain.Role))
|
role := c.Locals("role").(domain.Role)
|
||||||
companyID := c.Locals("company_id").(int64)
|
companyID := c.Locals("company_id").(int64)
|
||||||
|
|
||||||
var senderID int64
|
var senderID int64
|
||||||
|
|
||||||
//TODO: check to make sure that the cashiers aren't transferring TO branch wallet
|
//TODO: check to make sure that the cashiers aren't transferring TO branch wallet
|
||||||
if role == string(domain.RoleCustomer) {
|
if role == domain.RoleCustomer {
|
||||||
h.logger.Error("Unauthorized access", "userID", userID, "role", role)
|
h.logger.Error("Unauthorized access", "userID", userID, "role", role)
|
||||||
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||||
} else if role == string(domain.RoleBranchManager) || role == string(domain.RoleAdmin) || role == string(domain.RoleSuperAdmin) {
|
} else if role == domain.RoleBranchManager || role == domain.RoleAdmin || role == domain.RoleSuperAdmin {
|
||||||
company, err := h.companySvc.GetCompanyByID(c.Context(), companyID)
|
company, err := h.companySvc.GetCompanyByID(c.Context(), companyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Error fetching company", err, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Error fetching company", err, nil)
|
||||||
|
|
@ -190,6 +197,7 @@ func (h *Handler) RefillWallet(c *fiber.Ctx) error {
|
||||||
|
|
||||||
receiverIDString := c.Params("id")
|
receiverIDString := c.Params("id")
|
||||||
|
|
||||||
|
userID := c.Locals("user_id").(int64)
|
||||||
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
|
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -197,13 +205,6 @@ func (h *Handler) RefillWallet(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
||||||
}
|
}
|
||||||
// Get sender ID from the cashier
|
// Get sender ID from the cashier
|
||||||
userID := c.Locals("user_id").(int64)
|
|
||||||
role := string(c.Locals("role").(domain.Role))
|
|
||||||
|
|
||||||
if role != string(domain.RoleSuperAdmin) {
|
|
||||||
h.logger.Error("Unauthorized access", "userID", userID, "role", role)
|
|
||||||
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var req CreateRefillReq
|
var req CreateRefillReq
|
||||||
|
|
||||||
|
|
@ -217,16 +218,11 @@ func (h *Handler) RefillWallet(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer, err := h.walletSvc.RefillWallet(c.Context(), domain.CreateTransfer{
|
transfer, err := h.walletSvc.AddToWallet(
|
||||||
Amount: domain.ToCurrency(req.Amount),
|
c.Context(), receiverID, domain.ToCurrency(req.Amount), domain.ValidInt64{
|
||||||
PaymentMethod: domain.TRANSFER_BANK,
|
|
||||||
ReceiverWalletID: receiverID,
|
|
||||||
CashierID: domain.ValidInt64{
|
|
||||||
Value: userID,
|
Value: userID,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
},
|
}, domain.TRANSFER_BANK, domain.PaymentDetails{})
|
||||||
Type: domain.TransferType("deposit"),
|
|
||||||
})
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil)
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,8 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove later
|
// TODO: Remove later
|
||||||
err = h.walletSvc.AddToWallet(c.Context(), newWallet.ID, domain.ToCurrency(100.0))
|
_, err = h.walletSvc.AddToWallet(
|
||||||
|
c.Context(), newWallet.ID, domain.ToCurrency(100.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Failed to update wallet for user", "userID", newUser.ID, "error", err)
|
h.logger.Error("Failed to update wallet for user", "userID", newUser.ID, "error", err)
|
||||||
|
|
@ -416,6 +417,7 @@ func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
|
||||||
users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, req.Role, companyID)
|
users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, req.Role, companyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("SearchUserByNameOrPhone failed", "error", err)
|
h.logger.Error("SearchUserByNameOrPhone failed", "error", err)
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,22 @@ func (a *App) CompanyOnly(c *fiber.Ctx) error {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) OnlyAdminAndAbove(c *fiber.Ctx) error {
|
||||||
|
userRole := c.Locals("role").(domain.Role)
|
||||||
|
if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin {
|
||||||
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token")
|
||||||
|
}
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) OnlyBranchManagerAndAbove(c *fiber.Ctx) error {
|
||||||
|
userRole := c.Locals("role").(domain.Role)
|
||||||
|
if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin && userRole != domain.RoleBranchManager {
|
||||||
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token")
|
||||||
|
}
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) WebsocketAuthMiddleware(c *fiber.Ctx) error {
|
func (a *App) WebsocketAuthMiddleware(c *fiber.Ctx) error {
|
||||||
tokenStr := c.Query("token")
|
tokenStr := c.Query("token")
|
||||||
if tokenStr == "" {
|
if tokenStr == "" {
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Get("/events", h.GetAllUpcomingEvents)
|
a.fiber.Get("/events", h.GetAllUpcomingEvents)
|
||||||
a.fiber.Get("/events/:id", h.GetUpcomingEventByID)
|
a.fiber.Get("/events/:id", h.GetUpcomingEventByID)
|
||||||
a.fiber.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
|
a.fiber.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
|
||||||
|
a.fiber.Get("/top-leagues", h.GetTopLeagues)
|
||||||
|
|
||||||
// Leagues
|
// Leagues
|
||||||
a.fiber.Get("/leagues", h.GetAllLeagues)
|
a.fiber.Get("/leagues", h.GetAllLeagues)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user