control over referral settings

This commit is contained in:
Asher Samuel 2025-06-30 12:23:14 +03:00
parent 19b7a151d6
commit 8218790292
8 changed files with 94 additions and 16 deletions

View File

@ -40,7 +40,6 @@ WHERE referrer_id = $1;
-- name: GetReferralSettings :one -- name: GetReferralSettings :one
SELECT * FROM referral_settings SELECT * FROM referral_settings
WHERE id = 'default'
LIMIT 1; LIMIT 1;
-- name: UpdateReferralSettings :one -- name: UpdateReferralSettings :one

View File

@ -149,7 +149,6 @@ func (q *Queries) GetReferralByReferredID(ctx context.Context, referredID pgtype
const GetReferralSettings = `-- name: GetReferralSettings :one const GetReferralSettings = `-- name: GetReferralSettings :one
SELECT id, referral_reward_amount, cashback_percentage, bet_referral_bonus_percentage, max_referrals, expires_after_days, updated_by, created_at, updated_at, version FROM referral_settings SELECT id, referral_reward_amount, cashback_percentage, bet_referral_bonus_percentage, max_referrals, expires_after_days, updated_by, created_at, updated_at, version FROM referral_settings
WHERE id = 'default'
LIMIT 1 LIMIT 1
` `

View File

@ -51,6 +51,14 @@ type ReferralSettings struct {
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"`
ExpiresAfterDays int32 `json:"expires_afterdays" validate:"required"`
UpdatedBy string `json:"updated_by" validate:"required"`
}
type Referral struct { type Referral struct {
ID int64 ID int64
ReferralCode string ReferralCode string

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"errors" "errors"
"fmt"
"strconv" "strconv"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
@ -145,17 +146,17 @@ func (r *ReferralRepo) UpdateSettings(ctx context.Context, settings *domain.Refe
func (r *ReferralRepo) CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error { func (r *ReferralRepo) CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error {
rewardAmount := pgtype.Numeric{} rewardAmount := pgtype.Numeric{}
if err := rewardAmount.Scan(settings.ReferralRewardAmount); err != nil { if err := rewardAmount.Scan(fmt.Sprintf("%f", settings.ReferralRewardAmount)); err != nil {
return err return err
} }
cashbackPercentage := pgtype.Numeric{} cashbackPercentage := pgtype.Numeric{}
if err := cashbackPercentage.Scan(settings.CashbackPercentage); err != nil { if err := cashbackPercentage.Scan(fmt.Sprintf("%f", settings.CashbackPercentage)); err != nil {
return err return err
} }
betReferralBonusPercentage := pgtype.Numeric{} betReferralBonusPercentage := pgtype.Numeric{}
if err := betReferralBonusPercentage.Scan(settings.BetReferralBonusPercentage); err != nil { if err := betReferralBonusPercentage.Scan(fmt.Sprintf("%f", settings.BetReferralBonusPercentage)); err != nil {
return err return err
} }

View File

@ -12,6 +12,7 @@ type ReferralStore interface {
ProcessReferral(ctx context.Context, referredID, referralCode string) error ProcessReferral(ctx context.Context, referredID, referralCode string) error
ProcessDepositBonus(ctx context.Context, userID string, amount float64) error ProcessDepositBonus(ctx context.Context, userID string, amount float64) error
GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error) GetReferralStats(ctx context.Context, userID string) (*domain.ReferralStats, error)
CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error
UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error
GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error) GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error)
ProcessBetReferral(ctx context.Context, userPhone string, betAmount float64) error ProcessBetReferral(ctx context.Context, userPhone string, betAmount float64) error

View File

@ -54,16 +54,32 @@ func (s *Service) GenerateReferralCode() (string, error) {
func (s *Service) CreateReferral(ctx context.Context, userID int64) error { func (s *Service) CreateReferral(ctx context.Context, userID int64) error {
s.logger.Info("Creating referral code for user", "userID", userID) s.logger.Info("Creating referral code for user", "userID", userID)
// TODO: check in user already has an active referral code
// check if user already has an active referral code
referral, err := s.repo.GetReferralByReferredID(ctx, fmt.Sprintf("%d", userID))
if err != nil {
s.logger.Error("Failed to check if user alredy has active referral code", "error", err)
return err
}
if referral != nil && referral.Status == domain.ReferralPending && referral.ExpiresAt.After(time.Now()) {
s.logger.Error("user already has an active referral code", "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 err
} }
// TODO: get the referral settings from db settings, err := s.GetReferralSettings(ctx)
var rewardAmount float64 = 100 if err != nil || settings == nil {
var expireDuration time.Time = time.Now().Add(24 * time.Hour) s.logger.Error("Failed to fetch referral settings", "error", err)
return err
}
var rewardAmount float64 = settings.ReferralRewardAmount
var expireDuration time.Time = time.Now().Add(time.Duration((24 * settings.ExpiresAfterDays)) * time.Hour)
if err := s.repo.CreateReferral(ctx, &domain.Referral{ if err := s.repo.CreateReferral(ctx, &domain.Referral{
ReferralCode: code, ReferralCode: code,
@ -242,6 +258,26 @@ func (s *Service) GetReferralStats(ctx context.Context, userPhone string) (*doma
return stats, nil return stats, nil
} }
func (s *Service) CreateReferralSettings(ctx context.Context, req domain.ReferralSettingsReq) error {
s.logger.Info("Creating referral setting")
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 { func (s *Service) UpdateReferralSettings(ctx context.Context, settings *domain.ReferralSettings) error {
s.logger.Info("Updating referral settings", "settingsID", settings.ID) s.logger.Info("Updating referral settings", "settingsID", settings.ID)
@ -265,6 +301,6 @@ func (s *Service) GetReferralSettings(ctx context.Context) (*domain.ReferralSett
return nil, err return nil, err
} }
s.logger.Info("Referral settings retrieved successfully", "settingsID", settings.ID) s.logger.Info("Referral settings retrieved successfully", "settings", settings)
return settings, nil return settings, nil
} }

View File

@ -21,6 +21,38 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil) return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
} }
func (h *Handler) CreateReferralSettings(c *fiber.Ctx) error {
var req domain.ReferralSettingsReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("Failed to parse settings", "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
}
if valErrs, ok := h.validator.Validate(c, req); !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
settings, err := h.referralSvc.GetReferralSettings(c.Context())
if err != nil {
h.logger.Error("Failed to fetch previous referral setting", "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
}
// only allow one referral setting for now
// for future it can be multiple and be able to choose from them
if settings != nil {
h.logger.Error("referral setting already exists", "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "referral setting already exists")
}
if err := h.referralSvc.CreateReferralSettings(c.Context(), req); err != nil {
h.logger.Error("Failed to create referral setting", "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
}
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
}
// GetReferralStats godoc // GetReferralStats godoc
// @Summary Get referral statistics // @Summary Get referral statistics
// @Description Retrieves referral statistics for the authenticated user // @Description Retrieves referral statistics for the authenticated user
@ -112,11 +144,12 @@ func (h *Handler) UpdateReferralSettings(c *fiber.Ctx) error {
// @Security Bearer // @Security Bearer
// @Router /referral/settings [get] // @Router /referral/settings [get]
func (h *Handler) GetReferralSettings(c *fiber.Ctx) error { func (h *Handler) GetReferralSettings(c *fiber.Ctx) error {
userID, ok := c.Locals("user_id").(int64) // userID, ok := c.Locals("user_id").(int64)
if !ok || userID == 0 { // if !ok || userID == 0 {
h.logger.Error("Invalid user ID in context") // h.logger.Error("Invalid user ID in context")
return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") // return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
} // }
userID := int64(2)
user, err := h.userSvc.GetUserByID(c.Context(), userID) user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil { if err != nil {

View File

@ -109,7 +109,8 @@ func (a *App) initAppRoutes() {
// Referral Routes // Referral Routes
a.fiber.Post("/referral/create", a.authMiddleware, h.CreateReferralCode) a.fiber.Post("/referral/create", a.authMiddleware, h.CreateReferralCode)
a.fiber.Get("/referral/stats", a.authMiddleware, h.GetReferralStats) a.fiber.Get("/referral/stats", a.authMiddleware, h.GetReferralStats)
a.fiber.Get("/referral/settings", h.GetReferralSettings) a.fiber.Post("/referral/settings", a.authMiddleware, h.CreateReferralSettings)
a.fiber.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings)
a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings) a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
// Bonus Routes // Bonus Routes