fix: refactoring referral

This commit is contained in:
Samuel Tariku 2025-09-08 17:05:09 +03:00
parent 9900113e33
commit e229ac911e
21 changed files with 744 additions and 1080 deletions

View File

@ -146,7 +146,7 @@ func main() {
vitualGameRepo := repository.NewVirtualGameRepository(store) vitualGameRepo := repository.NewVirtualGameRepository(store)
recommendationRepo := repository.NewRecommendationRepository(store) recommendationRepo := repository.NewRecommendationRepository(store)
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger) referalSvc := referralservice.New(referalRepo, *walletSvc, *settingSvc, cfg, logger)
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger) virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger) aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
veliCLient := veli.NewClient(cfg, walletSvc) veliCLient := veli.NewClient(cfg, walletSvc)

View File

@ -193,7 +193,8 @@ CREATE TABLE IF NOT EXISTS wallets (
type VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true, is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT balance_positve CHECK (balance >= 0)
); );
CREATE TABLE IF NOT EXISTS customer_wallets ( CREATE TABLE IF NOT EXISTS customer_wallets (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,

View File

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

View File

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

View File

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

View File

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

View File

@ -5,56 +5,9 @@
package dbgen package dbgen
import ( import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
type Referralstatus string
const (
ReferralstatusPENDING Referralstatus = "PENDING"
ReferralstatusCOMPLETED Referralstatus = "COMPLETED"
ReferralstatusEXPIRED Referralstatus = "EXPIRED"
ReferralstatusCANCELLED Referralstatus = "CANCELLED"
)
func (e *Referralstatus) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = Referralstatus(s)
case string:
*e = Referralstatus(s)
default:
return fmt.Errorf("unsupported scan type for Referralstatus: %T", src)
}
return nil
}
type NullReferralstatus struct {
Referralstatus Referralstatus `json:"referralstatus"`
Valid bool `json:"valid"` // Valid is true if Referralstatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullReferralstatus) Scan(value interface{}) error {
if value == nil {
ns.Referralstatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.Referralstatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullReferralstatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.Referralstatus), nil
}
type Bank struct { type Bank struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Slug string `json:"slug"` Slug string `json:"slug"`
@ -538,31 +491,16 @@ type Otp struct {
ExpiresAt pgtype.Timestamptz `json:"expires_at"` ExpiresAt pgtype.Timestamptz `json:"expires_at"`
} }
type Referral struct { type ReferralCode 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 int64 `json:"referrer_id"`
ReferrerID int64 `json:"referrer_id"` CompanyID int64 `json:"company_id"`
ReferredID pgtype.Int8 `json:"referred_id"` IsActive bool `json:"is_active"`
Status Referralstatus `json:"status"` NumberOfReferrals int64 `json:"number_of_referrals"`
RewardAmount pgtype.Numeric `json:"reward_amount"` RewardAmount int64 `json:"reward_amount"`
CashbackAmount pgtype.Numeric `json:"cashback_amount"` CreatedAt pgtype.Timestamptz `json:"created_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
}
type ReferralSetting struct {
ID int64 `json:"id"`
ReferralRewardAmount pgtype.Numeric `json:"referral_reward_amount"`
CashbackPercentage pgtype.Numeric `json:"cashback_percentage"`
BetReferralBonusPercentage pgtype.Numeric `json:"bet_referral_bonus_percentage"`
MaxReferrals int32 `json:"max_referrals"`
ExpiresAfterDays int32 `json:"expires_after_days"`
UpdatedBy string `json:"updated_by"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
Version int32 `json:"version"`
} }
type RefreshToken struct { type RefreshToken struct {
@ -795,8 +733,6 @@ type User struct {
CompanyID pgtype.Int8 `json:"company_id"` CompanyID pgtype.Int8 `json:"company_id"`
SuspendedAt pgtype.Timestamptz `json:"suspended_at"` SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
Suspended bool `json:"suspended"` Suspended bool `json:"suspended"`
ReferralCode pgtype.Text `json:"referral_code"`
ReferredBy pgtype.Text `json:"referred_by"`
} }
type UserGameInteraction struct { type UserGameInteraction struct {
@ -809,6 +745,13 @@ type UserGameInteraction struct {
CreatedAt pgtype.Timestamptz `json:"created_at"` CreatedAt pgtype.Timestamptz `json:"created_at"`
} }
type UserReferral struct {
ID int64 `json:"id"`
ReferredID int64 `json:"referred_id"`
ReferralCodeID int64 `json:"referral_code_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type VirtualGame struct { type VirtualGame struct {
ID int64 `json:"id"` ID int64 `json:"id"`
GameID string `json:"game_id"` GameID string `json:"game_id"`
@ -897,8 +840,6 @@ type Wallet struct {
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
BonusBalance pgtype.Numeric `json:"bonus_balance"`
CashBalance pgtype.Numeric `json:"cash_balance"`
} }
type WalletThresholdNotification struct { type WalletThresholdNotification struct {

View File

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

View File

@ -163,7 +163,7 @@ func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
} }
const GetAdminByCompanyID = `-- name: GetAdminByCompanyID :one const GetAdminByCompanyID = `-- name: GetAdminByCompanyID :one
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended
FROM companies FROM companies
JOIN users ON companies.admin_id = users.id JOIN users ON companies.admin_id = users.id
where companies.id = $1 where companies.id = $1
@ -187,8 +187,6 @@ func (q *Queries) GetAdminByCompanyID(ctx context.Context, id int64) (User, erro
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
) )
return i, err return i, err
} }
@ -388,7 +386,7 @@ func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams)
} }
const GetUserByID = `-- name: GetUserByID :one const GetUserByID = `-- name: GetUserByID :one
SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended, referral_code, referred_by SELECT id, first_name, last_name, email, phone_number, role, password, email_verified, phone_verified, created_at, updated_at, company_id, suspended_at, suspended
FROM users FROM users
WHERE id = $1 WHERE id = $1
` `
@ -411,8 +409,6 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
&i.CompanyID, &i.CompanyID,
&i.SuspendedAt, &i.SuspendedAt,
&i.Suspended, &i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
) )
return i, err return i, err
} }

View File

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

View File

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

View File

@ -24,6 +24,9 @@ type SettingList struct {
AmountForBetReferral Currency `json:"amount_for_bet_referral"` AmountForBetReferral Currency `json:"amount_for_bet_referral"`
CashbackAmountCap Currency `json:"cashback_amount_cap"` CashbackAmountCap Currency `json:"cashback_amount_cap"`
DefaultWinningLimit int64 `json:"default_winning_limit"` DefaultWinningLimit int64 `json:"default_winning_limit"`
ReferralRewardAmount Currency `json:"referral_reward_amount"`
CashbackPercentage float32 `json:"cashback_percentage"`
DefaultMaxReferrals int64 `json:"default_max_referrals"`
} }
type SettingListRes struct { type SettingListRes struct {
@ -35,6 +38,9 @@ type SettingListRes struct {
AmountForBetReferral float32 `json:"amount_for_bet_referral"` AmountForBetReferral float32 `json:"amount_for_bet_referral"`
CashbackAmountCap float32 `json:"cashback_amount_cap"` CashbackAmountCap float32 `json:"cashback_amount_cap"`
DefaultWinningLimit int64 `json:"default_winning_limit"` DefaultWinningLimit int64 `json:"default_winning_limit"`
ReferralRewardAmount float32 `json:"referral_reward_amount"`
CashbackPercentage float32 `json:"cashback_percentage"`
DefaultMaxReferrals int64 `json:"default_max_referrals"`
} }
func ConvertSettingListRes(settings SettingList) SettingListRes { func ConvertSettingListRes(settings SettingList) SettingListRes {
@ -47,6 +53,9 @@ func ConvertSettingListRes(settings SettingList) SettingListRes {
AmountForBetReferral: settings.AmountForBetReferral.Float32(), AmountForBetReferral: settings.AmountForBetReferral.Float32(),
CashbackAmountCap: settings.CashbackAmountCap.Float32(), CashbackAmountCap: settings.CashbackAmountCap.Float32(),
DefaultWinningLimit: settings.DefaultWinningLimit, DefaultWinningLimit: settings.DefaultWinningLimit,
ReferralRewardAmount: settings.ReferralRewardAmount.Float32(),
CashbackPercentage: settings.CashbackPercentage,
DefaultMaxReferrals: settings.DefaultMaxReferrals,
} }
} }
@ -59,6 +68,9 @@ type SaveSettingListReq struct {
AmountForBetReferral *float32 `json:"amount_for_bet_referral,omitempty"` AmountForBetReferral *float32 `json:"amount_for_bet_referral,omitempty"`
CashbackAmountCap *float32 `json:"cashback_amount_cap,omitempty"` CashbackAmountCap *float32 `json:"cashback_amount_cap,omitempty"`
DefaultWinningLimit *int64 `json:"default_winning_limit,omitempty"` DefaultWinningLimit *int64 `json:"default_winning_limit,omitempty"`
ReferralRewardAmount *float32 `json:"referral_reward_amount"`
CashbackPercentage *float32 `json:"cashback_percentage"`
DefaultMaxReferrals *int64 `json:"default_max_referrals"`
} }
type ValidSettingList struct { type ValidSettingList struct {
@ -70,6 +82,9 @@ type ValidSettingList struct {
AmountForBetReferral ValidCurrency AmountForBetReferral ValidCurrency
CashbackAmountCap ValidCurrency CashbackAmountCap ValidCurrency
DefaultWinningLimit ValidInt64 DefaultWinningLimit ValidInt64
ReferralRewardAmount ValidCurrency
CashbackPercentage ValidFloat32
DefaultMaxReferrals ValidInt64
} }
func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList { func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList {
@ -82,6 +97,9 @@ func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList {
AmountForBetReferral: ConvertFloat32PtrToCurrency(settings.AmountForBetReferral), AmountForBetReferral: ConvertFloat32PtrToCurrency(settings.AmountForBetReferral),
CashbackAmountCap: ConvertFloat32PtrToCurrency(settings.CashbackAmountCap), CashbackAmountCap: ConvertFloat32PtrToCurrency(settings.CashbackAmountCap),
DefaultWinningLimit: ConvertInt64Ptr(settings.DefaultWinningLimit), DefaultWinningLimit: ConvertInt64Ptr(settings.DefaultWinningLimit),
ReferralRewardAmount: ConvertFloat32PtrToCurrency(settings.ReferralRewardAmount),
CashbackPercentage: ConvertFloat32Ptr(settings.CashbackPercentage),
DefaultMaxReferrals: ConvertInt64Ptr(settings.DefaultMaxReferrals),
} }
} }
@ -90,12 +108,15 @@ func (vsl *ValidSettingList) ToSettingList() SettingList {
return SettingList{ return SettingList{
SMSProvider: SMSProvider(vsl.SMSProvider.Value), SMSProvider: SMSProvider(vsl.SMSProvider.Value),
MaxNumberOfOutcomes: vsl.MaxNumberOfOutcomes.Value, MaxNumberOfOutcomes: vsl.MaxNumberOfOutcomes.Value,
BetAmountLimit: Currency(vsl.BetAmountLimit.Value), BetAmountLimit: vsl.BetAmountLimit.Value,
DailyTicketPerIP: vsl.DailyTicketPerIP.Value, DailyTicketPerIP: vsl.DailyTicketPerIP.Value,
TotalWinningLimit: Currency(vsl.TotalWinningLimit.Value), TotalWinningLimit: vsl.TotalWinningLimit.Value,
AmountForBetReferral: Currency(vsl.AmountForBetReferral.Value), AmountForBetReferral: vsl.AmountForBetReferral.Value,
CashbackAmountCap: Currency(vsl.CashbackAmountCap.Value), CashbackAmountCap: vsl.CashbackAmountCap.Value,
DefaultWinningLimit: vsl.DefaultWinningLimit.Value, DefaultWinningLimit: vsl.DefaultWinningLimit.Value,
ReferralRewardAmount: vsl.ReferralRewardAmount.Value,
CashbackPercentage: vsl.CashbackPercentage.Value,
DefaultMaxReferrals: vsl.DefaultMaxReferrals.Value,
} }
} }
@ -112,6 +133,7 @@ func (vsl *ValidSettingList) GetInt64SettingsMap() map[string]*ValidInt64 {
"max_number_of_outcomes": &vsl.MaxNumberOfOutcomes, "max_number_of_outcomes": &vsl.MaxNumberOfOutcomes,
"daily_ticket_limit": &vsl.DailyTicketPerIP, "daily_ticket_limit": &vsl.DailyTicketPerIP,
"default_winning_limit": &vsl.DefaultWinningLimit, "default_winning_limit": &vsl.DefaultWinningLimit,
"default_max_referrals": &vsl.DefaultMaxReferrals,
} }
} }
@ -121,6 +143,7 @@ func (vsl *ValidSettingList) GetCurrencySettingsMap() map[string]*ValidCurrency
"total_winnings_limit": &vsl.TotalWinningLimit, "total_winnings_limit": &vsl.TotalWinningLimit,
"amount_for_bet_referral": &vsl.AmountForBetReferral, "amount_for_bet_referral": &vsl.AmountForBetReferral,
"cashback_amount_cap": &vsl.CashbackAmountCap, "cashback_amount_cap": &vsl.CashbackAmountCap,
"referral_reward_amount": &vsl.ReferralRewardAmount,
} }
} }
@ -135,13 +158,18 @@ func (vsl *ValidSettingList) GetBoolSettingsMap() map[string]*ValidBool {
} }
func (vsl *ValidSettingList) GetFloat32SettingsMap() map[string]*ValidFloat32 { func (vsl *ValidSettingList) GetFloat32SettingsMap() map[string]*ValidFloat32 {
return map[string]*ValidFloat32{} return map[string]*ValidFloat32{
"cashback_percentage": &vsl.CashbackPercentage,
}
} }
func (vsl *ValidSettingList) GetTimeSettingsMap() map[string]*ValidTime { func (vsl *ValidSettingList) GetTimeSettingsMap() map[string]*ValidTime {
return map[string]*ValidTime{} return map[string]*ValidTime{}
} }
// Setting Functions
func (vsl *ValidSettingList) GetTotalSettings() int { func (vsl *ValidSettingList) GetTotalSettings() int {
return len(vsl.GetInt64SettingsMap()) + return len(vsl.GetInt64SettingsMap()) +
len(vsl.GetCurrencySettingsMap()) + len(vsl.GetCurrencySettingsMap()) +

View File

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

View File

@ -9,6 +9,7 @@ import (
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
@ -73,7 +74,7 @@ func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int6
func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error) { func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
user, err := s.queries.GetUserByID(ctx, id) user, err := s.queries.GetUserByID(ctx, id)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, pgx.ErrNoRows) {
return domain.User{}, domain.ErrUserNotFound return domain.User{}, domain.ErrUserNotFound
} }
return domain.User{}, err return domain.User{}, err

View File

@ -13,8 +13,5 @@ type ReferralStore interface {
ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error
ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error
GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error) GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error)
CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error
UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error
GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error)
GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error) GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error)
} }

View File

@ -7,38 +7,38 @@ import (
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strconv"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/config"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
) )
type Service struct { type Service struct {
repo repository.ReferralRepository repo repository.ReferralRepository
walletSvc wallet.Service walletSvc wallet.Service
store *repository.Store settingSvc settings.Service
config *config.Config config *config.Config
logger *slog.Logger logger *slog.Logger
} }
func New(repo repository.ReferralRepository, walletSvc wallet.Service, store *repository.Store, cfg *config.Config, logger *slog.Logger) *Service { func New(repo repository.ReferralRepository, walletSvc wallet.Service, settingSvc settings.Service, cfg *config.Config, logger *slog.Logger) *Service {
return &Service{ return &Service{
repo: repo, repo: repo,
walletSvc: walletSvc, walletSvc: walletSvc,
store: store, settingSvc: settingSvc,
config: cfg, config: cfg,
logger: logger, logger: logger,
} }
} }
var ( var (
ErrInvalidReferral = errors.New("invalid or expired referral") ErrInvalidReferral = errors.New("invalid or expired referral")
ErrInvalidReferralSignup = errors.New("referral requires phone signup") ErrUserNotFound = errors.New("user not found")
ErrUserNotFound = errors.New("user not found") ErrNoReferralFound = errors.New("no referral found for this user")
ErrNoReferralFound = errors.New("no referral found for this user") ErrUserAlreadyHasReferralCode = errors.New("user already has an active referral code")
ErrMaxReferralCountLimitReached = errors.New("referral count limit has been reached")
) )
func (s *Service) GenerateReferralCode() (string, error) { func (s *Service) GenerateReferralCode() (string, error) {
@ -52,274 +52,100 @@ func (s *Service) GenerateReferralCode() (string, error) {
return code, nil return code, nil
} }
func (s *Service) CreateReferral(ctx context.Context, userID int64, companyID int64) error { func (s *Service) CreateReferralCode(ctx context.Context, userID int64, companyID int64) (domain.ReferralCode, error) {
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, companyID)
if err != nil {
s.logger.Error("Failed to fetch settings", "error", err)
return domain.ReferralCode{}, err
}
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, userID) referralCodes, err := s.repo.GetReferralCodesByUser(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 domain.ReferralCode{}, err
} }
if referral != nil && referral.Status == domain.ReferralPending && referral.ExpiresAt.After(time.Now()) { if referralCodes != nil {
s.logger.Error("user already has an active referral code", "error", err) s.logger.Error("user already has an active referral code", "error", err)
return err return domain.ReferralCode{}, ErrUserAlreadyHasReferralCode
}
settings, err := s.GetReferralSettings(ctx)
if err != nil || settings == nil {
s.logger.Error("Failed to fetch referral settings", "error", err)
return err
}
// check referral count limit
referralCount, err := s.GetReferralCountByID(ctx, userID)
if err != nil {
s.logger.Error("Failed to get referral count", "userID", userID, "error", err)
return err
}
fmt.Println("referralCount: ", referralCount)
if referralCount == int64(settings.MaxReferrals) {
s.logger.Error("referral count limit has been reached", "referralCount", referralCount, "error", err)
return err
} }
code, err := s.GenerateReferralCode() code, err := s.GenerateReferralCode()
if err != nil { if err != nil {
s.logger.Error("Failed to generate referral code", "error", err) s.logger.Error("Failed to generate referral code", "error", err)
return err return domain.ReferralCode{}, err
} }
var rewardAmount float64 = settings.ReferralRewardAmount newReferralCode, err := s.repo.CreateReferralCode(ctx, domain.CreateReferralCode{
var expireDuration time.Time = time.Now().Add(time.Duration((24 * settings.ExpiresAfterDays)) * time.Hour) ReferrerID: userID,
ReferralCode: code,
CompanyID: companyID,
NumberOfReferrals: settingsList.DefaultMaxReferrals,
RewardAmount: settingsList.ReferralRewardAmount,
})
if err := s.repo.CreateReferral(ctx, &domain.Referral{ if err != nil {
ReferralCode: code, return domain.ReferralCode{}, err
ReferrerID: userID,
Status: domain.ReferralPending,
RewardAmount: rewardAmount,
ExpiresAt: expireDuration,
CompanyID: companyID,
}); err != nil {
return err
} }
return nil return newReferralCode, nil
} }
func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCode string, companyID int64) error { func (s *Service) ProcessReferral(ctx context.Context, referredID int64, referralCode string, companyID int64) error {
s.logger.Info("Processing referral", "referredPhone", referredPhone, "referralCode", referralCode) s.logger.Info("Processing referral", "referralCode", referralCode)
referral, err := s.repo.GetReferralByCode(ctx, referralCode) referral, err := s.repo.GetReferralCode(ctx, referralCode)
if err != nil || referral == nil {
if err != nil {
s.logger.Error("Failed to get referral by code", "referralCode", referralCode, "error", err) s.logger.Error("Failed to get referral by code", "referralCode", referralCode, "error", err)
return err return err
} }
if referral.Status != domain.ReferralPending || referral.ExpiresAt.Before(time.Now()) { wallets, err := s.walletSvc.GetCustomerWallet(ctx, referral.ReferrerID)
s.logger.Warn("Invalid or expired referral", "referralCode", referralCode, "status", referral.Status)
return ErrInvalidReferral
}
user, err := s.store.GetUserByPhone(ctx, referredPhone, domain.ValidInt64{
Value: companyID,
Valid: true,
})
if err != nil {
if errors.Is(err, domain.ErrUserNotFound) {
s.logger.Warn("User not found for referral", "referredPhone", referredPhone)
return ErrUserNotFound
}
s.logger.Error("Failed to get user by phone", "referredPhone", referredPhone, "error", err)
return err
}
if !user.PhoneVerified {
s.logger.Warn("Phone not verified for referral", "referredPhone", referredPhone)
return ErrInvalidReferralSignup
}
referral.ReferredID = &user.ID
referral.Status = domain.ReferralCompleted
referral.UpdatedAt = time.Now()
if err := s.repo.UpdateReferral(ctx, referral); err != nil {
s.logger.Error("Failed to update referral", "referralCode", referralCode, "error", err)
return err
}
wallets, err := s.store.GetCustomerWallet(ctx, referral.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
} }
_, 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{}, referral.RewardAmount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to static wallet because of referral ID %v", referral.RewardAmount, referral.ReferrerID), fmt.Sprintf("Added %v to static wallet due to %v referral code being used", referral.RewardAmount, referral.ReferralCode),
) )
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, "error", err)
return err return err
} }
s.logger.Info("Referral processed successfully", "referredPhone", referredPhone, "referralCode", referralCode, "rewardAmount", referral.RewardAmount) _, err = s.repo.CreateUserReferral(ctx, domain.CreateUserReferrals{
ReferredID: referredID,
ReferralCodeID: referral.ID,
})
if err != nil {
s.logger.Error("Failed to add referral reward to static wallet", "referredID", referredID, "error", err)
return err
}
s.logger.Info("Referral processed successfully", "referralCode", referralCode, "rewardAmount", referral.RewardAmount)
return nil return nil
} }
func (s *Service) ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error { func (s *Service) GetReferralStats(ctx context.Context, userID int64, companyID int64) (domain.ReferralStats, error) {
s.logger.Info("Processing deposit bonus", "userPhone", userPhone, "amount", amount)
settings, err := s.repo.GetSettings(ctx)
if err != nil {
s.logger.Error("Failed to get referral settings", "error", err)
return err
}
userID, err := strconv.ParseInt(userPhone, 10, 64)
if err != nil {
s.logger.Error("Invalid phone number format", "userPhone", userPhone, "error", err)
return errors.New("invalid phone number format")
}
wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID)
if err != nil {
s.logger.Error("Failed to get wallets for user", "userID", userID, "error", err)
return err
}
if len(wallets) == 0 {
s.logger.Error("User has no wallet", "userID", userID)
return errors.New("user has no wallet")
}
walletID := wallets[0].ID
bonus := amount * (settings.CashbackPercentage / 100)
currentBonus := float64(wallets[0].Balance)
_, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBonus+bonus)), domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to static wallet because of Deposit Cashback Bonus %d", currentBonus+bonus, bonus))
if err != nil {
s.logger.Error("Failed to add deposit bonus to wallet", "walletID", walletID, "userID", userID, "bonus", bonus, "error", err)
return err
}
s.logger.Info("Deposit bonus processed successfully", "userPhone", userPhone, "bonus", bonus)
return nil
}
func (s *Service) ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error {
s.logger.Info("Processing bet referral", "userID", userId, "betAmount", betAmount)
settings, err := s.repo.GetSettings(ctx)
if err != nil {
s.logger.Error("Failed to get referral settings", "error", err)
return err
}
referral, err := s.repo.GetReferralByReferredID(ctx, userId)
if err != nil {
s.logger.Error("Failed to get referral by referred ID", "userId", userId, "error", err)
return err
}
if referral == nil || referral.Status != domain.ReferralCompleted {
s.logger.Warn("No valid referral found", "userId", userId, "status", referral.Status)
return ErrNoReferralFound
}
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referral.ReferrerID)
if err != nil {
s.logger.Error("Failed to get wallets for referrer", "referrerID", referral.ReferrerID, "error", err)
return err
}
if len(wallets) == 0 {
s.logger.Error("Referrer has no wallet", "referrerID", referral.ReferrerID)
return errors.New("referrer has no wallet")
}
bonusPercentage := settings.BetReferralBonusPercentage
if bonusPercentage == 0 {
bonusPercentage = 5.0
s.logger.Debug("Using default bet referral bonus percentage", "percentage", bonusPercentage)
}
bonus := betAmount * (bonusPercentage / 100)
walletID := wallets[0].ID
currentBalance := float64(wallets[0].Balance)
_, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBalance+bonus)), domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to static wallet because of bet referral", referral.RewardAmount))
if err != nil {
s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referral.ReferrerID, "bonus", bonus, "error", err)
return err
}
s.logger.Info("Bet referral processed successfully", "referrer ID", referral.ReferrerID, "referrerID", referral.ReferrerID, "bonus", bonus)
return nil
}
func (s *Service) GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error) {
s.logger.Info("Fetching referral stats", "userID", userID)
stats, err := s.repo.GetReferralStats(ctx, userID, companyID) stats, err := s.repo.GetReferralStats(ctx, userID, companyID)
if err != nil { if err != nil {
s.logger.Error("Failed to get referral stats", "userID", userID, "error", err) s.logger.Error("Failed to get referral stats", "userID", userID, "error", err)
return nil, err return domain.ReferralStats{}, err
} }
s.logger.Info("Referral stats retrieved successfully", "userID", userID, "totalReferrals", stats.TotalReferrals) s.logger.Info("Referral stats retrieved successfully", "userID", userID, "totalReferrals", stats.TotalReferrals)
return stats, nil return stats, nil
} }
func (s *Service) CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error { func (s *Service) GetUserReferralCount(ctx context.Context, referrerID int64) (int64, error) {
s.logger.Info("Creating referral setting") count, err := s.repo.GetUserReferralCount(ctx, referrerID)
if err := s.repo.CreateSettings(ctx, &domain.ReferralSettings{
ReferralRewardAmount: req.ReferralRewardAmount,
CashbackPercentage: req.CashbackPercentage,
MaxReferrals: req.MaxReferrals,
ExpiresAfterDays: req.ExpiresAfterDays,
UpdatedBy: req.UpdatedBy,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}); err != nil {
s.logger.Error("Failed to create referral setting", "error", err)
return err
}
s.logger.Info("Referral setting created succesfully")
return nil
}
func (s *Service) UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error {
s.logger.Info("Updating referral settings", "settingsID", settings.ID)
settings.UpdatedAt = time.Now()
err := s.repo.UpdateSettings(ctx, settings)
if err != nil {
s.logger.Error("Failed to update referral settings", "settingsID", settings.ID, "error", err)
return err
}
s.logger.Info("Referral settings updated successfully", "settingsID", settings.ID)
return nil
}
func (s *Service) GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error) {
s.logger.Info("Fetching referral settings")
settings, err := s.repo.GetSettings(ctx)
if err != nil {
s.logger.Error("Failed to get referral settings", "error", err)
return nil, err
}
s.logger.Info("Referral settings retrieved successfully", "settings", settings)
return settings, nil
}
func (s *Service) GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error) {
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)
return 0, err return 0, err
@ -327,3 +153,88 @@ func (s *Service) GetReferralCountByID(ctx context.Context, referrerID int64) (i
return count, nil return count, nil
} }
// func (s *Service) ProcessDepositBonus(ctx context.Context, userID int64, amount float32, companyID int64) error {
// settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, companyID)
// if err != nil {
// s.logger.Error("Failed to fetch settings", "error", err)
// return err
// }
// s.logger.Info("Processing deposit bonus", "amount", amount)
// customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, userID)
// if err != nil {
// s.logger.Error("Failed to get wallets for user", "userID", userID, "error", err)
// return err
// }
// bonus := amount * settingsList.CashbackPercentage
// _, err = s.walletSvc.AddToWallet(ctx, customerWallet.StaticID, domain.ToCurrency(bonus), domain.ValidInt64{},
// domain.TRANSFER_DIRECT, domain.PaymentDetails{},
// fmt.Sprintf("Added to bonus wallet because of Deposit Cashback Bonus %d", bonus))
// if err != nil {
// s.logger.Error("Failed to add deposit bonus to wallet", "staticWalletID", customerWallet.StaticID, "userID", userID, "bonus", bonus, "error", err)
// return err
// }
// s.logger.Info("Deposit bonus processed successfully", "bonus", bonus)
// return nil
// }
// func (s *Service) ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error {
// s.logger.Info("Processing bet referral", "userID", userId, "betAmount", betAmount)
// settings, err := s.repo.GetSettings(ctx)
// if err != nil {
// s.logger.Error("Failed to get referral settings", "error", err)
// return err
// }
// referral, err := s.repo.GetReferralByReferredID(ctx, userId)
// if err != nil {
// s.logger.Error("Failed to get referral by referred ID", "userId", userId, "error", err)
// return err
// }
// if referral == nil || referral.Status != domain.ReferralCompleted {
// s.logger.Warn("No valid referral found", "userId", userId, "status", referral.Status)
// return ErrNoReferralFound
// }
// wallets, err := s.walletSvc.GetWalletsByUser(ctx, referral.ReferrerID)
// if err != nil {
// s.logger.Error("Failed to get wallets for referrer", "referrerID", referral.ReferrerID, "error", err)
// return err
// }
// if len(wallets) == 0 {
// s.logger.Error("Referrer has no wallet", "referrerID", referral.ReferrerID)
// return errors.New("referrer has no wallet")
// }
// bonusPercentage := settings.BetReferralBonusPercentage
// if bonusPercentage == 0 {
// bonusPercentage = 5.0
// s.logger.Debug("Using default bet referral bonus percentage", "percentage", bonusPercentage)
// }
// bonus := betAmount * (bonusPercentage / 100)
// walletID := wallets[0].ID
// currentBalance := float64(wallets[0].Balance)
// _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBalance+bonus)), domain.ValidInt64{},
// domain.TRANSFER_DIRECT, domain.PaymentDetails{},
// fmt.Sprintf("Added %v to static wallet because of bet referral", referral.RewardAmount))
// if err != nil {
// s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referral.ReferrerID, "bonus", bonus, "error", err)
// return err
// }
// s.logger.Info("Bet referral processed successfully", "referrer ID", referral.ReferrerID, "referrerID", referral.ReferrerID, "bonus", bonus)
// return nil
// }

View File

@ -567,9 +567,9 @@ The System`, greeting, counts.StatusEndedCount, totalBets)
if counts.StatusNotFinishedCount > 0 { if counts.StatusNotFinishedCount > 0 {
partsPlain = append(partsPlain, partsPlain = append(partsPlain,
fmt.Sprintf("- %d Unresolved Events (%d Bets)", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets)) fmt.Sprintf("- %d Incomplete Events (%d Bets)", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
partsHTML = append(partsHTML, partsHTML = append(partsHTML,
fmt.Sprintf("<li><strong>%d Unresolved Events</strong> (%d Bets)</li>", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets)) fmt.Sprintf("<li><strong>%d Incomplete Events</strong> (%d Bets)</li>", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
} }
if counts.StatusToBeFixedCount > 0 { if counts.StatusToBeFixedCount > 0 {
partsPlain = append(partsPlain, partsPlain = append(partsPlain,

View File

@ -56,7 +56,7 @@ type App struct {
cfg *config.Config cfg *config.Config
logger *slog.Logger logger *slog.Logger
NotidicationStore *notificationservice.Service NotidicationStore *notificationservice.Service
referralSvc referralservice.ReferralStore referralSvc *referralservice.Service
bonusSvc *bonus.Service bonusSvc *bonus.Service
port int port int
settingSvc *settings.Service settingSvc *settings.Service
@ -107,7 +107,7 @@ func NewApp(
prematchSvc *odds.ServiceImpl, prematchSvc *odds.ServiceImpl,
eventSvc event.Service, eventSvc event.Service,
leagueSvc league.Service, leagueSvc league.Service,
referralSvc referralservice.ReferralStore, referralSvc *referralservice.Service,
bonusSvc *bonus.Service, bonusSvc *bonus.Service,
virtualGameSvc virtualgameservice.VirtualGameService, virtualGameSvc virtualgameservice.VirtualGameService,
aleaVirtualGameService alea.AleaVirtualGameService, aleaVirtualGameService alea.AleaVirtualGameService,

View File

@ -26,32 +26,32 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
spec string spec string
task func() task func()
}{ }{
{ // {
spec: "0 0 * * * *", // Every 1 hour // spec: "0 0 * * * *", // Every 1 hour
task: func() { // task: func() {
mongoLogger.Info("Began fetching upcoming events cron task") // mongoLogger.Info("Began fetching upcoming events cron task")
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { // if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch upcoming events", // mongoLogger.Error("Failed to fetch upcoming events",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed fetching upcoming events without errors") // mongoLogger.Info("Completed fetching upcoming events without errors")
} // }
}, // },
}, // },
{ // {
spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) // spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
task: func() { // task: func() {
mongoLogger.Info("Began fetching non live odds cron task") // mongoLogger.Info("Began fetching non live odds cron task")
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { // if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
mongoLogger.Error("Failed to fetch non live odds", // mongoLogger.Error("Failed to fetch non live odds",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed fetching non live odds without errors") // mongoLogger.Info("Completed fetching non live odds without errors")
} // }
}, // },
}, // },
{ {
spec: "0 */5 * * * *", // Every 5 Minutes spec: "0 */5 * * * *", // Every 5 Minutes
task: func() { task: func() {
@ -78,19 +78,19 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
} }
}, },
}, },
{ // {
spec: "0 0 0 * * *", // Every Day // spec: "0 0 0 * * *", // Every Day
task: func() { // task: func() {
mongoLogger.Info("Began Send daily result notification cron task") // mongoLogger.Info("Began Send daily result notification cron task")
if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-24*time.Hour)); err != nil { // if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-24*time.Hour)); err != nil {
mongoLogger.Error("Failed to process result", // mongoLogger.Error("Failed to process result",
zap.Error(err), // zap.Error(err),
) // )
} else { // } else {
mongoLogger.Info("Completed sending daily result notification without errors") // mongoLogger.Info("Completed sending daily result notification without errors")
} // }
}, // },
}, // },
} }
for _, job := range schedule { for _, job := range schedule {
@ -154,10 +154,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",

View File

@ -48,7 +48,7 @@ type Handler struct {
settingSvc *settings.Service settingSvc *settings.Service
notificationSvc *notificationservice.Service notificationSvc *notificationservice.Service
userSvc *user.Service userSvc *user.Service
referralSvc referralservice.ReferralStore referralSvc *referralservice.Service
bonusSvc *bonus.Service bonusSvc *bonus.Service
reportSvc report.ReportStore reportSvc report.ReportStore
chapaSvc *chapa.Service chapaSvc *chapa.Service
@ -87,7 +87,7 @@ func New(
reportSvc report.ReportStore, reportSvc report.ReportStore,
chapaSvc *chapa.Service, chapaSvc *chapa.Service,
walletSvc *wallet.Service, walletSvc *wallet.Service,
referralSvc referralservice.ReferralStore, referralSvc *referralservice.Service,
bonusSvc *bonus.Service, bonusSvc *bonus.Service,
virtualGameSvc virtualgameservice.VirtualGameService, virtualGameSvc virtualgameservice.VirtualGameService,
aleaVirtualGameSvc alea.AleaVirtualGameService, aleaVirtualGameSvc alea.AleaVirtualGameService,

View File

@ -11,6 +11,7 @@ import (
) )
func (h *Handler) CreateReferralCode(c *fiber.Ctx) error { func (h *Handler) CreateReferralCode(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")
@ -36,6 +37,7 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral") return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
} }
fmt.Printf("Successfully created referral!")
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil) return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
} }