enetpulse service + atlas orchestrator

This commit is contained in:
Yared Yemane 2025-09-24 21:00:13 +03:00
commit e41ce709a3
150 changed files with 9049 additions and 3962 deletions

View File

@ -46,6 +46,7 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/messenger" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/messenger"
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification" notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
@ -114,13 +115,11 @@ func main() {
authSvc := authentication.NewService(store, store, cfg.RefreshExpiry) authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
userSvc := user.NewService(store, store, messengerSvc, cfg) userSvc := user.NewService(store, store, messengerSvc, cfg)
eventSvc := event.New(cfg.Bet365Token, store, domain.MongoDBLogger) eventSvc := event.New(cfg.Bet365Token, store, *settingSvc, domain.MongoDBLogger, cfg)
oddsSvc := odds.New(store, cfg, eventSvc, logger, domain.MongoDBLogger) oddsSvc := odds.New(store, cfg, eventSvc, logger, domain.MongoDBLogger)
notificationRepo := repository.NewNotificationRepository(store) notificationRepo := repository.NewNotificationRepository(store)
virtuaGamesRepo := repository.NewVirtualGameRepository(store) virtuaGamesRepo := repository.NewVirtualGameRepository(store)
notificationSvc := notificationservice.New(notificationRepo, domain.MongoDBLogger, logger, cfg, messengerSvc, userSvc) notificationSvc := notificationservice.New(notificationRepo, domain.MongoDBLogger, logger, cfg, messengerSvc, userSvc)
var notificatioStore notificationservice.NotificationStore
// var userStore user.UserStore // var userStore user.UserStore
// Initialize producer // Initialize producer
@ -132,7 +131,6 @@ func main() {
wallet.WalletStore(store), wallet.WalletStore(store),
wallet.TransferStore(store), wallet.TransferStore(store),
wallet.DirectDepositStore(store), wallet.DirectDepositStore(store),
notificatioStore,
notificationSvc, notificationSvc,
userSvc, userSvc,
domain.MongoDBLogger, domain.MongoDBLogger,
@ -145,17 +143,18 @@ func main() {
leagueSvc := league.New(store) leagueSvc := league.New(store)
ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger, *settingSvc, notificationSvc) ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger, *settingSvc, notificationSvc)
betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, *companySvc, *settingSvc, *userSvc, notificationSvc, logger, domain.MongoDBLogger) betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, *companySvc, *settingSvc, *userSvc, notificationSvc, logger, domain.MongoDBLogger)
resultSvc := result.NewService(store, cfg, logger, domain.MongoDBLogger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc, *userSvc) resultSvc := result.NewService(store, cfg, logger, domain.MongoDBLogger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc, messengerSvc, *userSvc)
bonusSvc := bonus.NewService(store) bonusSvc := bonus.NewService(store, walletSvc, settingSvc, notificationSvc, domain.MongoDBLogger)
referalRepo := repository.NewReferralRepository(store) referalRepo := repository.NewReferralRepository(store)
vitualGameRepo := repository.NewVirtualGameRepository(store) vitualGameRepo := repository.NewVirtualGameRepository(store)
recommendationRepo := repository.NewRecommendationRepository(store) recommendationRepo := repository.NewRecommendationRepository(store)
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger) referalSvc := referralservice.New(referalRepo, *walletSvc, *settingSvc, cfg, logger, domain.MongoDBLogger)
raffleSvc := raffle.NewService(store)
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger) virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger) aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
veliCLient := veli.NewClient(cfg, walletSvc) veliCLient := veli.NewClient(cfg, walletSvc)
veliVirtualGameService := veli.New(virtualGameSvc, vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg) veliVirtualGameService := veli.New(virtualGameSvc, vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), domain.MongoDBLogger, cfg)
atlasClient := atlas.NewClient(cfg, walletSvc) atlasClient := atlas.NewClient(cfg, walletSvc)
atlasVirtualGameService := atlas.New(virtualGameSvc, vitualGameRepo, atlasClient, walletSvc, wallet.TransferStore(store), cfg) atlasVirtualGameService := atlas.New(virtualGameSvc, vitualGameRepo, atlasClient, walletSvc, wallet.TransferStore(store), cfg)
recommendationSvc := recommendation.NewService(recommendationRepo) recommendationSvc := recommendation.NewService(recommendationRepo)
@ -285,6 +284,7 @@ func main() {
eventSvc, eventSvc,
leagueSvc, leagueSvc,
referalSvc, referalSvc,
raffleSvc,
bonusSvc, bonusSvc,
virtualGameSvc, virtualGameSvc,
aleaService, aleaService,

View File

@ -0,0 +1,379 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Locations Initial Data
INSERT INTO branch_locations (key, value)
VALUES ('addis_ababa', 'Addis Ababa'),
('dire_dawa', 'Dire Dawa'),
('mekelle', 'Mekelle'),
('adama', 'Adama'),
('awassa', 'Awassa'),
('bahir_dar', 'Bahir Dar'),
('gonder', 'Gonder'),
('dessie', 'Dessie'),
('jimma', 'Jimma'),
('jijiga', 'Jijiga'),
('shashamane', 'Shashamane'),
('bishoftu', 'Bishoftu'),
('sodo', 'Sodo'),
('arba_minch', 'Arba Minch'),
('hosaena', 'Hosaena'),
('harar', 'Harar'),
('dilla', 'Dilla'),
('nekemte', 'Nekemte'),
('debre_birhan', 'Debre Birhan'),
('asella', 'Asella'),
('debre_markos', 'Debre Markos'),
('kombolcha', 'Kombolcha'),
('debre_tabor', 'Debre Tabor'),
('adigrat', 'Adigrat'),
('areka', 'Areka'),
('weldiya', 'Weldiya'),
('sebeta', 'Sebeta'),
('burayu', 'Burayu'),
('shire', 'Shire'),
('ambo', 'Ambo'),
('arsi_negele', 'Arsi Negele'),
('aksum', 'Aksum'),
('gambela', 'Gambela'),
('bale_robe', 'Bale Robe'),
('butajira', 'Butajira'),
('batu', 'Batu'),
('boditi', 'Boditi'),
('adwa', 'Adwa'),
('yirgalem', 'Yirgalem'),
('waliso', 'Waliso'),
('welkite', 'Welkite'),
('gode', 'Gode'),
('meki', 'Meki'),
('negele_borana', 'Negele Borana'),
('alaba_kulito', 'Alaba Kulito'),
('alamata,', 'Alamata,'),
('chiro', 'Chiro'),
('tepi', 'Tepi'),
('durame', 'Durame'),
('goba', 'Goba'),
('assosa', 'Assosa'),
('gimbi', 'Gimbi'),
('wukro', 'Wukro'),
('haramaya', 'Haramaya'),
('mizan_teferi', 'Mizan Teferi'),
('sawla', 'Sawla'),
('mojo', 'Mojo'),
('dembi_dolo', 'Dembi Dolo'),
('aleta_wendo', 'Aleta Wendo'),
('metu', 'Metu'),
('mota', 'Mota'),
('fiche', 'Fiche'),
('finote_selam', 'Finote Selam'),
('bule_hora_town', 'Bule Hora Town'),
('bonga', 'Bonga'),
('kobo', 'Kobo'),
('jinka', 'Jinka'),
('dangila', 'Dangila'),
('degehabur', 'Degehabur'),
('bedessa', 'Bedessa'),
('agaro', 'Agaro') ON CONFLICT (key) DO
UPDATE
SET value = EXCLUDED.value;
-- Settings Initial Data
INSERT INTO global_settings (key, value)
VALUES ('sms_provider', 'afro_message'),
('max_number_of_outcomes', '30'),
('bet_amount_limit', '10000000'),
('daily_ticket_limit', '50'),
('total_winnings_limit', '1000000'),
('amount_for_bet_referral', '1000000'),
('cashback_amount_cap', '1000'),
('default_winning_limit', '5000000'),
('referral_reward_amount', '10000'),
('cashback_percentage', '0.2'),
('default_max_referrals', '15'),
('minimum_bet_amount', '100'),
('bet_duplicate_limit', '5'),
('send_email_on_bet_finish', 'true'),
('send_sms_on_bet_finish', 'false'),
('welcome_bonus_active', 'false'),
('welcome_bonus_multiplier', '1.5'),
('welcome_bonus_cap', '100000'),
('welcome_bonus_count', '3'),
('welcome_bonus_expiry', '10') ON CONFLICT (key) DO NOTHING;
-- Users
INSERT INTO users (
id,
first_name,
last_name,
email,
phone_number,
password,
role,
email_verified,
phone_verified,
created_at,
updated_at,
suspended,
company_id
)
VALUES (
1,
'John',
'Doe',
'john.doe@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
),
(
2,
'Test',
'Admin',
'test.admin@gmail.com',
'0988554466',
crypt('password@123', gen_salt('bf'))::bytea,
'admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
),
(
3,
'Samuel',
'Tariku',
'cybersamt@gmail.com',
'0911111111',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
4,
'Kirubel',
'Kibru',
'kirubel.jkl679@gmail.com',
'0911554486',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
) ON CONFLICT (id) DO
UPDATE
SET first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
email = EXCLUDED.email,
phone_number = EXCLUDED.phone_number,
password = EXCLUDED.password,
role = EXCLUDED.role,
email_verified = EXCLUDED.email_verified,
phone_verified = EXCLUDED.phone_verified,
created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at,
suspended = EXCLUDED.suspended,
company_id = EXCLUDED.company_id;
-- Supported Operations
INSERT INTO supported_operations (id, name, description)
VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations') ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
description = EXCLUDED.description;
-- Wallets
INSERT INTO wallets (
id,
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
type,
currency,
is_active,
created_at,
updated_at
)
VALUES (
1,
10000,
TRUE,
TRUE,
TRUE,
1,
'regular_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
2,
5000,
FALSE,
TRUE,
TRUE,
1,
'static_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
3,
100000000,
TRUE,
TRUE,
TRUE,
2,
'company_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
4,
50000000,
TRUE,
TRUE,
TRUE,
2,
'branch_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
) ON CONFLICT (id) DO
UPDATE
SET balance = EXCLUDED.balance,
is_withdraw = EXCLUDED.is_withdraw,
is_bettable = EXCLUDED.is_bettable,
is_transferable = EXCLUDED.is_transferable,
user_id = EXCLUDED.user_id,
type = EXCLUDED.type,
currency = EXCLUDED.currency,
is_active = EXCLUDED.is_active,
created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at;
-- Customer Wallets
INSERT INTO customer_wallets (
id,
customer_id,
regular_wallet_id,
static_wallet_id
)
VALUES (1, 1, 1, 2) ON CONFLICT (id) DO
UPDATE
SET customer_id = EXCLUDED.customer_id,
regular_wallet_id = EXCLUDED.regular_wallet_id,
static_wallet_id = EXCLUDED.static_wallet_id;
-- Company
INSERT INTO companies (
id,
name,
slug,
admin_id,
wallet_id,
deducted_percentage,
is_active,
created_at,
updated_at
)
VALUES (
1,
'FortuneBets',
'fortunebets',
2,
3,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
) ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
slug = EXCLUDED.slug,
admin_id = EXCLUDED.admin_id,
wallet_id = EXCLUDED.wallet_id,
deducted_percentage = EXCLUDED.deducted_percentage,
is_active = EXCLUDED.is_active,
created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at;
-- Branch
INSERT INTO branches (
id,
name,
location,
wallet_id,
branch_manager_id,
company_id,
is_self_owned,
profit_percent,
is_active,
created_at,
updated_at
)
VALUES (
1,
'Test Branch',
'addis_ababa',
4,
2,
1,
TRUE,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
) ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
location = EXCLUDED.location,
wallet_id = EXCLUDED.wallet_id,
branch_manager_id = EXCLUDED.branch_manager_id,
company_id = EXCLUDED.company_id,
is_self_owned = EXCLUDED.is_self_owned,
profit_percent = EXCLUDED.profit_percent,
is_active = EXCLUDED.is_active,
created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at;
-- Bonus
INSERT INTO user_bonuses (
id,
name,
description,
type,
user_id,
reward_amount,
expires_at
)
VALUES (
1,
'Welcome Bonus',
'Awarded for deposit number (1 / 3)',
'welcome_bonus',
1,
1000,
now() + INTERVAL '1 day'
) ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
description = EXCLUDED.description,
type = EXCLUDED.type,
user_id = EXCLUDED.user_id,
reward_amount = EXCLUDED.reward_amount,
expires_at = EXCLUDED.expires_at;

148
db/data/002_veli_user.sql Normal file
View File

@ -0,0 +1,148 @@
-- Users
INSERT INTO users (
id,
first_name,
last_name,
email,
phone_number,
password,
role,
email_verified,
phone_verified,
created_at,
updated_at,
suspended,
company_id
)
VALUES (
5,
'Test',
'Veli',
'test.veli@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
),
(
6,
'Kirubel',
'Kibru',
'modernkibru@gmail.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
) ON CONFLICT (id) DO
UPDATE
SET first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
email = EXCLUDED.email,
phone_number = EXCLUDED.phone_number,
password = EXCLUDED.password,
role = EXCLUDED.role,
email_verified = EXCLUDED.email_verified,
phone_verified = EXCLUDED.phone_verified,
created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at,
suspended = EXCLUDED.suspended,
company_id = EXCLUDED.company_id;
INSERT INTO wallets (
id,
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
type,
currency,
is_active,
created_at,
updated_at
)
VALUES (
5,
10000,
TRUE,
TRUE,
TRUE,
1,
'regular_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
6,
5000,
FALSE,
TRUE,
TRUE,
1,
'static_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
7,
1000000,
TRUE,
TRUE,
TRUE,
1,
'regular_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
8,
5000,
FALSE,
TRUE,
TRUE,
1,
'static_wallet',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
) ON CONFLICT (id) DO
UPDATE
SET balance = EXCLUDED.balance,
is_withdraw = EXCLUDED.is_withdraw,
is_bettable = EXCLUDED.is_bettable,
is_transferable = EXCLUDED.is_transferable,
user_id = EXCLUDED.user_id,
type = EXCLUDED.type,
currency = EXCLUDED.currency,
is_active = EXCLUDED.is_active,
created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at;
-- Customer Wallets
INSERT INTO customer_wallets (
id,
customer_id,
regular_wallet_id,
static_wallet_id
)
VALUES (2, 5, 5, 6),
(3, 6, 7, 8) ON CONFLICT (id) DO
UPDATE
SET customer_id = EXCLUDED.customer_id,
regular_wallet_id = EXCLUDED.regular_wallet_id,
static_wallet_id = EXCLUDED.static_wallet_id;

View File

@ -0,0 +1,31 @@
-- For each table with an id sequence
SELECT setval(
pg_get_serial_sequence('users', 'id'),
COALESCE(MAX(id), 1)
)
FROM users;
SELECT setval(
pg_get_serial_sequence('wallets', 'id'),
COALESCE(MAX(id), 1)
)
FROM wallets;
SELECT setval(
pg_get_serial_sequence('customer_wallets', 'id'),
COALESCE(MAX(id), 1)
)
FROM customer_wallets;
SELECT setval(
pg_get_serial_sequence('companies', 'id'),
COALESCE(MAX(id), 1)
)
FROM companies;
SELECT setval(
pg_get_serial_sequence('branches', 'id'),
COALESCE(MAX(id), 1)
)
FROM branches;
SELECT setval(
pg_get_serial_sequence('supported_operations', 'id'),
COALESCE(MAX(id), 1)
)
FROM supported_operations;

View File

@ -1,222 +0,0 @@
BEGIN;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Users
INSERT INTO users (
id,
first_name,
last_name,
email,
phone_number,
password,
role,
email_verified,
phone_verified,
created_at,
updated_at,
suspended,
company_id
)
VALUES (
1,
'John',
'Doe',
'john.doe@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
2,
'Test',
'Admin',
'test.admin@gmail.com',
'0988554466',
crypt('password123', gen_salt('bf'))::bytea,
'admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
1
),
(
3,
'Samuel',
'Tariku',
'cybersamt@gmail.com',
'0911111111',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
4,
'Kirubel',
'Kibru',
'kirubel.jkl679@gmail.com',
'0911554486',
crypt('password@123', gen_salt('bf'))::bytea,
'super_admin',
TRUE,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
),
(
5,
'Test',
'Veli',
'test.veli@example.com',
NULL,
crypt('password@123', gen_salt('bf'))::bytea,
'customer',
TRUE,
FALSE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
FALSE,
NULL
);
-- Supported Operations
INSERT INTO supported_operations (id, name, description)
VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations');
-- Wallets
INSERT INTO wallets (
id,
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
type,
currency,
is_active,
created_at,
updated_at
)
VALUES (
1,
10000,
TRUE,
TRUE,
TRUE,
1,
'regular',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
2,
5000,
FALSE,
TRUE,
TRUE,
1,
'static',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
3,
20000,
TRUE,
TRUE,
TRUE,
2,
'company_main',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
),
(
4,
15000,
TRUE,
TRUE,
TRUE,
2,
'branch_main',
'ETB',
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
-- Customer Wallets
INSERT INTO customer_wallets (
id,
customer_id,
regular_wallet_id,
static_wallet_id
)
VALUES (1, 1, 1, 2);
-- Company
INSERT INTO companies (
id,
name,
slug,
admin_id,
wallet_id,
deducted_percentage,
is_active,
created_at,
updated_at
)
VALUES (
1,
'FortuneBets',
'fortunebets',
2,
3,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
-- Branch
INSERT INTO branches (
id,
name,
location,
wallet_id,
branch_manager_id,
company_id,
is_self_owned,
profit_percent,
is_active,
created_at,
updated_at
)
VALUES (
1,
'Test Branch',
'addis_ababa',
4,
2,
1,
TRUE,
0.10,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
COMMIT;

View File

@ -18,42 +18,42 @@ CREATE TABLE IF NOT EXISTS users (
email IS NOT NULL email IS NOT NULL
OR phone_number IS NOT NULL OR phone_number IS NOT NULL
), ),
UNIQUE(email, company_id), UNIQUE (email, company_id),
UNIQUE (phone_number, company_id) UNIQUE (phone_number, company_id)
); );
CREATE TABLE IF NOT EXISTS virtual_game_providers ( CREATE TABLE IF NOT EXISTS virtual_game_providers (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
provider_id VARCHAR(100) UNIQUE NOT NULL, -- providerId from Veli Games provider_id VARCHAR(100) UNIQUE NOT NULL,
provider_name VARCHAR(255) NOT NULL, -- providerName -- providerId from Veli Games
logo_dark TEXT, -- logoForDark (URL) provider_name VARCHAR(255) NOT NULL,
logo_light TEXT, -- logoForLight (URL) -- providerName
enabled BOOLEAN NOT NULL DEFAULT TRUE, -- allow enabling/disabling providers logo_dark TEXT,
-- logoForDark (URL)
logo_light TEXT,
-- logoForLight (URL)
enabled BOOLEAN NOT NULL DEFAULT TRUE,
-- allow enabling/disabling providers
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ updated_at TIMESTAMPTZ
); );
CREATE TABLE IF NOT EXISTS virtual_games ( CREATE TABLE IF NOT EXISTS virtual_games (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
game_id VARCHAR(150) NOT NULL, game_id VARCHAR(150) NOT NULL,
provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE, provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
category VARCHAR(100), category VARCHAR(100),
device_type VARCHAR(100), device_type VARCHAR(100),
volatility VARCHAR(50), volatility VARCHAR(50),
rtp NUMERIC(5,2), rtp NUMERIC(5, 2),
has_demo BOOLEAN DEFAULT FALSE, has_demo BOOLEAN DEFAULT FALSE,
has_free_bets BOOLEAN DEFAULT FALSE, has_free_bets BOOLEAN DEFAULT FALSE,
bets NUMERIC[] DEFAULT '{}', bets NUMERIC [] DEFAULT '{}',
thumbnail TEXT, thumbnail TEXT,
status INT, status INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ updated_at TIMESTAMPTZ
); );
CREATE UNIQUE INDEX IF NOT EXISTS ux_virtual_games_provider_game ON virtual_games (provider_id, game_id);
CREATE UNIQUE INDEX IF NOT EXISTS ux_virtual_games_provider_game
ON virtual_games (provider_id, game_id);
CREATE TABLE IF NOT EXISTS wallets ( CREATE TABLE IF NOT EXISTS wallets (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
balance BIGINT NOT NULL DEFAULT 0, balance BIGINT NOT NULL DEFAULT 0,
@ -62,7 +62,14 @@ CREATE TABLE IF NOT EXISTS wallets (
is_bettable BOOLEAN NOT NULL, is_bettable BOOLEAN NOT NULL,
is_transferable BOOLEAN NOT NULL, is_transferable BOOLEAN NOT NULL,
user_id BIGINT NOT NULL, user_id BIGINT NOT NULL,
type VARCHAR(255) NOT NULL, type TEXT NOT NULL CHECK (
type IN (
'regular_wallet',
'static_wallet',
'branch_wallet',
'company_wallet'
)
),
is_active BOOLEAN NOT NULL DEFAULT true, is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
@ -118,7 +125,7 @@ CREATE TABLE exchange_rates (
to_currency VARCHAR(3) NOT NULL, to_currency VARCHAR(3) NOT NULL,
rate DECIMAL(19, 6) NOT NULL, rate DECIMAL(19, 6) NOT NULL,
valid_until TIMESTAMP NOT NULL, valid_until TIMESTAMP NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW (),
UNIQUE (from_currency, to_currency) UNIQUE (from_currency, to_currency)
); );
CREATE TABLE IF NOT EXISTS bet_outcomes ( CREATE TABLE IF NOT EXISTS bet_outcomes (
@ -186,7 +193,8 @@ CREATE TABLE IF NOT EXISTS wallets (
type VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true, is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT balance_positve CHECK (balance >= 0)
); );
CREATE TABLE IF NOT EXISTS customer_wallets ( CREATE TABLE IF NOT EXISTS customer_wallets (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -242,9 +250,9 @@ CREATE TABLE IF NOT EXISTS shop_bets (
cashed_out BOOLEAN DEFAULT FALSE NOT NULL, cashed_out BOOLEAN DEFAULT FALSE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(shop_transaction_id), UNIQUE (shop_transaction_id),
UNIQUE(bet_id), UNIQUE (bet_id),
UNIQUE(cashout_id) UNIQUE (cashout_id)
); );
CREATE TABLE IF NOT EXISTS shop_deposits ( CREATE TABLE IF NOT EXISTS shop_deposits (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -254,7 +262,7 @@ CREATE TABLE IF NOT EXISTS shop_deposits (
branch_wallet_id BIGINT NOT NULL, branch_wallet_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(shop_transaction_id) UNIQUE (shop_transaction_id)
); );
CREATE TABLE IF NOT EXISTS branches ( CREATE TABLE IF NOT EXISTS branches (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -268,7 +276,7 @@ CREATE TABLE IF NOT EXISTS branches (
is_self_owned BOOLEAN NOT NULL DEFAULT false, is_self_owned BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(wallet_id), UNIQUE (wallet_id),
CONSTRAINT profit_percentage_check CHECK ( CONSTRAINT profit_percentage_check CHECK (
profit_percent >= 0 profit_percent >= 0
AND profit_percent < 1 AND profit_percent < 1
@ -285,12 +293,9 @@ CREATE TABLE IF NOT EXISTS branch_cashiers (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL, user_id BIGINT NOT NULL,
branch_id BIGINT NOT NULL, branch_id BIGINT NOT NULL,
UNIQUE(user_id, branch_id) UNIQUE (user_id, branch_id)
);
CREATE TABLE IF NOT EXISTS branch_locations (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS branch_locations (key TEXT PRIMARY KEY, value TEXT NOT NULL);
CREATE TABLE events ( CREATE TABLE events (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
sport_id INT NOT NULL, sport_id INT NOT NULL,
@ -311,21 +316,15 @@ CREATE TABLE events (
match_period INT, match_period INT,
is_live BOOLEAN NOT NULL DEFAULT false, is_live BOOLEAN NOT NULL DEFAULT false,
status TEXT NOT NULL, status TEXT NOT NULL,
fetched_at TIMESTAMP DEFAULT now(), fetched_at TIMESTAMP DEFAULT now (),
source TEXT NOT NULL DEFAULT 'b365api' CHECK ( source TEXT NOT NULL DEFAULT 'b365api' CHECK (
source IN ( source IN ('b365api', 'bfair', '1xbet', 'bwin', 'enetpulse')
'b365api',
'bfair',
'1xbet',
'bwin',
'enetpulse'
)
), ),
default_is_active BOOLEAN NOT NULL DEFAULT true, default_is_active BOOLEAN NOT NULL DEFAULT true,
default_is_featured BOOLEAN NOT NULL DEFAULT false, default_is_featured BOOLEAN NOT NULL DEFAULT false,
default_winning_upper_limit INT NOT NULL, default_winning_upper_limit BIGINT NOT NULL,
is_monitored BOOLEAN NOT NULL DEFAULT FALSE, is_monitored BOOLEAN NOT NULL DEFAULT FALSE,
UNIQUE(id, source) UNIQUE (id, source)
); );
CREATE TABLE event_history ( CREATE TABLE event_history (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -341,7 +340,7 @@ CREATE TABLE company_event_settings (
is_featured BOOLEAN, is_featured BOOLEAN,
winning_upper_limit INT, winning_upper_limit INT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(company_id, event_id) UNIQUE (company_id, event_id)
); );
CREATE TABLE odds_market ( CREATE TABLE odds_market (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -352,13 +351,13 @@ CREATE TABLE odds_market (
market_id TEXT NOT NULL, market_id TEXT NOT NULL,
raw_odds JSONB NOT NULL, raw_odds JSONB NOT NULL,
default_is_active BOOLEAN NOT NULL DEFAULT true, default_is_active BOOLEAN NOT NULL DEFAULT true,
fetched_at TIMESTAMP DEFAULT now(), fetched_at TIMESTAMP DEFAULT now (),
expires_at TIMESTAMP NOT NULL, expires_at TIMESTAMP NOT NULL,
UNIQUE (event_id, market_id) UNIQUE (event_id, market_id)
); );
CREATE TABLE odd_history ( CREATE TABLE odd_history (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
odds_market_id BIGINT NOT NULL REFERENCES odds_market(id), odds_market_id BIGINT NOT NULL REFERENCES odds_market (id),
raw_odd_id BIGINT NOT NULL, raw_odd_id BIGINT NOT NULL,
market_id TEXT NOT NULL, market_id TEXT NOT NULL,
event_id TEXT NOT NULL, event_id TEXT NOT NULL,
@ -380,7 +379,7 @@ CREATE TABLE company_odd_settings (
is_active BOOLEAN, is_active BOOLEAN,
custom_raw_odds JSONB, custom_raw_odds JSONB,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(company_id, odds_market_id) UNIQUE (company_id, odds_market_id)
); );
CREATE TABLE result_log ( CREATE TABLE result_log (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -430,7 +429,7 @@ CREATE TABLE company_league_settings (
is_active BOOLEAN, is_active BOOLEAN,
is_featured BOOLEAN, is_featured BOOLEAN,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(league_id, company_id) UNIQUE (league_id, company_id)
); );
CREATE TABLE teams ( CREATE TABLE teams (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -447,24 +446,32 @@ CREATE TABLE IF NOT EXISTS global_settings (
); );
-- Tenant/Company-specific overrides -- Tenant/Company-specific overrides
CREATE TABLE IF NOT EXISTS company_settings ( CREATE TABLE IF NOT EXISTS company_settings (
company_id BIGINT NOT NULL REFERENCES companies(id) ON DELETE CASCADE, company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
key TEXT NOT NULL, key TEXT NOT NULL,
value TEXT NOT NULL, value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (company_id, key) PRIMARY KEY (company_id, key)
); );
CREATE TABLE bonus ( CREATE TABLE user_bonuses (
multiplier REAL NOT NULL,
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
balance_cap BIGINT NOT NULL DEFAULT 0 name TEXT NOT NULL,
description TEXT NOT NULL,
type TEXT NOT NULL,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
reward_amount BIGINT NOT NULL,
is_claimed BOOLEAN NOT NULL DEFAULT false,
expires_at TIMESTAMP NOT NULL,
claimed_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
); );
CREATE TABLE flags ( CREATE TABLE flags (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
bet_id BIGINT REFERENCES bets(id) ON DELETE CASCADE, bet_id BIGINT REFERENCES bets (id) ON DELETE CASCADE,
odds_market_id BIGINT REFERENCES odds_market(id), odds_market_id BIGINT REFERENCES odds_market (id),
reason TEXT, reason TEXT,
flagged_at TIMESTAMP DEFAULT NOW(), flagged_at TIMESTAMP DEFAULT NOW (),
resolved BOOLEAN DEFAULT FALSE, resolved BOOLEAN DEFAULT FALSE,
-- either bet or odd is flagged (not at the same time) -- either bet or odd is flagged (not at the same time)
CHECK ( CHECK (
@ -480,21 +487,56 @@ CREATE TABLE flags (
); );
CREATE TABLE direct_deposits ( CREATE TABLE direct_deposits (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES users(id), customer_id BIGINT NOT NULL REFERENCES users (id),
wallet_id BIGINT NOT NULL REFERENCES wallets(id), wallet_id BIGINT NOT NULL REFERENCES wallets (id),
amount NUMERIC(15, 2) NOT NULL, amount NUMERIC(15, 2) NOT NULL,
bank_reference TEXT NOT NULL, bank_reference TEXT NOT NULL,
sender_account TEXT NOT NULL, sender_account TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'rejected')), status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'rejected')),
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW (),
verified_by BIGINT REFERENCES users(id), verified_by BIGINT REFERENCES users (id),
verification_notes TEXT, verification_notes TEXT,
verified_at TIMESTAMP verified_at TIMESTAMP
); );
CREATE INDEX idx_direct_deposits_status ON direct_deposits(status); CREATE INDEX idx_direct_deposits_status ON direct_deposits (status);
CREATE INDEX idx_direct_deposits_customer ON direct_deposits(customer_id); CREATE INDEX idx_direct_deposits_customer ON direct_deposits (customer_id);
CREATE INDEX idx_direct_deposits_reference ON direct_deposits(bank_reference); CREATE INDEX idx_direct_deposits_reference ON direct_deposits (bank_reference);
-- Views CREATE TABLE IF NOT EXISTS raffles (
id SERIAL PRIMARY KEY,
company_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
expires_at TIMESTAMP NOT NULL,
type VARCHAR(50) NOT NULL CHECK (type IN ('virtual', 'sport')),
status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'completed'))
);
CREATE TABLE IF NOT EXISTS raffle_tickets (
id SERIAL PRIMARY KEY,
raffle_id INT NOT NULL REFERENCES raffles(id) ON DELETE CASCADE,
user_id INT NOT NULL,
is_active BOOL DEFAULT true
);
CREATE TABLE IF NOT EXISTS raffle_winners (
id SERIAL PRIMARY KEY,
raffle_id INT NOT NULL REFERENCES raffles(id) ON DELETE CASCADE,
user_id INT NOT NULL,
rank INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS raffle_sport_filters (
id SERIAL PRIMARY KEY,
raffle_id INT NOT NULL REFERENCES raffles(id) ON DELETE CASCADE,
sport_id BIGINT NOT NULL,
league_id BIGINT NOT NULL,
CONSTRAINT unique_raffle_sport_league UNIQUE (raffle_id, sport_id, league_id)
);
CREATE TABLE IF NOT EXISTS raffle_game_filters (
id SERIAL PRIMARY KEY,
raffle_id INT NOT NULL REFERENCES raffles(id) ON DELETE CASCADE,
game_id VARCHAR(150) NOT NULL,
CONSTRAINT unique_raffle_game UNIQUE (raffle_id, game_id)
);
------ Views
CREATE VIEW companies_details AS CREATE VIEW companies_details AS
SELECT companies.*, SELECT companies.*,
wallets.balance, wallets.balance,
@ -508,7 +550,7 @@ FROM companies
; ;
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,
users.phone_number AS manager_phone_number, users.phone_number AS manager_phone_number,
wallets.balance, wallets.balance,
wallets.is_active AS wallet_is_active wallets.is_active AS wallet_is_active
@ -522,9 +564,9 @@ CREATE TABLE IF NOT EXISTS supported_operations (
); );
CREATE VIEW bet_with_outcomes AS CREATE VIEW bet_with_outcomes AS
SELECT bets.*, SELECT bets.*,
CONCAT(users.first_name, ' ', users.last_name) AS full_name, CONCAT (users.first_name, ' ', users.last_name) AS full_name,
users.phone_number, users.phone_number,
JSON_AGG(bet_outcomes.*) AS outcomes JSON_AGG (bet_outcomes.*) AS outcomes
FROM bets FROM bets
LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id
LEFT JOIN users ON bets.user_id = users.id LEFT JOIN users ON bets.user_id = users.id
@ -534,7 +576,7 @@ GROUP BY bets.id,
users.phone_number; users.phone_number;
CREATE VIEW ticket_with_outcomes AS CREATE VIEW ticket_with_outcomes AS
SELECT tickets.*, SELECT tickets.*,
JSON_AGG(ticket_outcomes.*) AS outcomes JSON_AGG (ticket_outcomes.*) AS outcomes
FROM tickets 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;
@ -588,7 +630,7 @@ SELECT sb.*,
st.verified AS transaction_verified, st.verified AS transaction_verified,
bets.status, bets.status,
bets.total_odds, bets.total_odds,
JSON_AGG(bet_outcomes.*) AS outcomes JSON_AGG (bet_outcomes.*) AS outcomes
FROM shop_bets AS sb FROM shop_bets AS sb
JOIN shop_transactions st ON st.id = sb.shop_transaction_id JOIN shop_transactions st ON st.id = sb.shop_transaction_id
JOIN bets ON bets.id = sb.bet_id JOIN bets ON bets.id = sb.bet_id
@ -619,7 +661,7 @@ SELECT l.*,
COALESCE(cls.is_featured, l.default_is_featured) AS is_featured, COALESCE(cls.is_featured, l.default_is_featured) AS is_featured,
cls.updated_at cls.updated_at
FROM leagues l FROM leagues l
JOIN company_league_settings cls ON l.id = cls.league_id; LEFT JOIN company_league_settings cls ON l.id = cls.league_id;
CREATE VIEW event_with_settings AS CREATE VIEW event_with_settings AS
SELECT e.*, SELECT e.*,
ces.company_id, ces.company_id,
@ -632,7 +674,7 @@ SELECT e.*,
ces.updated_at, ces.updated_at,
l.country_code as league_cc l.country_code as league_cc
FROM events e FROM events e
JOIN company_event_settings ces ON e.id = ces.event_id LEFT JOIN company_event_settings ces ON e.id = ces.event_id
JOIN leagues l ON l.id = e.league_id; JOIN leagues l ON l.id = e.league_id;
CREATE VIEW event_with_country AS CREATE VIEW event_with_country AS
SELECT events.*, SELECT events.*,
@ -654,7 +696,7 @@ SELECT o.id,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds, COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at cos.updated_at
FROM odds_market o FROM odds_market o
JOIN company_odd_settings cos ON o.id = cos.odds_market_id; LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id;
CREATE VIEW odds_market_with_event AS CREATE VIEW odds_market_with_event AS
SELECT o.*, SELECT o.*,
e.is_monitored, e.is_monitored,
@ -665,47 +707,47 @@ FROM odds_market o
JOIN events e ON o.event_id = e.id; JOIN events e ON o.event_id = e.id;
-- Foreign Keys -- Foreign Keys
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);
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);
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 shop_transactions ALTER TABLE shop_transactions
ADD CONSTRAINT fk_shop_transactions_branches FOREIGN KEY (branch_id) REFERENCES branches(id), ADD CONSTRAINT fk_shop_transactions_branches FOREIGN KEY (branch_id) REFERENCES branches (id),
ADD CONSTRAINT fk_shop_transactions_users FOREIGN KEY (user_id) REFERENCES users(id); ADD CONSTRAINT fk_shop_transactions_users FOREIGN KEY (user_id) REFERENCES users (id);
ALTER TABLE shop_bets ALTER TABLE shop_bets
ADD CONSTRAINT fk_shop_bet_transactions FOREIGN KEY (shop_transaction_id) REFERENCES shop_transactions(id), ADD CONSTRAINT fk_shop_bet_transactions FOREIGN KEY (shop_transaction_id) REFERENCES shop_transactions (id),
ADD CONSTRAINT fk_shop_bet_bets FOREIGN KEY (bet_id) REFERENCES bets(id); ADD CONSTRAINT fk_shop_bet_bets FOREIGN KEY (bet_id) REFERENCES bets (id);
ALTER TABLE shop_deposits ALTER TABLE shop_deposits
ADD CONSTRAINT fk_shop_deposit_transactions FOREIGN KEY (shop_transaction_id) REFERENCES shop_transactions(id), ADD CONSTRAINT fk_shop_deposit_transactions FOREIGN KEY (shop_transaction_id) REFERENCES shop_transactions (id),
ADD CONSTRAINT fk_shop_deposit_customers FOREIGN KEY (customer_id) REFERENCES users(id); ADD CONSTRAINT fk_shop_deposit_customers FOREIGN KEY (customer_id) REFERENCES users (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),
ADD CONSTRAINT fk_branches_location FOREIGN KEY (location) REFERENCES branch_locations(key); ADD CONSTRAINT fk_branches_location FOREIGN KEY (location) REFERENCES branch_locations (key);
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;
ALTER TABLE company_league_settings ALTER TABLE company_league_settings
ADD CONSTRAINT fk_league_settings_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE, ADD CONSTRAINT fk_league_settings_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE,
ADD CONSTRAINT fk_league_settings_league FOREIGN KEY (league_id) REFERENCES leagues(id) ON DELETE CASCADE; ADD CONSTRAINT fk_league_settings_league FOREIGN KEY (league_id) REFERENCES leagues (id) ON DELETE CASCADE;
ALTER TABLE company_event_settings ALTER TABLE company_event_settings
ADD CONSTRAINT fk_event_settings_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE, ADD CONSTRAINT fk_event_settings_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE,
ADD CONSTRAINT fk_event_settings_event FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE; ADD CONSTRAINT fk_event_settings_event FOREIGN KEY (event_id) REFERENCES events (id) ON DELETE CASCADE;
ALTER TABLE company_odd_settings ALTER TABLE company_odd_settings
ADD CONSTRAINT fk_odds_settings_company FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE, ADD CONSTRAINT fk_odds_settings_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE,
ADD CONSTRAINT fk_odds_settings_odds_market FOREIGN KEY (odds_market_id) REFERENCES odds_market(id) ON DELETE CASCADE; ADD CONSTRAINT fk_odds_settings_odds_market FOREIGN KEY (odds_market_id) REFERENCES odds_market (id) ON DELETE CASCADE;

View File

@ -18,7 +18,8 @@ CREATE TABLE IF NOT EXISTS notifications (
'admin_alert', 'admin_alert',
'bet_result', 'bet_result',
'transfer_rejected', 'transfer_rejected',
'approval_required' 'approval_required',
'bonus_awarded'
) )
), ),
level TEXT NOT NULL CHECK (level IN ('info', 'error', 'warning', 'success')), level TEXT NOT NULL CHECK (level IN ('info', 'error', 'warning', 'success')),

View File

@ -1,46 +1,37 @@
CREATE TYPE ReferralStatus AS ENUM ('PENDING', 'COMPLETED', 'EXPIRED', 'CANCELLED'); -- CREATE TYPE ReferralStatus AS ENUM ('PENDING', 'COMPLETED', 'EXPIRED', 'CANCELLED');
CREATE TABLE IF NOT EXISTS referral_settings ( -- CREATE TABLE IF NOT EXISTS referral_settings (
id BIGSERIAL PRIMARY KEY, -- id BIGSERIAL PRIMARY KEY,
referral_reward_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00, -- referral_reward_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
cashback_percentage DECIMAL(5, 2) NOT NULL DEFAULT 0.00, -- cashback_percentage DECIMAL(5, 2) NOT NULL DEFAULT 0.00,
bet_referral_bonus_percentage NUMERIC DEFAULT 5.0, -- bet_referral_bonus_percentage NUMERIC DEFAULT 5.0,
max_referrals INTEGER NOT NULL DEFAULT 0, -- max_referrals INTEGER NOT NULL DEFAULT 0,
expires_after_days INTEGER NOT NULL DEFAULT 30, -- expires_after_days INTEGER NOT NULL DEFAULT 30,
updated_by VARCHAR(255) NOT NULL, -- updated_by VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, -- created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, -- updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
version INTEGER NOT NULL DEFAULT 0, -- version INTEGER NOT NULL DEFAULT 0,
CONSTRAINT referral_reward_amount_positive CHECK (referral_reward_amount >= 0), -- CONSTRAINT referral_reward_amount_positive CHECK (referral_reward_amount >= 0),
CONSTRAINT cashback_percentage_range CHECK ( -- CONSTRAINT cashback_percentage_range CHECK (
cashback_percentage >= 0 -- cashback_percentage >= 0
AND cashback_percentage <= 100 -- AND cashback_percentage <= 100
) -- )
); -- );
CREATE TABLE IF NOT EXISTS referrals ( CREATE TABLE IF NOT EXISTS referral_codes (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
referral_code VARCHAR(10) NOT NULL UNIQUE, referral_code VARCHAR(10) NOT NULL UNIQUE,
referrer_id VARCHAR(255) NOT NULL, referrer_id BIGINT NOT NULL UNIQUE REFERENCES users (id),
referred_id VARCHAR(255) UNIQUE, company_id BIGINT NOT NULL REFERENCES companies (id),
status ReferralStatus NOT NULL DEFAULT 'PENDING', is_active BOOLEAN NOT NULL DEFAULT true,
reward_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00, number_of_referrals BIGINT NOT NULL,
cashback_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00, reward_amount BIGINT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMPTZ NOT NULL, CONSTRAINT reward_amount_positive CHECK (reward_amount >= 0)
-- FOREIGN KEY (referrer_id) REFERENCES users (id),
-- FOREIGN KEY (referred_id) REFERENCES users (id),
CONSTRAINT reward_amount_positive CHECK (reward_amount >= 0),
CONSTRAINT cashback_amount_positive CHECK (cashback_amount >= 0)
); );
CREATE INDEX idx_referrals_referral_code ON referrals (referral_code); CREATE INDEX idx_referrals_referrer_id ON referral_codes (referrer_id);
CREATE INDEX idx_referrals_referrer_id ON referrals (referrer_id); CREATE TABLE IF NOT EXISTS user_referrals (
CREATE INDEX idx_referrals_status ON referrals (status); id BIGSERIAL PRIMARY KEY,
ALTER TABLE users referred_id BIGINT UNIQUE NOT NULL REFERENCES users (id),
ADD COLUMN IF NOT EXISTS referral_code VARCHAR(10) UNIQUE, referral_code_id BIGINT NOT NULL REFERENCES referral_codes (id),
ADD COLUMN IF NOT EXISTS referred_by VARCHAR(10); created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
-- Modify wallet table to track bonus money separately );
ALTER TABLE wallets
ADD COLUMN IF NOT EXISTS bonus_balance DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
ADD COLUMN IF NOT EXISTS cash_balance DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
ADD CONSTRAINT bonus_balance_positive CHECK (bonus_balance >= 0),
ADD CONSTRAINT cash_balance_positive CHECK (cash_balance >= 0);

View File

@ -1,11 +1,11 @@
-- Settings Initial Data -- -- Settings Initial Data
INSERT INTO global_settings (key, value) -- INSERT INTO global_settings (key, value)
VALUES ('sms_provider', 'afro_message'), -- VALUES ('sms_provider', 'afro_message'),
('max_number_of_outcomes', '30'), -- ('max_number_of_outcomes', '30'),
('bet_amount_limit', '10000000'), -- ('bet_amount_limit', '10000000'),
('daily_ticket_limit', '50'), -- ('daily_ticket_limit', '50'),
('total_winnings_limit', '1000000'), -- ('total_winnings_limit', '1000000'),
('amount_for_bet_referral', '1000000'), -- ('amount_for_bet_referral', '1000000'),
('cashback_amount_cap', '1000') ON CONFLICT (key) DO -- ('cashback_amount_cap', '1000') ON CONFLICT (key) DO
UPDATE -- UPDATE
SET value = EXCLUDED.value; -- SET value = EXCLUDED.value;

View File

@ -1,75 +1,75 @@
-- Locations Initial Data -- -- Locations Initial Data
INSERT INTO branch_locations (key, value) -- INSERT INTO branch_locations (key, value)
VALUES ('addis_ababa', 'Addis Ababa'), -- VALUES ('addis_ababa', 'Addis Ababa'),
('dire_dawa', 'Dire Dawa'), -- ('dire_dawa', 'Dire Dawa'),
('mekelle', 'Mekelle'), -- ('mekelle', 'Mekelle'),
('adama', 'Adama'), -- ('adama', 'Adama'),
('awassa', 'Awassa'), -- ('awassa', 'Awassa'),
('bahir_dar', 'Bahir Dar'), -- ('bahir_dar', 'Bahir Dar'),
('gonder', 'Gonder'), -- ('gonder', 'Gonder'),
('dessie', 'Dessie'), -- ('dessie', 'Dessie'),
('jimma', 'Jimma'), -- ('jimma', 'Jimma'),
('jijiga', 'Jijiga'), -- ('jijiga', 'Jijiga'),
('shashamane', 'Shashamane'), -- ('shashamane', 'Shashamane'),
('bishoftu', 'Bishoftu'), -- ('bishoftu', 'Bishoftu'),
('sodo', 'Sodo'), -- ('sodo', 'Sodo'),
('arba_minch', 'Arba Minch'), -- ('arba_minch', 'Arba Minch'),
('hosaena', 'Hosaena'), -- ('hosaena', 'Hosaena'),
('harar', 'Harar'), -- ('harar', 'Harar'),
('dilla', 'Dilla'), -- ('dilla', 'Dilla'),
('nekemte', 'Nekemte'), -- ('nekemte', 'Nekemte'),
('debre_birhan', 'Debre Birhan'), -- ('debre_birhan', 'Debre Birhan'),
('asella', 'Asella'), -- ('asella', 'Asella'),
('debre_markos', 'Debre Markos'), -- ('debre_markos', 'Debre Markos'),
('kombolcha', 'Kombolcha'), -- ('kombolcha', 'Kombolcha'),
('debre_tabor', 'Debre Tabor'), -- ('debre_tabor', 'Debre Tabor'),
('adigrat', 'Adigrat'), -- ('adigrat', 'Adigrat'),
('areka', 'Areka'), -- ('areka', 'Areka'),
('weldiya', 'Weldiya'), -- ('weldiya', 'Weldiya'),
('sebeta', 'Sebeta'), -- ('sebeta', 'Sebeta'),
('burayu', 'Burayu'), -- ('burayu', 'Burayu'),
('shire', 'Shire'), -- ('shire', 'Shire'),
('ambo', 'Ambo'), -- ('ambo', 'Ambo'),
('arsi_negele', 'Arsi Negele'), -- ('arsi_negele', 'Arsi Negele'),
('aksum', 'Aksum'), -- ('aksum', 'Aksum'),
('gambela', 'Gambela'), -- ('gambela', 'Gambela'),
('bale_robe', 'Bale Robe'), -- ('bale_robe', 'Bale Robe'),
('butajira', 'Butajira'), -- ('butajira', 'Butajira'),
('batu', 'Batu'), -- ('batu', 'Batu'),
('boditi', 'Boditi'), -- ('boditi', 'Boditi'),
('adwa', 'Adwa'), -- ('adwa', 'Adwa'),
('yirgalem', 'Yirgalem'), -- ('yirgalem', 'Yirgalem'),
('waliso', 'Waliso'), -- ('waliso', 'Waliso'),
('welkite', 'Welkite'), -- ('welkite', 'Welkite'),
('gode', 'Gode'), -- ('gode', 'Gode'),
('meki', 'Meki'), -- ('meki', 'Meki'),
('negele_borana', 'Negele Borana'), -- ('negele_borana', 'Negele Borana'),
('alaba_kulito', 'Alaba Kulito'), -- ('alaba_kulito', 'Alaba Kulito'),
('alamata,', 'Alamata,'), -- ('alamata,', 'Alamata,'),
('chiro', 'Chiro'), -- ('chiro', 'Chiro'),
('tepi', 'Tepi'), -- ('tepi', 'Tepi'),
('durame', 'Durame'), -- ('durame', 'Durame'),
('goba', 'Goba'), -- ('goba', 'Goba'),
('assosa', 'Assosa'), -- ('assosa', 'Assosa'),
('gimbi', 'Gimbi'), -- ('gimbi', 'Gimbi'),
('wukro', 'Wukro'), -- ('wukro', 'Wukro'),
('haramaya', 'Haramaya'), -- ('haramaya', 'Haramaya'),
('mizan_teferi', 'Mizan Teferi'), -- ('mizan_teferi', 'Mizan Teferi'),
('sawla', 'Sawla'), -- ('sawla', 'Sawla'),
('mojo', 'Mojo'), -- ('mojo', 'Mojo'),
('dembi_dolo', 'Dembi Dolo'), -- ('dembi_dolo', 'Dembi Dolo'),
('aleta_wendo', 'Aleta Wendo'), -- ('aleta_wendo', 'Aleta Wendo'),
('metu', 'Metu'), -- ('metu', 'Metu'),
('mota', 'Mota'), -- ('mota', 'Mota'),
('fiche', 'Fiche'), -- ('fiche', 'Fiche'),
('finote_selam', 'Finote Selam'), -- ('finote_selam', 'Finote Selam'),
('bule_hora_town', 'Bule Hora Town'), -- ('bule_hora_town', 'Bule Hora Town'),
('bonga', 'Bonga'), -- ('bonga', 'Bonga'),
('kobo', 'Kobo'), -- ('kobo', 'Kobo'),
('jinka', 'Jinka'), -- ('jinka', 'Jinka'),
('dangila', 'Dangila'), -- ('dangila', 'Dangila'),
('degehabur', 'Degehabur'), -- ('degehabur', 'Degehabur'),
('bedessa', 'Bedessa'), -- ('bedessa', 'Bedessa'),
('agaro', 'Agaro') ON CONFLICT (key) DO -- ('agaro', 'Agaro') ON CONFLICT (key) DO
UPDATE -- UPDATE
SET value = EXCLUDED.value; -- SET value = EXCLUDED.value;

View File

@ -1,218 +1,220 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Users -- -- Users
INSERT INTO users ( -- INSERT INTO users (
id, -- id,
first_name, -- first_name,
last_name, -- last_name,
email, -- email,
phone_number, -- phone_number,
password, -- password,
role, -- role,
email_verified, -- email_verified,
phone_verified, -- phone_verified,
created_at, -- created_at,
updated_at, -- updated_at,
suspended, -- suspended,
company_id -- company_id
) -- )
VALUES ( -- VALUES (
1, -- 1,
'John', -- 'John',
'Doe', -- 'Doe',
'john.doe@example.com', -- 'john.doe@example.com',
NULL, -- NULL,
crypt('password123', gen_salt('bf'))::bytea, -- crypt('password@123', gen_salt('bf'))::bytea,
'customer', -- 'customer',
TRUE, -- TRUE,
FALSE, -- FALSE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
FALSE, -- FALSE,
NULL -- 1
), -- ),
( -- (
2, -- 2,
'Test', -- 'Test',
'Admin', -- 'Admin',
'test.admin@gmail.com', -- 'test.admin@gmail.com',
'0988554466', -- '0988554466',
crypt('password123', gen_salt('bf'))::bytea, -- crypt('password@123', gen_salt('bf'))::bytea,
'admin', -- 'admin',
TRUE, -- TRUE,
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
FALSE, -- FALSE,
1 -- 1
), -- ),
( -- (
3, -- 3,
'Samuel', -- 'Samuel',
'Tariku', -- 'Tariku',
'cybersamt@gmail.com', -- 'cybersamt@gmail.com',
'0911111111', -- '0911111111',
crypt('password@123', gen_salt('bf'))::bytea, -- crypt('password@123', gen_salt('bf'))::bytea,
'super_admin', -- 'super_admin',
TRUE, -- TRUE,
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
FALSE, -- FALSE,
NULL -- NULL
), -- ),
( -- (
4, -- 4,
'Kirubel', -- 'Kirubel',
'Kibru', -- 'Kibru',
'kirubel.jkl679@gmail.com', -- 'kirubel.jkl679@gmail.com',
'0911554486', -- '0911554486',
crypt('password@123', gen_salt('bf'))::bytea, -- crypt('password@123', gen_salt('bf'))::bytea,
'super_admin', -- 'super_admin',
TRUE, -- TRUE,
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
FALSE, -- FALSE,
NULL -- NULL
), -- ),
( -- (
5, -- 5,
'Test', -- 'Test',
'Veli', -- 'Veli',
'test.veli@example.com', -- 'test.veli@example.com',
NULL, -- NULL,
crypt('password@123', gen_salt('bf'))::bytea, -- crypt('password@123', gen_salt('bf'))::bytea,
'customer', -- 'customer',
TRUE, -- TRUE,
FALSE, -- FALSE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
FALSE, -- FALSE,
NULL -- 1
); -- );
-- Supported Operations -- -- Supported Operations
INSERT INTO supported_operations (id, name, description) -- INSERT INTO supported_operations (id, name, description)
VALUES (1, 'SportBook', 'Sportbook operations'), -- VALUES (1, 'SportBook', 'Sportbook operations'),
(2, 'Virtual', 'Virtual operations'); -- (2, 'Virtual', 'Virtual operations');
-- Wallets -- -- Wallets
INSERT INTO wallets ( -- INSERT INTO wallets (
id, -- id,
balance, -- balance,
is_withdraw, -- is_withdraw,
is_bettable, -- is_bettable,
is_transferable, -- is_transferable,
user_id, -- user_id,
type, -- type,
currency, -- currency,
is_active, -- is_active,
created_at, -- created_at,
updated_at -- updated_at
) -- )
VALUES ( -- VALUES (
1, -- 1,
10000, -- 10000,
TRUE, -- TRUE,
TRUE, -- TRUE,
TRUE, -- TRUE,
1, -- 1,
'regular', -- 'regular_wallet',
'ETB', -- 'ETB',
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP -- CURRENT_TIMESTAMP
), -- ),
( -- (
2, -- 2,
5000, -- 5000,
FALSE, -- FALSE,
TRUE, -- TRUE,
TRUE, -- TRUE,
1, -- 1,
'static', -- 'static_wallet',
'ETB', -- 'ETB',
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP -- CURRENT_TIMESTAMP
), -- ),
( -- (
3, -- 3,
20000, -- 20000,
TRUE, -- TRUE,
TRUE, -- TRUE,
TRUE, -- TRUE,
2, -- 2,
'company_main', -- 'company_wallet',
'ETB', -- 'ETB',
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP -- CURRENT_TIMESTAMP
), -- ),
( -- (
4, -- 4,
15000, -- 15000,
TRUE, -- TRUE,
TRUE, -- TRUE,
TRUE, -- TRUE,
2, -- 2,
'branch_main', -- 'branch_wallet',
'ETB', -- 'ETB',
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP -- CURRENT_TIMESTAMP
); -- );
-- Customer Wallets -- -- Customer Wallets
INSERT INTO customer_wallets ( -- INSERT INTO customer_wallets (
id, -- id,
customer_id, -- customer_id,
regular_wallet_id, -- regular_wallet_id,
static_wallet_id -- static_wallet_id
) -- )
VALUES (1, 1, 1, 2); -- VALUES (1, 1, 1, 2);
-- Company -- -- Company
INSERT INTO companies ( -- INSERT INTO companies (
id, -- id,
name, -- name,
admin_id, -- slug,
wallet_id, -- admin_id,
deducted_percentage, -- wallet_id,
is_active, -- deducted_percentage,
created_at, -- is_active,
updated_at -- created_at,
) -- updated_at
VALUES ( -- )
1, -- VALUES (
'Test Company', -- 1,
2, -- 'FortuneBets',
3, -- 'fortunebets',
0.10, -- 2,
TRUE, -- 3,
CURRENT_TIMESTAMP, -- 0.10,
CURRENT_TIMESTAMP -- TRUE,
); -- CURRENT_TIMESTAMP,
-- Branch -- CURRENT_TIMESTAMP
INSERT INTO branches ( -- );
id, -- -- Branch
name, -- INSERT INTO branches (
location, -- id,
wallet_id, -- name,
branch_manager_id, -- location,
company_id, -- wallet_id,
is_self_owned, -- branch_manager_id,
profit_percent, -- company_id,
is_active, -- is_self_owned,
created_at, -- profit_percent,
updated_at -- is_active,
) -- created_at,
VALUES ( -- updated_at
1, -- )
'Test Branch', -- VALUES (
'addis_ababa', -- 1,
4, -- 'Test Branch',
2, -- 'addis_ababa',
1, -- 4,
TRUE, -- 2,
0.10, -- 1,
TRUE, -- TRUE,
CURRENT_TIMESTAMP, -- 0.10,
CURRENT_TIMESTAMP -- TRUE,
); -- CURRENT_TIMESTAMP,
-- CURRENT_TIMESTAMP
-- );

View File

@ -1,17 +1,61 @@
-- name: CreateBonusMultiplier :exec -- name: CreateUserBonus :one
INSERT INTO bonus (multiplier, balance_cap) INSERT INTO user_bonuses (
VALUES ($1, $2); name,
description,
type,
user_id,
reward_amount,
expires_at
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *;
-- name: GetAllUserBonuses :many
SELECT *
FROM user_bonuses
WHERE (
user_id = sqlc.narg('user_id')
OR sqlc.narg('user_id') IS NULL
)
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetUserBonusByID :one
SELECT *
FROM user_bonuses
WHERE id = $1;
-- name: GetBonusMultiplier :many -- name: GetBonusCount :one
SELECT id, multiplier SELECT COUNT(*)
FROM bonus; FROM user_bonuses
WHERE (
-- name: GetBonusBalanceCap :many user_id = sqlc.narg('user_id')
SELECT id, balance_cap OR sqlc.narg('user_id') IS NULL
FROM bonus; );
-- name: GetBonusStats :one
-- name: UpdateBonusMultiplier :exec SELECT COUNT(*) AS total_bonuses,
UPDATE bonus COALESCE(SUM(reward_amount), 0)::bigint AS total_reward_earned,
SET multiplier = $1, COUNT(
balance_cap = $2 CASE
WHERE id = $3; WHEN is_claimed = true THEN 1
END
) AS claimed_bonuses,
COUNT(
CASE
WHEN expires_at < now() THEN 1
END
) AS expired_bonuses
FROM user_bonuses
JOIN users ON users.id = user_bonuses.user_id
WHERE (
company_id = sqlc.narg('company_id')
OR sqlc.narg('company_id') IS NULL
)
AND (
user_id = sqlc.narg('user_id')
OR sqlc.narg('user_id') IS NULL
);
-- name: UpdateUserBonus :exec
UPDATE user_bonuses
SET is_claimed = $2
WHERE id = $1;
-- name: DeleteUserBonus :exec
DELETE FROM user_bonuses
WHERE id = $1;

View File

@ -14,7 +14,8 @@ INSERT INTO events (
start_time, start_time,
is_live, is_live,
status, status,
source source,
default_winning_upper_limit
) )
VALUES ( VALUES (
$1, $1,
@ -31,7 +32,8 @@ VALUES (
$12, $12,
$13, $13,
$14, $14,
$15 $15,
$16
) ON CONFLICT (id) DO ) ON CONFLICT (id) DO
UPDATE UPDATE
SET sport_id = EXCLUDED.sport_id, SET sport_id = EXCLUDED.sport_id,
@ -44,7 +46,6 @@ SET sport_id = EXCLUDED.sport_id,
away_kit_image = EXCLUDED.away_kit_image, away_kit_image = EXCLUDED.away_kit_image,
league_id = EXCLUDED.league_id, league_id = EXCLUDED.league_id,
league_name = EXCLUDED.league_name, league_name = EXCLUDED.league_name,
league_cc = EXCLUDED.league_cc,
start_time = EXCLUDED.start_time, start_time = EXCLUDED.start_time,
score = EXCLUDED.score, score = EXCLUDED.score,
match_minute = EXCLUDED.match_minute, match_minute = EXCLUDED.match_minute,
@ -53,8 +54,9 @@ SET sport_id = EXCLUDED.sport_id,
match_period = EXCLUDED.match_period, match_period = EXCLUDED.match_period,
is_live = EXCLUDED.is_live, is_live = EXCLUDED.is_live,
source = EXCLUDED.source, source = EXCLUDED.source,
default_winning_upper_limit = EXCLUDED.default_winning_upper_limit,
fetched_at = now(); fetched_at = now();
-- name: InsertEventSettings :exec -- name: SaveEventSettings :exec
INSERT INTO company_event_settings ( INSERT INTO company_event_settings (
company_id, company_id,
event_id, event_id,
@ -152,16 +154,18 @@ ORDER BY start_time ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetTotalCompanyEvents :one -- name: GetTotalCompanyEvents :one
SELECT COUNT(*) SELECT COUNT(*)
FROM event_with_settings FROM events e
WHERE company_id = $1 LEFT JOIN company_event_settings ces ON e.id = ces.event_id
AND is_live = false AND ces.company_id = $1
JOIN leagues l ON l.id = e.league_id
WHERE is_live = false
AND status = 'upcoming' AND status = 'upcoming'
AND ( AND (
league_id = sqlc.narg('league_id') league_id = sqlc.narg('league_id')
OR sqlc.narg('league_id') IS NULL OR sqlc.narg('league_id') IS NULL
) )
AND ( AND (
sport_id = sqlc.narg('sport_id') e.sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL OR sqlc.narg('sport_id') IS NULL
) )
AND ( AND (
@ -178,14 +182,35 @@ WHERE company_id = $1
OR sqlc.narg('first_start_time') IS NULL OR sqlc.narg('first_start_time') IS NULL
) )
AND ( AND (
league_cc = sqlc.narg('country_code') l.country_code = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL OR sqlc.narg('country_code') IS NULL
)
AND (
ces.is_featured = sqlc.narg('is_featured')
OR e.default_is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL
)
AND (
ces.is_active = sqlc.narg('is_active')
OR e.default_is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
); );
-- name: GetEventsWithSettings :many -- name: GetEventsWithSettings :many
SELECT * SELECT e.*,
FROM event_with_settings ces.company_id,
WHERE company_id = $1 COALESCE(ces.is_active, e.default_is_active) AS is_active,
AND start_time > now() COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
COALESCE(
ces.winning_upper_limit,
e.default_winning_upper_limit
) AS winning_upper_limit,
ces.updated_at,
l.country_code as league_cc
FROM events e
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
AND ces.company_id = $1
JOIN leagues l ON l.id = e.league_id
WHERE start_time > now()
AND is_live = false AND is_live = false
AND status = 'upcoming' AND status = 'upcoming'
AND ( AND (
@ -193,7 +218,7 @@ WHERE company_id = $1
OR sqlc.narg('league_id') IS NULL OR sqlc.narg('league_id') IS NULL
) )
AND ( AND (
sport_id = sqlc.narg('sport_id') e.sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL OR sqlc.narg('sport_id') IS NULL
) )
AND ( AND (
@ -210,9 +235,19 @@ WHERE company_id = $1
OR sqlc.narg('first_start_time') IS NULL OR sqlc.narg('first_start_time') IS NULL
) )
AND ( AND (
league_cc = sqlc.narg('country_code') l.country_code = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL OR sqlc.narg('country_code') IS NULL
) )
AND (
ces.is_featured = sqlc.narg('is_featured')
OR e.default_is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL
)
AND (
ces.is_active = sqlc.narg('is_active')
OR e.default_is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
)
ORDER BY start_time ASC ORDER BY start_time ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetUpcomingByID :one -- name: GetUpcomingByID :one
@ -223,13 +258,27 @@ WHERE id = $1
AND status = 'upcoming' AND status = 'upcoming'
LIMIT 1; LIMIT 1;
-- name: GetEventWithSettingByID :one -- name: GetEventWithSettingByID :one
SELECT * SELECT e.*,
FROM event_with_settings ces.company_id,
WHERE id = $1 COALESCE(ces.is_active, e.default_is_active) AS is_active,
AND company_id = $2 COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
COALESCE(
ces.winning_upper_limit,
e.default_winning_upper_limit
) AS winning_upper_limit,
ces.updated_at,
l.country_code as league_cc
FROM events e
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
AND ces.company_id = $2
JOIN leagues l ON l.id = e.league_id
WHERE e.id = $1
AND is_live = false AND is_live = false
AND status = 'upcoming' AND status = 'upcoming'
LIMIT 1; LIMIT 1;
-- name: GetSportAndLeagueIDs :one
SELECT sport_id, league_id FROM events
WHERE id = $1;
-- name: UpdateMatchResult :exec -- name: UpdateMatchResult :exec
UPDATE events UPDATE events
SET score = $1, SET score = $1,
@ -243,19 +292,6 @@ WHERE id = $1;
UPDATE events UPDATE events
SET is_monitored = $1 SET is_monitored = $1
WHERE id = $2; WHERE id = $2;
-- name: UpdateEventSettings :exec
UPDATE company_event_settings
SET is_active = COALESCE(sqlc.narg('is_active'), is_active),
is_featured = COALESCE(
sqlc.narg('is_featured'),
is_featured
),
winning_upper_limit = COALESCE(
sqlc.narg('winning_upper_limit'),
winning_upper_limit
)
WHERE event_id = $1
AND company_id = $2;
-- name: DeleteEvent :exec -- name: DeleteEvent :exec
DELETE FROM events DELETE FROM events
WHERE id = $1; WHERE id = $1;

View File

@ -36,13 +36,18 @@ WHERE (
sport_id = sqlc.narg('sport_id') sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL OR sqlc.narg('sport_id') IS NULL
) )
AND (
name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
ORDER BY name ASC ORDER BY name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetAllLeaguesWithSettings :many -- name: GetTotalLeaguesWithSettings :one
SELECT * SELECT COUNT(*)
FROM league_with_settings FROM leagues l
WHERE (company_id = $1) LEFT JOIN company_league_settings cls ON l.id = cls.league_id
AND ( AND company_id = $1
WHERE (
country_code = sqlc.narg('country_code') country_code = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL OR sqlc.narg('country_code') IS NULL
) )
@ -52,12 +57,49 @@ WHERE (company_id = $1)
) )
AND ( AND (
is_active = sqlc.narg('is_active') is_active = sqlc.narg('is_active')
OR default_is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL OR sqlc.narg('is_active') IS NULL
) )
AND ( AND (
is_featured = sqlc.narg('is_featured') is_featured = sqlc.narg('is_featured')
OR default_is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL OR sqlc.narg('is_featured') IS NULL
) )
AND (
name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
);
-- name: GetAllLeaguesWithSettings :many
SELECT l.*,
cls.company_id,
COALESCE(cls.is_active, l.default_is_active) AS is_active,
COALESCE(cls.is_featured, l.default_is_featured) AS is_featured,
cls.updated_at
FROM leagues l
LEFT JOIN company_league_settings cls ON l.id = cls.league_id
AND company_id = $1
WHERE (
country_code = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
)
AND (
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
is_active = sqlc.narg('is_active')
OR default_is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
)
AND (
is_featured = sqlc.narg('is_featured')
OR default_is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL
)
AND (
name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
ORDER BY is_featured DESC, ORDER BY is_featured DESC,
name ASC name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');

View File

@ -26,7 +26,7 @@ SET market_type = EXCLUDED.market_type,
raw_odds = EXCLUDED.raw_odds, raw_odds = EXCLUDED.raw_odds,
fetched_at = EXCLUDED.fetched_at, fetched_at = EXCLUDED.fetched_at,
expires_at = EXCLUDED.expires_at; expires_at = EXCLUDED.expires_at;
-- name: InsertOddSettings :exec -- name: SaveOddSettings :exec
INSERT INTO company_odd_settings ( INSERT INTO company_odd_settings (
company_id, company_id,
odds_market_id, odds_market_id,
@ -42,21 +42,69 @@ SELECT *
FROM odds_market_with_event FROM odds_market_with_event
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetAllOddsWithSettings :many -- name: GetAllOddsWithSettings :many
SELECT * SELECT o.id,
FROM odds_market_with_settings o.event_id,
WHERE company_id = $1 o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $1
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetOddByID :one
SELECT *
FROM odds_market_with_event
WHERE id = $1;
-- name: GetOddsByMarketID :one -- name: GetOddsByMarketID :one
SELECT * SELECT *
FROM odds_market_with_event FROM odds_market_with_event
WHERE market_id = $1 WHERE market_id = $1
AND event_id = $2; AND event_id = $2;
-- name: GetOddsWithSettingsByMarketID :one -- name: GetOddsWithSettingsByMarketID :one
SELECT * SELECT o.id,
FROM odds_market_with_settings o.event_id,
o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $3
WHERE market_id = $1 WHERE market_id = $1
AND event_id = $2 AND event_id = $2;
AND company_id = $3; -- name: GetOddsWithSettingsByID :one
SELECT o.id,
o.event_id,
o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $2
WHERE o.id = $1;
-- name: GetOddsByEventID :many -- name: GetOddsByEventID :many
SELECT * SELECT *
FROM odds_market_with_event FROM odds_market_with_event
@ -75,10 +123,23 @@ WHERE event_id = $1
) )
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetOddsWithSettingsByEventID :many -- name: GetOddsWithSettingsByEventID :many
SELECT * SELECT o.id,
FROM odds_market_with_settings o.event_id,
WHERE event_id = $1 o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $2 AND company_id = $2
WHERE event_id = $1
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: DeleteOddsForEvent :exec -- name: DeleteOddsForEvent :exec
DELETE FROM odds_market DELETE FROM odds_market

73
db/query/raffle.sql Normal file
View File

@ -0,0 +1,73 @@
-- name: CreateRaffle :one
INSERT INTO raffles (company_id, name, expires_at, type)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetRafflesOfCompany :many
SELECT * FROM raffles WHERE company_id = $1;
-- name: DeleteRaffle :one
DELETE FROM raffles
WHERE id = $1
RETURNING *;
-- name: UpdateRaffleTicketStatus :exec
UPDATE raffle_tickets
SET is_active = $1
WHERE id = $2;
-- name: CreateRaffleTicket :one
INSERT INTO raffle_tickets (raffle_id, user_id)
VALUES ($1, $2)
RETURNING *;
-- name: GetUserRaffleTickets :many
SELECT
rt.id AS ticket_id,
rt.user_id,
r.name,
r.type,
r.expires_at,
r.status
FROM raffle_tickets rt
JOIN raffles r ON rt.raffle_id = r.id
WHERE rt.user_id = $1;
-- name: GetRaffleStanding :many
SELECT
u.id AS user_id,
rt.raffle_id,
u.first_name,
u.last_name,
u.phone_number,
u.email,
COUNT(*) AS ticket_count
FROM raffle_tickets rt
JOIN users u ON rt.user_id = u.id
WHERE rt.is_active = true
AND rt.raffle_id = $1
GROUP BY u.id, rt.raffle_id, u.first_name, u.last_name, u.phone_number, u.email
ORDER BY ticket_count DESC
LIMIT $2;
-- name: CreateRaffleWinner :one
INSERT INTO raffle_winners (raffle_id, user_id, rank)
VALUES ($1, $2, $3)
RETURNING *;
-- name: SetRaffleComplete :exec
UPDATE raffles
SET status = 'completed'
WHERE id = $1;
-- name: AddSportRaffleFilter :one
INSERT INTO raffle_sport_filters (raffle_id, sport_id, league_id)
VALUES ($1, $2, $3)
RETURNING *;
-- name: CheckValidSportRaffleFilter :one
SELECT COUNT(*) > 0 AS exists
FROM raffle_sport_filters
WHERE raffle_id = $1
AND sport_id = $2
AND league_id = $3;

View File

@ -1,77 +1,51 @@
-- name: CreateReferral :one -- name: CreateReferralCode :one
INSERT INTO referrals ( INSERT INTO referral_codes (
referral_code, referral_code,
referrer_id, referrer_id,
status, company_id,
reward_amount, number_of_referrals,
expires_at reward_amount
) VALUES ( )
$1, $2, $3, $4, $5 VALUES ($1, $2, $3, $4, $5)
) RETURNING *;
-- name: GetReferralByCode :one
SELECT * FROM referrals
WHERE referral_code = $1;
-- name: UpdateReferral :one
UPDATE referrals
SET
referred_id = $2,
status = $3,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING *; RETURNING *;
-- name: CreateUserReferral :one
-- name: UpdateReferralCode :exec INSERT INTO user_referrals (referred_id, referral_code_id)
UPDATE users VALUES ($1, $2)
SET RETURNING *;
referral_code = $2, -- name: GetReferralCodeByUser :many
updated_at = CURRENT_TIMESTAMP SELECt *
WHERE id = $1; FROM referral_codes
-- name: GetReferralStats :one
SELECT
COUNT(*) as total_referrals,
COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) as completed_referrals,
COALESCE(SUM(reward_amount), 0) as total_reward_earned,
COALESCE(SUM(CASE WHEN status = 'PENDING' THEN reward_amount END), 0) as pending_rewards
FROM referrals
WHERE referrer_id = $1; WHERE referrer_id = $1;
-- name: GetReferralCode :one
-- name: GetReferralSettings :one SELECT *
SELECT * FROM referral_settings FROM referral_codes
LIMIT 1; WHERE referral_code = $1;
-- name: UpdateReferralCode :exec
-- name: UpdateReferralSettings :one UPDATE referral_codes
UPDATE referral_settings SET is_active = $2,
SET referral_code = $3,
referral_reward_amount = $2, number_of_referrals = $4,
cashback_percentage = $3, reward_amount = $5,
bet_referral_bonus_percentage= $4, updated_at = CURRENT_TIMESTAMP
max_referrals = $5, WHERE id = $1;
expires_after_days = $6, -- name: GetReferralStats :one
updated_by = $7, SELECT COUNT(*) AS total_referrals,
updated_at = CURRENT_TIMESTAMP COALESCE(SUM(reward_amount), 0)::bigint AS total_reward_earned
WHERE id = $1 FROM user_referrals
RETURNING *; JOIN referral_codes ON referral_codes.id = referral_code_id
WHERE referrer_id = $1
-- name: CreateReferralSettings :one AND company_id = $2;
INSERT INTO referral_settings ( -- name: GetUserReferral :one
referral_reward_amount, SELECT *
cashback_percentage, FROM user_referrals
max_referrals, WHERE referred_id = $1;
bet_referral_bonus_percentage, -- name: GetUserReferralsByCode :many
expires_after_days, SELECT user_referrals.*
updated_by FROM user_referrals
) VALUES ( JOIN referral_codes ON referral_codes.id = referral_code_id
$1, $2, $3, $4, $5, $6 WHERE referral_code = $1;
) RETURNING *; -- name: GetUserReferralsCount :one
SELECT COUNT(*)
-- name: GetReferralByReferredID :one FROM user_referrals
SELECT * FROM referrals WHERE referred_id = $1 LIMIT 1; JOIN referral_codes ON referral_codes.id = referral_code_id
WHERE referrer_id = $1;
-- name: GetActiveReferralByReferrerID :one
SELECT * FROM referrals WHERE referrer_id = $1 AND status = 'PENDING' LIMIT 1;
-- name: GetReferralCountByID :one
SELECT count(*) FROM referrals WHERE referrer_id = $1;

View File

@ -27,7 +27,9 @@ SELECT *
FROM company_settings FROM company_settings
WHERE key = $1; WHERE key = $1;
-- name: GetOverrideSettings :many -- name: GetOverrideSettings :many
SELECT gs.*, SELECT gs.key,
gs.created_at,
gs.updated_at,
COALESCE(cs.value, gs.value) AS value COALESCE(cs.value, gs.value) AS value
FROM global_settings gs FROM global_settings gs
LEFT JOIN company_settings cs ON cs.key = gs.key LEFT JOIN company_settings cs ON cs.key = gs.key

View File

@ -30,6 +30,19 @@ WHERE id = $1;
SELECT * SELECT *
FROM wallet_transfer_details FROM wallet_transfer_details
WHERE reference_number = $1; WHERE reference_number = $1;
-- name: GetTransferStats :one
SELECT COUNT(*) AS total_transfers, COUNT(*) FILTER (
WHERE type = 'deposit'
) AS total_deposits,
COUNT(*) FILTER (
WHERE type = 'withdraw'
) AS total_withdraw,
COUNT(*) FILTER (
WHERE type = 'wallet'
) AS total_wallet_to_wallet
FROM wallet_transfer
WHERE sender_wallet_id = $1
OR receiver_wallet_id = $1;
-- name: UpdateTransferVerification :exec -- name: UpdateTransferVerification :exec
UPDATE wallet_transfer UPDATE wallet_transfer
SET verified = $1, SET verified = $1,

View File

@ -193,7 +193,7 @@ SET password = $1,
WHERE ( WHERE (
email = $2 email = $2
OR phone_number = $3 OR phone_number = $3
AND company_id = $4 AND company_id = $5
); );
-- name: GetAdminByCompanyID :one -- name: GetAdminByCompanyID :one
SELECT users.* SELECT users.*

View File

@ -1,77 +1,157 @@
-- name: CreateVirtualGameProvider :one -- name: CreateVirtualGameProvider :one
INSERT INTO virtual_game_providers ( INSERT INTO virtual_game_providers (
provider_id, provider_name, logo_dark, logo_light, enabled provider_id,
) VALUES ( provider_name,
$1, $2, $3, $4, $5 logo_dark,
) RETURNING id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at; logo_light,
enabled
)
VALUES ($1, $2, $3, $4, $5)
RETURNING id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at;
-- name: DeleteVirtualGameProvider :exec -- name: DeleteVirtualGameProvider :exec
DELETE FROM virtual_game_providers DELETE FROM virtual_game_providers
WHERE provider_id = $1; WHERE provider_id = $1;
-- name: DeleteAllVirtualGameProviders :exec -- name: DeleteAllVirtualGameProviders :exec
DELETE FROM virtual_game_providers; DELETE FROM virtual_game_providers;
-- name: GetVirtualGameProviderByID :one -- name: GetVirtualGameProviderByID :one
SELECT id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at SELECT id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at
FROM virtual_game_providers FROM virtual_game_providers
WHERE provider_id = $1; WHERE provider_id = $1;
-- name: ListVirtualGameProviders :many -- name: ListVirtualGameProviders :many
SELECT id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at SELECT id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at
FROM virtual_game_providers FROM virtual_game_providers
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT $1 OFFSET $2; LIMIT $1 OFFSET $2;
-- name: CountVirtualGameProviders :one -- name: CountVirtualGameProviders :one
SELECT COUNT(*) AS total SELECT COUNT(*) AS total
FROM virtual_game_providers; FROM virtual_game_providers;
-- name: UpdateVirtualGameProviderEnabled :one -- name: UpdateVirtualGameProviderEnabled :one
UPDATE virtual_game_providers UPDATE virtual_game_providers
SET enabled = $2, SET enabled = $2,
updated_at = CURRENT_TIMESTAMP updated_at = CURRENT_TIMESTAMP
WHERE provider_id = $1 WHERE provider_id = $1
RETURNING id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at; RETURNING id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at;
-- name: CreateVirtualGameSession :one -- name: CreateVirtualGameSession :one
INSERT INTO virtual_game_sessions ( INSERT INTO virtual_game_sessions (
user_id, game_id, session_token, currency, status, expires_at user_id,
) VALUES ( game_id,
$1, $2, $3, $4, $5, $6 session_token,
) RETURNING id, user_id, game_id, session_token, currency, status, created_at, updated_at, expires_at; currency,
status,
expires_at
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id,
user_id,
game_id,
session_token,
currency,
status,
created_at,
updated_at,
expires_at;
-- name: GetVirtualGameSessionByToken :one -- name: GetVirtualGameSessionByToken :one
SELECT id, user_id, game_id, session_token, currency, status, created_at, updated_at, expires_at SELECT id,
user_id,
game_id,
session_token,
currency,
status,
created_at,
updated_at,
expires_at
FROM virtual_game_sessions FROM virtual_game_sessions
WHERE session_token = $1; WHERE session_token = $1;
-- name: UpdateVirtualGameSessionStatus :exec -- name: UpdateVirtualGameSessionStatus :exec
UPDATE virtual_game_sessions UPDATE virtual_game_sessions
SET status = $2, updated_at = CURRENT_TIMESTAMP SET status = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1; WHERE id = $1;
-- name: CreateVirtualGameTransaction :one -- name: CreateVirtualGameTransaction :one
INSERT INTO virtual_game_transactions ( INSERT INTO virtual_game_transactions (
session_id, user_id, company_id, provider, wallet_id, transaction_type, amount, currency, external_transaction_id, status session_id,
) VALUES ( user_id,
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10 company_id,
) RETURNING id, session_id, user_id, company_id, provider, wallet_id, transaction_type, amount, currency, external_transaction_id, status, created_at, updated_at; provider,
-- name: CreateVirtualGameHistory :one wallet_id,
INSERT INTO virtual_game_histories ( transaction_type,
amount,
currency,
external_transaction_id,
status
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id,
session_id, session_id,
user_id, user_id,
company_id, company_id,
provider, provider,
wallet_id, wallet_id,
game_id,
transaction_type, transaction_type,
amount, amount,
currency, currency,
external_transaction_id, external_transaction_id,
reference_transaction_id, status,
status created_at,
) VALUES ( updated_at;
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 -- name: CreateVirtualGameHistory :one
) RETURNING INSERT INTO virtual_game_histories (
id, session_id,
user_id,
company_id,
provider,
wallet_id,
game_id,
transaction_type,
amount,
currency,
external_transaction_id,
reference_transaction_id,
status
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id,
session_id, session_id,
user_id, user_id,
company_id, company_id,
@ -87,60 +167,78 @@ INSERT INTO virtual_game_histories (
created_at, created_at,
updated_at; updated_at;
-- name: GetVirtualGameTransactionByExternalID :one -- name: GetVirtualGameTransactionByExternalID :one
SELECT id, session_id, user_id, wallet_id, transaction_type, amount, currency, external_transaction_id, status, created_at, updated_at SELECT id,
session_id,
user_id,
wallet_id,
transaction_type,
amount,
currency,
external_transaction_id,
status,
created_at,
updated_at
FROM virtual_game_transactions FROM virtual_game_transactions
WHERE external_transaction_id = $1; WHERE external_transaction_id = $1;
-- name: UpdateVirtualGameTransactionStatus :exec -- name: UpdateVirtualGameTransactionStatus :exec
UPDATE virtual_game_transactions UPDATE virtual_game_transactions
SET status = $2, updated_at = CURRENT_TIMESTAMP SET status = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1; WHERE id = $1;
-- name: GetVirtualGameSummaryInRange :many -- name: GetVirtualGameSummaryInRange :many
SELECT SELECT c.name AS company_name,
c.name AS company_name,
vg.name AS game_name, vg.name AS game_name,
COUNT(vgt.id) AS number_of_bets, COUNT(vgt.id) AS number_of_bets,
COALESCE(SUM(vgt.amount), 0) AS total_transaction_sum COALESCE(SUM(vgt.amount), 0) AS total_transaction_sum
FROM virtual_game_transactions vgt FROM virtual_game_transactions vgt
JOIN virtual_game_sessions vgs ON vgt.session_id = vgs.id JOIN virtual_game_sessions vgs ON vgt.session_id = vgs.id
JOIN virtual_games vg ON vgs.game_id = vg.id JOIN virtual_games vg ON vgs.game_id = vg.id
JOIN companies c ON vgt.company_id = c.id JOIN companies c ON vgt.company_id = c.id
WHERE vgt.transaction_type = 'BET' WHERE vgt.transaction_type = 'BET'
AND vgt.created_at BETWEEN $1 AND $2 AND vgt.created_at BETWEEN $1 AND $2
GROUP BY c.name, vg.name; GROUP BY c.name,
vg.name;
-- name: AddFavoriteGame :exec -- name: AddFavoriteGame :exec
INSERT INTO favorite_games ( INSERT INTO favorite_games (user_id, game_id, created_at)
user_id, VALUES ($1, $2, NOW()) ON CONFLICT (user_id, game_id) DO NOTHING;
game_id,
created_at
) VALUES ($1, $2, NOW())
ON CONFLICT (user_id, game_id) DO NOTHING;
-- name: RemoveFavoriteGame :exec -- name: RemoveFavoriteGame :exec
DELETE FROM favorite_games DELETE FROM favorite_games
WHERE user_id = $1 AND game_id = $2; WHERE user_id = $1
AND game_id = $2;
-- name: ListFavoriteGames :many -- name: ListFavoriteGames :many
SELECT game_id SELECT game_id
FROM favorite_games FROM favorite_games
WHERE user_id = $1; WHERE user_id = $1;
-- name: CreateVirtualGame :one -- name: CreateVirtualGame :one
INSERT INTO virtual_games ( INSERT INTO virtual_games (
game_id, game_id,
provider_id, provider_id,
name, name,
category, category,
device_type, device_type,
volatility, volatility,
rtp, rtp,
has_demo, has_demo,
has_free_bets, has_free_bets,
bets, bets,
thumbnail, thumbnail,
status status
) VALUES ( )
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 VALUES (
) $1,
RETURNING $2,
id, $3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id,
game_id, game_id,
provider_id, provider_id,
name, name,
@ -155,10 +253,8 @@ RETURNING
status, status,
created_at, created_at,
updated_at; updated_at;
-- name: GetAllVirtualGames :many -- name: GetAllVirtualGames :many
SELECT SELECT vg.id,
vg.id,
vg.game_id, vg.game_id,
vg.provider_id, vg.provider_id,
vp.provider_name, vp.provider_name,
@ -175,14 +271,20 @@ SELECT
vg.created_at, vg.created_at,
vg.updated_at vg.updated_at
FROM virtual_games vg FROM virtual_games vg
JOIN virtual_game_providers vp ON vg.provider_id = vp.provider_id JOIN virtual_game_providers vp ON vg.provider_id = vp.provider_id
WHERE WHERE (
($1::text IS NULL OR vg.category = $1) -- category filter (optional) vg.category = sqlc.narg('category')
AND ($2::text IS NULL OR vg.name ILIKE '%' || $2 || '%') -- search by name (optional) OR sqlc.narg('category') IS NULL
)
AND (
name ILIKE '%' || sqlc.narg('name') || '%'
OR sqlc.narg('name') IS NULL
)
AND (
vg.provider_id = sqlc.narg('provider_id')
OR sqlc.narg('provider_id') IS NULL
)
ORDER BY vg.created_at DESC ORDER BY vg.created_at DESC
LIMIT $3 OFFSET $4; LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: DeleteAllVirtualGames :exec -- name: DeleteAllVirtualGames :exec
DELETE FROM virtual_games; DELETE FROM virtual_games;

View File

@ -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.30.0
// source: auth.sql // source: auth.sql
package dbgen package dbgen
@ -76,7 +76,7 @@ func (q *Queries) GetRefreshTokenByUserID(ctx context.Context, userID int64) (Re
} }
const GetUserByEmailPhone = `-- name: GetUserByEmailPhone :one const GetUserByEmailPhone = `-- name: GetUserByEmailPhone :one
SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended, referral_code, referred_by SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended
FROM users FROM users
WHERE ( WHERE (
email = $1 email = $1
@ -112,8 +112,6 @@ func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPho
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
) )
return i, err return i, err
} }

View File

@ -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.30.0
// source: bet.sql // source: bet.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: bet_stat.sql // source: bet_stat.sql
package dbgen package dbgen

View File

@ -1,49 +1,112 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: bonus.sql // source: bonus.sql
package dbgen package dbgen
import ( import (
"context" "context"
"github.com/jackc/pgx/v5/pgtype"
) )
const CreateBonusMultiplier = `-- name: CreateBonusMultiplier :exec const CreateUserBonus = `-- name: CreateUserBonus :one
INSERT INTO bonus (multiplier, balance_cap) INSERT INTO user_bonuses (
VALUES ($1, $2) name,
description,
type,
user_id,
reward_amount,
expires_at
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, name, description, type, user_id, reward_amount, is_claimed, expires_at, claimed_at, created_at, updated_at
` `
type CreateBonusMultiplierParams struct { type CreateUserBonusParams struct {
Multiplier float32 `json:"multiplier"` Name string `json:"name"`
BalanceCap int64 `json:"balance_cap"` Description string `json:"description"`
Type string `json:"type"`
UserID int64 `json:"user_id"`
RewardAmount int64 `json:"reward_amount"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
} }
func (q *Queries) CreateBonusMultiplier(ctx context.Context, arg CreateBonusMultiplierParams) error { func (q *Queries) CreateUserBonus(ctx context.Context, arg CreateUserBonusParams) (UserBonuse, error) {
_, err := q.db.Exec(ctx, CreateBonusMultiplier, arg.Multiplier, arg.BalanceCap) row := q.db.QueryRow(ctx, CreateUserBonus,
arg.Name,
arg.Description,
arg.Type,
arg.UserID,
arg.RewardAmount,
arg.ExpiresAt,
)
var i UserBonuse
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.Type,
&i.UserID,
&i.RewardAmount,
&i.IsClaimed,
&i.ExpiresAt,
&i.ClaimedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const DeleteUserBonus = `-- name: DeleteUserBonus :exec
DELETE FROM user_bonuses
WHERE id = $1
`
func (q *Queries) DeleteUserBonus(ctx context.Context, id int64) error {
_, err := q.db.Exec(ctx, DeleteUserBonus, id)
return err return err
} }
const GetBonusBalanceCap = `-- name: GetBonusBalanceCap :many const GetAllUserBonuses = `-- name: GetAllUserBonuses :many
SELECT id, balance_cap SELECT id, name, description, type, user_id, reward_amount, is_claimed, expires_at, claimed_at, created_at, updated_at
FROM bonus FROM user_bonuses
WHERE (
user_id = $1
OR $1 IS NULL
)
LIMIT $3 OFFSET $2
` `
type GetBonusBalanceCapRow struct { type GetAllUserBonusesParams struct {
ID int64 `json:"id"` UserID pgtype.Int8 `json:"user_id"`
BalanceCap int64 `json:"balance_cap"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
} }
func (q *Queries) GetBonusBalanceCap(ctx context.Context) ([]GetBonusBalanceCapRow, error) { func (q *Queries) GetAllUserBonuses(ctx context.Context, arg GetAllUserBonusesParams) ([]UserBonuse, error) {
rows, err := q.db.Query(ctx, GetBonusBalanceCap) rows, err := q.db.Query(ctx, GetAllUserBonuses, arg.UserID, arg.Offset, arg.Limit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []GetBonusBalanceCapRow var items []UserBonuse
for rows.Next() { for rows.Next() {
var i GetBonusBalanceCapRow var i UserBonuse
if err := rows.Scan(&i.ID, &i.BalanceCap); err != nil { if err := rows.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.Type,
&i.UserID,
&i.RewardAmount,
&i.IsClaimed,
&i.ExpiresAt,
&i.ClaimedAt,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err return nil, err
} }
items = append(items, i) items = append(items, i)
@ -54,50 +117,108 @@ func (q *Queries) GetBonusBalanceCap(ctx context.Context) ([]GetBonusBalanceCapR
return items, nil return items, nil
} }
const GetBonusMultiplier = `-- name: GetBonusMultiplier :many const GetBonusCount = `-- name: GetBonusCount :one
SELECT id, multiplier SELECT COUNT(*)
FROM bonus FROM user_bonuses
WHERE (
user_id = $1
OR $1 IS NULL
)
` `
type GetBonusMultiplierRow struct { func (q *Queries) GetBonusCount(ctx context.Context, userID pgtype.Int8) (int64, error) {
ID int64 `json:"id"` row := q.db.QueryRow(ctx, GetBonusCount, userID)
Multiplier float32 `json:"multiplier"` var count int64
err := row.Scan(&count)
return count, err
} }
func (q *Queries) GetBonusMultiplier(ctx context.Context) ([]GetBonusMultiplierRow, error) { const GetBonusStats = `-- name: GetBonusStats :one
rows, err := q.db.Query(ctx, GetBonusMultiplier) SELECT COUNT(*) AS total_bonuses,
if err != nil { COALESCE(SUM(reward_amount), 0)::bigint AS total_reward_earned,
return nil, err COUNT(
} CASE
defer rows.Close() WHEN is_claimed = true THEN 1
var items []GetBonusMultiplierRow END
for rows.Next() { ) AS claimed_bonuses,
var i GetBonusMultiplierRow COUNT(
if err := rows.Scan(&i.ID, &i.Multiplier); err != nil { CASE
return nil, err WHEN expires_at < now() THEN 1
} END
items = append(items, i) ) AS expired_bonuses
} FROM user_bonuses
if err := rows.Err(); err != nil { JOIN users ON users.id = user_bonuses.user_id
return nil, err WHERE (
} company_id = $1
return items, nil OR $1 IS NULL
} )
AND (
const UpdateBonusMultiplier = `-- name: UpdateBonusMultiplier :exec user_id = $2
UPDATE bonus OR $2 IS NULL
SET multiplier = $1, )
balance_cap = $2
WHERE id = $3
` `
type UpdateBonusMultiplierParams struct { type GetBonusStatsParams struct {
Multiplier float32 `json:"multiplier"` CompanyID pgtype.Int8 `json:"company_id"`
BalanceCap int64 `json:"balance_cap"` UserID pgtype.Int8 `json:"user_id"`
ID int64 `json:"id"`
} }
func (q *Queries) UpdateBonusMultiplier(ctx context.Context, arg UpdateBonusMultiplierParams) error { type GetBonusStatsRow struct {
_, err := q.db.Exec(ctx, UpdateBonusMultiplier, arg.Multiplier, arg.BalanceCap, arg.ID) TotalBonuses int64 `json:"total_bonuses"`
TotalRewardEarned int64 `json:"total_reward_earned"`
ClaimedBonuses int64 `json:"claimed_bonuses"`
ExpiredBonuses int64 `json:"expired_bonuses"`
}
func (q *Queries) GetBonusStats(ctx context.Context, arg GetBonusStatsParams) (GetBonusStatsRow, error) {
row := q.db.QueryRow(ctx, GetBonusStats, arg.CompanyID, arg.UserID)
var i GetBonusStatsRow
err := row.Scan(
&i.TotalBonuses,
&i.TotalRewardEarned,
&i.ClaimedBonuses,
&i.ExpiredBonuses,
)
return i, err
}
const GetUserBonusByID = `-- name: GetUserBonusByID :one
SELECT id, name, description, type, user_id, reward_amount, is_claimed, expires_at, claimed_at, created_at, updated_at
FROM user_bonuses
WHERE id = $1
`
func (q *Queries) GetUserBonusByID(ctx context.Context, id int64) (UserBonuse, error) {
row := q.db.QueryRow(ctx, GetUserBonusByID, id)
var i UserBonuse
err := row.Scan(
&i.ID,
&i.Name,
&i.Description,
&i.Type,
&i.UserID,
&i.RewardAmount,
&i.IsClaimed,
&i.ExpiresAt,
&i.ClaimedAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateUserBonus = `-- name: UpdateUserBonus :exec
UPDATE user_bonuses
SET is_claimed = $2
WHERE id = $1
`
type UpdateUserBonusParams struct {
ID int64 `json:"id"`
IsClaimed bool `json:"is_claimed"`
}
func (q *Queries) UpdateUserBonus(ctx context.Context, arg UpdateUserBonusParams) error {
_, err := q.db.Exec(ctx, UpdateUserBonus, arg.ID, arg.IsClaimed)
return err return err
} }

View File

@ -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.30.0
// source: branch.sql // source: branch.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: cashier.sql // source: cashier.sql
package dbgen package dbgen
@ -12,7 +12,7 @@ import (
) )
const GetAllCashiers = `-- name: GetAllCashiers :many const GetAllCashiers = `-- name: GetAllCashiers :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by, SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended,
branch_id, branch_id,
branches.name AS branch_name, branches.name AS branch_name,
branches.wallet_id AS branch_wallet, branches.wallet_id AS branch_wallet,
@ -57,8 +57,6 @@ type GetAllCashiersRow struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
SuspendedAt pgtype.Timestamptz `json:"suspended_at"` SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
Suspended bool `json:"suspended"` Suspended bool `json:"suspended"`
ReferralCode pgtype.Text `json:"referral_code"`
ReferredBy pgtype.Text `json:"referred_by"`
BranchID int64 `json:"branch_id"` BranchID int64 `json:"branch_id"`
BranchName string `json:"branch_name"` BranchName string `json:"branch_name"`
BranchWallet int64 `json:"branch_wallet"` BranchWallet int64 `json:"branch_wallet"`
@ -89,8 +87,6 @@ func (q *Queries) GetAllCashiers(ctx context.Context, arg GetAllCashiersParams)
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
&i.BranchID, &i.BranchID,
&i.BranchName, &i.BranchName,
&i.BranchWallet, &i.BranchWallet,
@ -107,7 +103,7 @@ func (q *Queries) GetAllCashiers(ctx context.Context, arg GetAllCashiersParams)
} }
const GetCashierByID = `-- name: GetCashierByID :one const GetCashierByID = `-- name: GetCashierByID :one
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by, SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended,
branch_id, branch_id,
branches.name AS branch_name, branches.name AS branch_name,
branches.wallet_id AS branch_wallet, branches.wallet_id AS branch_wallet,
@ -133,8 +129,6 @@ type GetCashierByIDRow struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
SuspendedAt pgtype.Timestamptz `json:"suspended_at"` SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
Suspended bool `json:"suspended"` Suspended bool `json:"suspended"`
ReferralCode pgtype.Text `json:"referral_code"`
ReferredBy pgtype.Text `json:"referred_by"`
BranchID int64 `json:"branch_id"` BranchID int64 `json:"branch_id"`
BranchName string `json:"branch_name"` BranchName string `json:"branch_name"`
BranchWallet int64 `json:"branch_wallet"` BranchWallet int64 `json:"branch_wallet"`
@ -159,8 +153,6 @@ func (q *Queries) GetCashierByID(ctx context.Context, id int64) (GetCashierByIDR
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
&i.BranchID, &i.BranchID,
&i.BranchName, &i.BranchName,
&i.BranchWallet, &i.BranchWallet,
@ -170,7 +162,7 @@ func (q *Queries) GetCashierByID(ctx context.Context, id int64) (GetCashierByIDR
} }
const GetCashiersByBranch = `-- name: GetCashiersByBranch :many const GetCashiersByBranch = `-- name: GetCashiersByBranch :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended
FROM branch_cashiers FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id JOIN users ON branch_cashiers.user_id = users.id
JOIN branches ON branches.id = branch_id JOIN branches ON branches.id = branch_id
@ -201,8 +193,6 @@ func (q *Queries) GetCashiersByBranch(ctx context.Context, branchID int64) ([]Us
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
); err != nil { ); err != nil {
return nil, err return nil, err
} }

View File

@ -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.30.0
// source: company.sql // source: company.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: copyfrom.go // source: copyfrom.go
package dbgen package dbgen

View File

@ -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.30.0
package dbgen package dbgen

View File

@ -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.30.0
// source: direct_deposit.sql // source: direct_deposit.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: disabled_odds.sql // source: disabled_odds.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: event_history.sql // source: event_history.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: events.sql // source: events.sql
package dbgen package dbgen
@ -78,10 +78,21 @@ func (q *Queries) GetAllUpcomingEvents(ctx context.Context) ([]EventWithCountry,
} }
const GetEventWithSettingByID = `-- name: GetEventWithSettingByID :one const GetEventWithSettingByID = `-- name: GetEventWithSettingByID :one
SELECT id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, company_id, is_active, is_featured, winning_upper_limit, updated_at, league_cc SELECT e.id, e.sport_id, e.match_name, e.home_team, e.away_team, e.home_team_id, e.away_team_id, e.home_kit_image, e.away_kit_image, e.league_id, e.league_name, e.start_time, e.score, e.match_minute, e.timer_status, e.added_time, e.match_period, e.is_live, e.status, e.fetched_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
FROM event_with_settings ces.company_id,
WHERE id = $1 COALESCE(ces.is_active, e.default_is_active) AS is_active,
AND company_id = $2 COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
COALESCE(
ces.winning_upper_limit,
e.default_winning_upper_limit
) AS winning_upper_limit,
ces.updated_at,
l.country_code as league_cc
FROM events e
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
AND ces.company_id = $2
JOIN leagues l ON l.id = e.league_id
WHERE e.id = $1
AND is_live = false AND is_live = false
AND status = 'upcoming' AND status = 'upcoming'
LIMIT 1 LIMIT 1
@ -92,9 +103,43 @@ type GetEventWithSettingByIDParams struct {
CompanyID int64 `json:"company_id"` CompanyID int64 `json:"company_id"`
} }
func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithSettingByIDParams) (EventWithSetting, error) { type GetEventWithSettingByIDRow struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
StartTime pgtype.Timestamp `json:"start_time"`
Score pgtype.Text `json:"score"`
MatchMinute pgtype.Int4 `json:"match_minute"`
TimerStatus pgtype.Text `json:"timer_status"`
AddedTime pgtype.Int4 `json:"added_time"`
MatchPeriod pgtype.Int4 `json:"match_period"`
IsLive bool `json:"is_live"`
Status string `json:"status"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
LeagueCc pgtype.Text `json:"league_cc"`
}
func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithSettingByIDParams) (GetEventWithSettingByIDRow, error) {
row := q.db.QueryRow(ctx, GetEventWithSettingByID, arg.ID, arg.CompanyID) row := q.db.QueryRow(ctx, GetEventWithSettingByID, arg.ID, arg.CompanyID)
var i EventWithSetting var i GetEventWithSettingByIDRow
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.SportID, &i.SportID,
@ -132,10 +177,21 @@ func (q *Queries) GetEventWithSettingByID(ctx context.Context, arg GetEventWithS
} }
const GetEventsWithSettings = `-- name: GetEventsWithSettings :many const GetEventsWithSettings = `-- name: GetEventsWithSettings :many
SELECT id, sport_id, match_name, home_team, away_team, home_team_id, away_team_id, home_kit_image, away_kit_image, league_id, league_name, start_time, score, match_minute, timer_status, added_time, match_period, is_live, status, fetched_at, source, default_is_active, default_is_featured, default_winning_upper_limit, is_monitored, company_id, is_active, is_featured, winning_upper_limit, updated_at, league_cc SELECT e.id, e.sport_id, e.match_name, e.home_team, e.away_team, e.home_team_id, e.away_team_id, e.home_kit_image, e.away_kit_image, e.league_id, e.league_name, e.start_time, e.score, e.match_minute, e.timer_status, e.added_time, e.match_period, e.is_live, e.status, e.fetched_at, e.source, e.default_is_active, e.default_is_featured, e.default_winning_upper_limit, e.is_monitored,
FROM event_with_settings ces.company_id,
WHERE company_id = $1 COALESCE(ces.is_active, e.default_is_active) AS is_active,
AND start_time > now() COALESCE(ces.is_featured, e.default_is_featured) AS is_featured,
COALESCE(
ces.winning_upper_limit,
e.default_winning_upper_limit
) AS winning_upper_limit,
ces.updated_at,
l.country_code as league_cc
FROM events e
LEFT JOIN company_event_settings ces ON e.id = ces.event_id
AND ces.company_id = $1
JOIN leagues l ON l.id = e.league_id
WHERE start_time > now()
AND is_live = false AND is_live = false
AND status = 'upcoming' AND status = 'upcoming'
AND ( AND (
@ -143,7 +199,7 @@ WHERE company_id = $1
OR $2 IS NULL OR $2 IS NULL
) )
AND ( AND (
sport_id = $3 e.sport_id = $3
OR $3 IS NULL OR $3 IS NULL
) )
AND ( AND (
@ -160,11 +216,21 @@ WHERE company_id = $1
OR $6 IS NULL OR $6 IS NULL
) )
AND ( AND (
league_cc = $7 l.country_code = $7
OR $7 IS NULL OR $7 IS NULL
) )
AND (
ces.is_featured = $8
OR e.default_is_featured = $8
OR $8 IS NULL
)
AND (
ces.is_active = $9
OR e.default_is_active = $9
OR $9 IS NULL
)
ORDER BY start_time ASC ORDER BY start_time ASC
LIMIT $9 OFFSET $8 LIMIT $11 OFFSET $10
` `
type GetEventsWithSettingsParams struct { type GetEventsWithSettingsParams struct {
@ -175,11 +241,47 @@ type GetEventsWithSettingsParams struct {
LastStartTime pgtype.Timestamp `json:"last_start_time"` LastStartTime pgtype.Timestamp `json:"last_start_time"`
FirstStartTime pgtype.Timestamp `json:"first_start_time"` FirstStartTime pgtype.Timestamp `json:"first_start_time"`
CountryCode pgtype.Text `json:"country_code"` CountryCode pgtype.Text `json:"country_code"`
IsFeatured pgtype.Bool `json:"is_featured"`
IsActive pgtype.Bool `json:"is_active"`
Offset pgtype.Int4 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSettingsParams) ([]EventWithSetting, error) { type GetEventsWithSettingsRow struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
StartTime pgtype.Timestamp `json:"start_time"`
Score pgtype.Text `json:"score"`
MatchMinute pgtype.Int4 `json:"match_minute"`
TimerStatus pgtype.Text `json:"timer_status"`
AddedTime pgtype.Int4 `json:"added_time"`
MatchPeriod pgtype.Int4 `json:"match_period"`
IsLive bool `json:"is_live"`
Status string `json:"status"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
LeagueCc pgtype.Text `json:"league_cc"`
}
func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSettingsParams) ([]GetEventsWithSettingsRow, error) {
rows, err := q.db.Query(ctx, GetEventsWithSettings, rows, err := q.db.Query(ctx, GetEventsWithSettings,
arg.CompanyID, arg.CompanyID,
arg.LeagueID, arg.LeagueID,
@ -188,6 +290,8 @@ func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSe
arg.LastStartTime, arg.LastStartTime,
arg.FirstStartTime, arg.FirstStartTime,
arg.CountryCode, arg.CountryCode,
arg.IsFeatured,
arg.IsActive,
arg.Offset, arg.Offset,
arg.Limit, arg.Limit,
) )
@ -195,9 +299,9 @@ func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSe
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []EventWithSetting var items []GetEventsWithSettingsRow
for rows.Next() { for rows.Next() {
var i EventWithSetting var i GetEventsWithSettingsRow
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.SportID, &i.SportID,
@ -401,18 +505,37 @@ func (q *Queries) GetPaginatedUpcomingEvents(ctx context.Context, arg GetPaginat
return items, nil return items, nil
} }
const GetSportAndLeagueIDs = `-- name: GetSportAndLeagueIDs :one
SELECT sport_id, league_id FROM events
WHERE id = $1
`
type GetSportAndLeagueIDsRow struct {
SportID int32 `json:"sport_id"`
LeagueID int64 `json:"league_id"`
}
func (q *Queries) GetSportAndLeagueIDs(ctx context.Context, id string) (GetSportAndLeagueIDsRow, error) {
row := q.db.QueryRow(ctx, GetSportAndLeagueIDs, id)
var i GetSportAndLeagueIDsRow
err := row.Scan(&i.SportID, &i.LeagueID)
return i, err
}
const GetTotalCompanyEvents = `-- name: GetTotalCompanyEvents :one const GetTotalCompanyEvents = `-- name: GetTotalCompanyEvents :one
SELECT COUNT(*) SELECT COUNT(*)
FROM event_with_settings FROM events e
WHERE company_id = $1 LEFT JOIN company_event_settings ces ON e.id = ces.event_id
AND is_live = false AND ces.company_id = $1
JOIN leagues l ON l.id = e.league_id
WHERE is_live = false
AND status = 'upcoming' AND status = 'upcoming'
AND ( AND (
league_id = $2 league_id = $2
OR $2 IS NULL OR $2 IS NULL
) )
AND ( AND (
sport_id = $3 e.sport_id = $3
OR $3 IS NULL OR $3 IS NULL
) )
AND ( AND (
@ -429,9 +552,19 @@ WHERE company_id = $1
OR $6 IS NULL OR $6 IS NULL
) )
AND ( AND (
league_cc = $7 l.country_code = $7
OR $7 IS NULL OR $7 IS NULL
) )
AND (
ces.is_featured = $8
OR e.default_is_featured = $8
OR $8 IS NULL
)
AND (
ces.is_active = $9
OR e.default_is_active = $9
OR $9 IS NULL
)
` `
type GetTotalCompanyEventsParams struct { type GetTotalCompanyEventsParams struct {
@ -442,6 +575,8 @@ type GetTotalCompanyEventsParams struct {
LastStartTime pgtype.Timestamp `json:"last_start_time"` LastStartTime pgtype.Timestamp `json:"last_start_time"`
FirstStartTime pgtype.Timestamp `json:"first_start_time"` FirstStartTime pgtype.Timestamp `json:"first_start_time"`
CountryCode pgtype.Text `json:"country_code"` CountryCode pgtype.Text `json:"country_code"`
IsFeatured pgtype.Bool `json:"is_featured"`
IsActive pgtype.Bool `json:"is_active"`
} }
func (q *Queries) GetTotalCompanyEvents(ctx context.Context, arg GetTotalCompanyEventsParams) (int64, error) { func (q *Queries) GetTotalCompanyEvents(ctx context.Context, arg GetTotalCompanyEventsParams) (int64, error) {
@ -453,6 +588,8 @@ func (q *Queries) GetTotalCompanyEvents(ctx context.Context, arg GetTotalCompany
arg.LastStartTime, arg.LastStartTime,
arg.FirstStartTime, arg.FirstStartTime,
arg.CountryCode, arg.CountryCode,
arg.IsFeatured,
arg.IsActive,
) )
var count int64 var count int64
err := row.Scan(&count) err := row.Scan(&count)
@ -573,7 +710,8 @@ INSERT INTO events (
start_time, start_time,
is_live, is_live,
status, status,
source source,
default_winning_upper_limit
) )
VALUES ( VALUES (
$1, $1,
@ -590,7 +728,8 @@ VALUES (
$12, $12,
$13, $13,
$14, $14,
$15 $15,
$16
) ON CONFLICT (id) DO ) ON CONFLICT (id) DO
UPDATE UPDATE
SET sport_id = EXCLUDED.sport_id, SET sport_id = EXCLUDED.sport_id,
@ -603,7 +742,6 @@ SET sport_id = EXCLUDED.sport_id,
away_kit_image = EXCLUDED.away_kit_image, away_kit_image = EXCLUDED.away_kit_image,
league_id = EXCLUDED.league_id, league_id = EXCLUDED.league_id,
league_name = EXCLUDED.league_name, league_name = EXCLUDED.league_name,
league_cc = EXCLUDED.league_cc,
start_time = EXCLUDED.start_time, start_time = EXCLUDED.start_time,
score = EXCLUDED.score, score = EXCLUDED.score,
match_minute = EXCLUDED.match_minute, match_minute = EXCLUDED.match_minute,
@ -612,25 +750,27 @@ SET sport_id = EXCLUDED.sport_id,
match_period = EXCLUDED.match_period, match_period = EXCLUDED.match_period,
is_live = EXCLUDED.is_live, is_live = EXCLUDED.is_live,
source = EXCLUDED.source, source = EXCLUDED.source,
default_winning_upper_limit = EXCLUDED.default_winning_upper_limit,
fetched_at = now() fetched_at = now()
` `
type InsertEventParams struct { type InsertEventParams struct {
ID string `json:"id"` ID string `json:"id"`
SportID int32 `json:"sport_id"` SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"` MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"` HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"` AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"` HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"` AwayTeamID int64 `json:"away_team_id"`
HomeKitImage string `json:"home_kit_image"` HomeKitImage string `json:"home_kit_image"`
AwayKitImage string `json:"away_kit_image"` AwayKitImage string `json:"away_kit_image"`
LeagueID int64 `json:"league_id"` LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"` LeagueName string `json:"league_name"`
StartTime pgtype.Timestamp `json:"start_time"` StartTime pgtype.Timestamp `json:"start_time"`
IsLive bool `json:"is_live"` IsLive bool `json:"is_live"`
Status string `json:"status"` Status string `json:"status"`
Source string `json:"source"` Source string `json:"source"`
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
} }
func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error { func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error {
@ -650,40 +790,7 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error
arg.IsLive, arg.IsLive,
arg.Status, arg.Status,
arg.Source, arg.Source,
) arg.DefaultWinningUpperLimit,
return err
}
const InsertEventSettings = `-- name: InsertEventSettings :exec
INSERT INTO company_event_settings (
company_id,
event_id,
is_active,
is_featured,
winning_upper_limit
)
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured,
winning_upper_limit = EXCLUDED.winning_upper_limit
`
type InsertEventSettingsParams struct {
CompanyID int64 `json:"company_id"`
EventID string `json:"event_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"`
}
func (q *Queries) InsertEventSettings(ctx context.Context, arg InsertEventSettingsParams) error {
_, err := q.db.Exec(ctx, InsertEventSettings,
arg.CompanyID,
arg.EventID,
arg.IsActive,
arg.IsFeatured,
arg.WinningUpperLimit,
) )
return err return err
} }
@ -727,6 +834,40 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
return items, nil return items, nil
} }
const SaveEventSettings = `-- name: SaveEventSettings :exec
INSERT INTO company_event_settings (
company_id,
event_id,
is_active,
is_featured,
winning_upper_limit
)
VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
is_featured = EXCLUDED.is_featured,
winning_upper_limit = EXCLUDED.winning_upper_limit
`
type SaveEventSettingsParams struct {
CompanyID int64 `json:"company_id"`
EventID string `json:"event_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"`
}
func (q *Queries) SaveEventSettings(ctx context.Context, arg SaveEventSettingsParams) error {
_, err := q.db.Exec(ctx, SaveEventSettings,
arg.CompanyID,
arg.EventID,
arg.IsActive,
arg.IsFeatured,
arg.WinningUpperLimit,
)
return err
}
const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec
UPDATE events UPDATE events
SET is_monitored = $1 SET is_monitored = $1
@ -743,40 +884,6 @@ func (q *Queries) UpdateEventMonitored(ctx context.Context, arg UpdateEventMonit
return err return err
} }
const UpdateEventSettings = `-- name: UpdateEventSettings :exec
UPDATE company_event_settings
SET is_active = COALESCE($3, is_active),
is_featured = COALESCE(
$4,
is_featured
),
winning_upper_limit = COALESCE(
$5,
winning_upper_limit
)
WHERE event_id = $1
AND company_id = $2
`
type UpdateEventSettingsParams struct {
EventID string `json:"event_id"`
CompanyID int64 `json:"company_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"`
}
func (q *Queries) UpdateEventSettings(ctx context.Context, arg UpdateEventSettingsParams) error {
_, err := q.db.Exec(ctx, UpdateEventSettings,
arg.EventID,
arg.CompanyID,
arg.IsActive,
arg.IsFeatured,
arg.WinningUpperLimit,
)
return err
}
const UpdateMatchResult = `-- name: UpdateMatchResult :exec const UpdateMatchResult = `-- name: UpdateMatchResult :exec
UPDATE events UPDATE events
SET score = $1, SET score = $1,

View File

@ -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.30.0
// source: events_stat.sql // source: events_stat.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: flags.sql // source: flags.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: institutions.sql // source: institutions.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: issue_reporting.sql // source: issue_reporting.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: leagues.sql // source: leagues.sql
package dbgen package dbgen
@ -44,13 +44,18 @@ WHERE (
sport_id = $2 sport_id = $2
OR $2 IS NULL OR $2 IS NULL
) )
AND (
name ILIKE '%' || $3 || '%'
OR $3 IS NULL
)
ORDER BY name ASC ORDER BY name ASC
LIMIT $4 OFFSET $3 LIMIT $5 OFFSET $4
` `
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"`
Query pgtype.Text `json:"query"`
Offset pgtype.Int4 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
@ -59,6 +64,7 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
rows, err := q.db.Query(ctx, GetAllLeagues, rows, err := q.db.Query(ctx, GetAllLeagues,
arg.CountryCode, arg.CountryCode,
arg.SportID, arg.SportID,
arg.Query,
arg.Offset, arg.Offset,
arg.Limit, arg.Limit,
) )
@ -90,10 +96,15 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
} }
const GetAllLeaguesWithSettings = `-- name: GetAllLeaguesWithSettings :many const GetAllLeaguesWithSettings = `-- name: GetAllLeaguesWithSettings :many
SELECT id, name, img_url, country_code, bet365_id, sport_id, default_is_active, default_is_featured, company_id, is_active, is_featured, updated_at SELECT l.id, l.name, l.img_url, l.country_code, l.bet365_id, l.sport_id, l.default_is_active, l.default_is_featured,
FROM league_with_settings cls.company_id,
WHERE (company_id = $1) COALESCE(cls.is_active, l.default_is_active) AS is_active,
AND ( COALESCE(cls.is_featured, l.default_is_featured) AS is_featured,
cls.updated_at
FROM leagues l
LEFT JOIN company_league_settings cls ON l.id = cls.league_id
AND company_id = $1
WHERE (
country_code = $2 country_code = $2
OR $2 IS NULL OR $2 IS NULL
) )
@ -103,15 +114,21 @@ WHERE (company_id = $1)
) )
AND ( AND (
is_active = $4 is_active = $4
OR default_is_active = $4
OR $4 IS NULL OR $4 IS NULL
) )
AND ( AND (
is_featured = $5 is_featured = $5
OR default_is_featured = $5
OR $5 IS NULL OR $5 IS NULL
) )
AND (
name ILIKE '%' || $6 || '%'
OR $6 IS NULL
)
ORDER BY is_featured DESC, ORDER BY is_featured DESC,
name ASC name ASC
LIMIT $7 OFFSET $6 LIMIT $8 OFFSET $7
` `
type GetAllLeaguesWithSettingsParams struct { type GetAllLeaguesWithSettingsParams struct {
@ -120,17 +137,34 @@ type GetAllLeaguesWithSettingsParams struct {
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"` IsFeatured pgtype.Bool `json:"is_featured"`
Query pgtype.Text `json:"query"`
Offset pgtype.Int4 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeaguesWithSettingsParams) ([]LeagueWithSetting, error) { type GetAllLeaguesWithSettingsRow struct {
ID int64 `json:"id"`
Name string `json:"name"`
ImgUrl pgtype.Text `json:"img_url"`
CountryCode pgtype.Text `json:"country_code"`
Bet365ID pgtype.Int4 `json:"bet365_id"`
SportID int32 `json:"sport_id"`
DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeaguesWithSettingsParams) ([]GetAllLeaguesWithSettingsRow, error) {
rows, err := q.db.Query(ctx, GetAllLeaguesWithSettings, rows, err := q.db.Query(ctx, GetAllLeaguesWithSettings,
arg.CompanyID, arg.CompanyID,
arg.CountryCode, arg.CountryCode,
arg.SportID, arg.SportID,
arg.IsActive, arg.IsActive,
arg.IsFeatured, arg.IsFeatured,
arg.Query,
arg.Offset, arg.Offset,
arg.Limit, arg.Limit,
) )
@ -138,9 +172,9 @@ func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeagu
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []LeagueWithSetting var items []GetAllLeaguesWithSettingsRow
for rows.Next() { for rows.Next() {
var i LeagueWithSetting var i GetAllLeaguesWithSettingsRow
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.Name, &i.Name,
@ -165,6 +199,58 @@ func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeagu
return items, nil return items, nil
} }
const GetTotalLeaguesWithSettings = `-- name: GetTotalLeaguesWithSettings :one
SELECT COUNT(*)
FROM leagues l
LEFT JOIN company_league_settings cls ON l.id = cls.league_id
AND company_id = $1
WHERE (
country_code = $2
OR $2 IS NULL
)
AND (
sport_id = $3
OR $3 IS NULL
)
AND (
is_active = $4
OR default_is_active = $4
OR $4 IS NULL
)
AND (
is_featured = $5
OR default_is_featured = $5
OR $5 IS NULL
)
AND (
name ILIKE '%' || $6 || '%'
OR $6 IS NULL
)
`
type GetTotalLeaguesWithSettingsParams struct {
CompanyID int64 `json:"company_id"`
CountryCode pgtype.Text `json:"country_code"`
SportID pgtype.Int4 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"`
Query pgtype.Text `json:"query"`
}
func (q *Queries) GetTotalLeaguesWithSettings(ctx context.Context, arg GetTotalLeaguesWithSettingsParams) (int64, error) {
row := q.db.QueryRow(ctx, GetTotalLeaguesWithSettings,
arg.CompanyID,
arg.CountryCode,
arg.SportID,
arg.IsActive,
arg.IsFeatured,
arg.Query,
)
var count int64
err := row.Scan(&count)
return count, err
}
const InsertLeague = `-- name: InsertLeague :exec const InsertLeague = `-- name: InsertLeague :exec
INSERT INTO leagues ( INSERT INTO leagues (
id, id,

View File

@ -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.30.0
// source: location.sql // source: location.sql
package dbgen package dbgen

View File

@ -1,60 +1,13 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
package dbgen package dbgen
import ( import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
type Referralstatus string
const (
ReferralstatusPENDING Referralstatus = "PENDING"
ReferralstatusCOMPLETED Referralstatus = "COMPLETED"
ReferralstatusEXPIRED Referralstatus = "EXPIRED"
ReferralstatusCANCELLED Referralstatus = "CANCELLED"
)
func (e *Referralstatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = Referralstatus(s)
case string:
*e = Referralstatus(s)
default:
return fmt.Errorf("unsupported scan type for Referralstatus: %T", src)
}
return nil
}
type NullReferralstatus struct {
Referralstatus Referralstatus `json:"referralstatus"`
Valid bool `json:"valid"` // Valid is true if Referralstatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullReferralstatus) Scan(value interface{}) error {
if value == nil {
ns.Referralstatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.Referralstatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullReferralstatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.Referralstatus), nil
}
type Bank struct { type Bank struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Slug string `json:"slug"` Slug string `json:"slug"`
@ -126,12 +79,6 @@ type BetWithOutcome struct {
Outcomes []BetOutcome `json:"outcomes"` Outcomes []BetOutcome `json:"outcomes"`
} }
type Bonu struct {
Multiplier float32 `json:"multiplier"`
ID int64 `json:"id"`
BalanceCap int64 `json:"balance_cap"`
}
type Branch struct { type Branch struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@ -321,7 +268,7 @@ type Event struct {
Source string `json:"source"` Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"` IsMonitored bool `json:"is_monitored"`
} }
@ -356,7 +303,7 @@ type EventWithCountry struct {
Source string `json:"source"` Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"` IsMonitored bool `json:"is_monitored"`
LeagueCc pgtype.Text `json:"league_cc"` LeagueCc pgtype.Text `json:"league_cc"`
} }
@ -385,9 +332,9 @@ type EventWithSetting struct {
Source string `json:"source"` Source string `json:"source"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
IsMonitored bool `json:"is_monitored"` IsMonitored bool `json:"is_monitored"`
CompanyID int64 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"` IsFeatured bool `json:"is_featured"`
WinningUpperLimit int32 `json:"winning_upper_limit"` WinningUpperLimit int32 `json:"winning_upper_limit"`
@ -447,7 +394,7 @@ type LeagueWithSetting struct {
SportID int32 `json:"sport_id"` SportID int32 `json:"sport_id"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
CompanyID int64 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
IsFeatured bool `json:"is_featured"` IsFeatured bool `json:"is_featured"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
@ -520,7 +467,7 @@ type OddsMarketWithSetting struct {
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"` FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"` ExpiresAt pgtype.Timestamp `json:"expires_at"`
CompanyID int64 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
RawOdds []byte `json:"raw_odds"` RawOdds []byte `json:"raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
@ -538,30 +485,54 @@ type Otp struct {
ExpiresAt pgtype.Timestamptz `json:"expires_at"` ExpiresAt pgtype.Timestamptz `json:"expires_at"`
} }
type Referral struct { type Raffle struct {
ID int64 `json:"id"` ID int32 `json:"id"`
ReferralCode string `json:"referral_code"` CompanyID int32 `json:"company_id"`
ReferrerID string `json:"referrer_id"` Name string `json:"name"`
ReferredID pgtype.Text `json:"referred_id"` CreatedAt pgtype.Timestamp `json:"created_at"`
Status Referralstatus `json:"status"` ExpiresAt pgtype.Timestamp `json:"expires_at"`
RewardAmount pgtype.Numeric `json:"reward_amount"` Type string `json:"type"`
CashbackAmount pgtype.Numeric `json:"cashback_amount"` Status string `json:"status"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
} }
type ReferralSetting struct { type RaffleGameFilter struct {
ID int64 `json:"id"` ID int32 `json:"id"`
ReferralRewardAmount pgtype.Numeric `json:"referral_reward_amount"` RaffleID int32 `json:"raffle_id"`
CashbackPercentage pgtype.Numeric `json:"cashback_percentage"` GameID string `json:"game_id"`
BetReferralBonusPercentage pgtype.Numeric `json:"bet_referral_bonus_percentage"` }
MaxReferrals int32 `json:"max_referrals"`
ExpiresAfterDays int32 `json:"expires_after_days"` type RaffleSportFilter struct {
UpdatedBy string `json:"updated_by"` ID int32 `json:"id"`
CreatedAt pgtype.Timestamptz `json:"created_at"` RaffleID int32 `json:"raffle_id"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"` SportID int64 `json:"sport_id"`
Version int32 `json:"version"` LeagueID int64 `json:"league_id"`
}
type RaffleTicket struct {
ID int32 `json:"id"`
RaffleID int32 `json:"raffle_id"`
UserID int32 `json:"user_id"`
IsActive pgtype.Bool `json:"is_active"`
}
type RaffleWinner struct {
ID int32 `json:"id"`
RaffleID int32 `json:"raffle_id"`
UserID int32 `json:"user_id"`
Rank int32 `json:"rank"`
CreatedAt pgtype.Timestamp `json:"created_at"`
}
type ReferralCode struct {
ID int64 `json:"id"`
ReferralCode string `json:"referral_code"`
ReferrerID int64 `json:"referrer_id"`
CompanyID int64 `json:"company_id"`
IsActive bool `json:"is_active"`
NumberOfReferrals int64 `json:"number_of_referrals"`
RewardAmount int64 `json:"reward_amount"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
} }
type RefreshToken struct { type RefreshToken struct {
@ -794,8 +765,20 @@ type User struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
SuspendedAt pgtype.Timestamptz `json:"suspended_at"` SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
Suspended bool `json:"suspended"` Suspended bool `json:"suspended"`
ReferralCode pgtype.Text `json:"referral_code"` }
ReferredBy pgtype.Text `json:"referred_by"`
type UserBonuse struct {
ID int64 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type"`
UserID int64 `json:"user_id"`
RewardAmount int64 `json:"reward_amount"`
IsClaimed bool `json:"is_claimed"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
ClaimedAt pgtype.Timestamp `json:"claimed_at"`
CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
} }
type UserGameInteraction struct { type UserGameInteraction struct {
@ -808,6 +791,13 @@ type UserGameInteraction struct {
CreatedAt pgtype.Timestamptz `json:"created_at"` CreatedAt pgtype.Timestamptz `json:"created_at"`
} }
type UserReferral struct {
ID int64 `json:"id"`
ReferredID int64 `json:"referred_id"`
ReferralCodeID int64 `json:"referral_code_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type VirtualGame struct { type VirtualGame struct {
ID int64 `json:"id"` ID int64 `json:"id"`
GameID string `json:"game_id"` GameID string `json:"game_id"`
@ -896,8 +886,6 @@ type Wallet struct {
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
BonusBalance pgtype.Numeric `json:"bonus_balance"`
CashBalance pgtype.Numeric `json:"cash_balance"`
} }
type WalletThresholdNotification struct { type WalletThresholdNotification struct {

View File

@ -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.30.0
// source: monitor.sql // source: monitor.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: notification.sql // source: notification.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: odd_history.sql // source: odd_history.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: odds.sql // source: odds.sql
package dbgen package dbgen
@ -68,9 +68,22 @@ func (q *Queries) GetAllOdds(ctx context.Context, arg GetAllOddsParams) ([]OddsM
} }
const GetAllOddsWithSettings = `-- name: GetAllOddsWithSettings :many const GetAllOddsWithSettings = `-- name: GetAllOddsWithSettings :many
SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at SELECT o.id,
FROM odds_market_with_settings o.event_id,
WHERE company_id = $1 o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $1
LIMIT $3 OFFSET $2 LIMIT $3 OFFSET $2
` `
@ -80,15 +93,31 @@ type GetAllOddsWithSettingsParams struct {
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWithSettingsParams) ([]OddsMarketWithSetting, error) { type GetAllOddsWithSettingsRow struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
RawOdds []byte `json:"raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWithSettingsParams) ([]GetAllOddsWithSettingsRow, error) {
rows, err := q.db.Query(ctx, GetAllOddsWithSettings, arg.CompanyID, arg.Offset, arg.Limit) rows, err := q.db.Query(ctx, GetAllOddsWithSettings, arg.CompanyID, arg.Offset, arg.Limit)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []OddsMarketWithSetting var items []GetAllOddsWithSettingsRow
for rows.Next() { for rows.Next() {
var i OddsMarketWithSetting var i GetAllOddsWithSettingsRow
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.EventID, &i.EventID,
@ -114,6 +143,34 @@ func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWith
return items, nil return items, nil
} }
const GetOddByID = `-- name: GetOddByID :one
SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source
FROM odds_market_with_event
WHERE id = $1
`
func (q *Queries) GetOddByID(ctx context.Context, id int64) (OddsMarketWithEvent, error) {
row := q.db.QueryRow(ctx, GetOddByID, id)
var i OddsMarketWithEvent
err := row.Scan(
&i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName,
&i.MarketCategory,
&i.MarketID,
&i.RawOdds,
&i.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.IsMonitored,
&i.IsLive,
&i.Status,
&i.Source,
)
return i, err
}
const GetOddsByEventID = `-- name: GetOddsByEventID :many const GetOddsByEventID = `-- name: GetOddsByEventID :many
SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source
FROM odds_market_with_event FROM odds_market_with_event
@ -219,10 +276,23 @@ func (q *Queries) GetOddsByMarketID(ctx context.Context, arg GetOddsByMarketIDPa
} }
const GetOddsWithSettingsByEventID = `-- name: GetOddsWithSettingsByEventID :many const GetOddsWithSettingsByEventID = `-- name: GetOddsWithSettingsByEventID :many
SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at SELECT o.id,
FROM odds_market_with_settings o.event_id,
WHERE event_id = $1 o.market_type,
o.market_name,
o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $2 AND company_id = $2
WHERE event_id = $1
LIMIT $4 OFFSET $3 LIMIT $4 OFFSET $3
` `
@ -233,7 +303,23 @@ type GetOddsWithSettingsByEventIDParams struct {
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsWithSettingsByEventIDParams) ([]OddsMarketWithSetting, error) { type GetOddsWithSettingsByEventIDRow struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
RawOdds []byte `json:"raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsWithSettingsByEventIDParams) ([]GetOddsWithSettingsByEventIDRow, error) {
rows, err := q.db.Query(ctx, GetOddsWithSettingsByEventID, rows, err := q.db.Query(ctx, GetOddsWithSettingsByEventID,
arg.EventID, arg.EventID,
arg.CompanyID, arg.CompanyID,
@ -244,9 +330,9 @@ func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsW
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []OddsMarketWithSetting var items []GetOddsWithSettingsByEventIDRow
for rows.Next() { for rows.Next() {
var i OddsMarketWithSetting var i GetOddsWithSettingsByEventIDRow
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.EventID, &i.EventID,
@ -272,23 +358,50 @@ func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsW
return items, nil return items, nil
} }
const GetOddsWithSettingsByMarketID = `-- name: GetOddsWithSettingsByMarketID :one const GetOddsWithSettingsByID = `-- name: GetOddsWithSettingsByID :one
SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at SELECT o.id,
FROM odds_market_with_settings o.event_id,
WHERE market_id = $1 o.market_type,
AND event_id = $2 o.market_name,
AND company_id = $3 o.market_category,
o.market_id,
o.default_is_active,
o.fetched_at,
o.expires_at,
cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $2
WHERE o.id = $1
` `
type GetOddsWithSettingsByMarketIDParams struct { type GetOddsWithSettingsByIDParams struct {
MarketID string `json:"market_id"` ID int64 `json:"id"`
EventID string `json:"event_id"` CompanyID int64 `json:"company_id"`
CompanyID int64 `json:"company_id"`
} }
func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOddsWithSettingsByMarketIDParams) (OddsMarketWithSetting, error) { type GetOddsWithSettingsByIDRow struct {
row := q.db.QueryRow(ctx, GetOddsWithSettingsByMarketID, arg.MarketID, arg.EventID, arg.CompanyID) ID int64 `json:"id"`
var i OddsMarketWithSetting EventID string `json:"event_id"`
MarketType string `json:"market_type"`
MarketName string `json:"market_name"`
MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
RawOdds []byte `json:"raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
func (q *Queries) GetOddsWithSettingsByID(ctx context.Context, arg GetOddsWithSettingsByIDParams) (GetOddsWithSettingsByIDRow, error) {
row := q.db.QueryRow(ctx, GetOddsWithSettingsByID, arg.ID, arg.CompanyID)
var i GetOddsWithSettingsByIDRow
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.EventID, &i.EventID,
@ -307,34 +420,68 @@ func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOdds
return i, err return i, err
} }
const InsertOddSettings = `-- name: InsertOddSettings :exec const GetOddsWithSettingsByMarketID = `-- name: GetOddsWithSettingsByMarketID :one
INSERT INTO company_odd_settings ( SELECT o.id,
company_id, o.event_id,
odds_market_id, o.market_type,
is_active, o.market_name,
custom_raw_odds o.market_category,
) o.market_id,
VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO o.default_is_active,
UPDATE o.fetched_at,
SET is_active = EXCLUDED.is_active, o.expires_at,
custom_raw_odds = EXCLUDED.custom_raw_odds cos.company_id,
COALESCE(cos.is_active, o.default_is_active) AS is_active,
COALESCE(cos.custom_raw_odds, o.raw_odds) AS raw_odds,
cos.updated_at
FROM odds_market o
LEFT JOIN company_odd_settings cos ON o.id = cos.odds_market_id
AND company_id = $3
WHERE market_id = $1
AND event_id = $2
` `
type InsertOddSettingsParams struct { type GetOddsWithSettingsByMarketIDParams struct {
CompanyID int64 `json:"company_id"` MarketID string `json:"market_id"`
OddsMarketID int64 `json:"odds_market_id"` EventID string `json:"event_id"`
IsActive pgtype.Bool `json:"is_active"` CompanyID int64 `json:"company_id"`
CustomRawOdds []byte `json:"custom_raw_odds"`
} }
func (q *Queries) InsertOddSettings(ctx context.Context, arg InsertOddSettingsParams) error { type GetOddsWithSettingsByMarketIDRow struct {
_, err := q.db.Exec(ctx, InsertOddSettings, ID int64 `json:"id"`
arg.CompanyID, EventID string `json:"event_id"`
arg.OddsMarketID, MarketType string `json:"market_type"`
arg.IsActive, MarketName string `json:"market_name"`
arg.CustomRawOdds, MarketCategory string `json:"market_category"`
MarketID string `json:"market_id"`
DefaultIsActive bool `json:"default_is_active"`
FetchedAt pgtype.Timestamp `json:"fetched_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive bool `json:"is_active"`
RawOdds []byte `json:"raw_odds"`
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOddsWithSettingsByMarketIDParams) (GetOddsWithSettingsByMarketIDRow, error) {
row := q.db.QueryRow(ctx, GetOddsWithSettingsByMarketID, arg.MarketID, arg.EventID, arg.CompanyID)
var i GetOddsWithSettingsByMarketIDRow
err := row.Scan(
&i.ID,
&i.EventID,
&i.MarketType,
&i.MarketName,
&i.MarketCategory,
&i.MarketID,
&i.DefaultIsActive,
&i.FetchedAt,
&i.ExpiresAt,
&i.CompanyID,
&i.IsActive,
&i.RawOdds,
&i.UpdatedAt,
) )
return err return i, err
} }
const InsertOddsMarket = `-- name: InsertOddsMarket :exec const InsertOddsMarket = `-- name: InsertOddsMarket :exec
@ -391,3 +538,33 @@ func (q *Queries) InsertOddsMarket(ctx context.Context, arg InsertOddsMarketPara
) )
return err return err
} }
const SaveOddSettings = `-- name: SaveOddSettings :exec
INSERT INTO company_odd_settings (
company_id,
odds_market_id,
is_active,
custom_raw_odds
)
VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO
UPDATE
SET is_active = EXCLUDED.is_active,
custom_raw_odds = EXCLUDED.custom_raw_odds
`
type SaveOddSettingsParams struct {
CompanyID int64 `json:"company_id"`
OddsMarketID int64 `json:"odds_market_id"`
IsActive pgtype.Bool `json:"is_active"`
CustomRawOdds []byte `json:"custom_raw_odds"`
}
func (q *Queries) SaveOddSettings(ctx context.Context, arg SaveOddSettingsParams) error {
_, err := q.db.Exec(ctx, SaveOddSettings,
arg.CompanyID,
arg.OddsMarketID,
arg.IsActive,
arg.CustomRawOdds,
)
return err
}

View File

@ -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.30.0
// source: otp.sql // source: otp.sql
package dbgen package dbgen

328
gen/db/raffle.sql.go Normal file
View File

@ -0,0 +1,328 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: raffle.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const AddSportRaffleFilter = `-- name: AddSportRaffleFilter :one
INSERT INTO raffle_sport_filters (raffle_id, sport_id, league_id)
VALUES ($1, $2, $3)
RETURNING id, raffle_id, sport_id, league_id
`
type AddSportRaffleFilterParams struct {
RaffleID int32 `json:"raffle_id"`
SportID int64 `json:"sport_id"`
LeagueID int64 `json:"league_id"`
}
func (q *Queries) AddSportRaffleFilter(ctx context.Context, arg AddSportRaffleFilterParams) (RaffleSportFilter, error) {
row := q.db.QueryRow(ctx, AddSportRaffleFilter, arg.RaffleID, arg.SportID, arg.LeagueID)
var i RaffleSportFilter
err := row.Scan(
&i.ID,
&i.RaffleID,
&i.SportID,
&i.LeagueID,
)
return i, err
}
const CheckValidSportRaffleFilter = `-- name: CheckValidSportRaffleFilter :one
SELECT COUNT(*) > 0 AS exists
FROM raffle_sport_filters
WHERE raffle_id = $1
AND sport_id = $2
AND league_id = $3
`
type CheckValidSportRaffleFilterParams struct {
RaffleID int32 `json:"raffle_id"`
SportID int64 `json:"sport_id"`
LeagueID int64 `json:"league_id"`
}
func (q *Queries) CheckValidSportRaffleFilter(ctx context.Context, arg CheckValidSportRaffleFilterParams) (bool, error) {
row := q.db.QueryRow(ctx, CheckValidSportRaffleFilter, arg.RaffleID, arg.SportID, arg.LeagueID)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const CreateRaffle = `-- name: CreateRaffle :one
INSERT INTO raffles (company_id, name, expires_at, type)
VALUES ($1, $2, $3, $4)
RETURNING id, company_id, name, created_at, expires_at, type, status
`
type CreateRaffleParams struct {
CompanyID int32 `json:"company_id"`
Name string `json:"name"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
Type string `json:"type"`
}
func (q *Queries) CreateRaffle(ctx context.Context, arg CreateRaffleParams) (Raffle, error) {
row := q.db.QueryRow(ctx, CreateRaffle,
arg.CompanyID,
arg.Name,
arg.ExpiresAt,
arg.Type,
)
var i Raffle
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Name,
&i.CreatedAt,
&i.ExpiresAt,
&i.Type,
&i.Status,
)
return i, err
}
const CreateRaffleTicket = `-- name: CreateRaffleTicket :one
INSERT INTO raffle_tickets (raffle_id, user_id)
VALUES ($1, $2)
RETURNING id, raffle_id, user_id, is_active
`
type CreateRaffleTicketParams struct {
RaffleID int32 `json:"raffle_id"`
UserID int32 `json:"user_id"`
}
func (q *Queries) CreateRaffleTicket(ctx context.Context, arg CreateRaffleTicketParams) (RaffleTicket, error) {
row := q.db.QueryRow(ctx, CreateRaffleTicket, arg.RaffleID, arg.UserID)
var i RaffleTicket
err := row.Scan(
&i.ID,
&i.RaffleID,
&i.UserID,
&i.IsActive,
)
return i, err
}
const CreateRaffleWinner = `-- name: CreateRaffleWinner :one
INSERT INTO raffle_winners (raffle_id, user_id, rank)
VALUES ($1, $2, $3)
RETURNING id, raffle_id, user_id, rank, created_at
`
type CreateRaffleWinnerParams struct {
RaffleID int32 `json:"raffle_id"`
UserID int32 `json:"user_id"`
Rank int32 `json:"rank"`
}
func (q *Queries) CreateRaffleWinner(ctx context.Context, arg CreateRaffleWinnerParams) (RaffleWinner, error) {
row := q.db.QueryRow(ctx, CreateRaffleWinner, arg.RaffleID, arg.UserID, arg.Rank)
var i RaffleWinner
err := row.Scan(
&i.ID,
&i.RaffleID,
&i.UserID,
&i.Rank,
&i.CreatedAt,
)
return i, err
}
const DeleteRaffle = `-- name: DeleteRaffle :one
DELETE FROM raffles
WHERE id = $1
RETURNING id, company_id, name, created_at, expires_at, type, status
`
func (q *Queries) DeleteRaffle(ctx context.Context, id int32) (Raffle, error) {
row := q.db.QueryRow(ctx, DeleteRaffle, id)
var i Raffle
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Name,
&i.CreatedAt,
&i.ExpiresAt,
&i.Type,
&i.Status,
)
return i, err
}
const GetRaffleStanding = `-- name: GetRaffleStanding :many
SELECT
u.id AS user_id,
rt.raffle_id,
u.first_name,
u.last_name,
u.phone_number,
u.email,
COUNT(*) AS ticket_count
FROM raffle_tickets rt
JOIN users u ON rt.user_id = u.id
WHERE rt.is_active = true
AND rt.raffle_id = $1
GROUP BY u.id, rt.raffle_id, u.first_name, u.last_name, u.phone_number, u.email
ORDER BY ticket_count DESC
LIMIT $2
`
type GetRaffleStandingParams struct {
RaffleID int32 `json:"raffle_id"`
Limit int32 `json:"limit"`
}
type GetRaffleStandingRow struct {
UserID int64 `json:"user_id"`
RaffleID int32 `json:"raffle_id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
PhoneNumber pgtype.Text `json:"phone_number"`
Email pgtype.Text `json:"email"`
TicketCount int64 `json:"ticket_count"`
}
func (q *Queries) GetRaffleStanding(ctx context.Context, arg GetRaffleStandingParams) ([]GetRaffleStandingRow, error) {
rows, err := q.db.Query(ctx, GetRaffleStanding, arg.RaffleID, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetRaffleStandingRow
for rows.Next() {
var i GetRaffleStandingRow
if err := rows.Scan(
&i.UserID,
&i.RaffleID,
&i.FirstName,
&i.LastName,
&i.PhoneNumber,
&i.Email,
&i.TicketCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetRafflesOfCompany = `-- name: GetRafflesOfCompany :many
SELECT id, company_id, name, created_at, expires_at, type, status FROM raffles WHERE company_id = $1
`
func (q *Queries) GetRafflesOfCompany(ctx context.Context, companyID int32) ([]Raffle, error) {
rows, err := q.db.Query(ctx, GetRafflesOfCompany, companyID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Raffle
for rows.Next() {
var i Raffle
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.Name,
&i.CreatedAt,
&i.ExpiresAt,
&i.Type,
&i.Status,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserRaffleTickets = `-- name: GetUserRaffleTickets :many
SELECT
rt.id AS ticket_id,
rt.user_id,
r.name,
r.type,
r.expires_at,
r.status
FROM raffle_tickets rt
JOIN raffles r ON rt.raffle_id = r.id
WHERE rt.user_id = $1
`
type GetUserRaffleTicketsRow struct {
TicketID int32 `json:"ticket_id"`
UserID int32 `json:"user_id"`
Name string `json:"name"`
Type string `json:"type"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
Status string `json:"status"`
}
func (q *Queries) GetUserRaffleTickets(ctx context.Context, userID int32) ([]GetUserRaffleTicketsRow, error) {
rows, err := q.db.Query(ctx, GetUserRaffleTickets, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetUserRaffleTicketsRow
for rows.Next() {
var i GetUserRaffleTicketsRow
if err := rows.Scan(
&i.TicketID,
&i.UserID,
&i.Name,
&i.Type,
&i.ExpiresAt,
&i.Status,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SetRaffleComplete = `-- name: SetRaffleComplete :exec
UPDATE raffles
SET status = 'completed'
WHERE id = $1
`
func (q *Queries) SetRaffleComplete(ctx context.Context, id int32) error {
_, err := q.db.Exec(ctx, SetRaffleComplete, id)
return err
}
const UpdateRaffleTicketStatus = `-- name: UpdateRaffleTicketStatus :exec
UPDATE raffle_tickets
SET is_active = $1
WHERE id = $2
`
type UpdateRaffleTicketStatusParams struct {
IsActive pgtype.Bool `json:"is_active"`
ID int32 `json:"id"`
}
func (q *Queries) UpdateRaffleTicketStatus(ctx context.Context, arg UpdateRaffleTicketStatusParams) error {
_, err := q.db.Exec(ctx, UpdateRaffleTicketStatus, arg.IsActive, arg.ID)
return err
}

View File

@ -1,335 +1,254 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: referal.sql // source: referal.sql
package dbgen package dbgen
import ( import (
"context" "context"
"github.com/jackc/pgx/v5/pgtype"
) )
const CreateReferral = `-- name: CreateReferral :one const CreateReferralCode = `-- name: CreateReferralCode :one
INSERT INTO referrals ( INSERT INTO referral_codes (
referral_code, referral_code,
referrer_id, referrer_id,
status, company_id,
reward_amount, number_of_referrals,
expires_at reward_amount
) VALUES ( )
$1, $2, $3, $4, $5 VALUES ($1, $2, $3, $4, $5)
) RETURNING id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at RETURNING id, referral_code, referrer_id, company_id, is_active, number_of_referrals, reward_amount, created_at, updated_at
` `
type CreateReferralParams struct { type CreateReferralCodeParams struct {
ReferralCode string `json:"referral_code"` ReferralCode string `json:"referral_code"`
ReferrerID string `json:"referrer_id"` ReferrerID int64 `json:"referrer_id"`
Status Referralstatus `json:"status"` CompanyID int64 `json:"company_id"`
RewardAmount pgtype.Numeric `json:"reward_amount"` NumberOfReferrals int64 `json:"number_of_referrals"`
ExpiresAt pgtype.Timestamptz `json:"expires_at"` RewardAmount int64 `json:"reward_amount"`
} }
func (q *Queries) CreateReferral(ctx context.Context, arg CreateReferralParams) (Referral, error) { func (q *Queries) CreateReferralCode(ctx context.Context, arg CreateReferralCodeParams) (ReferralCode, error) {
row := q.db.QueryRow(ctx, CreateReferral, row := q.db.QueryRow(ctx, CreateReferralCode,
arg.ReferralCode, arg.ReferralCode,
arg.ReferrerID, arg.ReferrerID,
arg.Status, arg.CompanyID,
arg.NumberOfReferrals,
arg.RewardAmount, arg.RewardAmount,
arg.ExpiresAt,
) )
var i Referral var i ReferralCode
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.ReferralCode, &i.ReferralCode,
&i.ReferrerID, &i.ReferrerID,
&i.ReferredID, &i.CompanyID,
&i.Status, &i.IsActive,
&i.NumberOfReferrals,
&i.RewardAmount, &i.RewardAmount,
&i.CashbackAmount,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.ExpiresAt,
) )
return i, err return i, err
} }
const CreateReferralSettings = `-- name: CreateReferralSettings :one const CreateUserReferral = `-- name: CreateUserReferral :one
INSERT INTO referral_settings ( INSERT INTO user_referrals (referred_id, referral_code_id)
referral_reward_amount, VALUES ($1, $2)
cashback_percentage, RETURNING id, referred_id, referral_code_id, created_at
max_referrals,
bet_referral_bonus_percentage,
expires_after_days,
updated_by
) VALUES (
$1, $2, $3, $4, $5, $6
) RETURNING id, referral_reward_amount, cashback_percentage, bet_referral_bonus_percentage, max_referrals, expires_after_days, updated_by, created_at, updated_at, version
` `
type CreateReferralSettingsParams struct { type CreateUserReferralParams struct {
ReferralRewardAmount pgtype.Numeric `json:"referral_reward_amount"` ReferredID int64 `json:"referred_id"`
CashbackPercentage pgtype.Numeric `json:"cashback_percentage"` ReferralCodeID int64 `json:"referral_code_id"`
MaxReferrals int32 `json:"max_referrals"`
BetReferralBonusPercentage pgtype.Numeric `json:"bet_referral_bonus_percentage"`
ExpiresAfterDays int32 `json:"expires_after_days"`
UpdatedBy string `json:"updated_by"`
} }
func (q *Queries) CreateReferralSettings(ctx context.Context, arg CreateReferralSettingsParams) (ReferralSetting, error) { func (q *Queries) CreateUserReferral(ctx context.Context, arg CreateUserReferralParams) (UserReferral, error) {
row := q.db.QueryRow(ctx, CreateReferralSettings, row := q.db.QueryRow(ctx, CreateUserReferral, arg.ReferredID, arg.ReferralCodeID)
arg.ReferralRewardAmount, var i UserReferral
arg.CashbackPercentage,
arg.MaxReferrals,
arg.BetReferralBonusPercentage,
arg.ExpiresAfterDays,
arg.UpdatedBy,
)
var i ReferralSetting
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.ReferralRewardAmount,
&i.CashbackPercentage,
&i.BetReferralBonusPercentage,
&i.MaxReferrals,
&i.ExpiresAfterDays,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.Version,
)
return i, err
}
const GetActiveReferralByReferrerID = `-- name: GetActiveReferralByReferrerID :one
SELECT id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at FROM referrals WHERE referrer_id = $1 AND status = 'PENDING' LIMIT 1
`
func (q *Queries) GetActiveReferralByReferrerID(ctx context.Context, referrerID string) (Referral, error) {
row := q.db.QueryRow(ctx, GetActiveReferralByReferrerID, referrerID)
var i Referral
err := row.Scan(
&i.ID,
&i.ReferralCode,
&i.ReferrerID,
&i.ReferredID, &i.ReferredID,
&i.Status, &i.ReferralCodeID,
&i.RewardAmount,
&i.CashbackAmount,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt,
&i.ExpiresAt,
) )
return i, err return i, err
} }
const GetReferralByCode = `-- name: GetReferralByCode :one const GetReferralCode = `-- name: GetReferralCode :one
SELECT id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at FROM referrals SELECT id, referral_code, referrer_id, company_id, is_active, number_of_referrals, reward_amount, created_at, updated_at
FROM referral_codes
WHERE referral_code = $1 WHERE referral_code = $1
` `
func (q *Queries) GetReferralByCode(ctx context.Context, referralCode string) (Referral, error) { func (q *Queries) GetReferralCode(ctx context.Context, referralCode string) (ReferralCode, error) {
row := q.db.QueryRow(ctx, GetReferralByCode, referralCode) row := q.db.QueryRow(ctx, GetReferralCode, referralCode)
var i Referral var i ReferralCode
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.ReferralCode, &i.ReferralCode,
&i.ReferrerID, &i.ReferrerID,
&i.ReferredID, &i.CompanyID,
&i.Status, &i.IsActive,
&i.NumberOfReferrals,
&i.RewardAmount, &i.RewardAmount,
&i.CashbackAmount,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.ExpiresAt,
) )
return i, err return i, err
} }
const GetReferralByReferredID = `-- name: GetReferralByReferredID :one const GetReferralCodeByUser = `-- name: GetReferralCodeByUser :many
SELECT id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at FROM referrals WHERE referred_id = $1 LIMIT 1 SELECt id, referral_code, referrer_id, company_id, is_active, number_of_referrals, reward_amount, created_at, updated_at
FROM referral_codes
WHERE referrer_id = $1
` `
func (q *Queries) GetReferralByReferredID(ctx context.Context, referredID pgtype.Text) (Referral, error) { func (q *Queries) GetReferralCodeByUser(ctx context.Context, referrerID int64) ([]ReferralCode, error) {
row := q.db.QueryRow(ctx, GetReferralByReferredID, referredID) rows, err := q.db.Query(ctx, GetReferralCodeByUser, referrerID)
var i Referral if err != nil {
return nil, err
}
defer rows.Close()
var items []ReferralCode
for rows.Next() {
var i ReferralCode
if err := rows.Scan(
&i.ID,
&i.ReferralCode,
&i.ReferrerID,
&i.CompanyID,
&i.IsActive,
&i.NumberOfReferrals,
&i.RewardAmount,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetReferralStats = `-- name: GetReferralStats :one
SELECT COUNT(*) AS total_referrals,
COALESCE(SUM(reward_amount), 0)::bigint AS total_reward_earned
FROM user_referrals
JOIN referral_codes ON referral_codes.id = referral_code_id
WHERE referrer_id = $1
AND company_id = $2
`
type GetReferralStatsParams struct {
ReferrerID int64 `json:"referrer_id"`
CompanyID int64 `json:"company_id"`
}
type GetReferralStatsRow struct {
TotalReferrals int64 `json:"total_referrals"`
TotalRewardEarned int64 `json:"total_reward_earned"`
}
func (q *Queries) GetReferralStats(ctx context.Context, arg GetReferralStatsParams) (GetReferralStatsRow, error) {
row := q.db.QueryRow(ctx, GetReferralStats, arg.ReferrerID, arg.CompanyID)
var i GetReferralStatsRow
err := row.Scan(&i.TotalReferrals, &i.TotalRewardEarned)
return i, err
}
const GetUserReferral = `-- name: GetUserReferral :one
SELECT id, referred_id, referral_code_id, created_at
FROM user_referrals
WHERE referred_id = $1
`
func (q *Queries) GetUserReferral(ctx context.Context, referredID int64) (UserReferral, error) {
row := q.db.QueryRow(ctx, GetUserReferral, referredID)
var i UserReferral
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.ReferralCode,
&i.ReferrerID,
&i.ReferredID, &i.ReferredID,
&i.Status, &i.ReferralCodeID,
&i.RewardAmount,
&i.CashbackAmount,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt,
&i.ExpiresAt,
) )
return i, err return i, err
} }
const GetReferralCountByID = `-- name: GetReferralCountByID :one const GetUserReferralsByCode = `-- name: GetUserReferralsByCode :many
SELECT count(*) FROM referrals WHERE referrer_id = $1 SELECT user_referrals.id, user_referrals.referred_id, user_referrals.referral_code_id, user_referrals.created_at
FROM user_referrals
JOIN referral_codes ON referral_codes.id = referral_code_id
WHERE referral_code = $1
` `
func (q *Queries) GetReferralCountByID(ctx context.Context, referrerID string) (int64, error) { func (q *Queries) GetUserReferralsByCode(ctx context.Context, referralCode string) ([]UserReferral, error) {
row := q.db.QueryRow(ctx, GetReferralCountByID, referrerID) rows, err := q.db.Query(ctx, GetUserReferralsByCode, referralCode)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UserReferral
for rows.Next() {
var i UserReferral
if err := rows.Scan(
&i.ID,
&i.ReferredID,
&i.ReferralCodeID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserReferralsCount = `-- name: GetUserReferralsCount :one
SELECT COUNT(*)
FROM user_referrals
JOIN referral_codes ON referral_codes.id = referral_code_id
WHERE referrer_id = $1
`
func (q *Queries) GetUserReferralsCount(ctx context.Context, referrerID int64) (int64, error) {
row := q.db.QueryRow(ctx, GetUserReferralsCount, referrerID)
var count int64 var count int64
err := row.Scan(&count) err := row.Scan(&count)
return count, err return count, err
} }
const GetReferralSettings = `-- name: GetReferralSettings :one
SELECT id, referral_reward_amount, cashback_percentage, bet_referral_bonus_percentage, max_referrals, expires_after_days, updated_by, created_at, updated_at, version FROM referral_settings
LIMIT 1
`
func (q *Queries) GetReferralSettings(ctx context.Context) (ReferralSetting, error) {
row := q.db.QueryRow(ctx, GetReferralSettings)
var i ReferralSetting
err := row.Scan(
&i.ID,
&i.ReferralRewardAmount,
&i.CashbackPercentage,
&i.BetReferralBonusPercentage,
&i.MaxReferrals,
&i.ExpiresAfterDays,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.Version,
)
return i, err
}
const GetReferralStats = `-- name: GetReferralStats :one
SELECT
COUNT(*) as total_referrals,
COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) as completed_referrals,
COALESCE(SUM(reward_amount), 0) as total_reward_earned,
COALESCE(SUM(CASE WHEN status = 'PENDING' THEN reward_amount END), 0) as pending_rewards
FROM referrals
WHERE referrer_id = $1
`
type GetReferralStatsRow struct {
TotalReferrals int64 `json:"total_referrals"`
CompletedReferrals int64 `json:"completed_referrals"`
TotalRewardEarned interface{} `json:"total_reward_earned"`
PendingRewards interface{} `json:"pending_rewards"`
}
func (q *Queries) GetReferralStats(ctx context.Context, referrerID string) (GetReferralStatsRow, error) {
row := q.db.QueryRow(ctx, GetReferralStats, referrerID)
var i GetReferralStatsRow
err := row.Scan(
&i.TotalReferrals,
&i.CompletedReferrals,
&i.TotalRewardEarned,
&i.PendingRewards,
)
return i, err
}
const UpdateReferral = `-- name: UpdateReferral :one
UPDATE referrals
SET
referred_id = $2,
status = $3,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at
`
type UpdateReferralParams struct {
ID int64 `json:"id"`
ReferredID pgtype.Text `json:"referred_id"`
Status Referralstatus `json:"status"`
}
func (q *Queries) UpdateReferral(ctx context.Context, arg UpdateReferralParams) (Referral, error) {
row := q.db.QueryRow(ctx, UpdateReferral, arg.ID, arg.ReferredID, arg.Status)
var i Referral
err := row.Scan(
&i.ID,
&i.ReferralCode,
&i.ReferrerID,
&i.ReferredID,
&i.Status,
&i.RewardAmount,
&i.CashbackAmount,
&i.CreatedAt,
&i.UpdatedAt,
&i.ExpiresAt,
)
return i, err
}
const UpdateReferralCode = `-- name: UpdateReferralCode :exec const UpdateReferralCode = `-- name: UpdateReferralCode :exec
UPDATE users UPDATE referral_codes
SET SET is_active = $2,
referral_code = $2, referral_code = $3,
updated_at = CURRENT_TIMESTAMP number_of_referrals = $4,
reward_amount = $5,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1 WHERE id = $1
` `
type UpdateReferralCodeParams struct { type UpdateReferralCodeParams struct {
ID int64 `json:"id"` ID int64 `json:"id"`
ReferralCode pgtype.Text `json:"referral_code"` IsActive bool `json:"is_active"`
ReferralCode string `json:"referral_code"`
NumberOfReferrals int64 `json:"number_of_referrals"`
RewardAmount int64 `json:"reward_amount"`
} }
func (q *Queries) UpdateReferralCode(ctx context.Context, arg UpdateReferralCodeParams) error { func (q *Queries) UpdateReferralCode(ctx context.Context, arg UpdateReferralCodeParams) error {
_, err := q.db.Exec(ctx, UpdateReferralCode, arg.ID, arg.ReferralCode) _, err := q.db.Exec(ctx, UpdateReferralCode,
arg.ID,
arg.IsActive,
arg.ReferralCode,
arg.NumberOfReferrals,
arg.RewardAmount,
)
return err return err
} }
const UpdateReferralSettings = `-- name: UpdateReferralSettings :one
UPDATE referral_settings
SET
referral_reward_amount = $2,
cashback_percentage = $3,
bet_referral_bonus_percentage= $4,
max_referrals = $5,
expires_after_days = $6,
updated_by = $7,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, referral_reward_amount, cashback_percentage, bet_referral_bonus_percentage, max_referrals, expires_after_days, updated_by, created_at, updated_at, version
`
type UpdateReferralSettingsParams struct {
ID int64 `json:"id"`
ReferralRewardAmount pgtype.Numeric `json:"referral_reward_amount"`
CashbackPercentage pgtype.Numeric `json:"cashback_percentage"`
BetReferralBonusPercentage pgtype.Numeric `json:"bet_referral_bonus_percentage"`
MaxReferrals int32 `json:"max_referrals"`
ExpiresAfterDays int32 `json:"expires_after_days"`
UpdatedBy string `json:"updated_by"`
}
func (q *Queries) UpdateReferralSettings(ctx context.Context, arg UpdateReferralSettingsParams) (ReferralSetting, error) {
row := q.db.QueryRow(ctx, UpdateReferralSettings,
arg.ID,
arg.ReferralRewardAmount,
arg.CashbackPercentage,
arg.BetReferralBonusPercentage,
arg.MaxReferrals,
arg.ExpiresAfterDays,
arg.UpdatedBy,
)
var i ReferralSetting
err := row.Scan(
&i.ID,
&i.ReferralRewardAmount,
&i.CashbackPercentage,
&i.BetReferralBonusPercentage,
&i.MaxReferrals,
&i.ExpiresAfterDays,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.Version,
)
return i, err
}

View File

@ -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.30.0
// source: report.sql // source: report.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: result.sql // source: result.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: result_log.sql // source: result_log.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: settings.sql // source: settings.sql
package dbgen package dbgen
@ -181,7 +181,9 @@ func (q *Queries) GetGlobalSettings(ctx context.Context) ([]GlobalSetting, error
} }
const GetOverrideSettings = `-- name: GetOverrideSettings :many const GetOverrideSettings = `-- name: GetOverrideSettings :many
SELECT gs.key, gs.value, gs.created_at, gs.updated_at, SELECT gs.key,
gs.created_at,
gs.updated_at,
COALESCE(cs.value, gs.value) AS value COALESCE(cs.value, gs.value) AS value
FROM global_settings gs FROM global_settings gs
LEFT JOIN company_settings cs ON cs.key = gs.key LEFT JOIN company_settings cs ON cs.key = gs.key
@ -190,10 +192,9 @@ FROM global_settings gs
type GetOverrideSettingsRow struct { type GetOverrideSettingsRow struct {
Key string `json:"key"` Key string `json:"key"`
Value string `json:"value"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
Value_2 string `json:"value_2"` Value string `json:"value"`
} }
func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]GetOverrideSettingsRow, error) { func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]GetOverrideSettingsRow, error) {
@ -207,10 +208,9 @@ func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]G
var i GetOverrideSettingsRow var i GetOverrideSettingsRow
if err := rows.Scan( if err := rows.Scan(
&i.Key, &i.Key,
&i.Value,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Value_2, &i.Value,
); err != nil { ); err != nil {
return nil, err return nil, err
} }

View File

@ -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.30.0
// source: shop_transactions.sql // source: shop_transactions.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: ticket.sql // source: ticket.sql
package dbgen package dbgen

View File

@ -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.30.0
// source: transfer.sql // source: transfer.sql
package dbgen package dbgen
@ -182,6 +182,40 @@ func (q *Queries) GetTransferByReference(ctx context.Context, referenceNumber st
return i, err return i, err
} }
const GetTransferStats = `-- name: GetTransferStats :one
SELECT COUNT(*) AS total_transfers, COUNT(*) FILTER (
WHERE type = 'deposit'
) AS total_deposits,
COUNT(*) FILTER (
WHERE type = 'withdraw'
) AS total_withdraw,
COUNT(*) FILTER (
WHERE type = 'wallet'
) AS total_wallet_to_wallet
FROM wallet_transfer
WHERE sender_wallet_id = $1
OR receiver_wallet_id = $1
`
type GetTransferStatsRow struct {
TotalTransfers int64 `json:"total_transfers"`
TotalDeposits int64 `json:"total_deposits"`
TotalWithdraw int64 `json:"total_withdraw"`
TotalWalletToWallet int64 `json:"total_wallet_to_wallet"`
}
func (q *Queries) GetTransferStats(ctx context.Context, senderWalletID pgtype.Int8) (GetTransferStatsRow, error) {
row := q.db.QueryRow(ctx, GetTransferStats, senderWalletID)
var i GetTransferStatsRow
err := row.Scan(
&i.TotalTransfers,
&i.TotalDeposits,
&i.TotalWithdraw,
&i.TotalWalletToWallet,
)
return i, err
}
const GetTransfersByWallet = `-- name: GetTransfersByWallet :many const GetTransfersByWallet = `-- name: GetTransfersByWallet :many
SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, session_id, status, payment_method, created_at, updated_at, first_name, last_name, phone_number SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, session_id, status, payment_method, created_at, updated_at, first_name, last_name, phone_number
FROM wallet_transfer_details FROM wallet_transfer_details

View File

@ -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.30.0
// source: user.sql // source: user.sql
package dbgen package dbgen
@ -163,7 +163,7 @@ func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
} }
const GetAdminByCompanyID = `-- name: GetAdminByCompanyID :one const GetAdminByCompanyID = `-- name: GetAdminByCompanyID :one
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended
FROM companies FROM companies
JOIN users ON companies.admin_id = users.id JOIN users ON companies.admin_id = users.id
where companies.id = $1 where companies.id = $1
@ -187,8 +187,6 @@ func (q *Queries) GetAdminByCompanyID(ctx context.Context, id int64) (User, erro
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
) )
return i, err return i, err
} }
@ -388,7 +386,7 @@ func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams)
} }
const GetUserByID = `-- name: GetUserByID :one const GetUserByID = `-- name: GetUserByID :one
SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended, referral_code, referred_by SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended
FROM users FROM users
WHERE id = $1 WHERE id = $1
` `
@ -411,8 +409,6 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
) )
return i, err return i, err
} }
@ -587,7 +583,7 @@ SET password = $1,
WHERE ( WHERE (
email = $2 email = $2
OR phone_number = $3 OR phone_number = $3
AND company_id = $4 AND company_id = $5
) )
` `
@ -596,6 +592,7 @@ type UpdatePasswordParams struct {
Email pgtype.Text `json:"email"` Email pgtype.Text `json:"email"`
PhoneNumber pgtype.Text `json:"phone_number"` PhoneNumber pgtype.Text `json:"phone_number"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"`
CompanyID pgtype.Int8 `json:"company_id"`
} }
func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error { func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error {
@ -604,6 +601,7 @@ func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams)
arg.Email, arg.Email,
arg.PhoneNumber, arg.PhoneNumber,
arg.UpdatedAt, arg.UpdatedAt,
arg.CompanyID,
) )
return err return err
} }

View File

@ -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.30.0
// source: virtual_games.sql // source: virtual_games.sql
package dbgen package dbgen
@ -12,12 +12,8 @@ import (
) )
const AddFavoriteGame = `-- name: AddFavoriteGame :exec const AddFavoriteGame = `-- name: AddFavoriteGame :exec
INSERT INTO favorite_games ( INSERT INTO favorite_games (user_id, game_id, created_at)
user_id, VALUES ($1, $2, NOW()) ON CONFLICT (user_id, game_id) DO NOTHING
game_id,
created_at
) VALUES ($1, $2, NOW())
ON CONFLICT (user_id, game_id) DO NOTHING
` `
type AddFavoriteGameParams struct { type AddFavoriteGameParams struct {
@ -44,23 +40,34 @@ func (q *Queries) CountVirtualGameProviders(ctx context.Context) (int64, error)
const CreateVirtualGame = `-- name: CreateVirtualGame :one const CreateVirtualGame = `-- name: CreateVirtualGame :one
INSERT INTO virtual_games ( INSERT INTO virtual_games (
game_id, game_id,
provider_id, provider_id,
name, name,
category, category,
device_type, device_type,
volatility, volatility,
rtp, rtp,
has_demo, has_demo,
has_free_bets, has_free_bets,
bets, bets,
thumbnail, thumbnail,
status status
) VALUES ( )
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 VALUES (
) $1,
RETURNING $2,
id, $3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id,
game_id, game_id,
provider_id, provider_id,
name, name,
@ -130,22 +137,34 @@ func (q *Queries) CreateVirtualGame(ctx context.Context, arg CreateVirtualGamePa
const CreateVirtualGameHistory = `-- name: CreateVirtualGameHistory :one const CreateVirtualGameHistory = `-- name: CreateVirtualGameHistory :one
INSERT INTO virtual_game_histories ( INSERT INTO virtual_game_histories (
session_id, session_id,
user_id, user_id,
company_id, company_id,
provider, provider,
wallet_id, wallet_id,
game_id, game_id,
transaction_type, transaction_type,
amount, amount,
currency, currency,
external_transaction_id, external_transaction_id,
reference_transaction_id, reference_transaction_id,
status status
) VALUES ( )
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 VALUES (
) RETURNING $1,
id, $2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id,
session_id, session_id,
user_id, user_id,
company_id, company_id,
@ -215,10 +234,21 @@ func (q *Queries) CreateVirtualGameHistory(ctx context.Context, arg CreateVirtua
const CreateVirtualGameProvider = `-- name: CreateVirtualGameProvider :one const CreateVirtualGameProvider = `-- name: CreateVirtualGameProvider :one
INSERT INTO virtual_game_providers ( INSERT INTO virtual_game_providers (
provider_id, provider_name, logo_dark, logo_light, enabled provider_id,
) VALUES ( provider_name,
$1, $2, $3, $4, $5 logo_dark,
) RETURNING id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at logo_light,
enabled
)
VALUES ($1, $2, $3, $4, $5)
RETURNING id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at
` `
type CreateVirtualGameProviderParams struct { type CreateVirtualGameProviderParams struct {
@ -253,10 +283,23 @@ func (q *Queries) CreateVirtualGameProvider(ctx context.Context, arg CreateVirtu
const CreateVirtualGameSession = `-- name: CreateVirtualGameSession :one const CreateVirtualGameSession = `-- name: CreateVirtualGameSession :one
INSERT INTO virtual_game_sessions ( INSERT INTO virtual_game_sessions (
user_id, game_id, session_token, currency, status, expires_at user_id,
) VALUES ( game_id,
$1, $2, $3, $4, $5, $6 session_token,
) RETURNING id, user_id, game_id, session_token, currency, status, created_at, updated_at, expires_at currency,
status,
expires_at
)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id,
user_id,
game_id,
session_token,
currency,
status,
created_at,
updated_at,
expires_at
` `
type CreateVirtualGameSessionParams struct { type CreateVirtualGameSessionParams struct {
@ -294,10 +337,31 @@ func (q *Queries) CreateVirtualGameSession(ctx context.Context, arg CreateVirtua
const CreateVirtualGameTransaction = `-- name: CreateVirtualGameTransaction :one const CreateVirtualGameTransaction = `-- name: CreateVirtualGameTransaction :one
INSERT INTO virtual_game_transactions ( INSERT INTO virtual_game_transactions (
session_id, user_id, company_id, provider, wallet_id, transaction_type, amount, currency, external_transaction_id, status session_id,
) VALUES ( user_id,
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10 company_id,
) RETURNING id, session_id, user_id, company_id, provider, wallet_id, transaction_type, amount, currency, external_transaction_id, status, created_at, updated_at provider,
wallet_id,
transaction_type,
amount,
currency,
external_transaction_id,
status
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id,
session_id,
user_id,
company_id,
provider,
wallet_id,
transaction_type,
amount,
currency,
external_transaction_id,
status,
created_at,
updated_at
` `
type CreateVirtualGameTransactionParams struct { type CreateVirtualGameTransactionParams struct {
@ -390,8 +454,7 @@ func (q *Queries) DeleteVirtualGameProvider(ctx context.Context, providerID stri
} }
const GetAllVirtualGames = `-- name: GetAllVirtualGames :many const GetAllVirtualGames = `-- name: GetAllVirtualGames :many
SELECT SELECT vg.id,
vg.id,
vg.game_id, vg.game_id,
vg.provider_id, vg.provider_id,
vp.provider_name, vp.provider_name,
@ -408,19 +471,29 @@ SELECT
vg.created_at, vg.created_at,
vg.updated_at vg.updated_at
FROM virtual_games vg FROM virtual_games vg
JOIN virtual_game_providers vp ON vg.provider_id = vp.provider_id JOIN virtual_game_providers vp ON vg.provider_id = vp.provider_id
WHERE WHERE (
($1::text IS NULL OR vg.category = $1) -- category filter (optional) vg.category = $1
AND ($2::text IS NULL OR vg.name ILIKE '%' || $2 || '%') -- search by name (optional) OR $1 IS NULL
)
AND (
name ILIKE '%' || $2 || '%'
OR $2 IS NULL
)
AND (
vg.provider_id = $3
OR $3 IS NULL
)
ORDER BY vg.created_at DESC ORDER BY vg.created_at DESC
LIMIT $3 OFFSET $4 LIMIT $5 OFFSET $4
` `
type GetAllVirtualGamesParams struct { type GetAllVirtualGamesParams struct {
Column1 string `json:"column_1"` Category pgtype.Text `json:"category"`
Column2 string `json:"column_2"` Name pgtype.Text `json:"name"`
Limit int32 `json:"limit"` ProviderID pgtype.Text `json:"provider_id"`
Offset int32 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
} }
type GetAllVirtualGamesRow struct { type GetAllVirtualGamesRow struct {
@ -444,10 +517,11 @@ type GetAllVirtualGamesRow struct {
func (q *Queries) GetAllVirtualGames(ctx context.Context, arg GetAllVirtualGamesParams) ([]GetAllVirtualGamesRow, error) { func (q *Queries) GetAllVirtualGames(ctx context.Context, arg GetAllVirtualGamesParams) ([]GetAllVirtualGamesRow, error) {
rows, err := q.db.Query(ctx, GetAllVirtualGames, rows, err := q.db.Query(ctx, GetAllVirtualGames,
arg.Column1, arg.Category,
arg.Column2, arg.Name,
arg.Limit, arg.ProviderID,
arg.Offset, arg.Offset,
arg.Limit,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -485,7 +559,14 @@ func (q *Queries) GetAllVirtualGames(ctx context.Context, arg GetAllVirtualGames
} }
const GetVirtualGameProviderByID = `-- name: GetVirtualGameProviderByID :one const GetVirtualGameProviderByID = `-- name: GetVirtualGameProviderByID :one
SELECT id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at SELECT id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at
FROM virtual_game_providers FROM virtual_game_providers
WHERE provider_id = $1 WHERE provider_id = $1
` `
@ -507,7 +588,15 @@ func (q *Queries) GetVirtualGameProviderByID(ctx context.Context, providerID str
} }
const GetVirtualGameSessionByToken = `-- name: GetVirtualGameSessionByToken :one const GetVirtualGameSessionByToken = `-- name: GetVirtualGameSessionByToken :one
SELECT id, user_id, game_id, session_token, currency, status, created_at, updated_at, expires_at SELECT id,
user_id,
game_id,
session_token,
currency,
status,
created_at,
updated_at,
expires_at
FROM virtual_game_sessions FROM virtual_game_sessions
WHERE session_token = $1 WHERE session_token = $1
` `
@ -530,18 +619,18 @@ func (q *Queries) GetVirtualGameSessionByToken(ctx context.Context, sessionToken
} }
const GetVirtualGameSummaryInRange = `-- name: GetVirtualGameSummaryInRange :many const GetVirtualGameSummaryInRange = `-- name: GetVirtualGameSummaryInRange :many
SELECT SELECT c.name AS company_name,
c.name AS company_name,
vg.name AS game_name, vg.name AS game_name,
COUNT(vgt.id) AS number_of_bets, COUNT(vgt.id) AS number_of_bets,
COALESCE(SUM(vgt.amount), 0) AS total_transaction_sum COALESCE(SUM(vgt.amount), 0) AS total_transaction_sum
FROM virtual_game_transactions vgt FROM virtual_game_transactions vgt
JOIN virtual_game_sessions vgs ON vgt.session_id = vgs.id JOIN virtual_game_sessions vgs ON vgt.session_id = vgs.id
JOIN virtual_games vg ON vgs.game_id = vg.id JOIN virtual_games vg ON vgs.game_id = vg.id
JOIN companies c ON vgt.company_id = c.id JOIN companies c ON vgt.company_id = c.id
WHERE vgt.transaction_type = 'BET' WHERE vgt.transaction_type = 'BET'
AND vgt.created_at BETWEEN $1 AND $2 AND vgt.created_at BETWEEN $1 AND $2
GROUP BY c.name, vg.name GROUP BY c.name,
vg.name
` `
type GetVirtualGameSummaryInRangeParams struct { type GetVirtualGameSummaryInRangeParams struct {
@ -582,7 +671,17 @@ func (q *Queries) GetVirtualGameSummaryInRange(ctx context.Context, arg GetVirtu
} }
const GetVirtualGameTransactionByExternalID = `-- name: GetVirtualGameTransactionByExternalID :one const GetVirtualGameTransactionByExternalID = `-- name: GetVirtualGameTransactionByExternalID :one
SELECT id, session_id, user_id, wallet_id, transaction_type, amount, currency, external_transaction_id, status, created_at, updated_at SELECT id,
session_id,
user_id,
wallet_id,
transaction_type,
amount,
currency,
external_transaction_id,
status,
created_at,
updated_at
FROM virtual_game_transactions FROM virtual_game_transactions
WHERE external_transaction_id = $1 WHERE external_transaction_id = $1
` `
@ -647,7 +746,14 @@ func (q *Queries) ListFavoriteGames(ctx context.Context, userID int64) ([]int64,
} }
const ListVirtualGameProviders = `-- name: ListVirtualGameProviders :many const ListVirtualGameProviders = `-- name: ListVirtualGameProviders :many
SELECT id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at SELECT id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at
FROM virtual_game_providers FROM virtual_game_providers
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT $1 OFFSET $2 LIMIT $1 OFFSET $2
@ -689,7 +795,8 @@ func (q *Queries) ListVirtualGameProviders(ctx context.Context, arg ListVirtualG
const RemoveFavoriteGame = `-- name: RemoveFavoriteGame :exec const RemoveFavoriteGame = `-- name: RemoveFavoriteGame :exec
DELETE FROM favorite_games DELETE FROM favorite_games
WHERE user_id = $1 AND game_id = $2 WHERE user_id = $1
AND game_id = $2
` `
type RemoveFavoriteGameParams struct { type RemoveFavoriteGameParams struct {
@ -707,7 +814,14 @@ UPDATE virtual_game_providers
SET enabled = $2, SET enabled = $2,
updated_at = CURRENT_TIMESTAMP updated_at = CURRENT_TIMESTAMP
WHERE provider_id = $1 WHERE provider_id = $1
RETURNING id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at RETURNING id,
provider_id,
provider_name,
logo_dark,
logo_light,
enabled,
created_at,
updated_at
` `
type UpdateVirtualGameProviderEnabledParams struct { type UpdateVirtualGameProviderEnabledParams struct {
@ -733,7 +847,8 @@ func (q *Queries) UpdateVirtualGameProviderEnabled(ctx context.Context, arg Upda
const UpdateVirtualGameSessionStatus = `-- name: UpdateVirtualGameSessionStatus :exec const UpdateVirtualGameSessionStatus = `-- name: UpdateVirtualGameSessionStatus :exec
UPDATE virtual_game_sessions UPDATE virtual_game_sessions
SET status = $2, updated_at = CURRENT_TIMESTAMP SET status = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1 WHERE id = $1
` `
@ -749,7 +864,8 @@ func (q *Queries) UpdateVirtualGameSessionStatus(ctx context.Context, arg Update
const UpdateVirtualGameTransactionStatus = `-- name: UpdateVirtualGameTransactionStatus :exec const UpdateVirtualGameTransactionStatus = `-- name: UpdateVirtualGameTransactionStatus :exec
UPDATE virtual_game_transactions UPDATE virtual_game_transactions
SET status = $2, updated_at = CURRENT_TIMESTAMP SET status = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1 WHERE id = $1
` `

View File

@ -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.30.0
// source: wallet.sql // source: wallet.sql
package dbgen package dbgen
@ -50,7 +50,7 @@ INSERT INTO wallets (
type type
) )
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
RETURNING id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance RETURNING id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at
` `
type CreateWalletParams struct { type CreateWalletParams struct {
@ -82,8 +82,6 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
&i.IsActive, &i.IsActive,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.BonusBalance,
&i.CashBalance,
) )
return i, err return i, err
} }
@ -188,7 +186,7 @@ func (q *Queries) GetAllCustomerWallet(ctx context.Context) ([]CustomerWalletDet
} }
const GetAllWallets = `-- name: GetAllWallets :many const GetAllWallets = `-- name: GetAllWallets :many
SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at
FROM wallets FROM wallets
` `
@ -213,8 +211,6 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
&i.IsActive, &i.IsActive,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.BonusBalance,
&i.CashBalance,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@ -319,7 +315,7 @@ func (q *Queries) GetCustomerWallet(ctx context.Context, customerID int64) (Cust
} }
const GetWalletByID = `-- name: GetWalletByID :one const GetWalletByID = `-- name: GetWalletByID :one
SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at
FROM wallets FROM wallets
WHERE id = $1 WHERE id = $1
` `
@ -339,14 +335,12 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
&i.IsActive, &i.IsActive,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.BonusBalance,
&i.CashBalance,
) )
return i, err return i, err
} }
const GetWalletByUserID = `-- name: GetWalletByUserID :many const GetWalletByUserID = `-- name: GetWalletByUserID :many
SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, bonus_balance, cash_balance SELECT id, balance, currency, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at
FROM wallets FROM wallets
WHERE user_id = $1 WHERE user_id = $1
` `
@ -372,8 +366,6 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
&i.IsActive, &i.IsActive,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.BonusBalance,
&i.CashBalance,
); err != nil { ); err != nil {
return nil, err return nil, err
} }

View File

@ -10,3 +10,10 @@ type RefreshToken struct {
CreatedAt time.Time CreatedAt time.Time
Revoked bool Revoked bool
} }
// I used this because i was getting an error with the ValidInt64
// when it was being unmarshaled by the jwt
type NullJwtInt64 struct {
Value int64
Valid bool
}

View File

@ -235,6 +235,7 @@ func ConvertDBBetWithOutcomes(bet dbgen.BetWithOutcome) GetBet {
return GetBet{ return GetBet{
ID: bet.ID, ID: bet.ID,
CompanyID: bet.CompanyID,
Amount: Currency(bet.Amount), Amount: Currency(bet.Amount),
TotalOdds: bet.TotalOdds, TotalOdds: bet.TotalOdds,
Status: OutcomeStatus(bet.Status), Status: OutcomeStatus(bet.Status),

172
internal/domain/bonus.go Normal file
View File

@ -0,0 +1,172 @@
package domain
import (
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/jackc/pgx/v5/pgtype"
)
type BonusType string
var (
WelcomeBonus BonusType = "welcome_bonus"
DepositBonus BonusType = "deposit_bonus"
)
type UserBonus struct {
ID int64
Name string
Description string
UserID int64
Type BonusType
RewardAmount Currency
IsClaimed bool
ExpiresAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type UserBonusRes struct {
ID int64 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
UserID int64 `json:"user_id"`
Type BonusType `json:"type"`
RewardAmount float32 `json:"reward_amount"`
IsClaimed bool `json:"is_claimed"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func ConvertToBonusRes(bonus UserBonus) UserBonusRes {
return UserBonusRes{
ID: bonus.ID,
Name: bonus.Name,
Description: bonus.Description,
Type: bonus.Type,
UserID: bonus.UserID,
RewardAmount: bonus.RewardAmount.Float32(),
IsClaimed: bonus.IsClaimed,
ExpiresAt: bonus.ExpiresAt,
CreatedAt: bonus.CreatedAt,
UpdatedAt: bonus.UpdatedAt,
}
}
func ConvertToBonusResList(bonuses []UserBonus) []UserBonusRes {
result := make([]UserBonusRes, len(bonuses))
for i, bonus := range bonuses {
result[i] = ConvertToBonusRes(bonus)
}
return result
}
type CreateBonus struct {
Name string
Description string
Type BonusType
UserID int64
RewardAmount Currency
ExpiresAt time.Time
}
// type CreateBonusReq struct {
// Name string `json:"name"`
// Description string `json:"description"`
// Type BonusType `json:"type"`
// UserID int64 `json:"user_id"`
// RewardAmount float32 `json:"reward_amount"`
// ExpiresAt time.Time `json:"expires_at"`
// }
// func ConvertCreateBonusReq(bonus CreateBonusReq, companyID int64) CreateBonus {
// return CreateBonus{
// Name: bonus.Name,
// Description: bonus.Description,
// Type: bonus.Type,
// UserID: bonus.UserID,
// RewardAmount: ToCurrency(bonus.RewardAmount),
// ExpiresAt: bonus.ExpiresAt,
// }
// }
func ConvertCreateBonus(bonus CreateBonus) dbgen.CreateUserBonusParams {
return dbgen.CreateUserBonusParams{
Name: bonus.Name,
Description: bonus.Description,
Type: string(bonus.Type),
UserID: bonus.UserID,
RewardAmount: int64(bonus.RewardAmount),
ExpiresAt: pgtype.Timestamp{
Time: bonus.ExpiresAt,
Valid: true,
},
}
}
func ConvertDBBonus(bonus dbgen.UserBonuse) UserBonus {
return UserBonus{
ID: bonus.ID,
Name: bonus.Name,
Description: bonus.Description,
Type: BonusType(bonus.Type),
UserID: bonus.UserID,
RewardAmount: Currency(bonus.RewardAmount),
IsClaimed: bonus.IsClaimed,
ExpiresAt: bonus.ExpiresAt.Time,
CreatedAt: bonus.CreatedAt.Time,
UpdatedAt: bonus.UpdatedAt.Time,
}
}
func ConvertDBBonuses(bonuses []dbgen.UserBonuse) []UserBonus {
result := make([]UserBonus, len(bonuses))
for i, bonus := range bonuses {
result[i] = ConvertDBBonus(bonus)
}
return result
}
type BonusFilter struct {
UserID ValidInt64
CompanyID ValidInt64
Limit ValidInt
Offset ValidInt
}
type BonusStats struct {
TotalBonus int64
TotalRewardAmount Currency
ClaimedBonuses int64
ExpiredBonuses int64
}
type BonusStatsRes struct {
TotalBonus int64 `json:"total_bonus"`
TotalRewardAmount float32 `json:"total_reward_amount"`
ClaimedBonuses int64 `json:"claimed_bonuses"`
ExpiredBonuses int64 `json:"expired_bonuses"`
}
func ConvertToBonusStatsRes(bonus BonusStats) BonusStatsRes {
return BonusStatsRes{
TotalBonus: bonus.TotalBonus,
TotalRewardAmount: bonus.TotalRewardAmount.Float32(),
ClaimedBonuses: bonus.ClaimedBonuses,
ExpiredBonuses: bonus.ExpiredBonuses,
}
}
func ConvertDBBonusStats(stats dbgen.GetBonusStatsRow) BonusStats {
return BonusStats{
TotalBonus: stats.TotalBonuses,
TotalRewardAmount: Currency(stats.TotalRewardEarned),
ClaimedBonuses: stats.ClaimedBonuses,
ExpiredBonuses: stats.ExpiredBonuses,
}
}

View File

@ -69,7 +69,7 @@ type BaseEvent struct {
IsMonitored bool IsMonitored bool
DefaultIsFeatured bool DefaultIsFeatured bool
DefaultIsActive bool DefaultIsActive bool
DefaultWinningUpperLimit int32 DefaultWinningUpperLimit int64
Score ValidString Score ValidString
MatchMinute ValidInt MatchMinute ValidInt
TimerStatus ValidString TimerStatus ValidString
@ -97,92 +97,99 @@ type BaseEventRes struct {
IsMonitored bool `json:"is_monitored"` IsMonitored bool `json:"is_monitored"`
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
Score string `json:"score"`
MatchMinute int `json:"match_minute"`
TimerStatus string `json:"timer_status"`
AddedTime int `json:"added_time"`
MatchPeriod int `json:"match_period"`
IsLive bool `json:"is_live"`
FetchedAt time.Time `json:"fetched_at"`
}
type EventWithSettings struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
LeagueCC ValidString
StartTime time.Time
Source EventSource
Status EventStatus
IsMonitored bool
IsFeatured bool
IsActive bool
WinningUpperLimit int32
DefaultIsFeatured bool
DefaultIsActive bool
DefaultWinningUpperLimit int64
Score ValidString
MatchMinute ValidInt
TimerStatus ValidString
AddedTime ValidInt
MatchPeriod ValidInt
IsLive bool
UpdatedAt time.Time
FetchedAt time.Time
}
type CreateEvent struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
StartTime time.Time
IsLive bool
Status EventStatus
Source EventSource
DefaultWinningUpperLimit int64
}
type EventWithSettingsRes struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeTeamImage string `json:"home_team_image"`
AwayTeamImage string `json:"away_team_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"`
StartTime time.Time `json:"start_time"`
Source EventSource `json:"source"`
Status EventStatus `json:"status"`
IsMonitored bool `json:"is_monitored"`
IsFeatured bool `json:"is_featured"`
IsActive bool `json:"is_active"`
WinningUpperLimit int32 `json:"winning_upper_limit"`
DefaultIsFeatured bool `json:"default_is_featured"`
DefaultIsActive bool `json:"default_is_active"`
DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"`
Score string `json:"score,omitempty"` Score string `json:"score,omitempty"`
MatchMinute int `json:"match_minute,omitempty"` MatchMinute int `json:"match_minute,omitempty"`
TimerStatus string `json:"timer_status,omitempty"` TimerStatus string `json:"timer_status,omitempty"`
AddedTime int `json:"added_time,omitempty"` AddedTime int `json:"added_time,omitempty"`
MatchPeriod int `json:"match_period,omitempty"` MatchPeriod int `json:"match_period,omitempty"`
IsLive bool `json:"is_live"` IsLive bool `json:"is_live"`
UpdatedAt time.Time `json:"updated_at"`
FetchedAt time.Time `json:"fetched_at"` FetchedAt time.Time `json:"fetched_at"`
} }
type EventWithSettings struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
LeagueCC ValidString
StartTime time.Time
Source EventSource
Status EventStatus
IsFeatured bool
IsMonitored bool
IsActive bool
WinningUpperLimit int32
Score ValidString
MatchMinute ValidInt
TimerStatus ValidString
AddedTime ValidInt
MatchPeriod ValidInt
IsLive bool
UpdatedAt time.Time
FetchedAt time.Time
}
type CreateEvent struct {
ID string
SportID int32
MatchName string
HomeTeam string
AwayTeam string
HomeTeamID int64
AwayTeamID int64
HomeTeamImage string
AwayTeamImage string
LeagueID int64
LeagueName string
StartTime time.Time
IsLive bool
Status EventStatus
Source EventSource
}
type EventWithSettingsRes struct {
ID string `json:"id"`
SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"`
HomeTeamImage string `json:"home_team_image"`
AwayTeamImage string `json:"away_team_image"`
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"`
StartTime time.Time `json:"start_time"`
Source EventSource `json:"source"`
Status EventStatus `json:"status"`
IsFeatured bool `json:"is_featured"`
IsMonitored bool `json:"is_monitored"`
IsActive bool `json:"is_active"`
WinningUpperLimit int32 `json:"winning_upper_limit"`
Score string `json:"score,omitempty"`
MatchMinute int `json:"match_minute,omitempty"`
TimerStatus string `json:"timer_status,omitempty"`
AddedTime int `json:"added_time,omitempty"`
MatchPeriod int `json:"match_period,omitempty"`
IsLive bool `json:"is_live"`
UpdatedAt time.Time `json:"updated_at"`
FetchedAt time.Time `json:"fetched_at"`
}
type EventSettings struct { type EventSettings struct {
CompanyID int64 CompanyID int64
@ -212,6 +219,7 @@ type EventFilter struct {
Offset ValidInt32 Offset ValidInt32
MatchStatus ValidString // e.g., "upcoming", "in_play", "ended" MatchStatus ValidString // e.g., "upcoming", "in_play", "ended"
Featured ValidBool Featured ValidBool
Active ValidBool
} }
func ConvertDBEvent(event dbgen.EventWithCountry) BaseEvent { func ConvertDBEvent(event dbgen.EventWithCountry) BaseEvent {
@ -273,26 +281,27 @@ func ConvertDBEvents(events []dbgen.EventWithCountry) []BaseEvent {
func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams { func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams {
return dbgen.InsertEventParams{ return dbgen.InsertEventParams{
ID: e.ID, ID: e.ID,
SportID: e.SportID, SportID: e.SportID,
MatchName: e.MatchName, MatchName: e.MatchName,
HomeTeam: e.HomeTeam, HomeTeam: e.HomeTeam,
AwayTeam: e.AwayTeam, AwayTeam: e.AwayTeam,
HomeTeamID: e.HomeTeamID, HomeTeamID: e.HomeTeamID,
AwayTeamID: e.AwayTeamID, AwayTeamID: e.AwayTeamID,
HomeKitImage: e.HomeTeamImage, HomeKitImage: e.HomeTeamImage,
AwayKitImage: e.AwayTeamImage, AwayKitImage: e.AwayTeamImage,
LeagueID: e.LeagueID, LeagueID: e.LeagueID,
LeagueName: e.LeagueName, LeagueName: e.LeagueName,
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true}, StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
IsLive: e.IsLive, IsLive: e.IsLive,
Status: string(e.Status), Status: string(e.Status),
Source: string(e.Source), Source: string(e.Source),
DefaultWinningUpperLimit: e.DefaultWinningUpperLimit,
} }
} }
func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.InsertEventSettingsParams { func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEventSettingsParams {
return dbgen.InsertEventSettingsParams{ return dbgen.SaveEventSettingsParams{
CompanyID: eventSettings.CompanyID, CompanyID: eventSettings.CompanyID,
EventID: eventSettings.EventID, EventID: eventSettings.EventID,
IsActive: eventSettings.IsActive.ToPG(), IsActive: eventSettings.IsActive.ToPG(),
@ -318,13 +327,15 @@ func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings {
Value: event.LeagueCc.String, Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid, Valid: event.LeagueCc.Valid,
}, },
StartTime: event.StartTime.Time.UTC(), StartTime: event.StartTime.Time.UTC(),
Source: EventSource(event.Source), Source: EventSource(event.Source),
Status: EventStatus(event.Status), Status: EventStatus(event.Status),
IsFeatured: event.IsFeatured, IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored, IsMonitored: event.IsMonitored,
IsActive: event.IsActive, IsActive: event.IsActive,
WinningUpperLimit: event.WinningUpperLimit, DefaultIsFeatured: event.DefaultIsFeatured,
DefaultIsActive: event.DefaultIsActive,
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
Score: ValidString{ Score: ValidString{
Value: event.Score.String, Value: event.Score.String,
Valid: event.Score.Valid, Valid: event.Score.Valid,
@ -359,8 +370,8 @@ func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSett
return result return result
} }
func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.UpdateEventSettingsParams { func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettingsParams {
return dbgen.UpdateEventSettingsParams{ return dbgen.SaveEventSettingsParams{
EventID: event.EventID, EventID: event.EventID,
CompanyID: event.CompanyID, CompanyID: event.CompanyID,
IsActive: event.IsActive.ToPG(), IsActive: event.IsActive.ToPG(),
@ -409,32 +420,35 @@ func ConvertEventResList(events []BaseEvent) []BaseEventRes {
func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes { func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
return EventWithSettingsRes{ return EventWithSettingsRes{
ID: event.ID, ID: event.ID,
SportID: event.SportID, SportID: event.SportID,
MatchName: event.MatchName, MatchName: event.MatchName,
HomeTeam: event.HomeTeam, HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam, AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID, HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID, AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeTeamImage, HomeTeamImage: event.HomeTeamImage,
AwayTeamImage: event.AwayTeamImage, AwayTeamImage: event.AwayTeamImage,
LeagueID: event.LeagueID, LeagueID: event.LeagueID,
LeagueName: event.LeagueName, LeagueName: event.LeagueName,
LeagueCC: event.LeagueCC.Value, LeagueCC: event.LeagueCC.Value,
StartTime: event.StartTime.UTC(), StartTime: event.StartTime.UTC(),
Source: EventSource(event.Source), Source: EventSource(event.Source),
Status: EventStatus(event.Status), Status: EventStatus(event.Status),
IsFeatured: event.IsFeatured, IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored, IsMonitored: event.IsMonitored,
IsActive: event.IsActive, IsActive: event.IsActive,
WinningUpperLimit: event.WinningUpperLimit, DefaultIsFeatured: event.DefaultIsFeatured,
Score: event.Score.Value, DefaultIsActive: event.DefaultIsActive,
MatchMinute: event.MatchMinute.Value, DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
TimerStatus: event.TimerStatus.Value, WinningUpperLimit: event.WinningUpperLimit,
AddedTime: event.AddedTime.Value, Score: event.Score.Value,
MatchPeriod: event.MatchPeriod.Value, MatchMinute: event.MatchMinute.Value,
IsLive: event.IsLive, TimerStatus: event.TimerStatus.Value,
FetchedAt: event.FetchedAt.UTC(), AddedTime: event.AddedTime.Value,
MatchPeriod: event.MatchPeriod.Value,
IsLive: event.IsLive,
FetchedAt: event.FetchedAt.UTC(),
} }
} }

View File

@ -0,0 +1,27 @@
package domain
import (
"encoding/json"
"fmt"
)
// Custom type for fields that can be string or int
type StringOrNumber string
func (s *StringOrNumber) UnmarshalJSON(data []byte) error {
// Try as string
var str string
if err := json.Unmarshal(data, &str); err == nil {
*s = StringOrNumber(str)
return nil
}
// Try as number
var num json.Number
if err := json.Unmarshal(data, &num); err == nil {
*s = StringOrNumber(num.String())
return nil
}
return fmt.Errorf("StringOrNumber: cannot unmarshal %s", string(data))
}

View File

@ -8,24 +8,30 @@ import (
// The ID and the Bet365 IDs we have here are both gotten from the betapi // The ID and the Bet365 IDs we have here are both gotten from the betapi
type LeagueWithSettings struct { type LeagueWithSettings struct {
ID int64 ID int64
Name string Name string
CompanyID int64 CompanyID int64
CountryCode ValidString CountryCode ValidString
Bet365ID ValidInt32 Bet365ID ValidInt32
SportID int32 SportID int32
IsActive bool IsActive bool
IsFeatured bool IsFeatured bool
UpdatedAt time.Time DefaultIsActive bool
DefaultIsFeatured bool
UpdatedAt time.Time
} }
type LeagueWithSettingsRes struct { type LeagueWithSettingsRes struct {
ID int64 `json:"id" example:"1"` ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"BPL"` Name string `json:"name" example:"BPL"`
CountryCode string `json:"cc" example:"uk"` CompanyID int64 `json:"company_id" example:"1"`
Bet365ID int32 `json:"bet365_id" example:"1121"` CountryCode string `json:"cc" example:"uk"`
IsActive bool `json:"is_active" example:"false"` Bet365ID int32 `json:"bet365_id" example:"1121"`
SportID int32 `json:"sport_id" example:"1"` IsActive bool `json:"is_active" example:"false"`
IsFeatured bool `json:"is_featured" example:"false"` SportID int32 `json:"sport_id" example:"1"`
IsFeatured bool `json:"is_featured" example:"false"`
DefaultIsActive bool `json:"default_is_active" example:"false"`
DefaultIsFeatured bool `json:"default_is_featured" example:"false"`
UpdatedAt time.Time `json:"updated_at"`
} }
type BaseLeague struct { type BaseLeague struct {
ID int64 ID int64
@ -82,6 +88,7 @@ type UpdateLeague struct {
} }
type LeagueFilter struct { type LeagueFilter struct {
Query ValidString
CountryCode ValidString CountryCode ValidString
SportID ValidInt32 SportID ValidInt32
IsActive ValidBool IsActive ValidBool
@ -137,12 +144,12 @@ func ConvertDBBaseLeagues(leagues []dbgen.League) []BaseLeague {
return result return result
} }
func ConvertDBLeagueWithSetting(lws dbgen.LeagueWithSetting) LeagueWithSettings { func ConvertDBLeagueWithSetting(lws dbgen.GetAllLeaguesWithSettingsRow) LeagueWithSettings {
return LeagueWithSettings{ return LeagueWithSettings{
ID: lws.ID, ID: lws.ID,
Name: lws.Name, Name: lws.Name,
CompanyID: lws.CompanyID, CompanyID: lws.CompanyID.Int64,
CountryCode: ValidString{ CountryCode: ValidString{
Value: lws.CountryCode.String, Value: lws.CountryCode.String,
Valid: lws.CountryCode.Valid, Valid: lws.CountryCode.Valid,
}, },
@ -154,10 +161,13 @@ func ConvertDBLeagueWithSetting(lws dbgen.LeagueWithSetting) LeagueWithSettings
SportID: lws.SportID, SportID: lws.SportID,
IsFeatured: lws.IsFeatured, IsFeatured: lws.IsFeatured,
UpdatedAt: lws.UpdatedAt.Time, UpdatedAt: lws.UpdatedAt.Time,
DefaultIsActive: lws.DefaultIsActive,
DefaultIsFeatured: lws.DefaultIsFeatured,
} }
} }
func ConvertDBLeagueWithSettings(lws []dbgen.LeagueWithSetting) []LeagueWithSettings { func ConvertDBLeagueWithSettings(lws []dbgen.GetAllLeaguesWithSettingsRow) []LeagueWithSettings {
result := make([]LeagueWithSettings, len(lws)) result := make([]LeagueWithSettings, len(lws))
for i, league := range lws { for i, league := range lws {
result[i] = ConvertDBLeagueWithSetting(league) result[i] = ConvertDBLeagueWithSetting(league)
@ -174,3 +184,50 @@ func ConvertUpdateLeague(updateLeague UpdateLeague) dbgen.UpdateLeagueParams {
SportID: updateLeague.SportID.ToPG(), SportID: updateLeague.SportID.ToPG(),
} }
} }
func ConvertLeagueWithSettingRes(lws LeagueWithSettings) LeagueWithSettingsRes {
return LeagueWithSettingsRes{
ID: lws.ID,
Name: lws.Name,
CompanyID: lws.CompanyID,
CountryCode: lws.CountryCode.Value,
Bet365ID: lws.Bet365ID.Value,
IsActive: lws.IsActive,
SportID: lws.SportID,
IsFeatured: lws.IsFeatured,
UpdatedAt: lws.UpdatedAt,
DefaultIsActive: lws.DefaultIsActive,
DefaultIsFeatured: lws.DefaultIsFeatured,
}
}
func ConvertLeagueWithSettingResList(leagues []LeagueWithSettings) []LeagueWithSettingsRes {
result := make([]LeagueWithSettingsRes, len(leagues))
for i, lws := range leagues {
result[i] = ConvertLeagueWithSettingRes(lws)
}
return result
}
func ConvertBaseLeagueRes(league BaseLeague) BaseLeagueRes {
return BaseLeagueRes{
ID: league.ID,
Name: league.Name,
CountryCode: league.CountryCode.Value,
Bet365ID: league.Bet365ID.Value,
SportID: league.SportID,
DefaultIsActive: league.DefaultIsActive,
DefaultIsFeatured: league.DefaultIsFeatured,
}
}
func ConvertBaseLeagueResList(leagues []BaseLeague) []BaseLeagueRes {
result := make([]BaseLeagueRes, len(leagues))
for i, league := range leagues {
result[i] = ConvertBaseLeagueRes(league)
}
return result
}

View File

@ -32,6 +32,7 @@ const (
NOTIFICATION_TYPE_BET_RESULT NotificationType = "bet_result" NOTIFICATION_TYPE_BET_RESULT NotificationType = "bet_result"
NOTIFICATION_TYPE_TRANSFER_REJECTED NotificationType = "transfer_rejected" NOTIFICATION_TYPE_TRANSFER_REJECTED NotificationType = "transfer_rejected"
NOTIFICATION_TYPE_APPROVAL_REQUIRED NotificationType = "approval_required" NOTIFICATION_TYPE_APPROVAL_REQUIRED NotificationType = "approval_required"
NOTIFICATION_TYPE_BONUS_AWARDED NotificationType = "bonus_awarded"
NotificationRecieverSideAdmin NotificationRecieverSide = "admin" NotificationRecieverSideAdmin NotificationRecieverSide = "admin"
NotificationRecieverSideCustomer NotificationRecieverSide = "customer" NotificationRecieverSideCustomer NotificationRecieverSide = "customer"
@ -73,7 +74,7 @@ type Notification struct {
RecipientID int64 `json:"recipient_id"` RecipientID int64 `json:"recipient_id"`
Type NotificationType `json:"type"` Type NotificationType `json:"type"`
Level NotificationLevel `json:"level"` Level NotificationLevel `json:"level"`
ErrorSeverity *NotificationErrorSeverity `json:"error_severity"` ErrorSeverity NotificationErrorSeverity `json:"error_severity"`
Reciever NotificationRecieverSide `json:"reciever"` Reciever NotificationRecieverSide `json:"reciever"`
IsRead bool `json:"is_read"` IsRead bool `json:"is_read"`
DeliveryStatus NotificationDeliveryStatus `json:"delivery_status,omitempty"` DeliveryStatus NotificationDeliveryStatus `json:"delivery_status,omitempty"`

View File

@ -27,7 +27,7 @@ type RawOdd struct {
// The Market ID for the json data can be either string / int which is causing problems when UnMarshalling // The Market ID for the json data can be either string / int which is causing problems when UnMarshalling
type OddsMarket struct { type OddsMarket struct {
ID ValidInt64 `json:"id"` ID StringOrNumber `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Odds []json.RawMessage `json:"odds"` Odds []json.RawMessage `json:"odds"`
Header string `json:"header,omitempty"` Header string `json:"header,omitempty"`

View File

@ -61,6 +61,17 @@ type CreateOddMarketSettings struct {
CustomRawOdds []map[string]interface{} CustomRawOdds []map[string]interface{}
} }
type CustomOdd struct {
OddID int64 `json:"odd_id"`
OddValue float32 `json:"odd_value"`
}
type CreateOddMarketSettingsReq struct {
OddMarketID int64 `json:"odd_market_id"`
IsActive *bool `json:"is_active,omitempty"`
CustomOdd []CustomOdd `json:"custom_odd,omitempty"`
}
type RawOddsByMarketID struct { type RawOddsByMarketID struct {
ID int64 `json:"id"` ID int64 `json:"id"`
MarketName string `json:"market_name"` MarketName string `json:"market_name"`
@ -136,12 +147,12 @@ func ConvertCreateOddMarket(oddMarket CreateOddMarket) (dbgen.InsertOddsMarketPa
}, nil }, nil
} }
func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.InsertOddSettingsParams, error) { func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.SaveOddSettingsParams, error) {
rawOddsBytes, err := json.Marshal(oms.CustomRawOdds) rawOddsBytes, err := json.Marshal(oms.CustomRawOdds)
if err != nil { if err != nil {
return dbgen.InsertOddSettingsParams{}, err return dbgen.SaveOddSettingsParams{}, err
} }
return dbgen.InsertOddSettingsParams{ return dbgen.SaveOddSettingsParams{
CompanyID: oms.CompanyID, CompanyID: oms.CompanyID,
OddsMarketID: oms.OddMarketID, OddsMarketID: oms.OddMarketID,
IsActive: oms.IsActive.ToPG(), IsActive: oms.IsActive.ToPG(),

83
internal/domain/raffle.go Normal file
View File

@ -0,0 +1,83 @@
package domain
import "time"
type Raffle struct {
ID int32
CompanyID int32
Name string
CreatedAt time.Time
ExpiresAt time.Time
Type string
Status string
}
type RaffleFilter struct {
// requireds will depend on type of raffle (sport or game)
Type string `json:"type" validate:"required,oneof=sport game"`
RaffleID int32 `json:"raffle_id" validate:"required"`
SportID int32 `json:"sport_id" validate:"required_if=Type sport"`
LeagueID int32 `json:"league_id" validate:"required_if=Type sport"`
GameID string `json:"game_id" validate:"required_if=Type game"`
}
type RaffleStanding struct {
UserID int64
RaffleID int32
FirstName string
LastName string
PhoneNumber string
Email string
TicketCount int64
}
type RaffleStandingRes struct {
UserID int64 `json:"user_id"`
RaffleID int32 `json:"raffle_id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
PhoneNumber string `json:"phone_number"`
Email string `json:"email"`
TicketCount int64 `json:"ticket_count"`
}
type RaffleWinnerParams struct {
RaffleID int32
UserID int32
Rank int32
}
type RaffleTicket struct {
ID int32
RaffleID int32
UserID int32
IsActive bool
}
type RaffleTicketRes struct {
TicketID int32
UserID int32
Name string
Type string
ExpiresAt time.Time
Status string
}
type CreateRaffle struct {
CompanyID int32 `json:"company_id" validate:"required"`
Name string `json:"name" validate:"required"`
ExpiresAt *time.Time `json:"expires_at" validate:"required"`
Type string `json:"type" validate:"required"`
}
type CreateRaffleTicket struct {
RaffleID int32 `json:"raffle_id" validate:"required"`
UserID int32 `json:"user_id" validate:"required"`
}
// aside from ID, atleast one of the fields should be required
type UpdateRaffleParams struct {
ID int32 `json:"id" validate:"required"`
Name string `json:"name" validate:"required_without_all=ExpiresAt"`
ExpiresAt *time.Time `json:"expires_at" validate:"required_without_all=Name"`
}

View File

@ -1,73 +1,186 @@
package domain package domain
import ( import (
"database/sql/driver"
"fmt"
"time" "time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
) )
type ReferralStatus string type ReferralCode struct {
ID int64
const ( ReferrerID int64
ReferralPending ReferralStatus = "PENDING" ReferralCode string
ReferralCompleted ReferralStatus = "COMPLETED" CompanyID int64
ReferralExpired ReferralStatus = "EXPIRED" NumberOfReferrals int64
ReferralCancelled ReferralStatus = "CANCELLED" RewardAmount Currency
) CreatedAt time.Time
UpdatedAt time.Time
func (rs *ReferralStatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*rs = ReferralStatus(s)
case string:
*rs = ReferralStatus(s)
default:
return fmt.Errorf("unsupported scan type for ReferralStatus: %T", src)
}
return nil
} }
func (rs ReferralStatus) Value() (driver.Value, error) { type ReferralCodeRes struct {
return string(rs), nil ID int64 `json:"id"`
ReferrerID int64 `json:"referrer_id"`
ReferralCode string `json:"referral_code"`
CompanyID int64 `json:"company_id"`
NumberOfReferrals int64 `json:"number_of_referrals"`
RewardAmount float32 `json:"reward_amount"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type CreateReferralCode struct {
ReferrerID int64
ReferralCode string
CompanyID int64
NumberOfReferrals int64
RewardAmount Currency
}
type UserReferral struct {
ReferredID int64
ReferralCodeID int64
}
type CreateUserReferrals struct {
ReferredID int64
ReferralCodeID int64
}
type UpdateReferralCode struct {
ID int64
IsActive bool
ReferralCode string
RewardAmount Currency
NumberOfReferrals int64
} }
type ReferralStats struct { type ReferralStats struct {
TotalReferrals int TotalReferrals int64
CompletedReferrals int TotalRewardEarned Currency
TotalRewardEarned float64
PendingRewards float64
} }
type ReferralSettings struct { type ReferralStatsRes struct {
ID int64 TotalReferrals int64 `json:"total_referrals"`
ReferralRewardAmount float64 TotalRewardEarned float32 `json:"total_reward_earned"`
CashbackPercentage float64
BetReferralBonusPercentage float64
MaxReferrals int32
ExpiresAfterDays int32
UpdatedBy string
CreatedAt time.Time
UpdatedAt time.Time
Version int32
} }
type ReferralSettingsReq struct { // type ReferralSettings struct {
ReferralRewardAmount float64 `json:"referral_reward_amount" validate:"required"` // ID int64
CashbackPercentage float64 `json:"cashback_percentage" validate:"required"` // ReferralRewardAmount float64
MaxReferrals int32 `json:"max_referrals" validate:"required"` // CashbackPercentage float64
ExpiresAfterDays int32 `json:"expires_afterdays" validate:"required"` // BetReferralBonusPercentage float64
UpdatedBy string `json:"updated_by" validate:"required"` // MaxReferrals int32
// ExpiresAfterDays int32
// UpdatedBy string
// CreatedAt time.Time
// UpdatedAt time.Time
// Version int32
// }
// type ReferralSettingsReq struct {
// ReferralRewardAmount float64 `json:"referral_reward_amount" validate:"required"`
// CashbackPercentage float64 `json:"cashback_percentage" validate:"required"`
// MaxReferrals int32 `json:"max_referrals" validate:"required"`
// UpdatedBy string `json:"updated_by" validate:"required"`
// }
func ConvertCreateReferralCode(code CreateReferralCode) dbgen.CreateReferralCodeParams {
return dbgen.CreateReferralCodeParams{
ReferralCode: code.ReferralCode,
ReferrerID: code.ReferrerID,
CompanyID: code.CompanyID,
NumberOfReferrals: code.NumberOfReferrals,
RewardAmount: int64(code.RewardAmount),
}
} }
type Referral struct { func ConvertDBReferralCode(code dbgen.ReferralCode) ReferralCode {
ID int64 return ReferralCode{
ReferralCode string ID: code.ID,
ReferrerID string ReferrerID: code.ReferrerID,
ReferredID *string ReferralCode: code.ReferralCode,
Status ReferralStatus NumberOfReferrals: code.NumberOfReferrals,
RewardAmount float64 RewardAmount: Currency(code.RewardAmount),
CashbackAmount float64 CompanyID: code.CompanyID,
CreatedAt time.Time CreatedAt: code.CreatedAt.Time,
UpdatedAt time.Time UpdatedAt: code.UpdatedAt.Time,
ExpiresAt time.Time }
}
func ConvertDBReferralCodes(codes []dbgen.ReferralCode) []ReferralCode {
result := make([]ReferralCode, len(codes))
for i, code := range codes {
result[i] = ConvertDBReferralCode(code)
}
return result
}
func ConvertCreateUserReferral(referral CreateUserReferrals) dbgen.CreateUserReferralParams {
return dbgen.CreateUserReferralParams{
ReferredID: referral.ReferredID,
ReferralCodeID: referral.ReferralCodeID,
}
}
func ConvertDBUserReferral(referral dbgen.UserReferral) UserReferral {
return UserReferral{
ReferredID: referral.ReferredID,
ReferralCodeID: referral.ReferralCodeID,
}
}
func ConvertDBUserReferrals(referrals []dbgen.UserReferral) []UserReferral {
result := make([]UserReferral, len(referrals))
for i, referral := range referrals {
result[i] = ConvertDBUserReferral(referral)
}
return result
}
func ConvertUpdateReferralCode(referralCode UpdateReferralCode) dbgen.UpdateReferralCodeParams {
return dbgen.UpdateReferralCodeParams{
ID: referralCode.ID,
IsActive: referralCode.IsActive,
ReferralCode: referralCode.ReferralCode,
NumberOfReferrals: referralCode.NumberOfReferrals,
RewardAmount: int64(referralCode.RewardAmount),
}
}
func ConvertDBReferralStats(stats dbgen.GetReferralStatsRow) ReferralStats {
return ReferralStats{
TotalReferrals: stats.TotalReferrals,
TotalRewardEarned: Currency(stats.TotalRewardEarned),
}
}
func ConvertReferralCodeRes(referral ReferralCode) ReferralCodeRes {
return ReferralCodeRes{
ID: referral.ID,
ReferrerID: referral.ReferrerID,
ReferralCode: referral.ReferralCode,
CompanyID: referral.CompanyID,
NumberOfReferrals: referral.NumberOfReferrals,
RewardAmount: referral.RewardAmount.Float32(),
CreatedAt: referral.CreatedAt,
UpdatedAt: referral.UpdatedAt,
}
}
func ConvertReferralCodeResList(referrals []ReferralCode) []ReferralCodeRes {
result := make([]ReferralCodeRes, len(referrals))
for i, referral := range referrals {
result[i] = ConvertReferralCodeRes(referral)
}
return result
}
func ConvertReferralStatsRes(stats ReferralStats) ReferralStatsRes {
return ReferralStatsRes{
TotalReferrals: stats.TotalReferrals,
TotalRewardEarned: stats.TotalRewardEarned.Float32(),
}
} }

View File

@ -3,16 +3,17 @@ package domain
type Role string type Role string
const ( const (
RoleSuperAdmin Role = "super_admin" RoleSuperAdmin Role = "super_admin"
RoleAdmin Role = "admin" RoleAdmin Role = "admin"
RoleBranchManager Role = "branch_manager" RoleBranchManager Role = "branch_manager"
RoleCustomer Role = "customer" RoleCustomer Role = "customer"
RoleCashier Role = "cashier" RoleCashier Role = "cashier"
RoleTransactionApprover Role = "transaction_approver"
) )
func (r Role) IsValid() bool { func (r Role) IsValid() bool {
switch r { switch r {
case RoleSuperAdmin, RoleAdmin, RoleBranchManager, RoleCustomer, RoleCashier: case RoleSuperAdmin, RoleAdmin, RoleBranchManager, RoleCustomer, RoleCashier, RoleTransactionApprover:
return true return true
default: default:
return false return false

View File

@ -16,67 +16,170 @@ var (
) )
type SettingList struct { type SettingList struct {
SMSProvider SMSProvider `json:"sms_provider"` SMSProvider SMSProvider `json:"sms_provider"`
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"` MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
BetAmountLimit Currency `json:"bet_amount_limit"` BetAmountLimit Currency `json:"bet_amount_limit"`
DailyTicketPerIP int64 `json:"daily_ticket_limit"` DailyTicketPerIP int64 `json:"daily_ticket_limit"`
TotalWinningLimit Currency `json:"total_winning_limit"` TotalWinningLimit Currency `json:"total_winning_limit"`
AmountForBetReferral Currency `json:"amount_for_bet_referral"` AmountForBetReferral Currency `json:"amount_for_bet_referral"`
CashbackAmountCap Currency `json:"cashback_amount_cap"` CashbackAmountCap Currency `json:"cashback_amount_cap"`
DefaultWinningLimit int64 `json:"default_winning_limit"`
ReferralRewardAmount Currency `json:"referral_reward_amount"`
CashbackPercentage float32 `json:"cashback_percentage"`
DefaultMaxReferrals int64 `json:"default_max_referrals"`
MinimumBetAmount Currency `json:"minimum_bet_amount"`
BetDuplicateLimit int64 `json:"bet_duplicate_limit"`
SendEmailOnBetFinish bool `json:"send_email_on_bet_finish"`
SendSMSOnBetFinish bool `json:"send_sms_on_bet_finish"`
WelcomeBonusActive bool `json:"welcome_bonus_active"`
WelcomeBonusMultiplier float32 `json:"welcome_bonus_multiplier"`
WelcomeBonusCap Currency `json:"welcome_bonus_cap"`
WelcomeBonusCount int64 `json:"welcome_bonus_count"`
WelcomeBonusExpire int64 `json:"welcome_bonus_expiry"`
} }
type SettingListRes struct { type SettingListRes struct {
SMSProvider SMSProvider `json:"sms_provider"` SMSProvider SMSProvider `json:"sms_provider"`
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"` MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
BetAmountLimit float32 `json:"bet_amount_limit"` BetAmountLimit float32 `json:"bet_amount_limit"`
DailyTicketPerIP int64 `json:"daily_ticket_limit"` DailyTicketPerIP int64 `json:"daily_ticket_limit"`
TotalWinningLimit float32 `json:"total_winning_limit"` TotalWinningLimit float32 `json:"total_winning_limit"`
AmountForBetReferral float32 `json:"amount_for_bet_referral"` AmountForBetReferral float32 `json:"amount_for_bet_referral"`
CashbackAmountCap float32 `json:"cashback_amount_cap"` CashbackAmountCap float32 `json:"cashback_amount_cap"`
DefaultWinningLimit int64 `json:"default_winning_limit"`
ReferralRewardAmount float32 `json:"referral_reward_amount"`
CashbackPercentage float32 `json:"cashback_percentage"`
DefaultMaxReferrals int64 `json:"default_max_referrals"`
MinimumBetAmount float32 `json:"minimum_bet_amount"`
BetDuplicateLimit int64 `json:"bet_duplicate_limit"`
SendEmailOnBetFinish bool `json:"send_email_on_bet_finish"`
SendSMSOnBetFinish bool `json:"send_sms_on_bet_finish"`
WelcomeBonusActive bool `json:"welcome_bonus_active"`
WelcomeBonusMultiplier float32 `json:"welcome_bonus_multiplier"`
WelcomeBonusCap float32 `json:"welcome_bonus_cap"`
WelcomeBonusCount int64 `json:"welcome_bonus_count"`
WelcomeBonusExpire int64 `json:"welcome_bonus_expiry"`
}
func ConvertSettingListRes(settings SettingList) SettingListRes {
return SettingListRes{
SMSProvider: settings.SMSProvider,
MaxNumberOfOutcomes: settings.MaxNumberOfOutcomes,
BetAmountLimit: settings.BetAmountLimit.Float32(),
DailyTicketPerIP: settings.DailyTicketPerIP,
TotalWinningLimit: settings.TotalWinningLimit.Float32(),
AmountForBetReferral: settings.AmountForBetReferral.Float32(),
CashbackAmountCap: settings.CashbackAmountCap.Float32(),
DefaultWinningLimit: settings.DefaultWinningLimit,
ReferralRewardAmount: settings.ReferralRewardAmount.Float32(),
CashbackPercentage: settings.CashbackPercentage,
DefaultMaxReferrals: settings.DefaultMaxReferrals,
MinimumBetAmount: settings.MinimumBetAmount.Float32(),
BetDuplicateLimit: settings.BetDuplicateLimit,
SendEmailOnBetFinish: settings.SendEmailOnBetFinish,
SendSMSOnBetFinish: settings.SendSMSOnBetFinish,
WelcomeBonusActive: settings.WelcomeBonusActive,
WelcomeBonusMultiplier: settings.WelcomeBonusMultiplier,
WelcomeBonusCap: settings.WelcomeBonusCap.Float32(),
WelcomeBonusCount: settings.WelcomeBonusCount,
WelcomeBonusExpire: settings.WelcomeBonusExpire,
}
} }
type SaveSettingListReq struct { type SaveSettingListReq struct {
SMSProvider *string `json:"sms_provider,omitempty"` SMSProvider *string `json:"sms_provider,omitempty"`
MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"` MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"`
BetAmountLimit *float32 `json:"bet_amount_limit,omitempty"` BetAmountLimit *float32 `json:"bet_amount_limit,omitempty"`
DailyTicketPerIP *int64 `json:"daily_ticket_limit,omitempty"` DailyTicketPerIP *int64 `json:"daily_ticket_limit,omitempty"`
TotalWinningLimit *float32 `json:"total_winning_limit,omitempty"` TotalWinningLimit *float32 `json:"total_winning_limit,omitempty"`
AmountForBetReferral *float32 `json:"amount_for_bet_referral,omitempty"` AmountForBetReferral *float32 `json:"amount_for_bet_referral,omitempty"`
CashbackAmountCap *float32 `json:"cashback_amount_cap,omitempty"` CashbackAmountCap *float32 `json:"cashback_amount_cap,omitempty"`
DefaultWinningLimit *int64 `json:"default_winning_limit,omitempty"`
ReferralRewardAmount *float32 `json:"referral_reward_amount"`
CashbackPercentage *float32 `json:"cashback_percentage"`
DefaultMaxReferrals *int64 `json:"default_max_referrals"`
MinimumBetAmount *float32 `json:"minimum_bet_amount"`
BetDuplicateLimit *int64 `json:"bet_duplicate_limit"`
SendEmailOnBetFinish *bool `json:"send_email_on_bet_finish"`
SendSMSOnBetFinish *bool `json:"send_sms_on_bet_finish"`
WelcomeBonusActive *bool `json:"welcome_bonus_active"`
WelcomeBonusMultiplier *float32 `json:"welcome_bonus_multiplier"`
WelcomeBonusCap *float32 `json:"welcome_bonus_cap"`
WelcomeBonusCount *int64 `json:"welcome_bonus_count"`
WelcomeBonusExpire *int64 `json:"welcome_bonus_expiry"`
}
type ValidSettingList struct {
SMSProvider ValidString
MaxNumberOfOutcomes ValidInt64
BetAmountLimit ValidCurrency
DailyTicketPerIP ValidInt64
TotalWinningLimit ValidCurrency
AmountForBetReferral ValidCurrency
CashbackAmountCap ValidCurrency
DefaultWinningLimit ValidInt64
ReferralRewardAmount ValidCurrency
CashbackPercentage ValidFloat32
DefaultMaxReferrals ValidInt64
MinimumBetAmount ValidCurrency
BetDuplicateLimit ValidInt64
SendEmailOnBetFinish ValidBool
SendSMSOnBetFinish ValidBool
WelcomeBonusActive ValidBool
WelcomeBonusMultiplier ValidFloat32
WelcomeBonusCap ValidCurrency
WelcomeBonusCount ValidInt64
WelcomeBonusExpire ValidInt64
} }
func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList { func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList {
return ValidSettingList{ return ValidSettingList{
SMSProvider: ConvertStringPtr(settings.SMSProvider), SMSProvider: ConvertStringPtr(settings.SMSProvider),
MaxNumberOfOutcomes: ConvertInt64Ptr(settings.MaxNumberOfOutcomes), MaxNumberOfOutcomes: ConvertInt64Ptr(settings.MaxNumberOfOutcomes),
BetAmountLimit: ConvertFloat32PtrToCurrency(settings.BetAmountLimit), BetAmountLimit: ConvertFloat32PtrToCurrency(settings.BetAmountLimit),
DailyTicketPerIP: ConvertInt64Ptr(settings.DailyTicketPerIP), DailyTicketPerIP: ConvertInt64Ptr(settings.DailyTicketPerIP),
TotalWinningLimit: ConvertFloat32PtrToCurrency(settings.TotalWinningLimit), TotalWinningLimit: ConvertFloat32PtrToCurrency(settings.TotalWinningLimit),
AmountForBetReferral: ConvertFloat32PtrToCurrency(settings.AmountForBetReferral), AmountForBetReferral: ConvertFloat32PtrToCurrency(settings.AmountForBetReferral),
CashbackAmountCap: ConvertFloat32PtrToCurrency(settings.CashbackAmountCap), CashbackAmountCap: ConvertFloat32PtrToCurrency(settings.CashbackAmountCap),
DefaultWinningLimit: ConvertInt64Ptr(settings.DefaultWinningLimit),
ReferralRewardAmount: ConvertFloat32PtrToCurrency(settings.ReferralRewardAmount),
CashbackPercentage: ConvertFloat32Ptr(settings.CashbackPercentage),
DefaultMaxReferrals: ConvertInt64Ptr(settings.DefaultMaxReferrals),
MinimumBetAmount: ConvertFloat32PtrToCurrency(settings.MinimumBetAmount),
BetDuplicateLimit: ConvertInt64Ptr(settings.BetDuplicateLimit),
SendEmailOnBetFinish: ConvertBoolPtr(settings.SendEmailOnBetFinish),
SendSMSOnBetFinish: ConvertBoolPtr(settings.SendSMSOnBetFinish),
WelcomeBonusActive: ConvertBoolPtr(settings.WelcomeBonusActive),
WelcomeBonusMultiplier: ConvertFloat32Ptr(settings.WelcomeBonusMultiplier),
WelcomeBonusCap: ConvertFloat32PtrToCurrency(settings.WelcomeBonusCap),
WelcomeBonusCount: ConvertInt64Ptr(settings.WelcomeBonusCount),
WelcomeBonusExpire: ConvertInt64Ptr(settings.WelcomeBonusExpire),
} }
} }
type ValidSettingList struct {
SMSProvider ValidString
MaxNumberOfOutcomes ValidInt64
BetAmountLimit ValidCurrency
DailyTicketPerIP ValidInt64
TotalWinningLimit ValidCurrency
AmountForBetReferral ValidCurrency
CashbackAmountCap ValidCurrency
}
// Always make sure to run the validation before converting this // Always make sure to run the validation before converting this
func (vsl *ValidSettingList) ToSettingList() SettingList { func (vsl *ValidSettingList) ToSettingList() SettingList {
return SettingList{ return SettingList{
SMSProvider: SMSProvider(vsl.SMSProvider.Value), SMSProvider: SMSProvider(vsl.SMSProvider.Value),
MaxNumberOfOutcomes: vsl.MaxNumberOfOutcomes.Value, MaxNumberOfOutcomes: vsl.MaxNumberOfOutcomes.Value,
BetAmountLimit: Currency(vsl.BetAmountLimit.Value), BetAmountLimit: vsl.BetAmountLimit.Value,
DailyTicketPerIP: vsl.DailyTicketPerIP.Value, DailyTicketPerIP: vsl.DailyTicketPerIP.Value,
TotalWinningLimit: Currency(vsl.TotalWinningLimit.Value), TotalWinningLimit: vsl.TotalWinningLimit.Value,
AmountForBetReferral: Currency(vsl.AmountForBetReferral.Value), AmountForBetReferral: vsl.AmountForBetReferral.Value,
CashbackAmountCap: Currency(vsl.CashbackAmountCap.Value), CashbackAmountCap: vsl.CashbackAmountCap.Value,
DefaultWinningLimit: vsl.DefaultWinningLimit.Value,
ReferralRewardAmount: vsl.ReferralRewardAmount.Value,
CashbackPercentage: vsl.CashbackPercentage.Value,
DefaultMaxReferrals: vsl.DefaultMaxReferrals.Value,
MinimumBetAmount: vsl.MinimumBetAmount.Value,
BetDuplicateLimit: vsl.BetDuplicateLimit.Value,
SendEmailOnBetFinish: vsl.SendEmailOnBetFinish.Value,
SendSMSOnBetFinish: vsl.SendSMSOnBetFinish.Value,
WelcomeBonusActive: vsl.WelcomeBonusActive.Value,
WelcomeBonusMultiplier: vsl.WelcomeBonusMultiplier.Value,
WelcomeBonusCap: vsl.WelcomeBonusCap.Value,
WelcomeBonusCount: vsl.WelcomeBonusCount.Value,
WelcomeBonusExpire: vsl.WelcomeBonusExpire.Value,
} }
} }
@ -92,6 +195,11 @@ func (vsl *ValidSettingList) GetInt64SettingsMap() map[string]*ValidInt64 {
return map[string]*ValidInt64{ return map[string]*ValidInt64{
"max_number_of_outcomes": &vsl.MaxNumberOfOutcomes, "max_number_of_outcomes": &vsl.MaxNumberOfOutcomes,
"daily_ticket_limit": &vsl.DailyTicketPerIP, "daily_ticket_limit": &vsl.DailyTicketPerIP,
"default_winning_limit": &vsl.DefaultWinningLimit,
"default_max_referrals": &vsl.DefaultMaxReferrals,
"bet_duplicate_limit": &vsl.BetDuplicateLimit,
"welcome_bonus_count": &vsl.WelcomeBonusCount,
"welcome_bonus_expiry": &vsl.WelcomeBonusExpire,
} }
} }
@ -101,6 +209,9 @@ func (vsl *ValidSettingList) GetCurrencySettingsMap() map[string]*ValidCurrency
"total_winnings_limit": &vsl.TotalWinningLimit, "total_winnings_limit": &vsl.TotalWinningLimit,
"amount_for_bet_referral": &vsl.AmountForBetReferral, "amount_for_bet_referral": &vsl.AmountForBetReferral,
"cashback_amount_cap": &vsl.CashbackAmountCap, "cashback_amount_cap": &vsl.CashbackAmountCap,
"referral_reward_amount": &vsl.ReferralRewardAmount,
"minimum_bet_amount": &vsl.MinimumBetAmount,
"welcome_bonus_cap": &vsl.WelcomeBonusCap,
} }
} }
@ -111,17 +222,26 @@ func (vsl *ValidSettingList) GetStringSettingsMap() map[string]*ValidString {
} }
func (vsl *ValidSettingList) GetBoolSettingsMap() map[string]*ValidBool { func (vsl *ValidSettingList) GetBoolSettingsMap() map[string]*ValidBool {
return map[string]*ValidBool{} return map[string]*ValidBool{
"send_email_on_bet_finish": &vsl.SendEmailOnBetFinish,
"send_sms_on_bet_finish": &vsl.SendSMSOnBetFinish,
"welcome_bonus_active": &vsl.WelcomeBonusActive,
}
} }
func (vsl *ValidSettingList) GetFloat32SettingsMap() map[string]*ValidFloat32 { func (vsl *ValidSettingList) GetFloat32SettingsMap() map[string]*ValidFloat32 {
return map[string]*ValidFloat32{} return map[string]*ValidFloat32{
"cashback_percentage": &vsl.CashbackPercentage,
"welcome_bonus_multiplier": &vsl.WelcomeBonusMultiplier,
}
} }
func (vsl *ValidSettingList) GetTimeSettingsMap() map[string]*ValidTime { func (vsl *ValidSettingList) GetTimeSettingsMap() map[string]*ValidTime {
return map[string]*ValidTime{} return map[string]*ValidTime{}
} }
// Setting Functions
func (vsl *ValidSettingList) GetTotalSettings() int { func (vsl *ValidSettingList) GetTotalSettings() int {
return len(vsl.GetInt64SettingsMap()) + return len(vsl.GetInt64SettingsMap()) +
len(vsl.GetCurrencySettingsMap()) + len(vsl.GetCurrencySettingsMap()) +
@ -157,57 +277,105 @@ func (vsl *ValidSettingList) GetAllValid() map[string]*bool {
return settingValid return settingValid
} }
func setValidSetting[T any](settings map[string]*T, searchKey string, setVal T) error { // func setValidSetting[T any](settings map[string]*T, searchKey string, searchVal string, setVal func(string) (T, error)) error {
for key, setting := range settings { // for key, setting := range settings {
// if key == searchKey {
// s, err := setVal(searchVal)
// if err != nil {
// return err
// }
// *setting = s
// }
// return nil
// }
// return ErrSettingNotFound
// }
func (vsl *ValidSettingList) SetInt64Setting(searchKey string, searchVal string) error {
for key, setting := range vsl.GetInt64SettingsMap() {
if key == searchKey { if key == searchKey {
*setting = setVal value, err := strconv.ParseInt(searchVal, 10, 64)
if err != nil {
return err
}
*setting = ValidInt64{Value: value, Valid: true}
return nil
} }
return nil
} }
return ErrSettingNotFound return ErrSettingNotFound
} }
func (vsl *ValidSettingList) SetInt64Setting(searchKey string, searchVal string) error {
value, err := strconv.ParseInt(searchVal, 10, 64)
if err != nil {
return err
}
return setValidSetting(vsl.GetInt64SettingsMap(), searchKey, ValidInt64{Value: value, Valid: true})
}
func (vsl *ValidSettingList) SetCurrencySetting(searchKey string, searchVal string) error { func (vsl *ValidSettingList) SetCurrencySetting(searchKey string, searchVal string) error {
value, err := strconv.ParseInt(searchVal, 10, 64) for key, setting := range vsl.GetCurrencySettingsMap() {
if err != nil { if key == searchKey {
return err value, err := strconv.ParseInt(searchVal, 10, 64)
if err != nil {
return err
}
*setting = ValidCurrency{Value: Currency(value), Valid: true}
return nil
}
} }
return setValidSetting(vsl.GetCurrencySettingsMap(), searchKey, ValidCurrency{Value: Currency(value), Valid: true})
return ErrSettingNotFound
} }
func (vsl *ValidSettingList) SetStringSetting(searchKey string, searchVal string) error { func (vsl *ValidSettingList) SetStringSetting(searchKey string, searchVal string) error {
return setValidSetting(vsl.GetStringSettingsMap(), searchKey, ValidString{Value: searchVal, Valid: true}) for key, setting := range vsl.GetStringSettingsMap() {
if key == searchKey {
*setting = ValidString{Value: searchVal, Valid: true}
return nil
}
}
return ErrSettingNotFound
} }
func (vsl *ValidSettingList) SetBoolSetting(searchKey string, searchVal string) error { func (vsl *ValidSettingList) SetBoolSetting(searchKey string, searchVal string) error {
value, err := strconv.ParseBool(searchVal) for key, setting := range vsl.GetBoolSettingsMap() {
if err != nil {
return err if key == searchKey {
value, err := strconv.ParseBool(searchVal)
if err != nil {
return err
}
*setting = ValidBool{Value: value, Valid: true}
return nil
}
} }
return setValidSetting(vsl.GetBoolSettingsMap(), searchKey, ValidBool{Value: value, Valid: true})
return ErrSettingNotFound
} }
func (vsl *ValidSettingList) SetFloat32Setting(searchKey string, searchVal string) error { func (vsl *ValidSettingList) SetFloat32Setting(searchKey string, searchVal string) error {
value, err := strconv.ParseFloat(searchVal, 32) for key, setting := range vsl.GetFloat32SettingsMap() {
if err != nil { if key == searchKey {
return err value, err := strconv.ParseFloat(searchVal, 32)
if err != nil {
return err
}
*setting = ValidFloat32{Value: float32(value), Valid: true}
return nil
}
} }
return setValidSetting(vsl.GetFloat32SettingsMap(), searchKey, ValidFloat32{Value: float32(value), Valid: true})
return ErrSettingNotFound
} }
func (vsl *ValidSettingList) SetTimeSetting(searchKey string, searchVal string) error { func (vsl *ValidSettingList) SetTimeSetting(searchKey string, searchVal string) error {
value, err := time.Parse(time.RFC3339, searchVal) for key, setting := range vsl.GetTimeSettingsMap() {
if err != nil { if key == searchKey {
return err value, err := time.Parse(time.RFC3339, searchVal)
if err != nil {
return err
}
*setting = ValidTime{Value: value, Valid: true}
return nil
}
} }
return setValidSetting(vsl.GetTimeSettingsMap(), searchKey, ValidTime{Value: value, Valid: true}) return ErrSettingNotFound
} }
func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) error { func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) error {
@ -223,9 +391,10 @@ func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) erro
for _, setter := range setters { for _, setter := range setters {
if err := setter(searchKey, searchVal); err != nil { if err := setter(searchKey, searchVal); err != nil {
if err == ErrSettingNotFound { if err == ErrSettingNotFound {
// fmt.Printf("setting is not found %v \n", searchKey)
continue // not this setter, try the next continue // not this setter, try the next
} }
return fmt.Errorf("error while processing setting %q: %w", searchKey, err) return fmt.Errorf("error while processing setting %q: %w \n", searchKey, err)
} }
return nil // successfully set return nil // successfully set
} }
@ -306,6 +475,7 @@ func validateSettings[T any](
var errs []string var errs []string
for key, s := range settings { for key, s := range settings {
if !customValidator(s) { if !customValidator(s) {
errs = append(errs, fmt.Sprintf("%v is invalid", key)) errs = append(errs, fmt.Sprintf("%v is invalid", key))
} }
} }
@ -378,6 +548,7 @@ func (vsl *ValidSettingList) ValidateAllSettings() error {
for _, validator := range validators { for _, validator := range validators {
if err := validator(); err != nil { if err := validator(); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} }
} }
@ -410,12 +581,12 @@ func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, er
if err == ErrSettingNotFound { if err == ErrSettingNotFound {
MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key)) MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key))
} }
MongoDBLogger.Error("unknown error while fetching settings", zap.Error(err))
} }
} }
if err := dbSettingList.ValidateAllSettings(); err != nil { if err := dbSettingList.ValidateAllSettings(); err != nil {
fmt.Printf("setting validation error: %v \n", err) MongoDBLogger.Warn("setting validation error", zap.Error(err), zap.Any("db_setting_list", dbSettingList))
MongoDBLogger.Warn("setting validation error", zap.Error(err))
return SettingList{}, err return SettingList{}, err
} }
@ -436,7 +607,6 @@ func ConvertDBOverrideSettingList(settings []dbgen.GetOverrideSettingsRow) (Sett
} }
if err := dbSettingList.ValidateAllSettings(); err != nil { if err := dbSettingList.ValidateAllSettings(); err != nil {
fmt.Printf("setting validation error: %v \n", err)
MongoDBLogger.Warn("setting validation error", zap.Error(err)) MongoDBLogger.Warn("setting validation error", zap.Error(err))
return SettingList{}, err return SettingList{}, err
} }

View File

@ -105,3 +105,10 @@ type CreateTransfer struct {
Status string `json:"status"` Status string `json:"status"`
CashierID ValidInt64 `json:"cashier_id"` CashierID ValidInt64 `json:"cashier_id"`
} }
type TransferStats struct {
TotalTransfer int64
TotalDeposits int64
TotalWithdraws int64
TotalWalletToWallet int64
}

View File

@ -23,7 +23,7 @@ type User struct {
UpdatedAt time.Time UpdatedAt time.Time
SuspendedAt time.Time SuspendedAt time.Time
Suspended bool Suspended bool
CompanyID ValidInt64 //This should be null CompanyID ValidInt64
} }
type UserFilter struct { type UserFilter struct {
@ -36,7 +36,6 @@ type UserFilter struct {
CreatedAfter ValidTime CreatedAfter ValidTime
} }
type RegisterUserReq struct { type RegisterUserReq struct {
FirstName string FirstName string
LastName string LastName string
@ -65,6 +64,7 @@ type ResetPasswordReq struct {
Password string Password string
Otp string Otp string
OtpMedium OtpMedium OtpMedium OtpMedium
CompanyID int64
} }
type UpdateUserReq struct { type UpdateUserReq struct {
UserId int64 UserId int64

View File

@ -31,6 +31,7 @@ func (n *ValidInt64) UnmarshalJSON(data []byte) error {
} }
v, err := strconv.ParseInt(s, 10, 64) v, err := strconv.ParseInt(s, 10, 64)
if err != nil { if err != nil {
fmt.Printf("Failed to parse the value of %v \n\n", s)
return err return err
} }
n.Value, n.Valid = v, true n.Value, n.Valid = v, true
@ -42,7 +43,7 @@ func (n *ValidInt64) UnmarshalJSON(data []byte) error {
n.Value, n.Valid = v, true n.Value, n.Valid = v, true
return nil return nil
} }
fmt.Printf("Failed to parse the value of %v", s)
return fmt.Errorf("invalid int64 value: %s", string(data)) return fmt.Errorf("invalid int64 value: %s", string(data))
} }

View File

@ -76,9 +76,10 @@ type CreateCustomerWallet struct {
type WalletType string type WalletType string
const ( const (
CustomerWalletType WalletType = "customer_wallet" RegularWalletType WalletType = "regular_wallet"
BranchWalletType WalletType = "branch_wallet" StaticWalletType WalletType = "static_wallet"
CompanyWalletType WalletType = "company_wallet" BranchWalletType WalletType = "branch_wallet"
CompanyWalletType WalletType = "company_wallet"
) )
// domain/wallet.go // domain/wallet.go
@ -92,18 +93,18 @@ const (
) )
type DirectDeposit struct { type DirectDeposit struct {
ID int64 ID int64 `json:"id"`
CustomerID int64 CustomerID int64 `json:"customer_id"`
WalletID int64 WalletID int64 `json:"wallet_id"`
Wallet Wallet // Joined data Wallet Wallet `json:"wallet"`
Amount Currency Amount Currency `json:"amount"`
BankReference string BankReference string `json:"bank_reference"`
SenderAccount string SenderAccount string `json:"sender_account"`
Status DirectDepositStatus Status DirectDepositStatus `json:"status"`
CreatedAt time.Time CreatedAt time.Time `json:"created_at"`
VerifiedBy *int64 // Nullable VerifiedBy *int64 `json:"verified_by"`
VerificationNotes string VerificationNotes string `json:"verification_notes"`
VerifiedAt *time.Time // Nullable VerifiedAt *time.Time `json:"verified_at"`
} }
type CreateDirectDeposit struct { type CreateDirectDeposit struct {
@ -124,14 +125,14 @@ type UpdateDirectDeposit struct {
} }
type DirectDepositRequest struct { type DirectDepositRequest struct {
CustomerID int64 `json:"customer_id" binding:"required"` CustomerID int64 `json:"customer_id" binding:"required"`
Amount Currency `json:"amount" binding:"required,gt=0"` Amount Currency `json:"amount" binding:"required,gt=0"`
BankReference string `json:"bank_reference" binding:"required"` BankReference string `json:"bank_reference" binding:"required"`
SenderAccount string `json:"sender_account" binding:"required"` SenderAccount string `json:"sender_account" binding:"required"`
} }
type VerifyDirectDepositRequest struct { type VerifyDirectDepositRequest struct {
DepositID int64 `json:"deposit_id" binding:"required"` DepositID int64 `json:"deposit_id" binding:"required"`
IsVerified bool `json:"is_verified" binding:"required"` IsVerified bool `json:"is_verified" binding:"required"`
Notes string `json:"notes"` Notes string `json:"notes"`
} }

View File

@ -1,10 +1,13 @@
package helpers package helpers
import ( import (
random "crypto/rand"
"fmt" "fmt"
"math/rand/v2" "strings"
"github.com/google/uuid" "github.com/google/uuid"
"math/big"
"math/rand/v2"
) )
func GenerateID() string { func GenerateID() string {
@ -24,3 +27,34 @@ func GenerateFastCode() string {
} }
return code return code
} }
func GenerateCashoutID() (string, error) {
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
const length int = 13
charLen := big.NewInt(int64(len(chars)))
result := make([]byte, length)
for i := 0; i < length; i++ {
index, err := random.Int(random.Reader, charLen)
if err != nil {
return "", err
}
result[i] = chars[index.Int64()]
}
return string(result), nil
}
func MaskPhone(phone string) string {
if phone == "" {
return ""
}
return phone[:4] + "**" + phone[len(phone)-2:]
}
func MaskEmail(email string) string {
if email == "" {
return ""
}
return email[:3] + "**" + email[strings.Index(email, "@"):]
}

View File

@ -10,6 +10,7 @@ import (
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -220,6 +221,46 @@ func (s *Store) UpdateStatus(ctx context.Context, id int64, status domain.Outcom
return err return err
} }
func (s *Store) SettleWinningBet(ctx context.Context, betID int64, userID int64, amount domain.Currency, status domain.OutcomeStatus) error {
tx, err := s.conn.BeginTx(ctx, pgx.TxOptions{})
if err != nil {
return err
}
qtx := s.queries.WithTx(tx)
wallet, err := qtx.GetCustomerWallet(ctx, userID)
if err != nil {
tx.Rollback(ctx)
return err
}
// 1. Update wallet
newAmount := wallet.RegularBalance + int64(amount)
if err := qtx.UpdateBalance(ctx, dbgen.UpdateBalanceParams{
Balance: newAmount,
ID: wallet.RegularID,
}); err != nil {
tx.Rollback(ctx)
return err
}
// 2. Update bet
if err := qtx.UpdateStatus(ctx, dbgen.UpdateStatusParams{
Status: int32(status),
ID: betID,
}); err != nil {
tx.Rollback(ctx)
return err
}
// 3. Commit both together
if err := tx.Commit(ctx); err != nil {
return err
}
return nil
}
func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) { func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) {
outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, dbgen.GetBetOutcomeByEventIDParams{ outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, dbgen.GetBetOutcomeByEventIDParams{

View File

@ -4,27 +4,80 @@ import (
"context" "context"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
) )
func (s *Store) CreateBonusMultiplier(ctx context.Context, multiplier float32, balance_cap int64) error { func (s *Store) CreateUserBonus(ctx context.Context, bonus domain.CreateBonus) (domain.UserBonus, error) {
return s.queries.CreateBonusMultiplier(ctx, dbgen.CreateBonusMultiplierParams{ newBonus, err := s.queries.CreateUserBonus(ctx, domain.ConvertCreateBonus(bonus))
Multiplier: multiplier,
BalanceCap: balance_cap, if err != nil {
return domain.UserBonus{}, err
}
return domain.ConvertDBBonus(newBonus), nil
}
func (s *Store) GetAllUserBonuses(ctx context.Context, filter domain.BonusFilter) ([]domain.UserBonus, error) {
bonuses, err := s.queries.GetAllUserBonuses(ctx, dbgen.GetAllUserBonusesParams{
UserID: filter.UserID.ToPG(),
Offset: filter.Offset.ToPG(),
Limit: filter.Limit.ToPG(),
}) })
if err != nil {
return nil, err
}
return domain.ConvertDBBonuses(bonuses), nil
} }
func (s *Store) GetBonusMultiplier(ctx context.Context) ([]dbgen.GetBonusMultiplierRow, error) { func (s *Store) GetBonusCount(ctx context.Context, filter domain.BonusFilter) (int64, error) {
return s.queries.GetBonusMultiplier(ctx) count, err := s.queries.GetBonusCount(ctx, filter.UserID.ToPG())
if err != nil {
return 0, err
}
return count, nil
} }
func (s *Store) GetBonusBalanceCap(ctx context.Context) ([]dbgen.GetBonusBalanceCapRow, error) { func (s *Store) GetBonusByID(ctx context.Context, bonusID int64) (domain.UserBonus, error) {
return s.queries.GetBonusBalanceCap(ctx) bonus, err := s.queries.GetUserBonusByID(ctx, bonusID)
if err != nil {
return domain.UserBonus{}, err
}
return domain.ConvertDBBonus(bonus), nil
} }
func (s *Store) UpdateBonusMultiplier(ctx context.Context, id int64, mulitplier float32, balance_cap int64) error {
return s.queries.UpdateBonusMultiplier(ctx, dbgen.UpdateBonusMultiplierParams{
ID: id,
Multiplier: mulitplier, func (s *Store) GetBonusStats(ctx context.Context, filter domain.BonusFilter) (domain.BonusStats, error) {
BalanceCap: balance_cap, bonus, err := s.queries.GetBonusStats(ctx, dbgen.GetBonusStatsParams{
CompanyID: filter.CompanyID.ToPG(),
UserID: filter.UserID.ToPG(),
}) })
if err != nil {
return domain.BonusStats{}, err
}
return domain.ConvertDBBonusStats(bonus), nil
}
func (s *Store) UpdateUserBonus(ctx context.Context, bonusID int64, IsClaimed bool) (error) {
err := s.queries.UpdateUserBonus(ctx, dbgen.UpdateUserBonusParams{
ID: bonusID,
IsClaimed: IsClaimed,
})
if err != nil {
return err
}
return nil
}
func (s *Store) DeleteUserBonus(ctx context.Context, bonusID int64) (error) {
err := s.queries.DeleteUserBonus(ctx, bonusID)
if err != nil {
return err
}
return nil
} }

View File

@ -2,12 +2,12 @@ package repository
import ( import (
"context" "context"
"database/sql"
"errors" "errors"
"fmt" "fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/pkgs/helpers" "github.com/SamuelTariku/FortuneBet-Backend/internal/pkgs/helpers"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
@ -15,11 +15,11 @@ func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany)
baseSlug := helpers.GenerateSlug(company.Name) baseSlug := helpers.GenerateSlug(company.Name)
uniqueSlug := baseSlug uniqueSlug := baseSlug
i := 1 i := 1
for { for {
_, err := s.queries.GetCompanyIDUsingSlug(ctx, uniqueSlug) _, err := s.queries.GetCompanyIDUsingSlug(ctx, uniqueSlug)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, pgx.ErrNoRows) {
// slug is unique // slug is unique
break break
} else { } else {

View File

@ -16,10 +16,6 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.CreateEvent) error {
return s.queries.InsertEvent(ctx, domain.ConvertCreateEvent(e)) return s.queries.InsertEvent(ctx, domain.ConvertCreateEvent(e))
} }
func (s *Store) InsertEventSettings(ctx context.Context, eventSetting domain.CreateEventSettings) error {
return s.queries.InsertEventSettings(ctx, domain.ConvertCreateEventSettings(eventSetting))
}
func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) { func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
return s.queries.ListLiveEvents(ctx) return s.queries.ListLiveEvents(ctx)
} }
@ -89,6 +85,8 @@ func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filt
FirstStartTime: filter.FirstStartTime.ToPG(), FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(), LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(), CountryCode: filter.CountryCode.ToPG(),
IsFeatured: filter.Featured.ToPG(),
IsActive: filter.Active.ToPG(),
}) })
if err != nil { if err != nil {
@ -103,13 +101,70 @@ func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filt
FirstStartTime: filter.FirstStartTime.ToPG(), FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(), LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(), CountryCode: filter.CountryCode.ToPG(),
IsFeatured: filter.Featured.ToPG(),
IsActive: filter.Active.ToPG(),
}) })
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value)) numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value))
return domain.ConvertDBEventWithSettings(events), int64(numberOfPages), nil
result := make([]domain.EventWithSettings, len(events))
for i, event := range events {
result[i] = domain.EventWithSettings{
ID: event.ID,
SportID: event.SportID,
MatchName: event.MatchName,
HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeKitImage,
AwayTeamImage: event.AwayKitImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: domain.ValidString{
Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid,
},
StartTime: event.StartTime.Time.UTC(),
Source: domain.EventSource(event.Source),
Status: domain.EventStatus(event.Status),
IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored,
IsActive: event.IsActive,
DefaultIsFeatured: event.DefaultIsFeatured,
DefaultIsActive: event.DefaultIsActive,
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
Score: domain.ValidString{
Value: event.Score.String,
Valid: event.Score.Valid,
},
MatchMinute: domain.ValidInt{
Value: int(event.MatchMinute.Int32),
Valid: event.MatchMinute.Valid,
},
TimerStatus: domain.ValidString{
Value: event.TimerStatus.String,
Valid: event.TimerStatus.Valid,
},
AddedTime: domain.ValidInt{
Value: int(event.AddedTime.Int32),
Valid: event.AddedTime.Valid,
},
MatchPeriod: domain.ValidInt{
Value: int(event.MatchPeriod.Int32),
Valid: event.MatchPeriod.Valid,
},
IsLive: event.IsLive,
UpdatedAt: event.UpdatedAt.Time,
FetchedAt: event.FetchedAt.Time,
}
}
return result, int64(numberOfPages), nil
} }
func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.BaseEvent, error) { func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.BaseEvent, error) {
event, err := s.queries.GetUpcomingByID(ctx, ID) event, err := s.queries.GetUpcomingByID(ctx, ID)
@ -121,14 +176,63 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Bas
} }
func (s *Store) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) { func (s *Store) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) {
event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{ event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{
ID: ID, ID: ID,
CompanyID: companyID, CompanyID: companyID,
}) })
if err != nil { if err != nil {
return domain.EventWithSettings{}, err return domain.EventWithSettings{}, err
} }
return domain.ConvertDBEventWithSetting(event), nil res := domain.EventWithSettings{
ID: event.ID,
SportID: event.SportID,
MatchName: event.MatchName,
HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeKitImage,
AwayTeamImage: event.AwayKitImage,
LeagueID: event.LeagueID,
LeagueName: event.LeagueName,
LeagueCC: domain.ValidString{
Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid,
},
StartTime: event.StartTime.Time.UTC(),
Source: domain.EventSource(event.Source),
Status: domain.EventStatus(event.Status),
IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored,
IsActive: event.IsActive,
DefaultIsFeatured: event.DefaultIsFeatured,
DefaultIsActive: event.DefaultIsActive,
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
Score: domain.ValidString{
Value: event.Score.String,
Valid: event.Score.Valid,
},
MatchMinute: domain.ValidInt{
Value: int(event.MatchMinute.Int32),
Valid: event.MatchMinute.Valid,
},
TimerStatus: domain.ValidString{
Value: event.TimerStatus.String,
Valid: event.TimerStatus.Valid,
},
AddedTime: domain.ValidInt{
Value: int(event.AddedTime.Int32),
Valid: event.AddedTime.Valid,
},
MatchPeriod: domain.ValidInt{
Value: int(event.MatchPeriod.Int32),
Valid: event.MatchPeriod.Valid,
},
IsLive: event.IsLive,
UpdatedAt: event.UpdatedAt.Time,
FetchedAt: event.FetchedAt.Time,
}
return res, nil
} }
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error { func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore string, status domain.EventStatus) error {
params := dbgen.UpdateMatchResultParams{ params := dbgen.UpdateMatchResultParams{
@ -176,7 +280,7 @@ func (s *Store) UpdateEventMonitored(ctx context.Context, eventID string, IsMoni
} }
func (s *Store) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { func (s *Store) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error {
return s.queries.UpdateEventSettings(ctx, domain.ConvertUpdateEventSettings(event)) return s.queries.SaveEventSettings(ctx, domain.ConvertUpdateEventSettings(event))
} }
func (s *Store) DeleteEvent(ctx context.Context, eventID string) error { func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
@ -186,3 +290,13 @@ func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {
} }
return nil return nil
} }
func (s *Store) GetSportAndLeagueIDs(ctx context.Context, eventID string) ([]int64, error) {
sportAndLeagueIDs, err := s.queries.GetSportAndLeagueIDs(ctx, eventID)
if err != nil {
return nil, err
}
res := []int64{int64(sportAndLeagueIDs.SportID), sportAndLeagueIDs.LeagueID}
return res, err
}

View File

@ -18,6 +18,7 @@ func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.Cr
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) { func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{ l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{
Query: filter.Query.ToPG(),
CountryCode: filter.CountryCode.ToPG(), CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(), SportID: filter.SportID.ToPG(),
Limit: pgtype.Int4{ Limit: pgtype.Int4{
@ -36,8 +37,10 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) (
return domain.ConvertDBBaseLeagues(l), nil return domain.ConvertDBBaseLeagues(l), nil
} }
func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) { func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error) {
l, err := s.queries.GetAllLeaguesWithSettings(ctx, dbgen.GetAllLeaguesWithSettingsParams{ l, err := s.queries.GetAllLeaguesWithSettings(ctx, dbgen.GetAllLeaguesWithSettingsParams{
Query: filter.Query.ToPG(),
CompanyID: companyID, CompanyID: companyID,
CountryCode: filter.CountryCode.ToPG(), CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(), SportID: filter.SportID.ToPG(),
@ -49,13 +52,27 @@ func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, fil
Int32: int32(filter.Offset.Value * filter.Limit.Value), Int32: int32(filter.Offset.Value * filter.Limit.Value),
Valid: filter.Offset.Valid, Valid: filter.Offset.Valid,
}, },
IsFeatured: filter.IsFeatured.ToPG(),
IsActive: filter.IsActive.ToPG(),
}) })
if err != nil { if err != nil {
return nil, err return nil, 0, err
} }
return domain.ConvertDBLeagueWithSettings(l), nil total, err := s.queries.GetTotalLeaguesWithSettings(ctx, dbgen.GetTotalLeaguesWithSettingsParams{
Query: filter.Query.ToPG(),
CompanyID: companyID,
CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(),
IsFeatured: filter.IsFeatured.ToPG(),
IsActive: filter.IsActive.ToPG(),
})
if err != nil {
return nil, 0, err
}
return domain.ConvertDBLeagueWithSettings(l), total, nil
} }
func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) { func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) {

View File

@ -39,8 +39,8 @@ func (s *Store) DisconnectWebSocket(recipientID int64) {
func (r *Repository) CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error) { func (r *Repository) CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error) {
var errorSeverity pgtype.Text var errorSeverity pgtype.Text
if notification.ErrorSeverity != nil { if notification.ErrorSeverity != "" {
errorSeverity.String = string(*notification.ErrorSeverity) errorSeverity.String = string(notification.ErrorSeverity)
errorSeverity.Valid = true errorSeverity.Valid = true
} }
@ -155,10 +155,12 @@ func (r *Repository) ListRecipientIDs(ctx context.Context, receiver domain.Notif
} }
func (r *Repository) mapDBToDomain(dbNotif *dbgen.Notification) *domain.Notification { func (r *Repository) mapDBToDomain(dbNotif *dbgen.Notification) *domain.Notification {
var errorSeverity *domain.NotificationErrorSeverity var errorSeverity domain.NotificationErrorSeverity
if dbNotif.ErrorSeverity.Valid { if dbNotif.ErrorSeverity.Valid {
s := domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String) errorSeverity = domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String)
errorSeverity = &s
} else {
errorSeverity = ""
} }
var deliveryChannel domain.DeliveryChannel var deliveryChannel domain.DeliveryChannel
@ -317,8 +319,6 @@ func (s *Store) CountUnreadNotifications(ctx context.Context, userID int64) (int
return count, nil return count, nil
} }
// func (s *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) { // func (s *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
// dbNotifications, err := s.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{ // dbNotifications, err := s.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
// Limit: int32(limit), // Limit: int32(limit),

View File

@ -88,13 +88,51 @@ func (s *Store) GetAllOddsWithSettings(ctx context.Context, companyID int64, fil
return nil, err return nil, err
} }
domainOdds, err := domain.ConvertDBOddMarketWithSettings(odds) // domainOdds, err := domain.ConvertDBOddMarketWithSettings(odds)
// if err != nil {
// return nil, err
// }
if err != nil { result := make([]domain.OddMarketWithSettings, len(odds))
return nil, err for i, o := range odds {
var rawOdds []json.RawMessage
if len(o.RawOdds) > 0 {
if err := json.Unmarshal(o.RawOdds, &rawOdds); err != nil {
return nil, err
}
} else {
rawOdds = []json.RawMessage{} // explicit empty slice
}
result[i] = domain.OddMarketWithSettings{
ID: o.ID,
EventID: o.EventID,
MarketType: o.MarketType,
MarketName: o.MarketName,
MarketCategory: o.MarketCategory,
MarketID: o.MarketID,
RawOdds: rawOdds,
FetchedAt: o.FetchedAt.Time,
ExpiresAt: o.ExpiresAt.Time,
IsActive: o.IsActive,
}
} }
return domainOdds, nil return result, nil
}
func (s *Store) GetOddByID(ctx context.Context, id int64) (domain.OddMarket, error) {
odd, err := s.queries.GetOddByID(ctx, id)
if err != nil {
return domain.OddMarket{}, err
}
convertedOdd, err := domain.ConvertDBOddMarket(odd)
if err != nil {
return domain.OddMarket{}, err
}
return convertedOdd, nil
} }
func (s *Store) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) { func (s *Store) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) {
@ -126,12 +164,76 @@ func (s *Store) GetOddsWithSettingsByMarketID(ctx context.Context, marketID stri
return domain.OddMarketWithSettings{}, err return domain.OddMarketWithSettings{}, err
} }
convertedOdd, err := domain.ConvertDBOddMarketWithSetting(odds) // convertedOdd, err := domain.ConvertDBOddMarketWithSetting(odds)
// if err != nil {
// return domain.OddMarketWithSettings{}, err
// }
var rawOdds []json.RawMessage
if len(odds.RawOdds) > 0 {
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
return domain.OddMarketWithSettings{}, err
}
} else {
rawOdds = []json.RawMessage{} // explicit empty slice
}
converted := domain.OddMarketWithSettings{
ID: odds.ID,
EventID: odds.EventID,
MarketType: odds.MarketType,
MarketName: odds.MarketName,
MarketCategory: odds.MarketCategory,
MarketID: odds.MarketID,
RawOdds: rawOdds,
FetchedAt: odds.FetchedAt.Time,
ExpiresAt: odds.ExpiresAt.Time,
IsActive: odds.IsActive,
}
return converted, nil
}
func (s *Store) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error) {
odds, err := s.queries.GetOddsWithSettingsByID(ctx, dbgen.GetOddsWithSettingsByIDParams{
ID: ID,
CompanyID: companyID,
})
if err != nil { if err != nil {
return domain.OddMarketWithSettings{}, err return domain.OddMarketWithSettings{}, err
} }
return convertedOdd, nil
// convertedOdd, err := domain.ConvertDBOddMarketWithSetting(odds)
// if err != nil {
// return domain.OddMarketWithSettings{}, err
// }
var rawOdds []json.RawMessage
if len(odds.RawOdds) > 0 {
if err := json.Unmarshal(odds.RawOdds, &rawOdds); err != nil {
return domain.OddMarketWithSettings{}, err
}
} else {
rawOdds = []json.RawMessage{} // explicit empty slice
}
converted := domain.OddMarketWithSettings{
ID: odds.ID,
EventID: odds.EventID,
MarketType: odds.MarketType,
MarketName: odds.MarketName,
MarketCategory: odds.MarketCategory,
MarketID: odds.MarketID,
RawOdds: rawOdds,
FetchedAt: odds.FetchedAt.Time,
ExpiresAt: odds.ExpiresAt.Time,
IsActive: odds.IsActive,
}
return converted, nil
} }
func (s *Store) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) { func (s *Store) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
@ -174,14 +276,49 @@ func (s *Store) GetOddsWithSettingsByEventID(ctx context.Context, upcomingID str
} }
// Map the results to domain.Odd // Map the results to domain.Odd
domainOdds, err := domain.ConvertDBOddMarketWithSettings(odds) // domainOdds, err := domain.ConvertDBOddMarketWithSettings(odds)
if err != nil { // if err != nil {
return nil, err // return nil, err
// }
result := make([]domain.OddMarketWithSettings, len(odds))
for i, o := range odds {
var rawOdds []json.RawMessage
if len(o.RawOdds) > 0 {
if err := json.Unmarshal(o.RawOdds, &rawOdds); err != nil {
return nil, err
}
} else {
rawOdds = []json.RawMessage{} // explicit empty slice
}
result[i] = domain.OddMarketWithSettings{
ID: o.ID,
EventID: o.EventID,
MarketType: o.MarketType,
MarketName: o.MarketName,
MarketCategory: o.MarketCategory,
MarketID: o.MarketID,
RawOdds: rawOdds,
FetchedAt: o.FetchedAt.Time,
ExpiresAt: o.ExpiresAt.Time,
IsActive: o.IsActive,
}
} }
return domainOdds, nil return result, nil
} }
func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error { func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error {
return s.queries.DeleteOddsForEvent(ctx, eventID) return s.queries.DeleteOddsForEvent(ctx, eventID)
} }
func (s *Store) SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error {
res, err := domain.ConvertCreateOddMarketSetting(odd)
if err != nil {
return nil
}
return s.queries.SaveOddSettings(ctx, res)
}

View File

@ -0,0 +1,193 @@
package repository
import (
"context"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5/pgtype"
)
func convertRaffleOutcome(raffle dbgen.Raffle) domain.Raffle {
return domain.Raffle{
ID: raffle.ID,
CompanyID: raffle.CompanyID,
Name: raffle.Name,
CreatedAt: raffle.CreatedAt.Time,
ExpiresAt: raffle.ExpiresAt.Time,
Type: raffle.Type,
Status: raffle.Status,
}
}
func convertRaffleTicketOutcome(raffle dbgen.RaffleTicket) domain.RaffleTicket {
return domain.RaffleTicket{
ID: raffle.ID,
RaffleID: raffle.RaffleID,
UserID: raffle.UserID,
IsActive: raffle.IsActive.Bool,
}
}
func convertJoinedRaffleTicketOutcome(raffle dbgen.GetUserRaffleTicketsRow) domain.RaffleTicketRes {
return domain.RaffleTicketRes{
TicketID: raffle.TicketID,
UserID: raffle.UserID,
Name: raffle.Name,
Type: raffle.Type,
ExpiresAt: raffle.ExpiresAt.Time,
Status: raffle.Status,
}
}
func convertCreateRaffle(raffle domain.CreateRaffle) dbgen.CreateRaffleParams {
return dbgen.CreateRaffleParams{
CompanyID: raffle.CompanyID,
Name: raffle.Name,
ExpiresAt: pgtype.Timestamp{
Time: *raffle.ExpiresAt,
Valid: true,
},
Type: raffle.Type,
}
}
func convertRaffleStanding(raffleStanding dbgen.GetRaffleStandingRow) domain.RaffleStanding {
return domain.RaffleStanding{
UserID: raffleStanding.UserID,
RaffleID: raffleStanding.RaffleID,
FirstName: raffleStanding.FirstName,
LastName: raffleStanding.LastName,
PhoneNumber: raffleStanding.PhoneNumber.String,
Email: raffleStanding.Email.String,
TicketCount: raffleStanding.TicketCount,
}
}
func (s *Store) CreateRaffle(ctx context.Context, raffle domain.CreateRaffle) (domain.Raffle, error) {
raffleRes, err := s.queries.CreateRaffle(ctx, convertCreateRaffle(raffle))
if err != nil {
return domain.Raffle{}, err
}
return convertRaffleOutcome(raffleRes), nil
}
func (s *Store) DeleteRaffle(ctx context.Context, raffleID int32) (domain.Raffle, error) {
raffleRes, err := s.queries.DeleteRaffle(ctx, raffleID)
if err != nil {
return domain.Raffle{}, err
}
return convertRaffleOutcome(raffleRes), nil
}
func (s *Store) GetRafflesOfCompany(ctx context.Context, companyID int32) ([]dbgen.Raffle, error) {
raffles, err := s.queries.GetRafflesOfCompany(ctx, companyID)
if err != nil {
return nil, err
}
return raffles, nil
}
func (s *Store) CreateRaffleTicket(ctx context.Context, raffleTicketParams domain.CreateRaffleTicket) (domain.RaffleTicket, error) {
raffleTicket, err := s.queries.CreateRaffleTicket(ctx, dbgen.CreateRaffleTicketParams{
RaffleID: raffleTicketParams.RaffleID,
UserID: raffleTicketParams.UserID,
})
if err != nil {
return domain.RaffleTicket{}, err
}
return convertRaffleTicketOutcome(raffleTicket), nil
}
func (s *Store) GetUserRaffleTickets(ctx context.Context, userID int32) ([]domain.RaffleTicketRes, error) {
raffleTickets, err := s.queries.GetUserRaffleTickets(ctx, userID)
if err != nil {
return nil, err
}
res := []domain.RaffleTicketRes{}
for _, raffle := range raffleTickets {
res = append(res, convertJoinedRaffleTicketOutcome(raffle))
}
return res, nil
}
func (s *Store) SuspendRaffleTicket(ctx context.Context, raffleTicketID int32) error {
return s.queries.UpdateRaffleTicketStatus(ctx, dbgen.UpdateRaffleTicketStatusParams{
ID: raffleTicketID,
IsActive: pgtype.Bool{
Bool: false,
Valid: true,
},
})
}
func (s *Store) UnSuspendRaffleTicket(ctx context.Context, raffleID int32) error {
return s.queries.UpdateRaffleTicketStatus(ctx, dbgen.UpdateRaffleTicketStatusParams{
ID: raffleID,
IsActive: pgtype.Bool{
Bool: true,
Valid: true,
},
})
}
// TODO: could also add -> suspend a specific user's raffle tickets
func (s *Store) GetRaffleStanding(ctx context.Context, raffleID, limit int32) ([]domain.RaffleStanding, error) {
raffleStanding, err := s.queries.GetRaffleStanding(ctx, dbgen.GetRaffleStandingParams{
RaffleID: raffleID,
Limit: limit,
})
if err != nil {
return nil, err
}
res := []domain.RaffleStanding{}
for _, standing := range raffleStanding {
res = append(res, convertRaffleStanding(standing))
}
return res, nil
}
func (s *Store) CreateRaffleWinner(ctx context.Context, raffleWinnerParams domain.RaffleWinnerParams) error {
_, err := s.queries.CreateRaffleWinner(ctx, dbgen.CreateRaffleWinnerParams{
RaffleID: raffleWinnerParams.RaffleID,
UserID: raffleWinnerParams.UserID,
Rank: raffleWinnerParams.Rank,
})
return err
}
func (s *Store) SetRaffleComplete(ctx context.Context, raffleID int32) error {
return s.queries.SetRaffleComplete(ctx, raffleID)
}
func (s *Store) AddSportRaffleFilter(ctx context.Context, raffleID int32, sportID, leagueID int64) error {
_, err := s.queries.AddSportRaffleFilter(ctx, dbgen.AddSportRaffleFilterParams{
RaffleID: raffleID,
SportID: sportID,
LeagueID: leagueID,
})
return err
}
func (s *Store) CheckValidSportRaffleFilter(ctx context.Context, raffleID int32, sportID, leagueID int64) (bool, error) {
res, err := s.queries.CheckValidSportRaffleFilter(ctx, dbgen.CheckValidSportRaffleFilterParams{
RaffleID: raffleID,
SportID: sportID,
LeagueID: leagueID,
})
if err != nil {
return false, err
}
return res, nil
}

View File

@ -2,28 +2,21 @@ package repository
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt"
"strconv"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5/pgtype"
) )
type ReferralRepository interface { type ReferralRepository interface {
CreateReferral(ctx context.Context, referral *domain.Referral) error CreateReferralCode(ctx context.Context, referralCode domain.CreateReferralCode) (domain.ReferralCode, error)
GetReferralByCode(ctx context.Context, code string) (*domain.Referral, error) CreateUserReferral(ctx context.Context, referral domain.CreateUserReferrals) (domain.UserReferral, error)
UpdateReferral(ctx context.Context, referral *domain.Referral) error GetReferralCodesByUser(ctx context.Context, userID int64) ([]domain.ReferralCode, error)
GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error) GetReferralCode(ctx context.Context, code string) (domain.ReferralCode, error)
GetSettings(ctx context.Context) (*domain.ReferralSettings, error) UpdateReferralCode(ctx context.Context, referral domain.UpdateReferralCode) error
UpdateSettings(ctx context.Context, settings *domain.ReferralSettings) error GetReferralStats(ctx context.Context, userID int64, companyID int64) (domain.ReferralStats, error)
CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error GetUserReferral(ctx context.Context, referredID int64) (domain.UserReferral, error)
GetReferralByReferredID(ctx context.Context, referredID string) (*domain.Referral, error) // New method GetUserReferralsByCode(ctx context.Context, code string) ([]domain.UserReferral, error)
GetReferralCountByID(ctx context.Context, referrerID string) (int64, error) GetUserReferralCount(ctx context.Context, referrerID int64) (int64, error)
GetActiveReferralByReferrerID(ctx context.Context, referrerID string) (*domain.Referral, error)
UpdateUserReferalCode(ctx context.Context, codedata domain.UpdateUserReferalCode) error
} }
type ReferralRepo struct { type ReferralRepo struct {
@ -34,248 +27,159 @@ func NewReferralRepository(store *Store) ReferralRepository {
return &ReferralRepo{store: store} return &ReferralRepo{store: store}
} }
func (r *ReferralRepo) UpdateUserReferalCode(ctx context.Context, codedata domain.UpdateUserReferalCode) error { func (r *ReferralRepo) CreateReferralCode(ctx context.Context, referralCode domain.CreateReferralCode) (domain.ReferralCode, error) {
params := dbgen.UpdateReferralCodeParams{ newReferralCode, err := r.store.queries.CreateReferralCode(ctx, domain.ConvertCreateReferralCode(referralCode))
ID: codedata.UserID,
ReferralCode: pgtype.Text{
String: codedata.Code,
Valid: true,
},
}
return r.store.queries.UpdateReferralCode(ctx, params)
}
func (r *ReferralRepo) CreateReferral(ctx context.Context, referral *domain.Referral) error {
rewardAmount := pgtype.Numeric{}
if err := rewardAmount.Scan(strconv.Itoa(int(referral.RewardAmount))); err != nil {
return err
}
params := dbgen.CreateReferralParams{
ReferralCode: referral.ReferralCode,
ReferrerID: referral.ReferrerID,
Status: dbgen.Referralstatus(referral.Status),
RewardAmount: rewardAmount,
ExpiresAt: pgtype.Timestamptz{Time: referral.ExpiresAt, Valid: true},
}
_, err := r.store.queries.CreateReferral(ctx, params)
return err
}
func (r *ReferralRepo) GetReferralByCode(ctx context.Context, code string) (*domain.Referral, error) {
dbReferral, err := r.store.queries.GetReferralByCode(ctx, code)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { return domain.ReferralCode{}, err
return nil, nil
}
return nil, err
} }
return r.mapToDomainReferral(&dbReferral), nil return domain.ConvertDBReferralCode(newReferralCode), nil
} }
func (r *ReferralRepo) UpdateReferral(ctx context.Context, referral *domain.Referral) error { func (r *ReferralRepo) CreateUserReferral(ctx context.Context, referral domain.CreateUserReferrals) (domain.UserReferral, error) {
var referredID pgtype.Text newReferral, err := r.store.queries.CreateUserReferral(ctx, domain.ConvertCreateUserReferral(referral))
if referral.ReferredID != nil {
referredID = pgtype.Text{String: *referral.ReferredID, Valid: true} if err != nil {
return domain.UserReferral{}, err
} }
params := dbgen.UpdateReferralParams{ return domain.ConvertDBUserReferral(newReferral), nil
ID: referral.ID,
ReferredID: referredID,
Status: dbgen.Referralstatus(referral.Status),
}
_, err := r.store.queries.UpdateReferral(ctx, params)
return err
} }
func (r *ReferralRepo) GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error) { func (r *ReferralRepo) GetReferralCodesByUser(ctx context.Context, userID int64) ([]domain.ReferralCode, error) {
stats, err := r.store.queries.GetReferralStats(ctx, userID) codes, err := r.store.queries.GetReferralCodeByUser(ctx, userID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &domain.ReferralStats{ return domain.ConvertDBReferralCodes(codes), nil
TotalReferrals: int(stats.TotalReferrals),
CompletedReferrals: int(stats.CompletedReferrals),
TotalRewardEarned: stats.TotalRewardEarned.(float64),
PendingRewards: stats.PendingRewards.(float64),
}, nil
} }
func (r *ReferralRepo) GetSettings(ctx context.Context) (*domain.ReferralSettings, error) { func (r *ReferralRepo) GetReferralCode(ctx context.Context, code string) (domain.ReferralCode, error) {
settings, err := r.store.queries.GetReferralSettings(ctx) referralCode, err := r.store.queries.GetReferralCode(ctx, code)
if err != nil {
return domain.ReferralCode{}, err
}
return domain.ConvertDBReferralCode(referralCode), nil
}
func (r *ReferralRepo) UpdateReferralCode(ctx context.Context, referral domain.UpdateReferralCode) error {
err := r.store.queries.UpdateReferralCode(ctx, domain.ConvertUpdateReferralCode(referral))
if err != nil {
return err
}
return nil
}
func (r *ReferralRepo) GetReferralStats(ctx context.Context, userID int64, companyID int64) (domain.ReferralStats, error) {
stats, err := r.store.queries.GetReferralStats(ctx, dbgen.GetReferralStatsParams{
ReferrerID: userID,
CompanyID: companyID,
})
if err != nil {
return domain.ReferralStats{}, err
}
return domain.ConvertDBReferralStats(stats), nil
}
func (r *ReferralRepo) GetUserReferral(ctx context.Context, referredID int64) (domain.UserReferral, error) {
dbReferral, err := r.store.queries.GetUserReferral(ctx, referredID)
if err != nil {
return domain.UserReferral{}, err
}
return domain.ConvertDBUserReferral(dbReferral), nil
}
func (r *ReferralRepo) GetUserReferralsByCode(ctx context.Context, code string) ([]domain.UserReferral, error) {
dbReferrals, err := r.store.queries.GetUserReferralsByCode(ctx, code)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, err return nil, err
} }
return r.mapToDomainSettings(&settings), nil
return domain.ConvertDBUserReferrals(dbReferrals), nil
} }
func (r *ReferralRepo) UpdateSettings(ctx context.Context, settings *domain.ReferralSettings) error { func (r *ReferralRepo) GetUserReferralCount(ctx context.Context, referrerID int64) (int64, error) {
rewardAmount := pgtype.Numeric{} count, err := r.store.queries.GetUserReferralsCount(ctx, referrerID)
if err := rewardAmount.Scan(settings.ReferralRewardAmount); err != nil {
return err
}
cashbackPercentage := pgtype.Numeric{}
if err := cashbackPercentage.Scan(settings.CashbackPercentage); err != nil {
return err
}
betReferralBonusPercentage := pgtype.Numeric{}
if err := betReferralBonusPercentage.Scan(settings.BetReferralBonusPercentage); err != nil {
return err
}
params := dbgen.UpdateReferralSettingsParams{
ID: settings.ID,
ReferralRewardAmount: rewardAmount,
CashbackPercentage: cashbackPercentage,
BetReferralBonusPercentage: betReferralBonusPercentage, // New field
MaxReferrals: settings.MaxReferrals,
ExpiresAfterDays: settings.ExpiresAfterDays,
UpdatedBy: settings.UpdatedBy,
}
_, err := r.store.queries.UpdateReferralSettings(ctx, params)
return err
}
func (r *ReferralRepo) CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error {
rewardAmount := pgtype.Numeric{}
if err := rewardAmount.Scan(fmt.Sprintf("%f", settings.ReferralRewardAmount)); err != nil {
return err
}
cashbackPercentage := pgtype.Numeric{}
if err := cashbackPercentage.Scan(fmt.Sprintf("%f", settings.CashbackPercentage)); err != nil {
return err
}
betReferralBonusPercentage := pgtype.Numeric{}
if err := betReferralBonusPercentage.Scan(fmt.Sprintf("%f", settings.BetReferralBonusPercentage)); err != nil {
return err
}
params := dbgen.CreateReferralSettingsParams{
ReferralRewardAmount: rewardAmount,
CashbackPercentage: cashbackPercentage,
BetReferralBonusPercentage: betReferralBonusPercentage, // New field
MaxReferrals: settings.MaxReferrals,
ExpiresAfterDays: settings.ExpiresAfterDays,
UpdatedBy: settings.UpdatedBy,
}
_, err := r.store.queries.CreateReferralSettings(ctx, params)
return err
}
func (r *ReferralRepo) GetReferralByReferredID(ctx context.Context, referredID string) (*domain.Referral, error) {
dbReferral, err := r.store.queries.GetReferralByReferredID(ctx, pgtype.Text{String: referredID, Valid: true})
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, err
}
return r.mapToDomainReferral(&dbReferral), nil
}
func (r *ReferralRepo) GetReferralCountByID(ctx context.Context, referrerID string) (int64, error) {
count, err := r.store.queries.GetReferralCountByID(ctx, referrerID)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, nil
}
return 0, err return 0, err
} }
return count, nil return count, nil
} }
func (r *ReferralRepo) GetActiveReferralByReferrerID(ctx context.Context, referrerID string) (*domain.Referral, error) { // func (r *ReferralRepo) mapToDomainReferral(dbRef *dbgen.Referral) *domain.Referral {
referral, err := r.store.queries.GetActiveReferralByReferrerID(ctx, referrerID) // var referredID *int64
if err != nil { // if dbRef.ReferredID.Valid {
if errors.Is(err, sql.ErrNoRows) { // referredID = &dbRef.ReferredID.Int64
return &domain.Referral{}, nil // }
}
return &domain.Referral{}, err
}
return r.mapToDomainReferral(&referral), nil // rewardAmount := 0.0
} // if dbRef.RewardAmount.Valid {
// if f8, err := dbRef.RewardAmount.Float64Value(); err == nil {
// rewardAmount = f8.Float64
// }
// }
func (r *ReferralRepo) mapToDomainReferral(dbRef *dbgen.Referral) *domain.Referral { // cashbackAmount := 0.0
var referredID *string // if dbRef.CashbackAmount.Valid {
if dbRef.ReferredID.Valid { // if f8, err := dbRef.CashbackAmount.Float64Value(); err == nil {
referredID = &dbRef.ReferredID.String // cashbackAmount = f8.Float64
} // }
// }
rewardAmount := 0.0 // return &domain.Referral{
if dbRef.RewardAmount.Valid { // ID: dbRef.ID,
if f8, err := dbRef.RewardAmount.Float64Value(); err == nil { // ReferralCode: dbRef.ReferralCode,
rewardAmount = f8.Float64 // ReferrerID: dbRef.ReferrerID,
} // ReferredID: referredID,
} // Status: domain.ReferralStatus(dbRef.Status),
// RewardAmount: rewardAmount,
// CashbackAmount: cashbackAmount,
// CreatedAt: dbRef.CreatedAt.Time,
// UpdatedAt: dbRef.UpdatedAt.Time,
// ExpiresAt: dbRef.ExpiresAt.Time,
// }
// }
cashbackAmount := 0.0 // func (r *ReferralRepo) mapToDomainSettings(dbSettings *dbgen.ReferralSetting) *domain.ReferralSettings {
if dbRef.CashbackAmount.Valid { // rewardAmount := 0.0
if f8, err := dbRef.CashbackAmount.Float64Value(); err == nil { // if dbSettings.ReferralRewardAmount.Valid {
cashbackAmount = f8.Float64 // if f8, err := dbSettings.ReferralRewardAmount.Float64Value(); err == nil {
} // rewardAmount = f8.Float64
} // }
// }
return &domain.Referral{ // cashbackPercentage := 0.0
ID: dbRef.ID, // if dbSettings.CashbackPercentage.Valid {
ReferralCode: dbRef.ReferralCode, // if f8, err := dbSettings.CashbackPercentage.Float64Value(); err == nil {
ReferrerID: dbRef.ReferrerID, // cashbackPercentage = f8.Float64
ReferredID: referredID, // }
Status: domain.ReferralStatus(dbRef.Status), // }
RewardAmount: rewardAmount,
CashbackAmount: cashbackAmount,
CreatedAt: dbRef.CreatedAt.Time,
UpdatedAt: dbRef.UpdatedAt.Time,
ExpiresAt: dbRef.ExpiresAt.Time,
}
}
func (r *ReferralRepo) mapToDomainSettings(dbSettings *dbgen.ReferralSetting) *domain.ReferralSettings { // betReferralBonusPercentage := 0.0
rewardAmount := 0.0 // if dbSettings.BetReferralBonusPercentage.Valid {
if dbSettings.ReferralRewardAmount.Valid { // if f8, err := dbSettings.BetReferralBonusPercentage.Float64Value(); err == nil {
if f8, err := dbSettings.ReferralRewardAmount.Float64Value(); err == nil { // betReferralBonusPercentage = f8.Float64
rewardAmount = f8.Float64 // }
} // }
}
cashbackPercentage := 0.0 // return &domain.ReferralSettings{
if dbSettings.CashbackPercentage.Valid { // ID: dbSettings.ID,
if f8, err := dbSettings.CashbackPercentage.Float64Value(); err == nil { // ReferralRewardAmount: rewardAmount,
cashbackPercentage = f8.Float64 // CashbackPercentage: cashbackPercentage,
} // BetReferralBonusPercentage: betReferralBonusPercentage, // New field
} // MaxReferrals: dbSettings.MaxReferrals,
// ExpiresAfterDays: dbSettings.ExpiresAfterDays,
betReferralBonusPercentage := 0.0 // UpdatedBy: dbSettings.UpdatedBy,
if dbSettings.BetReferralBonusPercentage.Valid { // CreatedAt: dbSettings.CreatedAt.Time,
if f8, err := dbSettings.BetReferralBonusPercentage.Float64Value(); err == nil { // UpdatedAt: dbSettings.UpdatedAt.Time,
betReferralBonusPercentage = f8.Float64 // Version: dbSettings.Version,
} // }
} // }
return &domain.ReferralSettings{
ID: dbSettings.ID,
ReferralRewardAmount: rewardAmount,
CashbackPercentage: cashbackPercentage,
BetReferralBonusPercentage: betReferralBonusPercentage, // New field
MaxReferrals: dbSettings.MaxReferrals,
ExpiresAfterDays: dbSettings.ExpiresAfterDays,
UpdatedBy: dbSettings.UpdatedBy,
CreatedAt: dbSettings.CreatedAt.Time,
UpdatedAt: dbSettings.UpdatedAt.Time,
Version: dbSettings.Version,
}
}

View File

@ -165,9 +165,9 @@ func (s *Store) GetOverrideSettingsList(ctx context.Context, companyID int64) (d
func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error { func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
return s.queries.DeleteCompanySetting(ctx, dbgen.DeleteCompanySettingParams{ return s.queries.DeleteCompanySetting(ctx, dbgen.DeleteCompanySettingParams{
CompanyID: companyID, CompanyID: companyID,
Key: key, Key: key,
}) })
} }
func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64,) error { func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
return s.queries.DeleteAllCompanySetting(ctx, companyID) return s.queries.DeleteAllCompanySetting(ctx, companyID)
} }

View File

@ -2,6 +2,7 @@ package repository
import ( import (
"context" "context"
"fmt"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -62,7 +63,7 @@ func (s *Store) CreateShopBet(ctx context.Context, bet domain.CreateShopBet) (do
if err != nil { if err != nil {
return domain.ShopBet{}, err return domain.ShopBet{}, err
} }
return convertDBShopBet(newShopBet), err return convertDBShopBet(newShopBet), err
} }
@ -104,8 +105,10 @@ func (s *Store) GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter)
func (s *Store) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error) { func (s *Store) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error) {
bet, err := s.queries.GetShopBetByID(ctx, id) bet, err := s.queries.GetShopBetByID(ctx, id)
if err != nil { if err != nil {
fmt.Printf("GetShopBetByID Repo BetID %d err %v \n", id, err.Error())
return domain.ShopBetDetail{}, err return domain.ShopBetDetail{}, err
} }
return convertDBShopBetDetail(bet), nil return convertDBShopBetDetail(bet), nil
} }

View File

@ -41,6 +41,7 @@ func convertDBTicketOutcomes(ticket dbgen.TicketWithOutcome) domain.GetTicket {
} }
return domain.GetTicket{ return domain.GetTicket{
ID: ticket.ID, ID: ticket.ID,
CompanyID: ticket.CompanyID,
Amount: domain.Currency(ticket.Amount), Amount: domain.Currency(ticket.Amount),
TotalOdds: ticket.TotalOdds, TotalOdds: ticket.TotalOdds,
Outcomes: outcomes, Outcomes: outcomes,

View File

@ -148,6 +148,24 @@ func (s *Store) GetTransferByID(ctx context.Context, id int64) (domain.TransferD
return convertDBTransferDetail(transfer), nil return convertDBTransferDetail(transfer), nil
} }
func (s *Store) GetTransferStats(ctx context.Context, walletID int64) (domain.TransferStats, error) {
stats, err := s.queries.GetTransferStats(ctx, pgtype.Int8{
Int64: walletID,
Valid: true,
})
if err != nil {
return domain.TransferStats{}, err
}
return domain.TransferStats{
TotalTransfer: stats.TotalTransfers,
TotalDeposits: stats.TotalDeposits,
TotalWithdraws: stats.TotalWithdraw,
TotalWalletToWallet: stats.TotalWalletToWallet,
}, nil
}
func (s *Store) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error { func (s *Store) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error {
err := s.queries.UpdateTransferVerification(ctx, dbgen.UpdateTransferVerificationParams{ err := s.queries.UpdateTransferVerification(ctx, dbgen.UpdateTransferVerificationParams{
ID: id, ID: id,

View File

@ -9,6 +9,7 @@ import (
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
@ -73,7 +74,7 @@ func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int6
func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error) { func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
user, err := s.queries.GetUserByID(ctx, id) user, err := s.queries.GetUserByID(ctx, id)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, pgx.ErrNoRows) {
return domain.User{}, domain.ErrUserNotFound return domain.User{}, domain.ErrUserNotFound
} }
return domain.User{}, err return domain.User{}, err
@ -428,7 +429,7 @@ func (s *Store) GetUserByPhone(ctx context.Context, phoneNum string, companyID d
}, nil }, nil
} }
func (s *Store) UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64) error { func (s *Store) UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64, companyId int64) error {
err := s.queries.MarkOtpAsUsed(ctx, dbgen.MarkOtpAsUsedParams{ err := s.queries.MarkOtpAsUsed(ctx, dbgen.MarkOtpAsUsedParams{
ID: usedOtpId, ID: usedOtpId,
UsedAt: pgtype.Timestamptz{ UsedAt: pgtype.Timestamptz{
@ -449,6 +450,10 @@ func (s *Store) UpdatePassword(ctx context.Context, identifier string, password
String: identifier, String: identifier,
Valid: true, Valid: true,
}, },
CompanyID: pgtype.Int8{
Int64: companyId,
Valid: true,
},
}) })
if err != nil { if err != nil {
return err return err

View File

@ -0,0 +1,247 @@
package bet
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"go.uber.org/zap"
)
func newBetResultNotification(userID int64, level domain.NotificationLevel, channel domain.DeliveryChannel, headline, message string, metadata any) *domain.Notification {
raw, _ := json.Marshal(metadata)
return &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: level,
Reciever: domain.NotificationRecieverSideCustomer,
DeliveryChannel: channel,
Payload: domain.NotificationPayload{
Headline: headline,
Message: message,
},
Priority: 2,
Metadata: raw,
}
}
type SendResultNotificationParam struct {
BetID int64
Status domain.OutcomeStatus
UserID int64
WinningAmount domain.Currency
Extra string
SendEmail bool
SendSMS bool
}
func (p SendResultNotificationParam) Validate() error {
if p.BetID == 0 {
return errors.New("BetID is required")
}
if p.UserID == 0 {
return errors.New("UserID is required")
}
return nil
}
func shouldSend(channel domain.DeliveryChannel, sendEmail, sendSMS bool) bool {
switch {
case channel == domain.DeliveryChannelEmail && sendEmail:
return true
case channel == domain.DeliveryChannelSMS && sendSMS:
return true
case channel == domain.DeliveryChannelInApp:
return true
default:
return false
}
}
func (s *Service) SendWinningStatusNotification(ctx context.Context, param SendResultNotificationParam) error {
if err := param.Validate(); err != nil {
return err
}
var headline string
var message string
switch param.Status {
case domain.OUTCOME_STATUS_WIN:
headline = fmt.Sprintf("Bet #%v Won!", param.BetID)
message = fmt.Sprintf(
"Congratulations! Your bet #%v has won. %.2f has been credited to your wallet.",
param.BetID,
param.WinningAmount.Float32(),
)
case domain.OUTCOME_STATUS_HALF:
headline = fmt.Sprintf("Bet #%v Half-Win", param.BetID)
message = fmt.Sprintf(
"Your bet #%v resulted in a half-win. %.2f has been credited to your wallet.",
param.BetID,
param.WinningAmount.Float32(),
)
case domain.OUTCOME_STATUS_VOID:
headline = fmt.Sprintf("Bet #%v Refunded", param.BetID)
message = fmt.Sprintf(
"Your bet #%v has been voided. %.2f has been refunded to your wallet.",
param.BetID,
param.WinningAmount.Float32(),
)
default:
return fmt.Errorf("unsupported status: %v", param.Status)
}
for _, channel := range []domain.DeliveryChannel{
domain.DeliveryChannelInApp,
domain.DeliveryChannelEmail,
domain.DeliveryChannelSMS,
} {
if !shouldSend(channel, param.SendEmail, param.SendSMS) {
continue
}
n := newBetResultNotification(param.UserID, domain.NotificationLevelSuccess, channel, headline, message, map[string]any{
"winning_amount": param.WinningAmount.Float32(),
"status": param.Status,
"more": param.Extra,
})
if err := s.notificationSvc.SendNotification(ctx, n); err != nil {
return err
}
}
return nil
}
func (s *Service) SendLosingStatusNotification(ctx context.Context, param SendResultNotificationParam) error {
if err := param.Validate(); err != nil {
return err
}
var headline string
var message string
switch param.Status {
case domain.OUTCOME_STATUS_LOSS:
headline = fmt.Sprintf("Bet #%v Lost", param.BetID)
message = "Unfortunately, your bet did not win this time. Better luck next time!"
default:
return fmt.Errorf("unsupported status: %v", param.Status)
}
for _, channel := range []domain.DeliveryChannel{
domain.DeliveryChannelInApp,
domain.DeliveryChannelEmail,
domain.DeliveryChannelSMS,
} {
if !shouldSend(channel, param.SendEmail, param.SendSMS) {
continue
}
n := newBetResultNotification(param.UserID, domain.NotificationLevelWarning, channel, headline, message, map[string]any{
"status": param.Status,
"more": param.Extra,
})
if err := s.notificationSvc.SendNotification(ctx, n); err != nil {
return err
}
}
return nil
}
func (s *Service) SendErrorStatusNotification(ctx context.Context, betID int64, status domain.OutcomeStatus, userID int64, extra string) error {
var headline string
var message string
switch status {
case domain.OUTCOME_STATUS_ERROR, domain.OUTCOME_STATUS_PENDING:
headline = fmt.Sprintf("Bet #%v Processing Issue", betID)
message = "We encountered a problem while processing your bet. Our team is working to resolve it as soon as possible."
default:
return fmt.Errorf("unsupported status: %v", status)
}
for _, channel := range []domain.DeliveryChannel{
domain.DeliveryChannelInApp,
domain.DeliveryChannelEmail,
} {
n := newBetResultNotification(userID, domain.NotificationLevelError, channel, headline, message, map[string]any{
"status": status,
"more": extra,
})
if err := s.notificationSvc.SendNotification(ctx, n); err != nil {
return err
}
}
return nil
}
func (s *Service) SendAdminAlertNotification(ctx context.Context, betID int64, status domain.OutcomeStatus, extra string, companyID int64) error {
var headline string
var message string
switch status {
case domain.OUTCOME_STATUS_ERROR, domain.OUTCOME_STATUS_PENDING:
headline = fmt.Sprintf("Processing Error for Bet #%v", betID)
message = "A processing error occurred with this bet. Please review and take corrective action."
default:
return fmt.Errorf("unsupported status: %v", status)
}
super_admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
Role: string(domain.RoleSuperAdmin),
})
if err != nil {
s.mongoLogger.Error("failed to get super_admin recipients",
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return err
}
admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
Role: string(domain.RoleAdmin),
CompanyID: domain.ValidInt64{
Value: companyID,
Valid: true,
},
})
if err != nil {
s.mongoLogger.Error("failed to get admin recipients",
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return err
}
users := append(super_admin_users, admin_users...)
for _, user := range users {
for _, channel := range []domain.DeliveryChannel{
domain.DeliveryChannelInApp,
domain.DeliveryChannelEmail,
} {
n := newBetResultNotification(user.ID, domain.NotificationLevelError, channel, headline, message, map[string]any{
"status": status,
"more": extra,
})
if err := s.notificationSvc.SendNotification(ctx, n); err != nil {
return err
}
}
}
return nil
}

View File

@ -31,20 +31,20 @@ import (
) )
var ( var (
ErrNoEventsAvailable = errors.New("Not enough events available with the given filters") ErrNoEventsAvailable = errors.New("not enough events available with the given filters")
ErrGenerateRandomOutcome = errors.New("Failed to generate any random outcome for events") ErrGenerateRandomOutcome = errors.New("failed to generate any random outcome for events")
ErrOutcomesNotCompleted = errors.New("Some bet outcomes are still pending") ErrOutcomesNotCompleted = errors.New("some bet outcomes are still pending")
ErrEventHasBeenRemoved = errors.New("Event has been removed") ErrEventHasBeenRemoved = errors.New("event has been removed")
ErrEventHasNotEnded = errors.New("Event has not ended yet") ErrEventHasNotEnded = errors.New("event has not ended yet")
ErrRawOddInvalid = errors.New("Prematch Raw Odd is Invalid") ErrRawOddInvalid = errors.New("prematch Raw Odd is Invalid")
ErrBranchIDRequired = errors.New("Branch ID required for this role") ErrBranchIDRequired = errors.New("branch ID required for this role")
ErrOutcomeLimit = errors.New("Too many outcomes on a single bet") ErrOutcomeLimit = errors.New("too many outcomes on a single bet")
ErrTotalBalanceNotEnough = errors.New("Total Wallet balance is insufficient to create bet") ErrTotalBalanceNotEnough = errors.New("total Wallet balance is insufficient to create bet")
ErrInvalidAmount = errors.New("Invalid amount") ErrInvalidAmount = errors.New("invalid amount")
ErrBetAmountTooHigh = errors.New("Cannot create a bet with an amount above limit") ErrBetAmountTooHigh = errors.New("cannot create a bet with an amount above limit")
ErrBetWinningTooHigh = errors.New("Total Winnings over set limit") ErrBetWinningTooHigh = errors.New("total Winnings over set limit")
) )
type Service struct { type Service struct {
@ -97,10 +97,6 @@ func (s *Service) GenerateCashoutID() (string, error) {
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
index, err := rand.Int(rand.Reader, charLen) index, err := rand.Int(rand.Reader, charLen)
if err != nil { if err != nil {
s.mongoLogger.Error("failed to generate random index for cashout ID",
zap.Int("position", i),
zap.Error(err),
)
return "", err return "", err
} }
result[i] = chars[index.Int64()] result[i] = chars[index.Int64()]
@ -221,7 +217,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
if err != nil { if err != nil {
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
if req.Amount < 1 { if req.Amount < settingsList.MinimumBetAmount.Float32() {
return domain.CreateBetRes{}, ErrInvalidAmount return domain.CreateBetRes{}, ErrInvalidAmount
} }
@ -283,8 +279,9 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
) )
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
if count >= 2 {
return domain.CreateBetRes{}, fmt.Errorf("bet already placed twice") if role == domain.RoleCustomer && count >= settingsList.BetDuplicateLimit {
return domain.CreateBetRes{}, fmt.Errorf("max user limit for duplicate bet")
} }
fastCode := helpers.GenerateFastCode() fastCode := helpers.GenerateFastCode()
@ -340,17 +337,20 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
if branch.BranchManagerID != userID { if role == domain.RoleBranchManager {
s.mongoLogger.Warn("unauthorized branch for branch manager", if branch.BranchManagerID != userID {
zap.Int64("branch_id", *req.BranchID), s.mongoLogger.Warn("unauthorized branch for branch manager",
zap.Error(err), zap.Int64("branch_id", *req.BranchID),
) zap.Error(err),
return domain.CreateBetRes{}, err )
return domain.CreateBetRes{}, err
}
} }
if branch.CompanyID != companyID {
if branch.CompanyID == companyID {
s.mongoLogger.Warn("unauthorized company", s.mongoLogger.Warn("unauthorized company",
zap.Int64("branch_id", *req.BranchID), zap.Int64("branch_id", *req.BranchID),
zap.Int64("branch_company_id", branch.CompanyID),
zap.Int64("company_id", companyID),
zap.Error(err), zap.Error(err),
) )
} }
@ -376,13 +376,13 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
) )
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
// //
default: default:
s.mongoLogger.Error("unknown role type", s.mongoLogger.Error("unknown role type",
zap.String("role", string(role)), zap.String("role", string(role)),
zap.Int64("user_id", userID), zap.Int64("user_id", userID),
) )
return domain.CreateBetRes{}, fmt.Errorf("Unknown Role Type") return domain.CreateBetRes{}, fmt.Errorf("unknown role type")
} }
bet, err := s.CreateBet(ctx, newBet) bet, err := s.CreateBet(ctx, newBet)
@ -583,25 +583,21 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
var newOdds []domain.CreateBetOutcome var newOdds []domain.CreateBetOutcome
var totalOdds float32 = 1 var totalOdds float32 = 1
eventLogger := s.mongoLogger.With(
zap.String("eventID", eventID),
zap.Int32("sportID", sportID),
zap.String("homeTeam", HomeTeam),
zap.String("awayTeam", AwayTeam),
)
markets, err := s.prematchSvc.GetOddsByEventID(ctx, eventID, domain.OddMarketWithEventFilter{}) markets, err := s.prematchSvc.GetOddsByEventID(ctx, eventID, domain.OddMarketWithEventFilter{})
if err != nil { if err != nil {
s.logger.Error("failed to get odds for event", "event id", eventID, "error", err) eventLogger.Error("failed to get odds for event", zap.Error(err))
s.mongoLogger.Error("failed to get odds for event",
zap.String("eventID", eventID),
zap.Int32("sportID", sportID),
zap.String("homeTeam", HomeTeam),
zap.String("awayTeam", AwayTeam),
zap.Error(err))
return nil, 0, err return nil, 0, err
} }
if len(markets) == 0 { if len(markets) == 0 {
s.logger.Error("empty odds for event", "event id", eventID) eventLogger.Warn("empty odds for event")
s.mongoLogger.Warn("empty odds for event",
zap.String("eventID", eventID),
zap.Int32("sportID", sportID),
zap.String("homeTeam", HomeTeam),
zap.String("awayTeam", AwayTeam))
return nil, 0, fmt.Errorf("empty odds or event %v", eventID) return nil, 0, fmt.Errorf("empty odds or event %v", eventID)
} }
@ -630,19 +626,13 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
err = json.Unmarshal(rawBytes, &selectedOdd) err = json.Unmarshal(rawBytes, &selectedOdd)
if err != nil { if err != nil {
s.logger.Error("Failed to unmarshal raw odd", "error", err) eventLogger.Warn("Failed to unmarshal raw odd", zap.Error(err))
s.mongoLogger.Warn("Failed to unmarshal raw odd",
zap.String("eventID", eventID),
zap.Int32("sportID", sportID),
zap.Error(err))
continue continue
} }
parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32) parsedOdd, err := strconv.ParseFloat(selectedOdd.Odds, 32)
if err != nil { if err != nil {
s.logger.Error("Failed to parse odd", "error", err) eventLogger.Warn("Failed to parse odd",
s.mongoLogger.Warn("Failed to parse odd",
zap.String("eventID", eventID),
zap.String("oddValue", selectedOdd.Odds), zap.String("oddValue", selectedOdd.Odds),
zap.Error(err)) zap.Error(err))
continue continue
@ -650,17 +640,13 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
eventIDInt, err := strconv.ParseInt(eventID, 10, 64) eventIDInt, err := strconv.ParseInt(eventID, 10, 64)
if err != nil { if err != nil {
s.logger.Error("Failed to parse eventID", "error", err) eventLogger.Warn("Failed to parse eventID", zap.Error(err))
s.mongoLogger.Warn("Failed to parse eventID",
zap.String("eventID", eventID),
zap.Error(err))
continue continue
} }
oddID, err := strconv.ParseInt(selectedOdd.ID, 10, 64) oddID, err := strconv.ParseInt(selectedOdd.ID, 10, 64)
if err != nil { if err != nil {
s.logger.Error("Failed to parse oddID", "error", err) eventLogger.Warn("Failed to parse oddID",
s.mongoLogger.Warn("Failed to parse oddID",
zap.String("oddID", selectedOdd.ID), zap.String("oddID", selectedOdd.ID),
zap.Error(err)) zap.Error(err))
continue continue
@ -668,8 +654,7 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
marketID, err := strconv.ParseInt(market.MarketID, 10, 64) marketID, err := strconv.ParseInt(market.MarketID, 10, 64)
if err != nil { if err != nil {
s.logger.Error("Failed to parse marketID", "error", err) eventLogger.Warn("Failed to parse marketID",
s.mongoLogger.Warn("Failed to parse marketID",
zap.String("marketID", market.MarketID), zap.String("marketID", market.MarketID),
zap.Error(err)) zap.Error(err))
continue continue
@ -696,22 +681,12 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
} }
if len(newOdds) == 0 { if len(newOdds) == 0 {
s.logger.Error("Bet Outcomes is empty for market", "selectedMarkets", len(selectedMarkets)) eventLogger.Error("Bet Outcomes is empty for market", zap.Int("selectedMarkets", len(selectedMarkets)))
s.mongoLogger.Error("Bet Outcomes is empty for market",
zap.String("eventID", eventID),
zap.Int32("sportID", sportID),
zap.String("homeTeam", HomeTeam),
zap.String("awayTeam", AwayTeam),
zap.Int("selectedMarkets", len(selectedMarkets)))
return nil, 0, ErrGenerateRandomOutcome return nil, 0, ErrGenerateRandomOutcome
} }
// ✅ Final success log (optional) // ✅ Final success log (optional)
s.mongoLogger.Info("Random bet outcomes generated successfully", eventLogger.Info("Random bet outcomes generated successfully", zap.Int("numOutcomes", len(newOdds)), zap.Float32("totalOdds", totalOdds))
zap.String("eventID", eventID),
zap.Int32("sportID", sportID),
zap.Int("numOutcomes", len(newOdds)),
zap.Float32("totalOdds", totalOdds))
return newOdds, totalOdds, nil return newOdds, totalOdds, nil
} }
@ -719,7 +694,15 @@ func (s *Service) GenerateRandomBetOutcomes(ctx context.Context, eventID string,
func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyID int64, leagueID domain.ValidInt64, sportID domain.ValidInt32, firstStartTime, lastStartTime domain.ValidTime) (domain.CreateBetRes, error) { func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyID int64, leagueID domain.ValidInt64, sportID domain.ValidInt32, firstStartTime, lastStartTime domain.ValidTime) (domain.CreateBetRes, error) {
// Get a unexpired event id // Get a unexpired event id
randomBetLogger := s.mongoLogger.With(
zap.Int64("userID", userID),
zap.Int64("branchID", branchID),
zap.Int64("companyID", companyID),
zap.Any("leagueID", leagueID),
zap.Any("sportID", sportID),
zap.Any("firstStartTime", firstStartTime),
zap.Any("lastStartTime", lastStartTime),
)
events, _, err := s.eventSvc.GetPaginatedUpcomingEvents(ctx, events, _, err := s.eventSvc.GetPaginatedUpcomingEvents(ctx,
domain.EventFilter{ domain.EventFilter{
SportID: sportID, SportID: sportID,
@ -729,17 +712,12 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyI
}) })
if err != nil { if err != nil {
s.mongoLogger.Error("failed to get paginated upcoming events", randomBetLogger.Error("failed to get paginated upcoming events", zap.Error(err))
zap.Int64("userID", userID),
zap.Int64("branchID", branchID),
zap.Error(err))
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
if len(events) == 0 { if len(events) == 0 {
s.mongoLogger.Warn("no events available for random bet", randomBetLogger.Warn("no events available for random bet")
zap.Int64("userID", userID),
zap.Int64("branchID", branchID))
return domain.CreateBetRes{}, ErrNoEventsAvailable return domain.CreateBetRes{}, ErrNoEventsAvailable
} }
@ -765,12 +743,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyI
newOdds, total, err := s.GenerateRandomBetOutcomes(ctx, event.ID, event.SportID, event.HomeTeam, event.AwayTeam, event.StartTime, numMarketsPerBet) newOdds, total, err := s.GenerateRandomBetOutcomes(ctx, event.ID, event.SportID, event.HomeTeam, event.AwayTeam, event.StartTime, numMarketsPerBet)
if err != nil { if err != nil {
s.logger.Error("failed to generate random bet outcome", "event id", event.ID, "error", err) s.mongoLogger.Error("failed to generate random bet outcome", zap.String("eventID", event.ID), zap.Error(err))
s.mongoLogger.Error("failed to generate random bet outcome",
zap.Int64("userID", userID),
zap.Int64("branchID", branchID),
zap.String("eventID", event.ID),
zap.String("error", fmt.Sprintf("%v", err)))
continue continue
} }
@ -779,10 +752,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyI
} }
if len(randomOdds) == 0 { if len(randomOdds) == 0 {
s.logger.Error("Failed to generate random any outcomes for all events") randomBetLogger.Error("Failed to generate random any outcomes for all events")
s.mongoLogger.Error("Failed to generate random any outcomes for all events",
zap.Int64("userID", userID),
zap.Int64("branchID", branchID))
return domain.CreateBetRes{}, ErrGenerateRandomOutcome return domain.CreateBetRes{}, ErrGenerateRandomOutcome
} }
@ -790,20 +760,13 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyI
outcomesHash, err := generateOutcomeHash(randomOdds) outcomesHash, err := generateOutcomeHash(randomOdds)
if err != nil { if err != nil {
s.mongoLogger.Error("failed to generate outcome hash", randomBetLogger.Error("failed to generate outcome hash", zap.Error(err))
zap.Int64("user_id", userID),
zap.Error(err),
)
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
count, err := s.GetBetCountByUserID(ctx, userID, outcomesHash) count, err := s.GetBetCountByUserID(ctx, userID, outcomesHash)
if err != nil { if err != nil {
s.mongoLogger.Error("failed to get bet count", randomBetLogger.Error("failed to get bet count", zap.String("outcome_hash", outcomesHash), zap.Error(err))
zap.Int64("user_id", userID),
zap.String("outcome_hash", outcomesHash),
zap.Error(err),
)
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
@ -825,10 +788,7 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyI
bet, err := s.CreateBet(ctx, newBet) bet, err := s.CreateBet(ctx, newBet)
if err != nil { if err != nil {
s.mongoLogger.Error("Failed to create a new random bet", randomBetLogger.Error("Failed to create a new random bet", zap.Error(err))
zap.Int64("userID", userID),
zap.Int64("branchID", branchID),
zap.String("bet", fmt.Sprintf("%+v", newBet)))
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
@ -838,19 +798,13 @@ func (s *Service) PlaceRandomBet(ctx context.Context, userID, branchID, companyI
rows, err := s.betStore.CreateBetOutcome(ctx, randomOdds) rows, err := s.betStore.CreateBetOutcome(ctx, randomOdds)
if err != nil { if err != nil {
s.mongoLogger.Error("Failed to create a new random bet outcome", randomBetLogger.Error("Failed to create a new random bet outcome", zap.Any("randomOdds", randomOdds))
zap.Int64("userID", userID),
zap.Int64("branchID", branchID),
zap.String("randomOdds", fmt.Sprintf("%+v", randomOdds)))
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
res := domain.ConvertCreateBetRes(bet, rows) res := domain.ConvertCreateBetRes(bet, rows)
s.mongoLogger.Info("Random bets placed successfully", randomBetLogger.Info("Random bets placed successfully")
zap.Int64("userID", userID),
zap.Int64("branchID", branchID),
zap.String("response", fmt.Sprintf("%+v", res)))
return res, nil return res, nil
} }
@ -897,53 +851,73 @@ func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) e
return s.betStore.UpdateCashOut(ctx, id, cashedOut) return s.betStore.UpdateCashOut(ctx, id, cashedOut)
} }
func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error { func (s *Service) UpdateStatus(ctx context.Context, betId int64, status domain.OutcomeStatus) error {
bet, err := s.GetBetByID(ctx, id)
updateLogger := s.mongoLogger.With(
zap.Int64("bet_id", betId),
zap.String("status", status.String()),
)
bet, err := s.GetBetByID(ctx, betId)
if err != nil { if err != nil {
s.mongoLogger.Error("failed to update bet status: invalid bet ID", updateLogger.Error("failed to update bet status: invalid bet ID", zap.Error(err))
zap.Int64("bet_id", id), return err
zap.Error(err), }
)
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, bet.CompanyID)
if err != nil {
updateLogger.Error("failed to get settings", zap.Error(err))
return err return err
} }
if status == domain.OUTCOME_STATUS_ERROR || status == domain.OUTCOME_STATUS_PENDING { if status == domain.OUTCOME_STATUS_ERROR || status == domain.OUTCOME_STATUS_PENDING {
s.SendAdminErrorAlertNotification(ctx, status, "") if err := s.SendAdminAlertNotification(ctx, betId, status, "", bet.CompanyID); err != nil {
s.SendErrorStatusNotification(ctx, status, bet.UserID, "") updateLogger.Error("failed to send admin notification", zap.Error(err))
s.mongoLogger.Error("Bet Status is error", return err
zap.Int64("bet_id", id), }
zap.Error(err),
) if err := s.SendErrorStatusNotification(ctx, betId, status, bet.UserID, ""); err != nil {
return s.betStore.UpdateStatus(ctx, id, status) updateLogger.Error("failed to send error notification to user", zap.Error(err))
return err
}
updateLogger.Error("bet entered error/pending state")
return s.betStore.UpdateStatus(ctx, betId, status)
} }
if bet.IsShopBet { if bet.IsShopBet {
return s.betStore.UpdateStatus(ctx, id, status) return s.betStore.UpdateStatus(ctx, betId, status)
} }
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, id) // After this point the bet is known to be a online customer bet
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, bet.UserID)
if err != nil { if err != nil {
s.mongoLogger.Error("failed to get customer wallet", updateLogger.Error("failed to get customer wallet", zap.Error(err))
zap.Int64("bet_id", id),
zap.Error(err),
)
return err return err
} }
resultNotification := SendResultNotificationParam{
BetID: betId,
Status: status,
UserID: bet.UserID,
SendEmail: settingsList.SendEmailOnBetFinish,
SendSMS: settingsList.SendSMSOnBetFinish,
}
var amount domain.Currency var amount domain.Currency
switch status { switch status {
case domain.OUTCOME_STATUS_LOSS: case domain.OUTCOME_STATUS_LOSS:
s.SendLosingStatusNotification(ctx, status, bet.UserID, "") err := s.SendLosingStatusNotification(ctx, resultNotification)
return s.betStore.UpdateStatus(ctx, id, status) if err != nil {
updateLogger.Error("failed to send notification", zap.Error(err))
return err
}
return s.betStore.UpdateStatus(ctx, betId, status)
case domain.OUTCOME_STATUS_WIN: case domain.OUTCOME_STATUS_WIN:
amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds) amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds)
s.SendWinningStatusNotification(ctx, status, bet.UserID, amount, "")
case domain.OUTCOME_STATUS_HALF: case domain.OUTCOME_STATUS_HALF:
amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds) / 2 amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds) / 2
s.SendWinningStatusNotification(ctx, status, bet.UserID, amount, "")
case domain.OUTCOME_STATUS_VOID: case domain.OUTCOME_STATUS_VOID:
amount = bet.Amount amount = bet.Amount
s.SendWinningStatusNotification(ctx, status, bet.UserID, amount, "")
default: default:
updateLogger.Error("invalid outcome status")
return fmt.Errorf("invalid outcome status") return fmt.Errorf("invalid outcome status")
} }
@ -951,7 +925,7 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet by system for winning a bet", amount.Float32())) domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet by system for winning a bet", amount.Float32()))
if err != nil { if err != nil {
s.mongoLogger.Error("failed to add winnings to wallet", updateLogger.Error("failed to add winnings to wallet",
zap.Int64("wallet_id", customerWallet.RegularID), zap.Int64("wallet_id", customerWallet.RegularID),
zap.Float32("amount", float32(amount)), zap.Float32("amount", float32(amount)),
zap.Error(err), zap.Error(err),
@ -959,231 +933,23 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
return err return err
} }
return s.betStore.UpdateStatus(ctx, id, status) if err := s.betStore.UpdateStatus(ctx, betId, status); err != nil {
} updateLogger.Error("failed to update bet status",
zap.String("status", status.String()),
func (s *Service) SendWinningStatusNotification(ctx context.Context, status domain.OutcomeStatus, userID int64, winningAmount domain.Currency, extra string) error {
var headline string
var message string
switch status {
case domain.OUTCOME_STATUS_WIN:
headline = "You Bet Has Won!"
message = fmt.Sprintf(
"You have been awarded %.2f",
winningAmount.Float32(),
)
case domain.OUTCOME_STATUS_HALF:
headline = "You have a half win"
message = fmt.Sprintf(
"You have been awarded %.2f",
winningAmount.Float32(),
)
case domain.OUTCOME_STATUS_VOID:
headline = "Your bet has been refunded"
message = fmt.Sprintf(
"You have been awarded %.2f",
winningAmount.Float32(),
)
}
betNotification := &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
DeliveryChannel: domain.DeliveryChannelInApp,
Payload: domain.NotificationPayload{
Headline: headline,
Message: message,
},
Priority: 2,
Metadata: fmt.Appendf(nil, `{
"winning_amount":%.2f,
"status":%v
"more": %v
}`, winningAmount.Float32(), status, extra),
}
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
return err
}
betNotification.DeliveryChannel = domain.DeliveryChannelEmail
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
return err
}
return nil
}
func (s *Service) SendLosingStatusNotification(ctx context.Context, status domain.OutcomeStatus, userID int64, extra string) error {
var headline string
var message string
switch status {
case domain.OUTCOME_STATUS_LOSS:
headline = "Your bet has lost"
message = "Better luck next time"
}
betNotification := &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
DeliveryChannel: domain.DeliveryChannelInApp,
Payload: domain.NotificationPayload{
Headline: headline,
Message: message,
},
Priority: 2,
Metadata: fmt.Appendf(nil, `{
"status":%v
"more": %v
}`, status, extra),
}
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
return err
}
betNotification.DeliveryChannel = domain.DeliveryChannelEmail
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
return err
}
return nil
}
func (s *Service) SendErrorStatusNotification(ctx context.Context, status domain.OutcomeStatus, userID int64, extra string) error {
var headline string
var message string
switch status {
case domain.OUTCOME_STATUS_ERROR, domain.OUTCOME_STATUS_PENDING:
headline = "There was an error with your bet"
message = "We have encounter an error with your bet. We will fix it as soon as we can"
}
errorSeverityLevel := domain.NotificationErrorSeverityFatal
betNotification := &domain.Notification{
RecipientID: userID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
DeliveryChannel: domain.DeliveryChannelInApp,
Payload: domain.NotificationPayload{
Headline: headline,
Message: message,
},
Priority: 1,
ErrorSeverity: &errorSeverityLevel,
Metadata: fmt.Appendf(nil, `{
"status":%v
"more": %v
}`, status, extra),
}
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
return err
}
betNotification.DeliveryChannel = domain.DeliveryChannelEmail
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
return err
}
return nil
}
func (s *Service) SendAdminErrorAlertNotification(ctx context.Context, status domain.OutcomeStatus, extra string) error {
var headline string
var message string
switch status {
case domain.OUTCOME_STATUS_ERROR, domain.OUTCOME_STATUS_PENDING:
headline = "There was an error processing bet"
message = "We have encounter an error with bet. We will fix it as soon as we can"
}
errorSeverity := domain.NotificationErrorSeverityHigh
betNotification := &domain.Notification{
ErrorSeverity: &errorSeverity,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
DeliveryChannel: domain.DeliveryChannelEmail,
Payload: domain.NotificationPayload{
Headline: headline,
Message: message,
},
Priority: 2,
Metadata: fmt.Appendf(nil, `{
"status":%v
"more": %v
}`, status, extra),
}
super_admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
Role: string(domain.RoleSuperAdmin),
})
if err != nil {
s.mongoLogger.Error("failed to get super_admin recipients",
zap.Error(err), zap.Error(err),
zap.Time("timestamp", time.Now()),
) )
return err return err
} }
admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{ resultNotification.WinningAmount = amount
Role: string(domain.RoleAdmin), if err := s.SendWinningStatusNotification(ctx, resultNotification); err != nil {
})
if err != nil { updateLogger.Error("failed to send winning notification",
s.mongoLogger.Error("failed to get admin recipients",
zap.Error(err), zap.Error(err),
zap.Time("timestamp", time.Now()),
) )
return err return err
} }
users := append(super_admin_users, admin_users...)
for _, user := range users {
betNotification.RecipientID = user.ID
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
s.mongoLogger.Error("failed to send admin notification",
zap.Int64("admin_id", user.ID),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return err
}
betNotification.DeliveryChannel = domain.DeliveryChannelEmail
if err := s.notificationSvc.SendNotification(ctx, betNotification); err != nil {
s.mongoLogger.Error("failed to send email admin notification",
zap.Int64("admin_id", user.ID),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return err
}
}
return nil return nil
} }
@ -1313,7 +1079,7 @@ func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error {
} }
func (s *Service) ProcessBetCashback(ctx context.Context) error { func (s *Service) ProcessBetCashback(ctx context.Context) error {
bets, err := s.betStore.GetBetsForCashback(ctx) bets, err := s.betStore.GetBetsForCashback(ctx)
if err != nil { if err != nil {
s.mongoLogger.Error("failed to fetch bets", s.mongoLogger.Error("failed to fetch bets",
@ -1322,7 +1088,6 @@ func (s *Service) ProcessBetCashback(ctx context.Context) error {
return err return err
} }
for _, bet := range bets { for _, bet := range bets {
shouldProcess := true shouldProcess := true
loseCount := 0 loseCount := 0
@ -1365,6 +1130,14 @@ func (s *Service) ProcessBetCashback(ctx context.Context) error {
} }
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, bet.CompanyID) settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, bet.CompanyID)
if err != nil {
s.mongoLogger.Error("Failed to get settings",
zap.Int64("userID", bet.UserID),
zap.Error(err))
return err
}
cashbackAmount := math.Min(float64(settingsList.CashbackAmountCap.Float32()), float64(calculateCashbackAmount(bet.Amount.Float32(), bet.TotalOdds))) cashbackAmount := math.Min(float64(settingsList.CashbackAmountCap.Float32()), float64(calculateCashbackAmount(bet.Amount.Float32(), bet.TotalOdds)))
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, domain.ToCurrency(float32(cashbackAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, _, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, domain.ToCurrency(float32(cashbackAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT,

View File

@ -0,0 +1,83 @@
package bonus
import (
"context"
"encoding/json"
"fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
type SendBonusNotificationParam struct {
BonusID int64
UserID int64
Type domain.BonusType
Amount domain.Currency
SendEmail bool
SendSMS bool
}
func shouldSend(channel domain.DeliveryChannel, sendEmail, sendSMS bool) bool {
switch {
case channel == domain.DeliveryChannelEmail && sendEmail:
return true
case channel == domain.DeliveryChannelSMS && sendSMS:
return true
case channel == domain.DeliveryChannelInApp:
return true
default:
return false
}
}
func (s *Service) SendBonusNotification(ctx context.Context, param SendBonusNotificationParam) error {
var headline string
var message string
switch param.Type {
case domain.WelcomeBonus:
headline = "You've been awarded a welcome bonus!"
message = fmt.Sprintf(
"Congratulations! A you've been given %.2f as a welcome bonus for you to bet on.",
param.Amount,
)
default:
return fmt.Errorf("unsupported bonus type: %v", param.Type)
}
for _, channel := range []domain.DeliveryChannel{
domain.DeliveryChannelInApp,
domain.DeliveryChannelEmail,
domain.DeliveryChannelSMS,
} {
if !shouldSend(channel, param.SendEmail, param.SendSMS) {
continue
}
raw, _ := json.Marshal(map[string]any{
"bonus_id": param.BonusID,
"type": param.Type,
})
n := &domain.Notification{
RecipientID: param.UserID,
DeliveryStatus: domain.DeliveryStatusPending,
IsRead: false,
Type: domain.NOTIFICATION_TYPE_BONUS_AWARDED,
Level: domain.NotificationLevelSuccess,
Reciever: domain.NotificationRecieverSideCustomer,
DeliveryChannel: channel,
Payload: domain.NotificationPayload{
Headline: headline,
Message: message,
},
Priority: 2,
Metadata: raw,
}
if err := s.notificationSvc.SendNotification(ctx, n); err != nil {
return err
}
}
return nil
}

View File

@ -3,12 +3,15 @@ package bonus
import ( import (
"context" "context"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
) )
type BonusStore interface { type BonusStore interface {
CreateBonusMultiplier(ctx context.Context, multiplier float32, balance_cap int64) error CreateUserBonus(ctx context.Context, bonus domain.CreateBonus) (domain.UserBonus, error)
GetBonusMultiplier(ctx context.Context) ([]dbgen.GetBonusMultiplierRow, error) GetAllUserBonuses(ctx context.Context, filter domain.BonusFilter) ([]domain.UserBonus, error)
GetBonusBalanceCap(ctx context.Context) ([]dbgen.GetBonusBalanceCapRow, error) GetBonusCount(ctx context.Context, filter domain.BonusFilter) (int64, error)
UpdateBonusMultiplier(ctx context.Context, id int64, mulitplier float32, balance_cap int64) error GetBonusByID(ctx context.Context, bonusID int64) (domain.UserBonus, error)
GetBonusStats(ctx context.Context, filter domain.BonusFilter) (domain.BonusStats, error)
UpdateUserBonus(ctx context.Context, bonusID int64, IsClaimed bool) error
DeleteUserBonus(ctx context.Context, bonusID int64) error
} }

View File

@ -2,32 +2,162 @@ package bonus
import ( import (
"context" "context"
"errors"
"fmt"
"math"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
"go.uber.org/zap"
) )
type Service struct { type Service struct {
bonusStore BonusStore bonusStore BonusStore
walletSvc *wallet.Service
settingSvc *settings.Service
notificationSvc *notificationservice.Service
mongoLogger *zap.Logger
} }
func NewService(bonusStore BonusStore) *Service { func NewService(bonusStore BonusStore, walletSvc *wallet.Service, settingSvc *settings.Service, notificationSvc *notificationservice.Service, mongoLogger *zap.Logger) *Service {
return &Service{ return &Service{
bonusStore: bonusStore, bonusStore: bonusStore,
walletSvc: walletSvc,
settingSvc: settingSvc,
notificationSvc: notificationSvc,
mongoLogger: mongoLogger,
} }
} }
func (s *Service) CreateBonusMultiplier(ctx context.Context, multiplier float32, balance_cap int64) error { var (
return s.bonusStore.CreateBonusMultiplier(ctx, multiplier, balance_cap) ErrWelcomeBonusNotActive = errors.New("welcome bonus is not active")
ErrWelcomeBonusCountReached = errors.New("welcome bonus max deposit count reached")
)
func (s *Service) CreateWelcomeBonus(ctx context.Context, amount domain.Currency, companyID int64, userID int64) error {
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, companyID)
if err != nil {
s.mongoLogger.Error("Failed to get settings",
zap.Int64("companyID", companyID),
zap.Error(err))
return err
}
if !settingsList.WelcomeBonusActive {
return ErrWelcomeBonusNotActive
}
wallet, err := s.walletSvc.GetCustomerWallet(ctx, userID)
if err != nil {
return err
}
stats, err := s.walletSvc.GetTransferStats(ctx, wallet.ID)
if err != nil {
return err
}
if stats.TotalDeposits > settingsList.WelcomeBonusCount {
return ErrWelcomeBonusCountReached
}
newBalance := math.Min(float64(amount)*float64(settingsList.WelcomeBonusMultiplier), float64(settingsList.WelcomeBonusCap))
bonus, err := s.CreateUserBonus(ctx, domain.CreateBonus{
Name: "Welcome Bonus",
Description: fmt.Sprintf("Awarded for deposit number (%v / %v)", stats.TotalDeposits, settingsList.WelcomeBonusCount),
UserID: userID,
Type: domain.WelcomeBonus,
RewardAmount: domain.Currency(newBalance),
ExpiresAt: time.Now().Add(time.Duration(settingsList.WelcomeBonusExpire) * 24 * time.Hour),
})
if err != nil {
return err
}
err = s.SendBonusNotification(ctx, SendBonusNotificationParam{
BonusID: bonus.ID,
UserID: userID,
Type: domain.DepositBonus,
Amount: domain.Currency(newBalance),
SendEmail: true,
SendSMS: false,
})
if err != nil {
return err
}
return nil
} }
func (s *Service) GetBonusMultiplier(ctx context.Context) ([]dbgen.GetBonusMultiplierRow, error) { var (
return s.bonusStore.GetBonusMultiplier(ctx) ErrBonusIsAlreadyClaimed = errors.New("bonus is already claimed")
ErrBonusUserIDNotMatch = errors.New("bonus user id is not a match")
)
func (s *Service) ProcessBonusClaim(ctx context.Context, bonusID, userID int64) error {
bonus, err := s.GetBonusByID(ctx, bonusID)
if err != nil {
return err
}
if bonus.UserID != userID {
}
if bonus.IsClaimed {
return ErrBonusIsAlreadyClaimed
}
wallet, err := s.walletSvc.GetCustomerWallet(ctx, bonus.UserID)
if err != nil {
return err
}
_, err = s.walletSvc.AddToWallet(
ctx, wallet.StaticID, bonus.RewardAmount,
domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to bonus wallet due to %v", bonus.RewardAmount, bonus.Type),
)
if err != nil {
return err
}
if err := s.UpdateUserBonus(ctx, bonusID, true); err != nil {
return err
}
return nil
} }
func (s *Service) GetBonusBalanceCap(ctx context.Context) ([]dbgen.GetBonusBalanceCapRow, error) { func (s *Service) CreateUserBonus(ctx context.Context, bonus domain.CreateBonus) (domain.UserBonus, error) {
return s.bonusStore.GetBonusBalanceCap(ctx) return s.bonusStore.CreateUserBonus(ctx, bonus)
}
func (s *Service) GetAllUserBonuses(ctx context.Context, filter domain.BonusFilter) ([]domain.UserBonus, error) {
return s.bonusStore.GetAllUserBonuses(ctx, filter)
} }
func (s *Service) UpdateBonusMultiplier(ctx context.Context, id int64, mulitplier float32, balance_cap int64) error { func (s *Service) GetBonusCount(ctx context.Context, filter domain.BonusFilter) (int64, error) {
return s.bonusStore.UpdateBonusMultiplier(ctx, id, mulitplier, balance_cap) return s.bonusStore.GetBonusCount(ctx, filter)
}
func (s *Service) GetBonusByID(ctx context.Context, bonusID int64) (domain.UserBonus, error) {
return s.bonusStore.GetBonusByID(ctx, bonusID)
}
func (s *Service) GetBonusStats(ctx context.Context, filter domain.BonusFilter) (domain.BonusStats, error) {
return s.bonusStore.GetBonusStats(ctx, filter)
}
func (s *Service) UpdateUserBonus(ctx context.Context, bonusID int64, IsClaimed bool) error {
return s.bonusStore.UpdateUserBonus(ctx, bonusID, IsClaimed)
}
func (s *Service) DeleteUserBonus(ctx context.Context, bonusID int64) error {
return s.bonusStore.DeleteUserBonus(ctx, bonusID)
} }

View File

@ -19,6 +19,7 @@ type Service interface {
IsEventMonitored(ctx context.Context, eventID string) (bool, error) IsEventMonitored(ctx context.Context, eventID string) (bool, error)
UpdateEventMonitored(ctx context.Context, eventID string, IsMonitored bool) error UpdateEventMonitored(ctx context.Context, eventID string, IsMonitored bool) error
GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error)
GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error)
UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error
GetSportAndLeagueIDs(ctx context.Context, eventID string) ([]int64, error)
} }

View File

@ -12,8 +12,11 @@ import (
"sync" "sync"
"time" "time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
"github.com/jackc/pgx/v5"
"go.uber.org/zap" "go.uber.org/zap"
// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event" // "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
) )
@ -21,14 +24,18 @@ import (
type service struct { type service struct {
token string token string
store *repository.Store store *repository.Store
settingSvc settings.Service
mongoLogger *zap.Logger mongoLogger *zap.Logger
cfg *config.Config
} }
func New(token string, store *repository.Store, mongoLogger *zap.Logger) Service { func New(token string, store *repository.Store, settingSvc settings.Service, mongoLogger *zap.Logger, cfg *config.Config) Service {
return &service{ return &service{
token: token, token: token,
store: store, store: store,
settingSvc: settingSvc,
mongoLogger: mongoLogger, mongoLogger: mongoLogger,
cfg: cfg,
} }
} }
@ -206,22 +213,39 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error {
} }
func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_url string, source domain.EventSource) { func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_url string, source domain.EventSource) {
const pageLimit int = 200
sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91}
// sportIDs := []int{1}
settingsList, err := s.settingSvc.GetGlobalSettingList(ctx)
if err != nil {
s.mongoLogger.Error("Failed to fetch event data for page", zap.Error(err))
return
}
var pageLimit int
var sportIDs []int
// Restricting the page to 1 on development, which drastically reduces the amount of events that is fetched
if s.cfg.Env == "development" {
pageLimit = 1
sportIDs = []int{1}
} else {
pageLimit = 200
sportIDs = []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91}
}
var skippedLeague []string
var totalEvents = 0
nilAway := 0
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 count int = 0 var pageCount int = 0
var skippedLeague []string var sportEvents = 0
var totalEvents = 0
logger := s.mongoLogger.With( logger := s.mongoLogger.With(
zap.String("source", string(source)), zap.String("source", string(source)),
zap.Int("sport_id", sportID), zap.Int("sport_id", sportID),
zap.String("sport_name", domain.Sport(sportID).String()), zap.String("sport_name", domain.Sport(sportID).String()),
zap.Int("count", count), zap.Int("count", pageCount),
zap.Int("totalEvents", totalEvents),
zap.Int("Skipped leagues", len(skippedLeague)), zap.Int("Skipped leagues", len(skippedLeague)),
) )
for page <= totalPages { for page <= totalPages {
@ -301,34 +325,33 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
// } // }
event := domain.CreateEvent{ event := domain.CreateEvent{
ID: ev.ID, ID: ev.ID,
SportID: convertInt32(ev.SportID), SportID: convertInt32(ev.SportID),
MatchName: "", HomeTeam: ev.Home.Name,
HomeTeam: ev.Home.Name, AwayTeam: "", // handle nil safely
AwayTeam: "", // handle nil safely HomeTeamID: convertInt64(ev.Home.ID),
HomeTeamID: convertInt64(ev.Home.ID), AwayTeamID: 0,
AwayTeamID: 0, LeagueID: convertInt64(ev.League.ID),
HomeTeamImage: "", LeagueName: ev.League.Name,
AwayTeamImage: "", StartTime: time.Unix(startUnix, 0).UTC(),
LeagueID: convertInt64(ev.League.ID), Source: source,
LeagueName: ev.League.Name, IsLive: false,
StartTime: time.Unix(startUnix, 0).UTC(), Status: domain.STATUS_PENDING,
Source: source, DefaultWinningUpperLimit: settingsList.DefaultWinningLimit,
IsLive: false,
Status: domain.STATUS_PENDING,
} }
if ev.Away != nil { if ev.Away != nil {
dataLogger.Info("event away is empty")
event.AwayTeam = ev.Away.Name event.AwayTeam = ev.Away.Name
event.AwayTeamID = convertInt64(ev.Away.ID) event.AwayTeamID = convertInt64(ev.Away.ID)
event.MatchName = ev.Home.Name + " vs " + ev.Away.Name event.MatchName = ev.Home.Name + " vs " + ev.Away.Name
} else {
nilAway += 1
} }
ok, err := s.CheckAndInsertEventHistory(ctx, event) ok, _ := s.CheckAndInsertEventHistory(ctx, event)
if err != nil { // if err != nil {
dataLogger.Error("failed to check and insert event history", zap.Error(err)) // dataLogger.Error("failed to check and insert event history", zap.Error(err))
} // }
if ok { if ok {
dataLogger.Info("event history has been recorded") dataLogger.Info("event history has been recorded")
@ -338,7 +361,8 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
if err != nil { if err != nil {
dataLogger.Error("failed to save upcoming event", zap.Error(err)) dataLogger.Error("failed to save upcoming event", zap.Error(err))
} }
totalEvents += 1 sportEvents += 1
} }
// log.Printf("⚠️ Skipped leagues %v", len(skippedLeague)) // log.Printf("⚠️ Skipped leagues %v", len(skippedLeague))
@ -346,26 +370,26 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur
totalPages = data.Pager.Total / data.Pager.PerPage totalPages = data.Pager.Total / data.Pager.PerPage
if count >= pageLimit { if pageCount >= pageLimit {
break break
} }
if page > totalPages { if page > totalPages {
break break
} }
count++ pageCount++
} }
s.mongoLogger.Info(
"Successfully fetched upcoming events",
zap.String("source", string(source)),
zap.Int("totalEvents", totalEvents),
zap.Int("sport_id", sportID),
zap.String("sport_name", domain.Sport(sportID).String()),
zap.Int("page", page),
zap.Int("total_pages", totalPages),
zap.Int("Skipped leagues", len(skippedLeague)),
)
logger.Info("Completed adding sport", zap.Int("number_of_events_in_sport", sportEvents))
totalEvents += sportEvents
} }
s.mongoLogger.Info(
"Successfully fetched upcoming events",
zap.String("source", string(source)),
zap.Int("totalEvents", totalEvents),
zap.Int("Skipped leagues", len(skippedLeague)),
zap.Int("Events with empty away data", nilAway),
)
} }
func (s *service) CheckAndInsertEventHistory(ctx context.Context, event domain.CreateEvent) (bool, error) { func (s *service) CheckAndInsertEventHistory(ctx context.Context, event domain.CreateEvent) (bool, error) {
@ -379,7 +403,9 @@ func (s *service) CheckAndInsertEventHistory(ctx context.Context, event domain.C
) )
if err != nil { if err != nil {
eventLogger.Error("failed to get event is_monitored", zap.Error(err)) if err != pgx.ErrNoRows {
eventLogger.Info("failed to get event is_monitored", zap.Error(err))
}
return false, err return false, err
} }
@ -479,9 +505,14 @@ func (s *service) GetEventsWithSettings(ctx context.Context, companyID int64, fi
return s.store.GetEventsWithSettings(ctx, companyID, filter) return s.store.GetEventsWithSettings(ctx, companyID, filter)
} }
func (s *service) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) { func (s *service) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) {
return s.store.GetEventWithSettingByID(ctx, ID, companyID) return s.store.GetEventWithSettingByID(ctx, ID, companyID)
} }
func (s *service) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { func (s *service) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error {
return s.store.UpdateEventSettings(ctx, event) return s.store.UpdateEventSettings(ctx, event)
} }
func (s *service) GetSportAndLeagueIDs(ctx context.Context, eventID string) ([]int64, error) {
return s.store.GetSportAndLeagueIDs(ctx, eventID)
}

View File

@ -10,7 +10,7 @@ type Service interface {
SaveLeague(ctx context.Context, league domain.CreateLeague) error SaveLeague(ctx context.Context, league domain.CreateLeague) error
SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error)
GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error)
CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error)
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error UpdateLeague(ctx context.Context, league domain.UpdateLeague) error
} }

View File

@ -29,7 +29,7 @@ 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) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) { func (s *service) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error) {
return s.store.GetAllLeaguesByCompany(ctx, companyID, filter) return s.store.GetAllLeaguesByCompany(ctx, companyID, filter)
} }

View File

@ -3,10 +3,9 @@ package messenger
import ( import (
"context" "context"
"github.com/resend/resend-go/v2" "github.com/resend/resend-go/v2"
) )
func (s *Service) SendEmail(ctx context.Context, receiverEmail, message string, subject string) error { func (s *Service) SendEmail(ctx context.Context, receiverEmail, message string, messageHTML string, subject string) error {
apiKey := s.config.ResendApiKey apiKey := s.config.ResendApiKey
client := resend.NewClient(apiKey) client := resend.NewClient(apiKey)
formattedSenderEmail := "FortuneBets <" + s.config.ResendSenderEmail + ">" formattedSenderEmail := "FortuneBets <" + s.config.ResendSenderEmail + ">"
@ -15,6 +14,7 @@ func (s *Service) SendEmail(ctx context.Context, receiverEmail, message string,
To: []string{receiverEmail}, To: []string{receiverEmail},
Subject: subject, Subject: subject,
Text: message, Text: message,
Html: messageHTML,
} }
_, err := client.Emails.Send(params) _, err := client.Emails.Send(params)

Some files were not shown because too many files have changed in this diff Show More