fixes while integrating
This commit is contained in:
parent
42788e6f9f
commit
910d592bef
343
db/data/001_initial_seed_data.sql
Normal file
343
db/data/001_initial_seed_data.sql
Normal file
|
|
@ -0,0 +1,343 @@
|
||||||
|
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') 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,
|
||||||
|
20000,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
2,
|
||||||
|
'company_wallet',
|
||||||
|
'ETB',
|
||||||
|
TRUE,
|
||||||
|
CURRENT_TIMESTAMP,
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
),
|
||||||
|
(
|
||||||
|
4,
|
||||||
|
15000,
|
||||||
|
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;
|
||||||
148
db/data/002_veli_user.sql
Normal file
148
db/data/002_veli_user.sql
Normal 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,
|
||||||
|
10000,
|
||||||
|
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;
|
||||||
|
|
@ -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;
|
|
||||||
|
|
@ -18,17 +18,21 @@ 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
|
||||||
);
|
);
|
||||||
|
|
@ -40,7 +44,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
|
||||||
|
|
@ -96,7 +107,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 (
|
||||||
|
|
@ -220,9 +231,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,
|
||||||
|
|
@ -232,7 +243,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,
|
||||||
|
|
@ -246,7 +257,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
|
||||||
|
|
@ -263,12 +274,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,
|
||||||
|
|
@ -289,21 +297,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 INT 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,
|
||||||
|
|
@ -319,7 +321,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,
|
||||||
|
|
@ -330,13 +332,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,
|
||||||
|
|
@ -358,7 +360,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,
|
||||||
|
|
@ -408,7 +410,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,
|
||||||
|
|
@ -425,7 +427,7 @@ 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,
|
||||||
|
|
@ -439,10 +441,10 @@ CREATE TABLE bonus (
|
||||||
);
|
);
|
||||||
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 (
|
||||||
|
|
@ -458,20 +460,20 @@ 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
|
-- Views
|
||||||
CREATE VIEW companies_details AS
|
CREATE VIEW companies_details AS
|
||||||
SELECT companies.*,
|
SELECT companies.*,
|
||||||
|
|
@ -486,7 +488,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
|
||||||
|
|
@ -500,9 +502,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
|
||||||
|
|
@ -512,7 +514,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;
|
||||||
|
|
@ -566,7 +568,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
|
||||||
|
|
@ -643,47 +645,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;
|
||||||
|
|
@ -18,17 +18,19 @@ CREATE TABLE IF NOT EXISTS referral_settings (
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS referrals (
|
CREATE TABLE IF NOT EXISTS referrals (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
company_id BIGINT NOT NULL REFERENCES companies (id) ON
|
||||||
|
DELETE CASCADE,
|
||||||
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 REFERENCES users (id),
|
||||||
referred_id VARCHAR(255) UNIQUE,
|
referred_id BIGINT UNIQUE REFERENCES users (id),
|
||||||
status ReferralStatus NOT NULL DEFAULT 'PENDING',
|
status ReferralStatus NOT NULL DEFAULT 'PENDING',
|
||||||
reward_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
reward_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||||
cashback_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
cashback_amount DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||||
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,
|
expires_at TIMESTAMPTZ NOT NULL -- FOREIGN KEY (referrer_id) REFERENCES users (id),
|
||||||
-- FOREIGN KEY (referrer_id) REFERENCES users (id),
|
-- FOREIGN KEY (referred_id) REFERENCES users (id),
|
||||||
-- FOREIGN KEY (referred_id) REFERENCES users (id),
|
,
|
||||||
CONSTRAINT reward_amount_positive CHECK (reward_amount >= 0),
|
CONSTRAINT reward_amount_positive CHECK (reward_amount >= 0),
|
||||||
CONSTRAINT cashback_amount_positive CHECK (cashback_amount >= 0)
|
CONSTRAINT cashback_amount_positive CHECK (cashback_amount >= 0)
|
||||||
);
|
);
|
||||||
|
|
@ -38,7 +40,7 @@ CREATE INDEX idx_referrals_status ON referrals (status);
|
||||||
ALTER TABLE users
|
ALTER TABLE users
|
||||||
ADD COLUMN IF NOT EXISTS referral_code VARCHAR(10) UNIQUE,
|
ADD COLUMN IF NOT EXISTS referral_code VARCHAR(10) UNIQUE,
|
||||||
ADD COLUMN IF NOT EXISTS referred_by VARCHAR(10);
|
ADD COLUMN IF NOT EXISTS referred_by VARCHAR(10);
|
||||||
-- Modify wallet table to track bonus money separately
|
-- Modify wallet TABLE to track bonus money separately
|
||||||
ALTER TABLE wallets
|
ALTER TABLE wallets
|
||||||
ADD COLUMN IF NOT EXISTS bonus_balance DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
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 COLUMN IF NOT EXISTS cash_balance DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
-- );
|
||||||
|
|
@ -1,77 +1,87 @@
|
||||||
-- name: CreateReferral :one
|
-- name: CreateReferral :one
|
||||||
INSERT INTO referrals (
|
INSERT INTO referrals (
|
||||||
referral_code,
|
referral_code,
|
||||||
referrer_id,
|
referrer_id,
|
||||||
status,
|
company_id,
|
||||||
reward_amount,
|
status,
|
||||||
expires_at
|
reward_amount,
|
||||||
) VALUES (
|
expires_at
|
||||||
$1, $2, $3, $4, $5
|
)
|
||||||
) RETURNING *;
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING *;
|
||||||
-- name: GetReferralByCode :one
|
-- name: GetReferralByCode :one
|
||||||
SELECT * FROM referrals
|
SELECT *
|
||||||
|
FROM referrals
|
||||||
WHERE referral_code = $1;
|
WHERE referral_code = $1;
|
||||||
|
|
||||||
-- name: UpdateReferral :one
|
-- name: UpdateReferral :one
|
||||||
UPDATE referrals
|
UPDATE referrals
|
||||||
SET
|
SET referred_id = $2,
|
||||||
referred_id = $2,
|
status = $3,
|
||||||
status = $3,
|
updated_at = CURRENT_TIMESTAMP
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: UpdateReferralCode :exec
|
-- name: UpdateReferralCode :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET
|
SET referral_code = $2,
|
||||||
referral_code = $2,
|
updated_at = CURRENT_TIMESTAMP
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: GetReferralStats :one
|
-- name: GetReferralStats :one
|
||||||
SELECT
|
SELECT COUNT(*) AS total_referrals,
|
||||||
COUNT(*) as total_referrals,
|
COUNT(
|
||||||
COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) as completed_referrals,
|
CASE
|
||||||
COALESCE(SUM(reward_amount), 0) as total_reward_earned,
|
WHEN status = 'COMPLETED' THEN 1
|
||||||
COALESCE(SUM(CASE WHEN status = 'PENDING' THEN reward_amount END), 0) as pending_rewards
|
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
|
FROM referrals
|
||||||
WHERE referrer_id = $1;
|
WHERE referrer_id = $1
|
||||||
|
AND company_id = $2;
|
||||||
-- name: GetReferralSettings :one
|
-- name: GetReferralSettings :one
|
||||||
SELECT * FROM referral_settings
|
SELECT *
|
||||||
|
FROM referral_settings
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
-- name: UpdateReferralSettings :one
|
-- name: UpdateReferralSettings :one
|
||||||
UPDATE referral_settings
|
UPDATE referral_settings
|
||||||
SET
|
SET referral_reward_amount = $2,
|
||||||
referral_reward_amount = $2,
|
cashback_percentage = $3,
|
||||||
cashback_percentage = $3,
|
bet_referral_bonus_percentage = $4,
|
||||||
bet_referral_bonus_percentage= $4,
|
max_referrals = $5,
|
||||||
max_referrals = $5,
|
expires_after_days = $6,
|
||||||
expires_after_days = $6,
|
updated_by = $7,
|
||||||
updated_by = $7,
|
updated_at = CURRENT_TIMESTAMP
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: CreateReferralSettings :one
|
-- name: CreateReferralSettings :one
|
||||||
INSERT INTO referral_settings (
|
INSERT INTO referral_settings (
|
||||||
referral_reward_amount,
|
referral_reward_amount,
|
||||||
cashback_percentage,
|
cashback_percentage,
|
||||||
max_referrals,
|
max_referrals,
|
||||||
bet_referral_bonus_percentage,
|
bet_referral_bonus_percentage,
|
||||||
expires_after_days,
|
expires_after_days,
|
||||||
updated_by
|
updated_by
|
||||||
) VALUES (
|
)
|
||||||
$1, $2, $3, $4, $5, $6
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
) RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: GetReferralByReferredID :one
|
-- name: GetReferralByReferredID :one
|
||||||
SELECT * FROM referrals WHERE referred_id = $1 LIMIT 1;
|
SELECT *
|
||||||
|
FROM referrals
|
||||||
|
WHERE referred_id = $1
|
||||||
|
LIMIT 1;
|
||||||
-- name: GetActiveReferralByReferrerID :one
|
-- name: GetActiveReferralByReferrerID :one
|
||||||
SELECT * FROM referrals WHERE referrer_id = $1 AND status = 'PENDING' LIMIT 1;
|
SELECT *
|
||||||
|
FROM referrals
|
||||||
|
WHERE referrer_id = $1
|
||||||
|
AND status = 'PENDING'
|
||||||
|
LIMIT 1;
|
||||||
-- name: GetReferralCountByID :one
|
-- name: GetReferralCountByID :one
|
||||||
SELECT count(*) FROM referrals WHERE referrer_id = $1;
|
SELECT COUNT(*)
|
||||||
|
FROM referrals
|
||||||
|
WHERE referrer_id = $1;
|
||||||
|
|
@ -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.*
|
||||||
|
|
|
||||||
|
|
@ -540,9 +540,10 @@ type Otp struct {
|
||||||
|
|
||||||
type Referral struct {
|
type Referral struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
ReferralCode string `json:"referral_code"`
|
ReferralCode string `json:"referral_code"`
|
||||||
ReferrerID string `json:"referrer_id"`
|
ReferrerID int64 `json:"referrer_id"`
|
||||||
ReferredID pgtype.Text `json:"referred_id"`
|
ReferredID pgtype.Int8 `json:"referred_id"`
|
||||||
Status Referralstatus `json:"status"`
|
Status Referralstatus `json:"status"`
|
||||||
RewardAmount pgtype.Numeric `json:"reward_amount"`
|
RewardAmount pgtype.Numeric `json:"reward_amount"`
|
||||||
CashbackAmount pgtype.Numeric `json:"cashback_amount"`
|
CashbackAmount pgtype.Numeric `json:"cashback_amount"`
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,21 @@ import (
|
||||||
|
|
||||||
const CreateReferral = `-- name: CreateReferral :one
|
const CreateReferral = `-- name: CreateReferral :one
|
||||||
INSERT INTO referrals (
|
INSERT INTO referrals (
|
||||||
referral_code,
|
referral_code,
|
||||||
referrer_id,
|
referrer_id,
|
||||||
status,
|
company_id,
|
||||||
reward_amount,
|
status,
|
||||||
expires_at
|
reward_amount,
|
||||||
) VALUES (
|
expires_at
|
||||||
$1, $2, $3, $4, $5
|
)
|
||||||
) RETURNING id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING id, company_id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateReferralParams struct {
|
type CreateReferralParams struct {
|
||||||
ReferralCode string `json:"referral_code"`
|
ReferralCode string `json:"referral_code"`
|
||||||
ReferrerID string `json:"referrer_id"`
|
ReferrerID int64 `json:"referrer_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
Status Referralstatus `json:"status"`
|
Status Referralstatus `json:"status"`
|
||||||
RewardAmount pgtype.Numeric `json:"reward_amount"`
|
RewardAmount pgtype.Numeric `json:"reward_amount"`
|
||||||
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
||||||
|
|
@ -35,6 +37,7 @@ func (q *Queries) CreateReferral(ctx context.Context, arg CreateReferralParams)
|
||||||
row := q.db.QueryRow(ctx, CreateReferral,
|
row := q.db.QueryRow(ctx, CreateReferral,
|
||||||
arg.ReferralCode,
|
arg.ReferralCode,
|
||||||
arg.ReferrerID,
|
arg.ReferrerID,
|
||||||
|
arg.CompanyID,
|
||||||
arg.Status,
|
arg.Status,
|
||||||
arg.RewardAmount,
|
arg.RewardAmount,
|
||||||
arg.ExpiresAt,
|
arg.ExpiresAt,
|
||||||
|
|
@ -42,6 +45,7 @@ func (q *Queries) CreateReferral(ctx context.Context, arg CreateReferralParams)
|
||||||
var i Referral
|
var i Referral
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
&i.CompanyID,
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferrerID,
|
&i.ReferrerID,
|
||||||
&i.ReferredID,
|
&i.ReferredID,
|
||||||
|
|
@ -57,15 +61,15 @@ func (q *Queries) CreateReferral(ctx context.Context, arg CreateReferralParams)
|
||||||
|
|
||||||
const CreateReferralSettings = `-- name: CreateReferralSettings :one
|
const CreateReferralSettings = `-- name: CreateReferralSettings :one
|
||||||
INSERT INTO referral_settings (
|
INSERT INTO referral_settings (
|
||||||
referral_reward_amount,
|
referral_reward_amount,
|
||||||
cashback_percentage,
|
cashback_percentage,
|
||||||
max_referrals,
|
max_referrals,
|
||||||
bet_referral_bonus_percentage,
|
bet_referral_bonus_percentage,
|
||||||
expires_after_days,
|
expires_after_days,
|
||||||
updated_by
|
updated_by
|
||||||
) VALUES (
|
)
|
||||||
$1, $2, $3, $4, $5, $6
|
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
|
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 CreateReferralSettingsParams struct {
|
||||||
|
|
@ -103,14 +107,19 @@ func (q *Queries) CreateReferralSettings(ctx context.Context, arg CreateReferral
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetActiveReferralByReferrerID = `-- name: GetActiveReferralByReferrerID :one
|
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
|
SELECT id, company_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) {
|
func (q *Queries) GetActiveReferralByReferrerID(ctx context.Context, referrerID int64) (Referral, error) {
|
||||||
row := q.db.QueryRow(ctx, GetActiveReferralByReferrerID, referrerID)
|
row := q.db.QueryRow(ctx, GetActiveReferralByReferrerID, referrerID)
|
||||||
var i Referral
|
var i Referral
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
&i.CompanyID,
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferrerID,
|
&i.ReferrerID,
|
||||||
&i.ReferredID,
|
&i.ReferredID,
|
||||||
|
|
@ -125,7 +134,8 @@ func (q *Queries) GetActiveReferralByReferrerID(ctx context.Context, referrerID
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetReferralByCode = `-- name: GetReferralByCode :one
|
const GetReferralByCode = `-- name: GetReferralByCode :one
|
||||||
SELECT id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at FROM referrals
|
SELECT id, company_id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at
|
||||||
|
FROM referrals
|
||||||
WHERE referral_code = $1
|
WHERE referral_code = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -134,6 +144,7 @@ func (q *Queries) GetReferralByCode(ctx context.Context, referralCode string) (R
|
||||||
var i Referral
|
var i Referral
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
&i.CompanyID,
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferrerID,
|
&i.ReferrerID,
|
||||||
&i.ReferredID,
|
&i.ReferredID,
|
||||||
|
|
@ -148,14 +159,18 @@ func (q *Queries) GetReferralByCode(ctx context.Context, referralCode string) (R
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetReferralByReferredID = `-- name: GetReferralByReferredID :one
|
const GetReferralByReferredID = `-- name: GetReferralByReferredID :one
|
||||||
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, company_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
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetReferralByReferredID(ctx context.Context, referredID pgtype.Text) (Referral, error) {
|
func (q *Queries) GetReferralByReferredID(ctx context.Context, referredID pgtype.Int8) (Referral, error) {
|
||||||
row := q.db.QueryRow(ctx, GetReferralByReferredID, referredID)
|
row := q.db.QueryRow(ctx, GetReferralByReferredID, referredID)
|
||||||
var i Referral
|
var i Referral
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
&i.CompanyID,
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferrerID,
|
&i.ReferrerID,
|
||||||
&i.ReferredID,
|
&i.ReferredID,
|
||||||
|
|
@ -170,10 +185,12 @@ func (q *Queries) GetReferralByReferredID(ctx context.Context, referredID pgtype
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetReferralCountByID = `-- name: GetReferralCountByID :one
|
const GetReferralCountByID = `-- name: GetReferralCountByID :one
|
||||||
SELECT count(*) FROM referrals WHERE referrer_id = $1
|
SELECT COUNT(*)
|
||||||
|
FROM referrals
|
||||||
|
WHERE referrer_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetReferralCountByID(ctx context.Context, referrerID string) (int64, error) {
|
func (q *Queries) GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error) {
|
||||||
row := q.db.QueryRow(ctx, GetReferralCountByID, referrerID)
|
row := q.db.QueryRow(ctx, GetReferralCountByID, referrerID)
|
||||||
var count int64
|
var count int64
|
||||||
err := row.Scan(&count)
|
err := row.Scan(&count)
|
||||||
|
|
@ -181,7 +198,8 @@ func (q *Queries) GetReferralCountByID(ctx context.Context, referrerID string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetReferralSettings = `-- name: GetReferralSettings :one
|
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
|
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
|
LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -204,15 +222,31 @@ func (q *Queries) GetReferralSettings(ctx context.Context) (ReferralSetting, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetReferralStats = `-- name: GetReferralStats :one
|
const GetReferralStats = `-- name: GetReferralStats :one
|
||||||
SELECT
|
SELECT COUNT(*) AS total_referrals,
|
||||||
COUNT(*) as total_referrals,
|
COUNT(
|
||||||
COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) as completed_referrals,
|
CASE
|
||||||
COALESCE(SUM(reward_amount), 0) as total_reward_earned,
|
WHEN status = 'COMPLETED' THEN 1
|
||||||
COALESCE(SUM(CASE WHEN status = 'PENDING' THEN reward_amount END), 0) as pending_rewards
|
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
|
FROM referrals
|
||||||
WHERE referrer_id = $1
|
WHERE referrer_id = $1
|
||||||
|
AND company_id = $2
|
||||||
`
|
`
|
||||||
|
|
||||||
|
type GetReferralStatsParams struct {
|
||||||
|
ReferrerID int64 `json:"referrer_id"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
}
|
||||||
|
|
||||||
type GetReferralStatsRow struct {
|
type GetReferralStatsRow struct {
|
||||||
TotalReferrals int64 `json:"total_referrals"`
|
TotalReferrals int64 `json:"total_referrals"`
|
||||||
CompletedReferrals int64 `json:"completed_referrals"`
|
CompletedReferrals int64 `json:"completed_referrals"`
|
||||||
|
|
@ -220,8 +254,8 @@ type GetReferralStatsRow struct {
|
||||||
PendingRewards interface{} `json:"pending_rewards"`
|
PendingRewards interface{} `json:"pending_rewards"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetReferralStats(ctx context.Context, referrerID string) (GetReferralStatsRow, error) {
|
func (q *Queries) GetReferralStats(ctx context.Context, arg GetReferralStatsParams) (GetReferralStatsRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetReferralStats, referrerID)
|
row := q.db.QueryRow(ctx, GetReferralStats, arg.ReferrerID, arg.CompanyID)
|
||||||
var i GetReferralStatsRow
|
var i GetReferralStatsRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.TotalReferrals,
|
&i.TotalReferrals,
|
||||||
|
|
@ -234,17 +268,16 @@ func (q *Queries) GetReferralStats(ctx context.Context, referrerID string) (GetR
|
||||||
|
|
||||||
const UpdateReferral = `-- name: UpdateReferral :one
|
const UpdateReferral = `-- name: UpdateReferral :one
|
||||||
UPDATE referrals
|
UPDATE referrals
|
||||||
SET
|
SET referred_id = $2,
|
||||||
referred_id = $2,
|
status = $3,
|
||||||
status = $3,
|
updated_at = CURRENT_TIMESTAMP
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at
|
RETURNING id, company_id, referral_code, referrer_id, referred_id, status, reward_amount, cashback_amount, created_at, updated_at, expires_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateReferralParams struct {
|
type UpdateReferralParams struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
ReferredID pgtype.Text `json:"referred_id"`
|
ReferredID pgtype.Int8 `json:"referred_id"`
|
||||||
Status Referralstatus `json:"status"`
|
Status Referralstatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,6 +286,7 @@ func (q *Queries) UpdateReferral(ctx context.Context, arg UpdateReferralParams)
|
||||||
var i Referral
|
var i Referral
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
&i.CompanyID,
|
||||||
&i.ReferralCode,
|
&i.ReferralCode,
|
||||||
&i.ReferrerID,
|
&i.ReferrerID,
|
||||||
&i.ReferredID,
|
&i.ReferredID,
|
||||||
|
|
@ -268,9 +302,8 @@ func (q *Queries) UpdateReferral(ctx context.Context, arg UpdateReferralParams)
|
||||||
|
|
||||||
const UpdateReferralCode = `-- name: UpdateReferralCode :exec
|
const UpdateReferralCode = `-- name: UpdateReferralCode :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET
|
SET referral_code = $2,
|
||||||
referral_code = $2,
|
updated_at = CURRENT_TIMESTAMP
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -286,14 +319,13 @@ func (q *Queries) UpdateReferralCode(ctx context.Context, arg UpdateReferralCode
|
||||||
|
|
||||||
const UpdateReferralSettings = `-- name: UpdateReferralSettings :one
|
const UpdateReferralSettings = `-- name: UpdateReferralSettings :one
|
||||||
UPDATE referral_settings
|
UPDATE referral_settings
|
||||||
SET
|
SET referral_reward_amount = $2,
|
||||||
referral_reward_amount = $2,
|
cashback_percentage = $3,
|
||||||
cashback_percentage = $3,
|
bet_referral_bonus_percentage = $4,
|
||||||
bet_referral_bonus_percentage= $4,
|
max_referrals = $5,
|
||||||
max_referrals = $5,
|
expires_after_days = $6,
|
||||||
expires_after_days = $6,
|
updated_by = $7,
|
||||||
updated_by = $7,
|
updated_at = CURRENT_TIMESTAMP
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $1
|
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
|
RETURNING id, referral_reward_amount, cashback_percentage, bet_referral_bonus_percentage, max_referrals, expires_after_days, updated_by, created_at, updated_at, version
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -587,7 +587,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 +596,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 +605,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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,9 @@ type ReferralSettingsReq struct {
|
||||||
type Referral struct {
|
type Referral struct {
|
||||||
ID int64
|
ID int64
|
||||||
ReferralCode string
|
ReferralCode string
|
||||||
ReferrerID string
|
ReferrerID int64
|
||||||
ReferredID *string
|
CompanyID int64
|
||||||
|
ReferredID *int64
|
||||||
Status ReferralStatus
|
Status ReferralStatus
|
||||||
RewardAmount float64
|
RewardAmount float64
|
||||||
CashbackAmount float64
|
CashbackAmount float64
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ type ReferralRepository interface {
|
||||||
CreateReferral(ctx context.Context, referral *domain.Referral) error
|
CreateReferral(ctx context.Context, referral *domain.Referral) error
|
||||||
GetReferralByCode(ctx context.Context, code string) (*domain.Referral, error)
|
GetReferralByCode(ctx context.Context, code string) (*domain.Referral, error)
|
||||||
UpdateReferral(ctx context.Context, referral *domain.Referral) error
|
UpdateReferral(ctx context.Context, referral *domain.Referral) error
|
||||||
GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error)
|
GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error)
|
||||||
GetSettings(ctx context.Context) (*domain.ReferralSettings, error)
|
GetSettings(ctx context.Context) (*domain.ReferralSettings, error)
|
||||||
UpdateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
UpdateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
||||||
CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
||||||
GetReferralByReferredID(ctx context.Context, referredID string) (*domain.Referral, error) // New method
|
GetReferralByReferredID(ctx context.Context, referredID int64) (*domain.Referral, error)
|
||||||
GetReferralCountByID(ctx context.Context, referrerID string) (int64, error)
|
GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error)
|
||||||
GetActiveReferralByReferrerID(ctx context.Context, referrerID string) (*domain.Referral, error)
|
GetActiveReferralByReferrerID(ctx context.Context, referrerID int64) (*domain.Referral, error)
|
||||||
UpdateUserReferalCode(ctx context.Context, codedata domain.UpdateUserReferalCode) error
|
UpdateUserReferalCode(ctx context.Context, codedata domain.UpdateUserReferalCode) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,6 +58,7 @@ func (r *ReferralRepo) CreateReferral(ctx context.Context, referral *domain.Refe
|
||||||
Status: dbgen.Referralstatus(referral.Status),
|
Status: dbgen.Referralstatus(referral.Status),
|
||||||
RewardAmount: rewardAmount,
|
RewardAmount: rewardAmount,
|
||||||
ExpiresAt: pgtype.Timestamptz{Time: referral.ExpiresAt, Valid: true},
|
ExpiresAt: pgtype.Timestamptz{Time: referral.ExpiresAt, Valid: true},
|
||||||
|
CompanyID: referral.CompanyID,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := r.store.queries.CreateReferral(ctx, params)
|
_, err := r.store.queries.CreateReferral(ctx, params)
|
||||||
|
|
@ -76,9 +77,9 @@ func (r *ReferralRepo) GetReferralByCode(ctx context.Context, code string) (*dom
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) UpdateReferral(ctx context.Context, referral *domain.Referral) error {
|
func (r *ReferralRepo) UpdateReferral(ctx context.Context, referral *domain.Referral) error {
|
||||||
var referredID pgtype.Text
|
var referredID pgtype.Int8
|
||||||
if referral.ReferredID != nil {
|
if referral.ReferredID != nil {
|
||||||
referredID = pgtype.Text{String: *referral.ReferredID, Valid: true}
|
referredID = pgtype.Int8{Int64: *referral.ReferredID, Valid: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
params := dbgen.UpdateReferralParams{
|
params := dbgen.UpdateReferralParams{
|
||||||
|
|
@ -91,8 +92,11 @@ func (r *ReferralRepo) UpdateReferral(ctx context.Context, referral *domain.Refe
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error) {
|
func (r *ReferralRepo) GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error) {
|
||||||
stats, err := r.store.queries.GetReferralStats(ctx, userID)
|
stats, err := r.store.queries.GetReferralStats(ctx, dbgen.GetReferralStatsParams{
|
||||||
|
ReferrerID: userID,
|
||||||
|
CompanyID: companyID,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -175,8 +179,8 @@ func (r *ReferralRepo) CreateSettings(ctx context.Context, settings *domain.Refe
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) GetReferralByReferredID(ctx context.Context, referredID string) (*domain.Referral, error) {
|
func (r *ReferralRepo) GetReferralByReferredID(ctx context.Context, referredID int64) (*domain.Referral, error) {
|
||||||
dbReferral, err := r.store.queries.GetReferralByReferredID(ctx, pgtype.Text{String: referredID, Valid: true})
|
dbReferral, err := r.store.queries.GetReferralByReferredID(ctx, pgtype.Int8{Int64: referredID, Valid: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -186,7 +190,7 @@ func (r *ReferralRepo) GetReferralByReferredID(ctx context.Context, referredID s
|
||||||
return r.mapToDomainReferral(&dbReferral), nil
|
return r.mapToDomainReferral(&dbReferral), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) GetReferralCountByID(ctx context.Context, referrerID string) (int64, error) {
|
func (r *ReferralRepo) GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error) {
|
||||||
count, err := r.store.queries.GetReferralCountByID(ctx, referrerID)
|
count, err := r.store.queries.GetReferralCountByID(ctx, referrerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
|
@ -198,7 +202,7 @@ func (r *ReferralRepo) GetReferralCountByID(ctx context.Context, referrerID stri
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) GetActiveReferralByReferrerID(ctx context.Context, referrerID string) (*domain.Referral, error) {
|
func (r *ReferralRepo) GetActiveReferralByReferrerID(ctx context.Context, referrerID int64) (*domain.Referral, error) {
|
||||||
referral, err := r.store.queries.GetActiveReferralByReferrerID(ctx, referrerID)
|
referral, err := r.store.queries.GetActiveReferralByReferrerID(ctx, referrerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
|
@ -211,9 +215,9 @@ func (r *ReferralRepo) GetActiveReferralByReferrerID(ctx context.Context, referr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) mapToDomainReferral(dbRef *dbgen.Referral) *domain.Referral {
|
func (r *ReferralRepo) mapToDomainReferral(dbRef *dbgen.Referral) *domain.Referral {
|
||||||
var referredID *string
|
var referredID *int64
|
||||||
if dbRef.ReferredID.Valid {
|
if dbRef.ReferredID.Valid {
|
||||||
referredID = &dbRef.ReferredID.String
|
referredID = &dbRef.ReferredID.Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
rewardAmount := 0.0
|
rewardAmount := 0.0
|
||||||
|
|
|
||||||
|
|
@ -428,7 +428,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 +449,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
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import (
|
||||||
|
|
||||||
type ReferralStore interface {
|
type ReferralStore interface {
|
||||||
GenerateReferralCode() (string, error)
|
GenerateReferralCode() (string, error)
|
||||||
CreateReferral(ctx context.Context, userID int64) error
|
CreateReferral(ctx context.Context, userID int64, companyID int64) error
|
||||||
ProcessReferral(ctx context.Context, referredPhone, referralCode string, companyID int64) error
|
ProcessReferral(ctx context.Context, referredPhone, referralCode string, companyID int64) error
|
||||||
ProcessDepositBonus(ctx context.Context, userID string, amount float64) error
|
ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error
|
||||||
GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error)
|
ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error
|
||||||
|
GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error)
|
||||||
CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error
|
CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error
|
||||||
UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
||||||
GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error)
|
GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error)
|
||||||
GetReferralCountByID(ctx context.Context, referrerID string) (int64, error)
|
GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error)
|
||||||
ProcessBetReferral(ctx context.Context, userPhone string, betAmount float64) error
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,11 @@ func (s *Service) GenerateReferralCode() (string, error) {
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) CreateReferral(ctx context.Context, userID int64) error {
|
func (s *Service) CreateReferral(ctx context.Context, userID int64, companyID int64) error {
|
||||||
s.logger.Info("Creating referral code for user", "userID", userID)
|
s.logger.Info("Creating referral code for user", "userID", userID)
|
||||||
|
|
||||||
// check if user already has an active referral code
|
// check if user already has an active referral code
|
||||||
referral, err := s.repo.GetActiveReferralByReferrerID(ctx, fmt.Sprintf("%d", userID))
|
referral, err := s.repo.GetActiveReferralByReferrerID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to check if user alredy has active referral code", "error", err)
|
s.logger.Error("Failed to check if user alredy has active referral code", "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -73,7 +73,7 @@ func (s *Service) CreateReferral(ctx context.Context, userID int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check referral count limit
|
// check referral count limit
|
||||||
referralCount, err := s.GetReferralCountByID(ctx, fmt.Sprintf("%d", userID))
|
referralCount, err := s.GetReferralCountByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get referral count", "userID", userID, "error", err)
|
s.logger.Error("Failed to get referral count", "userID", userID, "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -96,10 +96,11 @@ func (s *Service) CreateReferral(ctx context.Context, userID int64) error {
|
||||||
|
|
||||||
if err := s.repo.CreateReferral(ctx, &domain.Referral{
|
if err := s.repo.CreateReferral(ctx, &domain.Referral{
|
||||||
ReferralCode: code,
|
ReferralCode: code,
|
||||||
ReferrerID: fmt.Sprintf("%d", userID),
|
ReferrerID: userID,
|
||||||
Status: domain.ReferralPending,
|
Status: domain.ReferralPending,
|
||||||
RewardAmount: rewardAmount,
|
RewardAmount: rewardAmount,
|
||||||
ExpiresAt: expireDuration,
|
ExpiresAt: expireDuration,
|
||||||
|
CompanyID: companyID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +139,7 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
|
||||||
return ErrInvalidReferralSignup
|
return ErrInvalidReferralSignup
|
||||||
}
|
}
|
||||||
|
|
||||||
referral.ReferredID = &referredPhone
|
referral.ReferredID = &user.ID
|
||||||
referral.Status = domain.ReferralCompleted
|
referral.Status = domain.ReferralCompleted
|
||||||
referral.UpdatedAt = time.Now()
|
referral.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
|
@ -147,13 +148,7 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
referrerId, err := strconv.Atoi(referral.ReferrerID)
|
wallets, err := s.store.GetCustomerWallet(ctx, referral.ReferrerID)
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to convert referrer id", "referrerId", referral.ReferrerID, "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
wallets, err := s.store.GetCustomerWallet(ctx, int64(referrerId))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get referrer wallets", "referrerId", referral.ReferrerID, "error", err)
|
s.logger.Error("Failed to get referrer wallets", "referrerId", referral.ReferrerID, "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -161,7 +156,7 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
|
||||||
|
|
||||||
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID,
|
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID,
|
||||||
domain.ToCurrency(float32(referral.RewardAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
domain.ToCurrency(float32(referral.RewardAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
||||||
fmt.Sprintf("Added %v to static wallet because of referral ID %v", referral.RewardAmount, referrerId),
|
fmt.Sprintf("Added %v to static wallet because of referral ID %v", referral.RewardAmount, referral.ReferrerID),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to add referral reward to static wallet", "walletID", wallets.StaticID, "referrer phone number", referredPhone, "error", err)
|
s.logger.Error("Failed to add referral reward to static wallet", "walletID", wallets.StaticID, "referrer phone number", referredPhone, "error", err)
|
||||||
|
|
@ -212,8 +207,8 @@ func (s *Service) ProcessDepositBonus(ctx context.Context, userPhone string, amo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ProcessBetReferral(ctx context.Context, userPhone string, betAmount float64) error {
|
func (s *Service) ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error {
|
||||||
s.logger.Info("Processing bet referral", "userPhone", userPhone, "betAmount", betAmount)
|
s.logger.Info("Processing bet referral", "userID", userId, "betAmount", betAmount)
|
||||||
|
|
||||||
settings, err := s.repo.GetSettings(ctx)
|
settings, err := s.repo.GetSettings(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -221,29 +216,24 @@ func (s *Service) ProcessBetReferral(ctx context.Context, userPhone string, betA
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
referral, err := s.repo.GetReferralByReferredID(ctx, userPhone)
|
referral, err := s.repo.GetReferralByReferredID(ctx, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get referral by referred ID", "userPhone", userPhone, "error", err)
|
s.logger.Error("Failed to get referral by referred ID", "userId", userId, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if referral == nil || referral.Status != domain.ReferralCompleted {
|
if referral == nil || referral.Status != domain.ReferralCompleted {
|
||||||
s.logger.Warn("No valid referral found", "userPhone", userPhone, "status", referral.Status)
|
s.logger.Warn("No valid referral found", "userId", userId, "status", referral.Status)
|
||||||
return ErrNoReferralFound
|
return ErrNoReferralFound
|
||||||
}
|
}
|
||||||
|
|
||||||
referrerID, err := strconv.ParseInt(referral.ReferrerID, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Invalid referrer phone number format", "referrerID", referral.ReferrerID, "error", err)
|
|
||||||
return errors.New("invalid referrer phone number format")
|
|
||||||
}
|
|
||||||
|
|
||||||
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referrerID)
|
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referral.ReferrerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get wallets for referrer", "referrerID", referrerID, "error", err)
|
s.logger.Error("Failed to get wallets for referrer", "referrerID", referral.ReferrerID, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(wallets) == 0 {
|
if len(wallets) == 0 {
|
||||||
s.logger.Error("Referrer has no wallet", "referrerID", referrerID)
|
s.logger.Error("Referrer has no wallet", "referrerID", referral.ReferrerID)
|
||||||
return errors.New("referrer has no wallet")
|
return errors.New("referrer has no wallet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,24 +250,24 @@ func (s *Service) ProcessBetReferral(ctx context.Context, userPhone string, betA
|
||||||
domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
||||||
fmt.Sprintf("Added %v to static wallet because of bet referral", referral.RewardAmount))
|
fmt.Sprintf("Added %v to static wallet because of bet referral", referral.RewardAmount))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referrerID, "bonus", bonus, "error", err)
|
s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referral.ReferrerID, "bonus", bonus, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Info("Bet referral processed successfully", "userPhone", userPhone, "referrerID", referrerID, "bonus", bonus)
|
s.logger.Info("Bet referral processed successfully", "referrer ID", referral.ReferrerID, "referrerID", referral.ReferrerID, "bonus", bonus)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetReferralStats(ctx context.Context, userPhone string) (*domain.ReferralStats, error) {
|
func (s *Service) GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error) {
|
||||||
s.logger.Info("Fetching referral stats", "userPhone", userPhone)
|
s.logger.Info("Fetching referral stats", "userID", userID)
|
||||||
|
|
||||||
stats, err := s.repo.GetReferralStats(ctx, userPhone)
|
stats, err := s.repo.GetReferralStats(ctx, userID, companyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get referral stats", "userPhone", userPhone, "error", err)
|
s.logger.Error("Failed to get referral stats", "userID", userID, "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Info("Referral stats retrieved successfully", "userPhone", userPhone, "totalReferrals", stats.TotalReferrals)
|
s.logger.Info("Referral stats retrieved successfully", "userID", userID, "totalReferrals", stats.TotalReferrals)
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -328,7 +318,7 @@ func (s *Service) GetReferralSettings(ctx context.Context) (*domain.ReferralSett
|
||||||
return settings, nil
|
return settings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetReferralCountByID(ctx context.Context, referrerID string) (int64, error) {
|
func (s *Service) GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error) {
|
||||||
count, err := s.repo.GetReferralCountByID(ctx, referrerID)
|
count, err := s.repo.GetReferralCountByID(ctx, referrerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get referral count", "userID", referrerID, "error", err)
|
s.logger.Error("Failed to get referral count", "userID", referrerID, "error", err)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ type UserStore interface {
|
||||||
GetUserByEmail(ctx context.Context, email string, companyID domain.ValidInt64) (domain.User, error)
|
GetUserByEmail(ctx context.Context, email string, companyID domain.ValidInt64) (domain.User, error)
|
||||||
GetUserByPhone(ctx context.Context, phoneNum string, companyID domain.ValidInt64) (domain.User, error)
|
GetUserByPhone(ctx context.Context, phoneNum string, companyID domain.ValidInt64) (domain.User, error)
|
||||||
SearchUserByNameOrPhone(ctx context.Context, searchString string, role *domain.Role, companyID domain.ValidInt64) ([]domain.User, error)
|
SearchUserByNameOrPhone(ctx context.Context, searchString string, role *domain.Role, companyID domain.ValidInt64) ([]domain.User, error)
|
||||||
UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64) error // identifier verified email or phone
|
UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64, companyId int64) error
|
||||||
|
|
||||||
GetCustomerCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
GetCustomerCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
||||||
GetCustomerDetails(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.CustomerDetail, error)
|
GetCustomerDetails(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.CustomerDetail, error)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func (s *Service) ResetPassword(ctx context.Context, resetReq domain.ResetPasswo
|
||||||
}
|
}
|
||||||
// reset pass and mark otp as used
|
// reset pass and mark otp as used
|
||||||
|
|
||||||
err = s.userStore.UpdatePassword(ctx, sentTo, hashedPassword, otp.ID)
|
err = s.userStore.UpdatePassword(ctx, sentTo, hashedPassword, otp.ID, resetReq.CompanyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,10 +156,10 @@ func SetupReportandVirtualGameCronJobs(
|
||||||
spec string
|
spec string
|
||||||
period string
|
period string
|
||||||
}{
|
}{
|
||||||
{
|
// {
|
||||||
spec: "*/60 * * * * *", // Every 1 minute for testing
|
// spec: "*/60 * * * * *", // Every 1 minute for testing
|
||||||
period: "test",
|
// period: "test",
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
spec: "0 0 0 * * *", // Daily at midnight
|
spec: "0 0 0 * * *", // Daily at midnight
|
||||||
period: "daily",
|
period: "daily",
|
||||||
|
|
@ -254,8 +254,6 @@ func SetupReportandVirtualGameCronJobs(
|
||||||
log.Printf("Cron jobs started. Reports will be saved to: %s", outputDir)
|
log.Printf("Cron jobs started. Reports will be saved to: %s", outputDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func ProcessBetCashback(ctx context.Context, betService *betSvc.Service) {
|
func ProcessBetCashback(ctx context.Context, betService *betSvc.Service) {
|
||||||
c := cron.New(cron.WithSeconds())
|
c := cron.New(cron.WithSeconds())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,11 +196,13 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companyFilter := int64(c.QueryInt("company_id"))
|
||||||
filter := domain.UserFilter{
|
filter := domain.UserFilter{
|
||||||
Role: string(domain.RoleAdmin),
|
Role: string(domain.RoleAdmin),
|
||||||
CompanyID: domain.ValidInt64{
|
CompanyID: domain.ValidInt64{
|
||||||
Value: int64(c.QueryInt("company_id")),
|
Value: companyFilter,
|
||||||
Valid: false,
|
Valid: companyFilter != 0,
|
||||||
},
|
},
|
||||||
Page: domain.ValidInt{
|
Page: domain.ValidInt{
|
||||||
Value: c.QueryInt("page", 1) - 1,
|
Value: c.QueryInt("page", 1) - 1,
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,13 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusForbidden, "Only customers are allowed to login ")
|
return fiber.NewError(fiber.StatusForbidden, "Only customers are allowed to login ")
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, err := jwtutil.CreateJwt(successRes.UserId, successRes.Role, successRes.CompanyID, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
accessToken, err := jwtutil.CreateJwt(
|
||||||
|
successRes.UserId,
|
||||||
|
successRes.Role,
|
||||||
|
successRes.CompanyID,
|
||||||
|
h.jwtConfig.JwtAccessKey,
|
||||||
|
h.jwtConfig.JwtAccessExpiry,
|
||||||
|
);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to create access token",
|
h.mongoLoggerSvc.Error("Failed to create access token",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
|
|
||||||
|
|
@ -379,9 +379,110 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/sport/bet [get]
|
// @Router /api/v1/{tenant_slug}/sport/bet [get]
|
||||||
func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
||||||
|
role := c.Locals("role").(domain.Role)
|
||||||
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
// branchID := c.Locals("branch_id").(domain.ValidInt64)
|
||||||
|
|
||||||
|
var isShopBet domain.ValidBool
|
||||||
|
isShopBetQuery := c.Query("is_shop")
|
||||||
|
if isShopBetQuery != "" && role == domain.RoleSuperAdmin {
|
||||||
|
isShopBetParse, err := strconv.ParseBool(isShopBetQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("failed to parse is_shop_bet",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.String("is_shop", isShopBetQuery),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "failed to parse is_shop_bet")
|
||||||
|
}
|
||||||
|
isShopBet = domain.ValidBool{
|
||||||
|
Value: isShopBetParse,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchQuery := c.Query("query")
|
||||||
|
searchString := domain.ValidString{
|
||||||
|
Value: searchQuery,
|
||||||
|
Valid: searchQuery != "",
|
||||||
|
}
|
||||||
|
|
||||||
|
createdBeforeQuery := c.Query("created_before")
|
||||||
|
var createdBefore domain.ValidTime
|
||||||
|
if createdBeforeQuery != "" {
|
||||||
|
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("invalid created_before format",
|
||||||
|
zap.String("time", createdBeforeQuery),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format")
|
||||||
|
}
|
||||||
|
createdBefore = domain.ValidTime{
|
||||||
|
Value: createdBeforeParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAfterQuery := c.Query("created_after")
|
||||||
|
var createdAfter domain.ValidTime
|
||||||
|
if createdAfterQuery != "" {
|
||||||
|
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("invalid created_after format",
|
||||||
|
zap.String("created_after", createdAfterQuery),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format")
|
||||||
|
}
|
||||||
|
createdAfter = domain.ValidTime{
|
||||||
|
Value: createdAfterParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{
|
||||||
|
IsShopBet: isShopBet,
|
||||||
|
Query: searchString,
|
||||||
|
CreatedBefore: createdBefore,
|
||||||
|
CreatedAfter: createdAfter,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get all bets",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets፡"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]domain.BetRes, len(bets))
|
||||||
|
for i, bet := range bets {
|
||||||
|
res[i] = domain.ConvertBet(bet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All bets retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllTenants godoc
|
||||||
|
// @Summary Gets all bets
|
||||||
|
// @Description Gets all the bets
|
||||||
|
// @Tags bet
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.BetRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/{tenant_slug}/sport/bet [get]
|
||||||
|
func (h *Handler) GetAllTenantBets(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
h.BadRequestLogger().Error("invalid company id", zap.Any("company_id", companyID))
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
}
|
||||||
role := c.Locals("role").(domain.Role)
|
role := c.Locals("role").(domain.Role)
|
||||||
|
|
@ -485,8 +586,54 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
|
||||||
// @Success 200 {object} domain.BetRes
|
// @Success 200 {object} domain.BetRes
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/sport/bet/{id} [get]
|
// @Router /api/v1/sport/bet/{id} [get]
|
||||||
func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
func (h *Handler) GetBetByID(c *fiber.Ctx) error {
|
||||||
|
betID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(betID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Invalid bet ID",
|
||||||
|
zap.String("betID", betID),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
bet, err := h.betSvc.GetBetByID(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to get bet by ID",
|
||||||
|
zap.Int64("betID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusNotFound),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, "Failed to retrieve bet")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := domain.ConvertBet(bet)
|
||||||
|
|
||||||
|
// h.mongoLoggerSvc.Info("Bet retrieved successfully",
|
||||||
|
// zap.Int64("betID", id),
|
||||||
|
// zap.Int("status_code", fiber.StatusOK),
|
||||||
|
// zap.Time("timestamp", time.Now()),
|
||||||
|
// )
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Bet retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTenantBetByID godoc
|
||||||
|
// @Summary Gets bet by id
|
||||||
|
// @Description Gets a single bet by id
|
||||||
|
// @Tags bet
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Bet ID"
|
||||||
|
// @Success 200 {object} domain.BetRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/{tenant_slug}/sport/bet/{id} [get]
|
||||||
|
func (h *Handler) GetTenantBetByID(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
|
@ -696,8 +843,52 @@ func (h *Handler) UpdateCashOut(c *fiber.Ctx) error {
|
||||||
// @Success 200 {object} response.APIResponse
|
// @Success 200 {object} response.APIResponse
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/sport/bet/{id} [delete]
|
// @Router /api/v1/sport/bet/{id} [delete]
|
||||||
func (h *Handler) DeleteBet(c *fiber.Ctx) error {
|
func (h *Handler) DeleteBet(c *fiber.Ctx) error {
|
||||||
|
betID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(betID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid bet ID",
|
||||||
|
zap.String("betID", betID),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.betSvc.SetBetToRemoved(c.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to delete bet by ID",
|
||||||
|
zap.Int64("betID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete bet:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
h.mongoLoggerSvc.Info("Bet removed successfully",
|
||||||
|
zap.Int64("betID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusOK),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Bet removed successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTenantBet godoc
|
||||||
|
// @Summary Deletes bet by id
|
||||||
|
// @Description Deletes bet by id
|
||||||
|
// @Tags bet
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Bet ID"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/{tenant_slug}/sport/bet/{id} [delete]
|
||||||
|
func (h *Handler) DeleteTenantBet(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,7 @@ func (h *Handler) CreateBranchOperation(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Branch Operation Created", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Operation Created", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// GetBranchByID godoc
|
// GetBranchByID godoc
|
||||||
// @Summary Gets branch by id
|
// @Summary Gets branch by id
|
||||||
// @Description Gets a single branch by id
|
// @Description Gets a single branch by id
|
||||||
|
|
@ -295,6 +296,108 @@ func (h *Handler) GetBranchByID(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Branch retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Branch retrieved successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReturnBranchWallet godoc
|
||||||
|
// @Summary Unassign the branch wallet to company
|
||||||
|
// @Description Unassign the branch wallet to company
|
||||||
|
// @Tags branch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Branch ID"
|
||||||
|
// @Success 200 {object} domain.BranchDetailRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/branch/{id}/return [post]
|
||||||
|
func (h *Handler) ReturnBranchWallet(c *fiber.Ctx) error {
|
||||||
|
userID := c.Locals("user_id").(int64)
|
||||||
|
|
||||||
|
branchID := c.Params("id")
|
||||||
|
id, err := strconv.ParseInt(branchID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Invalid branch ID",
|
||||||
|
zap.String("branch", branchID),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid branch ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := h.branchSvc.GetBranchByID(c.Context(), id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to get branch by ID",
|
||||||
|
zap.Int64("branchID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := h.companySvc.GetCompanyByID(c.Context(), branch.CompanyID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to get company by ID",
|
||||||
|
zap.Int64("branchID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
branchWallet, err := h.walletSvc.GetWalletByID(c.Context(), branch.WalletID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to get wallet by ID",
|
||||||
|
zap.Int64("branchID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.walletSvc.AddToWallet(c.Context(),
|
||||||
|
company.WalletID,
|
||||||
|
branchWallet.Balance,
|
||||||
|
domain.ValidInt64{Value: userID, Valid: true},
|
||||||
|
domain.TRANSFER_DIRECT,
|
||||||
|
domain.PaymentDetails{},
|
||||||
|
fmt.Sprintf("Returning Branch %v Wallet to Company", branch.Name))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to add to company wallet",
|
||||||
|
zap.Int64("branchID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.walletSvc.DeductFromWallet(c.Context(),
|
||||||
|
branchWallet.ID,
|
||||||
|
branchWallet.Balance,
|
||||||
|
domain.ValidInt64{Value: userID, Valid: true},
|
||||||
|
domain.TRANSFER_DIRECT,
|
||||||
|
"Branch Wallet Balance has been returned to Company",
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to deduct from branch wallet",
|
||||||
|
zap.Int64("branchID", id),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
res := domain.ConvertBranchDetail(branch)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Branch Wallet Has been emptied", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// GetBranchByManagerID godoc
|
// GetBranchByManagerID godoc
|
||||||
// @Summary Gets branches by manager id
|
// @Summary Gets branches by manager id
|
||||||
// @Description Gets a branches by manager id
|
// @Description Gets a branches by manager id
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ type CustomersRes struct {
|
||||||
LastLogin time.Time `json:"last_login"`
|
LastLogin time.Time `json:"last_login"`
|
||||||
SuspendedAt time.Time `json:"suspended_at"`
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
Suspended bool `json:"suspended"`
|
Suspended bool `json:"suspended"`
|
||||||
|
CompanyID int64 `json:"company_id"`
|
||||||
|
CompanyName string `json:"company_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllCustomers godoc
|
// GetAllCustomers godoc
|
||||||
|
|
@ -156,6 +158,30 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error {
|
||||||
"Failed to retrieve user last login:"+err.Error())
|
"Failed to retrieve user last login:"+err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !customer.CompanyID.Valid {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company ID",
|
||||||
|
zap.Int64("userID", customer.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to retrieve company id for customer:")
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := h.companySvc.GetCompanyByID(c.Context(), customer.CompanyID.Value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company value",
|
||||||
|
zap.Int64("userID", customer.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to fetch company for customer:")
|
||||||
|
}
|
||||||
result[index] = CustomersRes{
|
result[index] = CustomersRes{
|
||||||
ID: customer.ID,
|
ID: customer.ID,
|
||||||
FirstName: customer.FirstName,
|
FirstName: customer.FirstName,
|
||||||
|
|
@ -170,6 +196,176 @@ func (h *Handler) GetAllCustomers(c *fiber.Ctx) error {
|
||||||
SuspendedAt: customer.SuspendedAt,
|
SuspendedAt: customer.SuspendedAt,
|
||||||
Suspended: customer.Suspended,
|
Suspended: customer.Suspended,
|
||||||
LastLogin: *lastLogin,
|
LastLogin: *lastLogin,
|
||||||
|
CompanyID: company.ID,
|
||||||
|
CompanyName: company.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WritePaginatedJSON(c, fiber.StatusOK, "Customers retrieved successfully", result, nil, filter.Page.Value, int(total))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllTenantCustomers godoc
|
||||||
|
// @Summary Get all Customers
|
||||||
|
// @Description Get all Customers
|
||||||
|
// @Tags customer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "Page number"
|
||||||
|
// @Param page_size query int false "Page size"
|
||||||
|
// @Success 200 {object} CustomersRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/tenant/{tenant_slug}/customer [get]
|
||||||
|
func (h *Handler) GetAllTenantCustomers(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
|
||||||
|
searchQuery := c.Query("query")
|
||||||
|
searchString := domain.ValidString{
|
||||||
|
Value: searchQuery,
|
||||||
|
Valid: searchQuery != "",
|
||||||
|
}
|
||||||
|
|
||||||
|
createdBeforeQuery := c.Query("created_before")
|
||||||
|
var createdBefore domain.ValidTime
|
||||||
|
if createdBeforeQuery != "" {
|
||||||
|
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("invalid created_before format",
|
||||||
|
zap.String("createdBefore", createdBeforeQuery),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format")
|
||||||
|
}
|
||||||
|
createdBefore = domain.ValidTime{
|
||||||
|
Value: createdBeforeParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAfterQuery := c.Query("created_after")
|
||||||
|
var createdAfter domain.ValidTime
|
||||||
|
if createdAfterQuery != "" {
|
||||||
|
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("invalid created_after format",
|
||||||
|
zap.String("createdAfter", createdAfterQuery),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format")
|
||||||
|
}
|
||||||
|
createdAfter = domain.ValidTime{
|
||||||
|
Value: createdAfterParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := domain.UserFilter{
|
||||||
|
Role: string(domain.RoleCustomer),
|
||||||
|
CompanyID: companyID,
|
||||||
|
Page: domain.ValidInt{
|
||||||
|
Value: c.QueryInt("page", 1) - 1,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
PageSize: domain.ValidInt{
|
||||||
|
Value: c.QueryInt("page_size", 10),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
Query: searchString,
|
||||||
|
CreatedBefore: createdBefore,
|
||||||
|
CreatedAfter: createdAfter,
|
||||||
|
}
|
||||||
|
valErrs, ok := h.validator.Validate(c, filter)
|
||||||
|
if !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
h.mongoLoggerSvc.Info("Failed to validate GetAllCustomer filters",
|
||||||
|
zap.Any("filter", filter),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.String("errMsg", errMsg),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
customers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("GetAllCustomers failed to get all users",
|
||||||
|
zap.Any("filter", filter),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Customers:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []CustomersRes = make([]CustomersRes, len(customers))
|
||||||
|
for index, customer := range customers {
|
||||||
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), customer.ID)
|
||||||
|
if err != nil {
|
||||||
|
if err == authentication.ErrRefreshTokenNotFound {
|
||||||
|
lastLogin = &customer.CreatedAt
|
||||||
|
} else {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||||
|
zap.Int64("userID", customer.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to retrieve user last login:"+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !customer.CompanyID.Valid {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company ID",
|
||||||
|
zap.Int64("userID", customer.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to retrieve company id for customer:")
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := h.companySvc.GetCompanyByID(c.Context(), customer.CompanyID.Value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company value",
|
||||||
|
zap.Int64("userID", customer.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to fetch company for customer:")
|
||||||
|
}
|
||||||
|
result[index] = CustomersRes{
|
||||||
|
ID: customer.ID,
|
||||||
|
FirstName: customer.FirstName,
|
||||||
|
LastName: customer.LastName,
|
||||||
|
Email: customer.Email,
|
||||||
|
PhoneNumber: customer.PhoneNumber,
|
||||||
|
Role: customer.Role,
|
||||||
|
EmailVerified: customer.EmailVerified,
|
||||||
|
PhoneVerified: customer.PhoneVerified,
|
||||||
|
CreatedAt: customer.CreatedAt,
|
||||||
|
UpdatedAt: customer.UpdatedAt,
|
||||||
|
SuspendedAt: customer.SuspendedAt,
|
||||||
|
Suspended: customer.Suspended,
|
||||||
|
LastLogin: *lastLogin,
|
||||||
|
CompanyID: company.ID,
|
||||||
|
CompanyName: company.Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,6 +418,29 @@ func (h *Handler) GetCustomerByID(c *fiber.Ctx) error {
|
||||||
lastLogin = &user.CreatedAt
|
lastLogin = &user.CreatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !user.CompanyID.Valid {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company ID",
|
||||||
|
zap.Int64("userID", user.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to retrieve company id for customer:")
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := h.companySvc.GetCompanyByID(c.Context(), user.CompanyID.Value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company value",
|
||||||
|
zap.Int64("userID", user.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to fetch company for customer:")
|
||||||
|
}
|
||||||
res := CustomersRes{
|
res := CustomersRes{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
FirstName: user.FirstName,
|
FirstName: user.FirstName,
|
||||||
|
|
@ -236,16 +455,226 @@ func (h *Handler) GetCustomerByID(c *fiber.Ctx) error {
|
||||||
SuspendedAt: user.SuspendedAt,
|
SuspendedAt: user.SuspendedAt,
|
||||||
Suspended: user.Suspended,
|
Suspended: user.Suspended,
|
||||||
LastLogin: *lastLogin,
|
LastLogin: *lastLogin,
|
||||||
|
CompanyID: company.ID,
|
||||||
|
CompanyName: company.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCustomerByID godoc
|
||||||
|
// @Summary Get customer by id
|
||||||
|
// @Description Get a single customer by id
|
||||||
|
// @Tags customer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {object} CustomersRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/tenant/{tenant_slug}/customer/{id} [get]
|
||||||
|
func (h *Handler) GetTenantCustomerByID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
|
||||||
|
userIDstr := c.Params("id")
|
||||||
|
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid customers ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get customers",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customers:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
||||||
|
if err != nil {
|
||||||
|
if err != authentication.ErrRefreshTokenNotFound {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLogin = &user.CreatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.CompanyID.Valid || user.CompanyID.Value != companyID.Value {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get customer",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customer:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
company, err := h.companySvc.GetCompanyByID(c.Context(), user.CompanyID.Value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user company value",
|
||||||
|
zap.Int64("userID", user.ID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError,
|
||||||
|
"Failed to fetch company for customer:")
|
||||||
|
}
|
||||||
|
res := CustomersRes{
|
||||||
|
ID: user.ID,
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: user.Email,
|
||||||
|
PhoneNumber: user.PhoneNumber,
|
||||||
|
Role: user.Role,
|
||||||
|
EmailVerified: user.EmailVerified,
|
||||||
|
PhoneVerified: user.PhoneVerified,
|
||||||
|
CreatedAt: user.CreatedAt,
|
||||||
|
UpdatedAt: user.UpdatedAt,
|
||||||
|
SuspendedAt: user.SuspendedAt,
|
||||||
|
Suspended: user.Suspended,
|
||||||
|
LastLogin: *lastLogin,
|
||||||
|
CompanyID: company.ID,
|
||||||
|
CompanyName: company.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTenantCustomerBets godoc
|
||||||
|
// @Summary Get tenant customer bets
|
||||||
|
// @Description Get tenant customer bets
|
||||||
|
// @Tags customer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {object} CustomersRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/tenant/{tenant_slug}/customer/{id}/bets [get]
|
||||||
|
func (h *Handler) GetTenantCustomerBets(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
|
||||||
|
userIDstr := c.Params("id")
|
||||||
|
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid customers ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get customers",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customers:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.CompanyID.Valid || user.CompanyID.Value != companyID.Value {
|
||||||
|
h.mongoLoggerSvc.Warn("User Attempt to access another companies customer",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customer bet")
|
||||||
|
}
|
||||||
|
|
||||||
|
bets, err := h.betSvc.GetBetByUserID(c.Context(), user.ID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get user bets",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get user bet:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]domain.BetRes, len(bets))
|
||||||
|
for i, bet := range bets {
|
||||||
|
res[i] = domain.ConvertBet(bet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "User's Bets retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomerBets godoc
|
||||||
|
// @Summary Get customer bets
|
||||||
|
// @Description Get customer bets
|
||||||
|
// @Tags customer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {object} CustomersRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/customer/{id}/bets [get]
|
||||||
|
func (h *Handler) GetCustomerBets(c *fiber.Ctx) error {
|
||||||
|
userIDstr := c.Params("id")
|
||||||
|
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid customers ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get customers",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get customers:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
bets, err := h.betSvc.GetBetByUserID(c.Context(), user.ID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get user bets",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get user bet:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]domain.BetRes, len(bets))
|
||||||
|
for i, bet := range bets {
|
||||||
|
res[i] = domain.ConvertBet(bet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "User's Bets retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
type updateCustomerReq struct {
|
type updateCustomerReq struct {
|
||||||
FirstName string `json:"first_name" example:"John"`
|
FirstName string `json:"first_name" example:"John"`
|
||||||
LastName string `json:"last_name" example:"Doe"`
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
Suspended bool `json:"suspended" example:"false"`
|
Suspended bool `json:"suspended" example:"false"`
|
||||||
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCustomers godoc
|
// UpdateCustomers godoc
|
||||||
|
|
@ -341,3 +770,108 @@ func (h *Handler) UpdateCustomer(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Customers updated successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Customers updated successfully", nil, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateTenantCustomer godoc
|
||||||
|
// @Summary Update Customers
|
||||||
|
// @Description Update Customers
|
||||||
|
// @Tags customer
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Customers body updateCustomerReq true "Update Customers"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/tenant/{tenant_slug}/customer/{id} [put]
|
||||||
|
func (h *Handler) UpdateTenantCustomer(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
var req updateCustomerReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("UpdateCustomers invalid request body",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := h.validator.Validate(c, req)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
h.mongoLoggerSvc.Info("Failed to validate UpdateCustomerReq",
|
||||||
|
zap.Any("request", req),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.String("ErrMsg", errMsg),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
CustomersIdStr := c.Params("id")
|
||||||
|
CustomersId, err := strconv.ParseInt(CustomersIdStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Invalid Customers ID",
|
||||||
|
zap.String("userID", CustomersIdStr),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Customers ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.userSvc.GetUserByID(c.Context(), CustomersId)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Customers Not Found",
|
||||||
|
zap.String("userID", CustomersIdStr),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Customers Not Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.CompanyID.Value != companyID.Value {
|
||||||
|
h.mongoLoggerSvc.Warn("User Attempt to update another companies customer",
|
||||||
|
zap.String("userID", CustomersIdStr),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Customers Not Found")
|
||||||
|
}
|
||||||
|
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
|
UserId: CustomersId,
|
||||||
|
FirstName: domain.ValidString{
|
||||||
|
Value: req.FirstName,
|
||||||
|
Valid: req.FirstName != "",
|
||||||
|
},
|
||||||
|
LastName: domain.ValidString{
|
||||||
|
Value: req.LastName,
|
||||||
|
Valid: req.LastName != "",
|
||||||
|
},
|
||||||
|
Suspended: domain.ValidBool{
|
||||||
|
Value: req.Suspended,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to update Customers",
|
||||||
|
zap.Int64("userID", CustomersId),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update Customers:"+err.Error())
|
||||||
|
}
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Customers updated successfully", nil, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
|
func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
userID, ok := c.Locals("user_id").(int64)
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
if !ok || userID == 0 {
|
if !ok || userID == 0 {
|
||||||
h.mongoLoggerSvc.Info("Invalid user ID in context",
|
h.mongoLoggerSvc.Info("Invalid user ID in context",
|
||||||
|
|
@ -21,7 +26,7 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
|
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.referralSvc.CreateReferral(c.Context(), userID); err != nil {
|
if err := h.referralSvc.CreateReferral(c.Context(), userID, companyID.Value); err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to create referral",
|
h.mongoLoggerSvc.Error("Failed to create referral",
|
||||||
zap.Int64("userID", userID),
|
zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
|
@ -35,6 +40,7 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error {
|
func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error {
|
||||||
|
|
||||||
var req domain.ReferralSettingsReq
|
var req domain.ReferralSettingsReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse settings",
|
h.mongoLoggerSvc.Info("Failed to parse settings",
|
||||||
|
|
@ -91,6 +97,57 @@ func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (h *Handler) GetReferralCode(c *fiber.Ctx) error {
|
||||||
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
// if !companyID.Valid {
|
||||||
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
// }
|
||||||
|
// userID, ok := c.Locals("user_id").(int64)
|
||||||
|
// if !ok || userID == 0 {
|
||||||
|
// h.mongoLoggerSvc.Error("Invalid user ID in context",
|
||||||
|
// zap.Int64("userID", userID),
|
||||||
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
// zap.Time("timestamp", time.Now()),
|
||||||
|
// )
|
||||||
|
// return fiber.NewError(fiber.StatusInternalServerError, "Invalid user id")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
// if err != nil {
|
||||||
|
// h.mongoLoggerSvc.Error("Failed to get user",
|
||||||
|
// zap.Int64("userID", userID),
|
||||||
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
// zap.Error(err),
|
||||||
|
// zap.Time("timestamp", time.Now()),
|
||||||
|
// )
|
||||||
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if !user.CompanyID.Valid || user.CompanyID.Value != companyID.Value {
|
||||||
|
// h.mongoLoggerSvc.Warn("User attempt to login to different company",
|
||||||
|
// zap.Int64("userID", userID),
|
||||||
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
// zap.Error(err),
|
||||||
|
// zap.Time("timestamp", time.Now()),
|
||||||
|
// )
|
||||||
|
// return fiber.NewError(fiber.StatusBadRequest, "Failed to retrieve user")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // referrals, err := h.referralSvc.GetReferralStats(c.Context(), user.ID)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// h.mongoLoggerSvc.Error("Failed to get user referrals",
|
||||||
|
// zap.Int64("userID", userID),
|
||||||
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
// zap.Error(err),
|
||||||
|
// zap.Time("timestamp", time.Now()),
|
||||||
|
// )
|
||||||
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user referral codes")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
// GetReferralStats godoc
|
// GetReferralStats godoc
|
||||||
// @Summary Get referral statistics
|
// @Summary Get referral statistics
|
||||||
// @Description Retrieves referral statistics for the authenticated user
|
// @Description Retrieves referral statistics for the authenticated user
|
||||||
|
|
@ -101,8 +158,13 @@ func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error {
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @Router /api/v1/referral/stats [get]
|
// @Router /api/v1/tenant/{tenant_slug}/referral/stats [get]
|
||||||
func (h *Handler) GetReferralStats(c *fiber.Ctx) error {
|
func (h *Handler) GetReferralStats(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
userID, ok := c.Locals("user_id").(int64)
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
if !ok || userID == 0 {
|
if !ok || userID == 0 {
|
||||||
h.mongoLoggerSvc.Error("Invalid user ID in context",
|
h.mongoLoggerSvc.Error("Invalid user ID in context",
|
||||||
|
|
@ -124,7 +186,17 @@ func (h *Handler) GetReferralStats(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
||||||
}
|
}
|
||||||
|
|
||||||
stats, err := h.referralSvc.GetReferralStats(c.Context(), user.PhoneNumber)
|
if !user.CompanyID.Valid || user.CompanyID.Value != companyID.Value {
|
||||||
|
h.mongoLoggerSvc.Warn("User attempt to login to different company",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Failed to retrieve user")
|
||||||
|
}
|
||||||
|
|
||||||
|
stats, err := h.referralSvc.GetReferralStats(c.Context(), user.ID, companyID.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to get referral stats",
|
h.mongoLoggerSvc.Error("Failed to get referral stats",
|
||||||
zap.Int64("userID", userID),
|
zap.Int64("userID", userID),
|
||||||
|
|
@ -227,33 +299,9 @@ func (h *Handler) GetReferralSettings(c *fiber.Ctx) error {
|
||||||
// h.logger.Error("Invalid user ID in context")
|
// h.logger.Error("Invalid user ID in context")
|
||||||
// return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
|
// return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
|
||||||
// }
|
// }
|
||||||
userID := int64(2)
|
|
||||||
|
|
||||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to get user",
|
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.Role != domain.RoleAdmin {
|
|
||||||
h.mongoLoggerSvc.Error("Admin access required",
|
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusForbidden),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusForbidden, "Admin access required")
|
|
||||||
}
|
|
||||||
|
|
||||||
settings, err := h.referralSvc.GetReferralSettings(c.Context())
|
settings, err := h.referralSvc.GetReferralSettings(c.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to get referral settings",
|
h.mongoLoggerSvc.Error("Failed to get referral settings",
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
zap.Time("timestamp", time.Now()),
|
||||||
|
|
|
||||||
438
internal/web_server/handlers/transaction_approver.go
Normal file
438
internal/web_server/handlers/transaction_approver.go
Normal file
|
|
@ -0,0 +1,438 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateTransactionApproverReq struct {
|
||||||
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
Password string `json:"password" example:"password123"`
|
||||||
|
CompanyID int64 `json:"company_id" example:"1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTransactionApprover godoc
|
||||||
|
// @Summary Create transaction approver
|
||||||
|
// @Description Create transaction approver
|
||||||
|
// @Tags admin
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param manger body CreateTransactionApproverReq true "Create transaction approver"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/admin [post]
|
||||||
|
func (h *Handler) CreateTransactionApprover(c *fiber.Ctx) error {
|
||||||
|
var companyID domain.ValidInt64
|
||||||
|
var req CreateTransactionApproverReq
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("failed to parse CreateAdmin request",
|
||||||
|
zap.Int64("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := h.validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
h.mongoLoggerSvc.Error("validation failed for CreateAdmin request",
|
||||||
|
zap.Int64("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Any("validation_errors", valErrs),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := h.companySvc.GetCompanyByID(c.Context(), req.CompanyID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
||||||
|
zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Int64("company_id", req.CompanyID),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
||||||
|
}
|
||||||
|
companyID = domain.ValidInt64{
|
||||||
|
Value: req.CompanyID,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
user := domain.CreateUserReq{
|
||||||
|
FirstName: req.FirstName,
|
||||||
|
LastName: req.LastName,
|
||||||
|
Email: req.Email,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
Password: req.Password,
|
||||||
|
Role: string(domain.RoleTransactionApprover),
|
||||||
|
CompanyID: companyID,
|
||||||
|
}
|
||||||
|
|
||||||
|
newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("failed to create admin user",
|
||||||
|
zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Any("request", req),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
h.mongoLoggerSvc.Info("transaction_approver created successfully",
|
||||||
|
zap.Int64("transaction_approver_id", newUser.ID),
|
||||||
|
zap.String("email", newUser.Email),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Transaction Approver created successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionApproverRes struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Role domain.Role `json:"role"`
|
||||||
|
EmailVerified bool `json:"email_verified"`
|
||||||
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
LastLogin time.Time `json:"last_login"`
|
||||||
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
|
Suspended bool `json:"suspended"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllAdmins godoc
|
||||||
|
// @Summary Get all Admins
|
||||||
|
// @Description Get all Admins
|
||||||
|
// @Tags admin
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "Page number"
|
||||||
|
// @Param page_size query int false "Page size"
|
||||||
|
// @Success 200 {object} AdminRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/t-approver [get]
|
||||||
|
func (h *Handler) GetAllTransactionApprovers(c *fiber.Ctx) error {
|
||||||
|
role := c.Locals("role").(domain.Role)
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
|
||||||
|
searchQuery := c.Query("query")
|
||||||
|
searchString := domain.ValidString{
|
||||||
|
Value: searchQuery,
|
||||||
|
Valid: searchQuery != "",
|
||||||
|
}
|
||||||
|
|
||||||
|
createdBeforeQuery := c.Query("created_before")
|
||||||
|
var createdBefore domain.ValidTime
|
||||||
|
if createdBeforeQuery != "" {
|
||||||
|
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Info("invalid start_time format", "error", err)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||||
|
}
|
||||||
|
createdBefore = domain.ValidTime{
|
||||||
|
Value: createdBeforeParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAfterQuery := c.Query("created_after")
|
||||||
|
var createdAfter domain.ValidTime
|
||||||
|
if createdAfterQuery != "" {
|
||||||
|
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Info("invalid start_time format", "error", err)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||||
|
}
|
||||||
|
createdAfter = domain.ValidTime{
|
||||||
|
Value: createdAfterParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var companyIDFilter domain.ValidInt64
|
||||||
|
if role == domain.RoleSuperAdmin {
|
||||||
|
companyIDQuery := int64(c.QueryInt("company_id"))
|
||||||
|
companyIDFilter = domain.ValidInt64{
|
||||||
|
Value: companyIDQuery,
|
||||||
|
Valid: companyIDQuery != 0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.logger.Info("invalid companyID")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Unable to get company ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
companyIDFilter = companyID
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := domain.UserFilter{
|
||||||
|
Role: string(domain.RoleTransactionApprover),
|
||||||
|
CompanyID: companyIDFilter,
|
||||||
|
Page: domain.ValidInt{
|
||||||
|
Value: c.QueryInt("page", 1) - 1,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
PageSize: domain.ValidInt{
|
||||||
|
Value: c.QueryInt("page_size", 10),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
Query: searchString,
|
||||||
|
CreatedBefore: createdBefore,
|
||||||
|
CreatedAfter: createdAfter,
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := h.validator.Validate(c, filter)
|
||||||
|
if !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
h.mongoLoggerSvc.Info("invalid filter values in GetAllAdmins request",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Any("validation_errors", valErrs),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
users, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("failed to get users from user service",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Any("filter", filter),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]TransactionApproverRes, len(users))
|
||||||
|
for index, admin := range users {
|
||||||
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID)
|
||||||
|
if err != nil {
|
||||||
|
if err == authentication.ErrRefreshTokenNotFound {
|
||||||
|
lastLogin = &admin.CreatedAt
|
||||||
|
} else {
|
||||||
|
h.mongoLoggerSvc.Error("failed to get last login for admin",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Int64("admin_id", admin.ID),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[index] = TransactionApproverRes{
|
||||||
|
ID: admin.ID,
|
||||||
|
FirstName: admin.FirstName,
|
||||||
|
LastName: admin.LastName,
|
||||||
|
Email: admin.Email,
|
||||||
|
PhoneNumber: admin.PhoneNumber,
|
||||||
|
Role: admin.Role,
|
||||||
|
EmailVerified: admin.EmailVerified,
|
||||||
|
PhoneVerified: admin.PhoneVerified,
|
||||||
|
CreatedAt: admin.CreatedAt,
|
||||||
|
UpdatedAt: admin.UpdatedAt,
|
||||||
|
SuspendedAt: admin.SuspendedAt,
|
||||||
|
Suspended: admin.Suspended,
|
||||||
|
LastLogin: *lastLogin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.mongoLoggerSvc.Info("approvers retrieved successfully",
|
||||||
|
zap.Int("status_code", fiber.StatusOK),
|
||||||
|
zap.Int("count", len(result)),
|
||||||
|
zap.Int("page", filter.Page.Value+1),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAdminByID godoc
|
||||||
|
// @Summary Get admin by id
|
||||||
|
// @Description Get a single admin by id
|
||||||
|
// @Tags admin
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID"
|
||||||
|
// @Success 200 {object} AdminRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/t-approver/{id} [get]
|
||||||
|
func (h *Handler) GetTransactionApproverByID(c *fiber.Ctx) error {
|
||||||
|
userIDstr := c.Params("id")
|
||||||
|
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("invalid admin ID param",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.String("param", userIDstr),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid admin ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("failed to fetch admin by ID",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Int64("admin_id", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get admin"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
||||||
|
if err != nil && err != authentication.ErrRefreshTokenNotFound {
|
||||||
|
h.mongoLoggerSvc.Error("failed to get admin last login",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Int64("admin_id", user.ID),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
||||||
|
}
|
||||||
|
if err == authentication.ErrRefreshTokenNotFound {
|
||||||
|
lastLogin = &user.CreatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
res := TransactionApproverRes{
|
||||||
|
ID: user.ID,
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
Email: user.Email,
|
||||||
|
PhoneNumber: user.PhoneNumber,
|
||||||
|
Role: user.Role,
|
||||||
|
EmailVerified: user.EmailVerified,
|
||||||
|
PhoneVerified: user.PhoneVerified,
|
||||||
|
CreatedAt: user.CreatedAt,
|
||||||
|
UpdatedAt: user.UpdatedAt,
|
||||||
|
SuspendedAt: user.SuspendedAt,
|
||||||
|
Suspended: user.Suspended,
|
||||||
|
LastLogin: *lastLogin,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.mongoLoggerSvc.Info("admin retrieved successfully",
|
||||||
|
zap.Int("status_code", fiber.StatusOK),
|
||||||
|
zap.Int64("admin_id", user.ID),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Admin retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type updateTransactionApproverReq struct {
|
||||||
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
|
Suspended bool `json:"suspended" example:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAdmin godoc
|
||||||
|
// @Summary Update Admin
|
||||||
|
// @Description Update Admin
|
||||||
|
// @Tags admin
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param admin body updateAdminReq true "Update Admin"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 401 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/t-approver/{id} [put]
|
||||||
|
func (h *Handler) UpdateTransactionApprover(c *fiber.Ctx) error {
|
||||||
|
var req updateTransactionApproverReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("UpdateAdmin failed - invalid request body",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
valErrs, ok := h.validator.Validate(c, req)
|
||||||
|
if !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
h.mongoLoggerSvc.Error("UpdateAdmin failed - validation errors",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Any("validation_errors", valErrs),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
ApproverIDStr := c.Params("id")
|
||||||
|
ApproverID, err := strconv.ParseInt(ApproverIDStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("UpdateAdmin failed - invalid Admin ID param",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.String("admin_id_param", ApproverIDStr),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Admin ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
|
UserId: ApproverID,
|
||||||
|
FirstName: domain.ValidString{
|
||||||
|
Value: req.FirstName,
|
||||||
|
Valid: req.FirstName != "",
|
||||||
|
},
|
||||||
|
LastName: domain.ValidString{
|
||||||
|
Value: req.LastName,
|
||||||
|
Valid: req.LastName != "",
|
||||||
|
},
|
||||||
|
Suspended: domain.ValidBool{
|
||||||
|
Value: req.Suspended,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("UpdateAdmin failed - user service error",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Int64("admin_id", ApproverID),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
h.mongoLoggerSvc.Info("UpdateAdmin succeeded",
|
||||||
|
zap.Int("status_code", fiber.StatusOK),
|
||||||
|
zap.Int64("admin_id", ApproverID),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Managers updated successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
@ -143,13 +143,13 @@ func (h *Handler) SendRegisterCode(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegisterUserReq struct {
|
type RegisterUserReq struct {
|
||||||
FirstName string `json:"first_name" example:"John"`
|
FirstName string `json:"first_name" example:"John"`
|
||||||
LastName string `json:"last_name" example:"Doe"`
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
Email string `json:"email" example:"john.doe@example.com"`
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
Password string `json:"password" example:"password123"`
|
Password string `json:"password" example:"password123"`
|
||||||
Otp string `json:"otp" example:"123456"`
|
Otp string `json:"otp" example:"123456"`
|
||||||
ReferalCode string `json:"referal_code" example:"ABC123"`
|
ReferralCode string `json:"referral_code" example:"ABC123"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterUser godoc
|
// RegisterUser godoc
|
||||||
|
|
@ -193,7 +193,7 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
PhoneNumber: req.PhoneNumber,
|
PhoneNumber: req.PhoneNumber,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Otp: req.Otp,
|
Otp: req.Otp,
|
||||||
ReferralCode: req.ReferalCode,
|
ReferralCode: req.ReferralCode,
|
||||||
OtpMedium: domain.OtpMediumEmail,
|
OtpMedium: domain.OtpMediumEmail,
|
||||||
CompanyID: companyID,
|
CompanyID: companyID,
|
||||||
Role: string(domain.RoleCustomer),
|
Role: string(domain.RoleCustomer),
|
||||||
|
|
@ -247,12 +247,12 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create user wallet:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create user wallet:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ReferalCode != "" {
|
if req.ReferralCode != "" {
|
||||||
err = h.referralSvc.ProcessReferral(c.Context(), req.PhoneNumber, req.ReferalCode, companyID.Value)
|
err = h.referralSvc.ProcessReferral(c.Context(), req.PhoneNumber, req.ReferralCode, companyID.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to process referral during registration",
|
h.mongoLoggerSvc.Error("Failed to process referral during registration",
|
||||||
zap.String("phone", req.PhoneNumber),
|
zap.String("phone", req.PhoneNumber),
|
||||||
zap.String("code", req.ReferalCode),
|
zap.String("code", req.ReferralCode),
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
zap.Time("timestamp", time.Now()),
|
||||||
)
|
)
|
||||||
|
|
@ -293,8 +293,70 @@ type ResetCodeReq struct {
|
||||||
// @Success 200 {object} response.APIResponse
|
// @Success 200 {object} response.APIResponse
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/sendResetCode [post]
|
// @Router /api/v1/user/sendResetCode [post]
|
||||||
func (h *Handler) SendResetCode(c *fiber.Ctx) error {
|
func (h *Handler) SendResetCode(c *fiber.Ctx) error {
|
||||||
|
var req ResetCodeReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to parse SendResetCode request",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sentTo string
|
||||||
|
var medium domain.OtpMedium
|
||||||
|
if req.Email != "" {
|
||||||
|
sentTo = req.Email
|
||||||
|
medium = domain.OtpMediumEmail
|
||||||
|
} else if req.PhoneNumber != "" {
|
||||||
|
sentTo = req.PhoneNumber
|
||||||
|
medium = domain.OtpMediumSms
|
||||||
|
} else {
|
||||||
|
h.mongoLoggerSvc.Info("Email or PhoneNumber must be provided",
|
||||||
|
zap.String("Email", req.Email),
|
||||||
|
zap.String("Phone Number", req.PhoneNumber),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Email or PhoneNumber must be provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.userSvc.SendResetCode(c.Context(), medium, sentTo, domain.AfroMessage, domain.ValidInt64{}); err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to send reset code",
|
||||||
|
zap.String("medium", string(medium)),
|
||||||
|
zap.String("sentTo", string(sentTo)),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to send reset code:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendTenantResetCode godoc
|
||||||
|
// @Summary Send reset code
|
||||||
|
// @Description Send reset code
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param resetCode body ResetCodeReq true "Send reset code"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/{tenant_slug}/user/sendResetCode [post]
|
||||||
|
func (h *Handler) SendTenantResetCode(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
|
@ -367,7 +429,7 @@ type ResetPasswordReq struct {
|
||||||
// @Success 200 {object} response.APIResponse
|
// @Success 200 {object} response.APIResponse
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/resetPassword [post]
|
// @Router /api/v1/user/resetPassword [post]
|
||||||
func (h *Handler) ResetPassword(c *fiber.Ctx) error {
|
func (h *Handler) ResetPassword(c *fiber.Ctx) error {
|
||||||
|
|
||||||
var req ResetPasswordReq
|
var req ResetPasswordReq
|
||||||
|
|
@ -421,6 +483,76 @@ func (h *Handler) ResetPassword(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Password reset successful", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Password reset successful", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResetTenantPassword godoc
|
||||||
|
// @Summary Reset tenant password
|
||||||
|
// @Description Reset tenant password
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param resetPassword body ResetPasswordReq true "Reset password"
|
||||||
|
// @Success 200 {object} response.APIResponse
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/{tenant_slug}/user/resetPassword [post]
|
||||||
|
func (h *Handler) ResetTenantPassword(c *fiber.Ctx) error {
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
|
||||||
|
var req ResetPasswordReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to parse ResetPassword request",
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||||
|
var errMsg string
|
||||||
|
for field, msg := range valErrs {
|
||||||
|
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
|
}
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
medium, err := getMedium(req.Email, req.PhoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Info("Failed to determine medium for ResetPassword",
|
||||||
|
zap.String("Email", req.Email),
|
||||||
|
zap.String("Phone Number", req.PhoneNumber),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
resetReq := domain.ResetPasswordReq{
|
||||||
|
Email: req.Email,
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
Password: req.Password,
|
||||||
|
Otp: req.Otp,
|
||||||
|
OtpMedium: medium,
|
||||||
|
CompanyID: companyID.Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.userSvc.ResetPassword(c.Context(), resetReq); err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to reset password",
|
||||||
|
zap.Any("userID", resetReq),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to reset password:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Password reset successful", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
type UserProfileRes struct {
|
type UserProfileRes struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
|
|
@ -503,6 +635,7 @@ func (h *Handler) CustomerProfile(c *fiber.Ctx) error {
|
||||||
|
|
||||||
lastLogin = &user.CreatedAt
|
lastLogin = &user.CreatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
res := CustomerProfileRes{
|
res := CustomerProfileRes{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
FirstName: user.FirstName,
|
FirstName: user.FirstName,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package jwtutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
|
@ -15,22 +16,23 @@ var (
|
||||||
ErrRefreshTokenNotFound = errors.New("refresh token not found")
|
ErrRefreshTokenNotFound = errors.New("refresh token not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type UserClaim struct {
|
type UserClaim struct {
|
||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
UserId int64
|
UserId int64
|
||||||
Role domain.Role
|
Role domain.Role
|
||||||
CompanyID domain.ValidInt64
|
CompanyID domain.NullJwtInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PopOKClaim struct {
|
type PopOKClaim struct {
|
||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
Lang string `json:"lang"`
|
Lang string `json:"lang"`
|
||||||
Mode string `json:"mode"`
|
Mode string `json:"mode"`
|
||||||
SessionID string `json:"session_id"`
|
SessionID string `json:"session_id"`
|
||||||
CompanyID domain.ValidInt64 `json:"company_id"`
|
CompanyID domain.NullJwtInt64 `json:"company_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type JwtConfig struct {
|
type JwtConfig struct {
|
||||||
|
|
@ -41,15 +43,18 @@ type JwtConfig struct {
|
||||||
func CreateJwt(userId int64, Role domain.Role, CompanyID domain.ValidInt64, key string, expiry int) (string, error) {
|
func CreateJwt(userId int64, Role domain.Role, CompanyID domain.ValidInt64, key string, expiry int) (string, error) {
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim{
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim{
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
Issuer: "github.com/lafetz/snippitstash",
|
Issuer: "fortune-bet",
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
Audience: jwt.ClaimStrings{"fortune.com"},
|
Audience: jwt.ClaimStrings{"api.fortunebets.net"},
|
||||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expiry) * time.Second)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expiry) * time.Second)),
|
||||||
},
|
},
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
Role: Role,
|
Role: Role,
|
||||||
CompanyID: CompanyID,
|
CompanyID: domain.NullJwtInt64{
|
||||||
|
Value: CompanyID.Value,
|
||||||
|
Valid: CompanyID.Valid,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
jwtToken, err := token.SignedString([]byte(key))
|
jwtToken, err := token.SignedString([]byte(key))
|
||||||
return jwtToken, err
|
return jwtToken, err
|
||||||
|
|
@ -70,7 +75,10 @@ func CreatePopOKJwt(userID int64, CompanyID domain.ValidInt64, username, currenc
|
||||||
Lang: lang,
|
Lang: lang,
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
SessionID: sessionID,
|
SessionID: sessionID,
|
||||||
CompanyID: CompanyID,
|
CompanyID: domain.NullJwtInt64{
|
||||||
|
Value: CompanyID.Value,
|
||||||
|
Valid: CompanyID.Valid,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return token.SignedString([]byte(key))
|
return token.SignedString([]byte(key))
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +92,7 @@ func ParseJwt(jwtToken string, key string) (*UserClaim, error) {
|
||||||
return nil, ErrExpiredToken
|
return nil, ErrExpiredToken
|
||||||
}
|
}
|
||||||
if errors.Is(err, jwt.ErrTokenMalformed) {
|
if errors.Is(err, jwt.ErrTokenMalformed) {
|
||||||
|
fmt.Printf("error %v", err.Error())
|
||||||
return nil, ErrMalformedToken
|
return nil, ErrMalformedToken
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package httpserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -56,6 +57,7 @@ func (a *App) authMiddleware(c *fiber.Ctx) error {
|
||||||
zap.String("ip_address", ip),
|
zap.String("ip_address", ip),
|
||||||
zap.String("user_agent", userAgent),
|
zap.String("user_agent", userAgent),
|
||||||
zap.Time("timestamp", time.Now()),
|
zap.Time("timestamp", time.Now()),
|
||||||
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token")
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token")
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +81,10 @@ func (a *App) authMiddleware(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
c.Locals("user_id", claim.UserId)
|
c.Locals("user_id", claim.UserId)
|
||||||
c.Locals("role", claim.Role)
|
c.Locals("role", claim.Role)
|
||||||
c.Locals("company_id", claim.CompanyID)
|
c.Locals("company_id", domain.ValidInt64{
|
||||||
|
Value: claim.CompanyID.Value,
|
||||||
|
Valid: claim.CompanyID.Valid,
|
||||||
|
})
|
||||||
c.Locals("refresh_token", refreshToken)
|
c.Locals("refresh_token", refreshToken)
|
||||||
|
|
||||||
var branchID domain.ValidInt64
|
var branchID domain.ValidInt64
|
||||||
|
|
@ -198,6 +203,7 @@ func (a *App) WebsocketAuthMiddleware(c *fiber.Ctx) error {
|
||||||
zap.String("ip_address", ip),
|
zap.String("ip_address", ip),
|
||||||
zap.String("user_agent", userAgent),
|
zap.String("user_agent", userAgent),
|
||||||
zap.Time("timestamp", time.Now()),
|
zap.Time("timestamp", time.Now()),
|
||||||
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, "Invalid token")
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid token")
|
||||||
}
|
}
|
||||||
|
|
@ -222,17 +228,20 @@ func (a *App) WebsocketAuthMiddleware(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) TenantMiddleware(c *fiber.Ctx) error {
|
func (a *App) TenantMiddleware(c *fiber.Ctx) error {
|
||||||
if tokenCID, ok := c.Locals("company_id").(domain.ValidInt64); ok && tokenCID.Valid {
|
|
||||||
return c.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
tenantSlug := c.Params("tenant_slug")
|
tenantSlug := c.Params("tenant_slug")
|
||||||
if tenantSlug == "" {
|
if tenantSlug == "" {
|
||||||
|
a.mongoLoggerSvc.Info("blank tenant param",
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "tenant is required for this route")
|
return fiber.NewError(fiber.StatusBadRequest, "tenant is required for this route")
|
||||||
}
|
}
|
||||||
|
|
||||||
companyID, err := a.companySvc.GetCompanyIDBySlug(c.Context(), tenantSlug)
|
companyID, err := a.companySvc.GetCompanyIDBySlug(c.Context(), tenantSlug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
a.mongoLoggerSvc.Info("failed to resolve tenant",
|
||||||
|
zap.String("tenant_slug", tenantSlug),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "failed to resolve tenant")
|
return fiber.NewError(fiber.StatusBadRequest, "failed to resolve tenant")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,3 +251,35 @@ func (a *App) TenantMiddleware(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) TenantAuthMiddleware(c *fiber.Ctx) error {
|
||||||
|
slugID, ok := c.Locals("tenant_id").(domain.ValidInt64)
|
||||||
|
|
||||||
|
if !ok || !slugID.Valid {
|
||||||
|
a.mongoLoggerSvc.Info("invalid tenant slug",
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid tenant slug")
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenCID, ok := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !ok || !tokenCID.Valid {
|
||||||
|
a.mongoLoggerSvc.Error("invalid company id in token",
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
zap.Bool("tokenCID Valid", tokenCID.Valid),
|
||||||
|
zap.Bool("ValidInt64 Type Check", ok),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "invalid company id in token")
|
||||||
|
}
|
||||||
|
|
||||||
|
if slugID.Value != tokenCID.Value {
|
||||||
|
a.mongoLoggerSvc.Error("token company-id doesn't match the slug company_id",
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "invalid company_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\nTenant successfully authenticated!\n")
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,16 +62,41 @@ func (a *App) initAppRoutes() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
a.fiber.Get("/routes", func(c *fiber.Ctx) error {
|
||||||
|
return c.JSON(a.fiber.Stack()) // prints all registered routes
|
||||||
|
})
|
||||||
|
|
||||||
// Groups
|
// Groups
|
||||||
groupV1 := a.fiber.Group("/api/v1")
|
groupV1 := a.fiber.Group("/api/v1")
|
||||||
tenant := groupV1.Group("/:tenant_slug", a.TenantMiddleware)
|
tenant := groupV1.Group("/tenant/:tenant_slug", a.TenantMiddleware)
|
||||||
tenantAuth := groupV1.Group("/:tenant_slug", a.authMiddleware, a.TenantMiddleware)
|
tenant.Get("/test", a.authMiddleware, a.authMiddleware, func(c *fiber.Ctx) error {
|
||||||
|
fmt.Printf("\nTest Route %v\n", c.Route().Path)
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("In the tenant auth test \n")
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"message": "Is is fine",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
tenant.Get("/", func(c *fiber.Ctx) error {
|
||||||
|
fmt.Printf("\nTenant Route %v\n", c.Route().Path)
|
||||||
|
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
if !companyID.Valid {
|
||||||
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
|
}
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"message": "Company Tenant Active",
|
||||||
|
})
|
||||||
|
})
|
||||||
//Direct_deposit
|
//Direct_deposit
|
||||||
groupV1.Post("/direct_deposit", a.authMiddleware, h.InitiateDirectDeposit)
|
groupV1.Post("/direct_deposit", a.authMiddleware, h.InitiateDirectDeposit)
|
||||||
groupV1.Post("/direct_deposit/verify", a.authMiddleware, h.VerifyDirectDeposit)
|
groupV1.Post("/direct_deposit/verify", a.authMiddleware, h.VerifyDirectDeposit)
|
||||||
groupV1.Get("/direct_deposit/pending", a.authMiddleware, h.GetPendingDirectDeposits)
|
groupV1.Get("/direct_deposit/pending", a.authMiddleware, h.GetPendingDirectDeposits)
|
||||||
|
|
||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
||||||
|
|
@ -141,28 +166,29 @@ func (a *App) initAppRoutes() {
|
||||||
// groupV1.Post("/arifpay/transaction-id/verify-transaction", a.authMiddleware, h.ArifpayVerifyByTransactionIDHandler)
|
// groupV1.Post("/arifpay/transaction-id/verify-transaction", a.authMiddleware, h.ArifpayVerifyByTransactionIDHandler)
|
||||||
// groupV1.Get("/arifpay/session-id/verify-transaction/:session_id", a.authMiddleware, h.ArifpayVerifyBySessionIDHandler)
|
// groupV1.Get("/arifpay/session-id/verify-transaction/:session_id", a.authMiddleware, h.ArifpayVerifyBySessionIDHandler)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// User Routes
|
// User Routes
|
||||||
tenant.Post("/user/resetPassword", h.ResetPassword)
|
groupV1.Post("/user/resetPassword", h.ResetPassword)
|
||||||
tenant.Post("/user/sendResetCode", h.SendResetCode)
|
groupV1.Post("/user/sendResetCode", h.SendResetCode)
|
||||||
|
|
||||||
|
tenant.Post("/user/resetPassword", h.ResetTenantPassword)
|
||||||
|
tenant.Post("/user/sendResetCode", h.SendTenantResetCode)
|
||||||
tenant.Post("/user/register", h.RegisterUser)
|
tenant.Post("/user/register", h.RegisterUser)
|
||||||
tenant.Post("/user/sendRegisterCode", h.SendRegisterCode)
|
tenant.Post("/user/sendRegisterCode", h.SendRegisterCode)
|
||||||
tenant.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
tenant.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
||||||
tenantAuth.Get("/user/customer-profile", h.CustomerProfile)
|
|
||||||
tenantAuth.Get("/user/admin-profile", h.AdminProfile)
|
tenant.Get("/user/customer-profile", a.authMiddleware, h.CustomerProfile)
|
||||||
tenantAuth.Get("/user/bets", h.GetBetByUserID)
|
tenant.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
||||||
|
tenant.Get("/user/bets", a.authMiddleware, h.GetBetByUserID)
|
||||||
|
|
||||||
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
||||||
groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
||||||
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
||||||
tenantAuth.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet)
|
tenant.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet)
|
||||||
tenantAuth.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
|
tenant.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
|
||||||
|
|
||||||
// Referral Routes
|
// Referral Routes
|
||||||
groupV1.Post("/referral/create", a.authMiddleware, h.CreateReferralCode)
|
tenant.Post("/referral/create", a.authMiddleware, h.CreateReferralCode)
|
||||||
groupV1.Get("/referral/stats", a.authMiddleware, h.GetReferralStats)
|
tenant.Get("/referral/stats", a.authMiddleware, h.GetReferralStats)
|
||||||
groupV1.Post("/referral/settings", a.authMiddleware, h.CreateReferralSettings)
|
groupV1.Post("/referral/settings", a.authMiddleware, h.CreateReferralSettings)
|
||||||
groupV1.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings)
|
groupV1.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings)
|
||||||
groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
|
groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
|
||||||
|
|
@ -177,15 +203,26 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/cashiers", a.authMiddleware, h.CreateCashier)
|
groupV1.Post("/cashiers", a.authMiddleware, h.CreateCashier)
|
||||||
groupV1.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier)
|
groupV1.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier)
|
||||||
|
|
||||||
|
tenant.Get("/customer", a.authMiddleware, h.GetAllTenantCustomers)
|
||||||
|
tenant.Get("/customer/:id", a.authMiddleware, h.GetTenantCustomerByID)
|
||||||
|
tenant.Put("/customer/:id", a.authMiddleware, h.UpdateTenantCustomer)
|
||||||
|
tenant.Get("/customer/:id/bets", a.authMiddleware, h.GetTenantCustomerBets)
|
||||||
|
|
||||||
groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers)
|
groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers)
|
||||||
groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID)
|
groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID)
|
||||||
groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer)
|
groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer)
|
||||||
|
tenant.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets)
|
||||||
|
|
||||||
groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins)
|
groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins)
|
||||||
groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID)
|
groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID)
|
||||||
groupV1.Post("/admin", a.authMiddleware, h.CreateAdmin)
|
groupV1.Post("/admin", a.authMiddleware, h.CreateAdmin)
|
||||||
groupV1.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin)
|
groupV1.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin)
|
||||||
|
|
||||||
|
groupV1.Get("/t-approver", a.authMiddleware, h.GetAllTransactionApprovers)
|
||||||
|
groupV1.Get("/t-approver/:id", a.authMiddleware, h.GetTransactionApproverByID)
|
||||||
|
groupV1.Post("/t-approver", a.authMiddleware, h.CreateTransactionApprover)
|
||||||
|
groupV1.Put("/t-approver/:id", a.authMiddleware, h.UpdateTransactionApprover)
|
||||||
|
|
||||||
groupV1.Get("/managers", a.authMiddleware, h.GetAllManagers)
|
groupV1.Get("/managers", a.authMiddleware, h.GetAllManagers)
|
||||||
groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID)
|
groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID)
|
||||||
groupV1.Post("/managers", a.authMiddleware, h.CreateManager)
|
groupV1.Post("/managers", a.authMiddleware, h.CreateManager)
|
||||||
|
|
@ -200,8 +237,8 @@ func (a *App) initAppRoutes() {
|
||||||
tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
|
tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
|
||||||
tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID)
|
tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID)
|
||||||
|
|
||||||
groupV1.Get("/events", a.authMiddleware, a.SuperAdminOnly, h.GetAllUpcomingEvents)
|
groupV1.Get("/events", a.authMiddleware, h.GetAllUpcomingEvents)
|
||||||
groupV1.Get("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.GetUpcomingEventByID)
|
groupV1.Get("/events/:id", a.authMiddleware, h.GetUpcomingEventByID)
|
||||||
groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
|
groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
|
||||||
|
|
||||||
tenant.Get("/events", h.GetTenantUpcomingEvents)
|
tenant.Get("/events", h.GetTenantUpcomingEvents)
|
||||||
|
|
@ -221,6 +258,7 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/branch", a.authMiddleware, h.CreateBranch)
|
groupV1.Post("/branch", a.authMiddleware, h.CreateBranch)
|
||||||
groupV1.Get("/branch", a.authMiddleware, h.GetAllBranches)
|
groupV1.Get("/branch", a.authMiddleware, h.GetAllBranches)
|
||||||
groupV1.Get("/branch/:id", a.authMiddleware, h.GetBranchByID)
|
groupV1.Get("/branch/:id", a.authMiddleware, h.GetBranchByID)
|
||||||
|
groupV1.Post("/branch/:id/return", a.authMiddleware, h.ReturnBranchWallet)
|
||||||
groupV1.Get("/branch/:id/bets", a.authMiddleware, h.GetBetByBranchID)
|
groupV1.Get("/branch/:id/bets", a.authMiddleware, h.GetBetByBranchID)
|
||||||
groupV1.Put("/branch/:id", a.authMiddleware, h.UpdateBranch)
|
groupV1.Put("/branch/:id", a.authMiddleware, h.UpdateBranch)
|
||||||
groupV1.Put("/branch/:id/set-active", a.authMiddleware, h.UpdateBranchStatus)
|
groupV1.Put("/branch/:id/set-active", a.authMiddleware, h.UpdateBranchStatus)
|
||||||
|
|
@ -258,15 +296,19 @@ func (a *App) initAppRoutes() {
|
||||||
tenant.Get("/ticket/:id", h.GetTicketByID)
|
tenant.Get("/ticket/:id", h.GetTicketByID)
|
||||||
|
|
||||||
// Bet Routes
|
// Bet Routes
|
||||||
tenantAuth.Post("/sport/bet", h.CreateBet)
|
tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet)
|
||||||
tenantAuth.Post("/sport/bet/fastcode", h.CreateBetWithFastCode)
|
tenant.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode)
|
||||||
tenant.Get("/sport/bet/fastcode/:fast_code", h.GetBetByFastCode)
|
tenant.Get("/sport/bet/fastcode/:fast_code", h.GetBetByFastCode)
|
||||||
tenantAuth.Get("/sport/bet", h.GetAllBet)
|
tenant.Get("/sport/bet", a.authMiddleware, h.GetAllTenantBets)
|
||||||
tenantAuth.Get("/sport/bet/:id", h.GetBetByID)
|
tenant.Get("/sport/bet/:id", a.authMiddleware, h.GetTenantBetByID)
|
||||||
tenantAuth.Patch("/sport/bet/:id", h.UpdateCashOut)
|
tenant.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut)
|
||||||
tenantAuth.Delete("/sport/bet/:id", h.DeleteBet)
|
tenant.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteTenantBet)
|
||||||
|
|
||||||
tenantAuth.Post("/sport/random/bet", h.RandomBet)
|
groupV1.Get("/sport/bet", a.authMiddleware, a.SuperAdminOnly, h.GetAllBet)
|
||||||
|
groupV1.Get("/sport/bet/:id", a.authMiddleware, a.SuperAdminOnly, h.GetBetByID)
|
||||||
|
groupV1.Delete("/sport/bet/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteBet)
|
||||||
|
|
||||||
|
tenant.Post("/sport/random/bet", a.authMiddleware, h.RandomBet)
|
||||||
|
|
||||||
// Wallet
|
// Wallet
|
||||||
groupV1.Get("/wallet", h.GetAllWallets)
|
groupV1.Get("/wallet", h.GetAllWallets)
|
||||||
|
|
@ -373,9 +415,9 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
|
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
|
||||||
groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
|
groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
|
||||||
|
|
||||||
tenantAuth.Post("/settings", h.SaveCompanySettingList)
|
tenant.Post("/settings", a.authMiddleware, h.SaveCompanySettingList)
|
||||||
tenantAuth.Get("/settings", h.GetCompanySettingList)
|
tenant.Get("/settings", a.authMiddleware, h.GetCompanySettingList)
|
||||||
tenantAuth.Delete("/settings/:key", h.DeleteCompanySetting)
|
tenant.Delete("/settings/:key", a.authMiddleware, h.DeleteCompanySetting)
|
||||||
tenantAuth.Delete("/settings", h.DeleteAllCompanySetting)
|
tenant.Delete("/settings", a.authMiddleware, h.DeleteAllCompanySetting)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
makefile
18
makefile
|
|
@ -56,8 +56,19 @@ restore:
|
||||||
restore_file:
|
restore_file:
|
||||||
@echo "Restoring latest backup..."
|
@echo "Restoring latest backup..."
|
||||||
gunzip -c $(file) | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh
|
gunzip -c $(file) | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh
|
||||||
|
|
||||||
|
.PHONY: seed_data
|
||||||
seed_data:
|
seed_data:
|
||||||
cat db/data/seed_data.sql | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh
|
|
||||||
|
@echo "Waiting for PostgreSQL to be ready..."
|
||||||
|
@until docker exec fortunebet-backend-postgres-1 pg_isready -U root -d gh; do \
|
||||||
|
echo "PostgreSQL is not ready yet..."; \
|
||||||
|
sleep 1; \
|
||||||
|
done
|
||||||
|
@for file in db/data/*.sql; do \
|
||||||
|
echo "Seeding $$file..."; \
|
||||||
|
cat $$file | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh; \
|
||||||
|
done
|
||||||
postgres_log:
|
postgres_log:
|
||||||
docker logs fortunebet-backend-postgres-1
|
docker logs fortunebet-backend-postgres-1
|
||||||
.PHONY: swagger
|
.PHONY: swagger
|
||||||
|
|
@ -69,11 +80,12 @@ logs:
|
||||||
@mkdir -p logs
|
@mkdir -p logs
|
||||||
db-up: | logs
|
db-up: | logs
|
||||||
@mkdir -p logs
|
@mkdir -p logs
|
||||||
@docker compose up -d postgres migrate mongo redis
|
@docker compose up -d postgres migrate mongo redis --wait migrate
|
||||||
|
@make seed_data
|
||||||
@docker logs fortunebet-backend-postgres-1 > logs/postgres.log 2>&1 &
|
@docker logs fortunebet-backend-postgres-1 > logs/postgres.log 2>&1 &
|
||||||
.PHONY: db-down
|
.PHONY: db-down
|
||||||
db-down:
|
db-down:
|
||||||
@docker compose down
|
@docker compose down -v
|
||||||
@docker volume rm fortunebet-backend_postgres_data
|
@docker volume rm fortunebet-backend_postgres_data
|
||||||
.PHONY: sqlc-gen
|
.PHONY: sqlc-gen
|
||||||
sqlc-gen:
|
sqlc-gen:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user