diff --git a/db/query/referal.sql b/db/query/referal.sql index a10b274..dd868ca 100644 --- a/db/query/referal.sql +++ b/db/query/referal.sql @@ -40,7 +40,6 @@ WHERE referrer_id = $1; -- name: GetReferralSettings :one SELECT * FROM referral_settings -WHERE id = 'default' LIMIT 1; -- name: UpdateReferralSettings :one diff --git a/gen/db/referal.sql.go b/gen/db/referal.sql.go index 3a7f337..9784440 100644 --- a/gen/db/referal.sql.go +++ b/gen/db/referal.sql.go @@ -149,7 +149,6 @@ func (q *Queries) GetReferralByReferredID(ctx context.Context, referredID pgtype 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 -WHERE id = 'default' LIMIT 1 ` diff --git a/internal/domain/referal.go b/internal/domain/referal.go index 9923806..1e528a4 100644 --- a/internal/domain/referal.go +++ b/internal/domain/referal.go @@ -51,6 +51,14 @@ type ReferralSettings struct { 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 { ID int64 ReferralCode string diff --git a/internal/repository/referal.go b/internal/repository/referal.go index a782cfb..105ce5d 100644 --- a/internal/repository/referal.go +++ b/internal/repository/referal.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "errors" + "fmt" "strconv" 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 { rewardAmount := pgtype.Numeric{} - if err := rewardAmount.Scan(settings.ReferralRewardAmount); err != nil { + if err := rewardAmount.Scan(fmt.Sprintf("%f", settings.ReferralRewardAmount)); err != nil { return err } cashbackPercentage := pgtype.Numeric{} - if err := cashbackPercentage.Scan(settings.CashbackPercentage); err != nil { + if err := cashbackPercentage.Scan(fmt.Sprintf("%f", settings.CashbackPercentage)); err != nil { return err } betReferralBonusPercentage := pgtype.Numeric{} - if err := betReferralBonusPercentage.Scan(settings.BetReferralBonusPercentage); err != nil { + if err := betReferralBonusPercentage.Scan(fmt.Sprintf("%f", settings.BetReferralBonusPercentage)); err != nil { return err } diff --git a/internal/services/referal/port.go b/internal/services/referal/port.go index 5fb867b..703f986 100644 --- a/internal/services/referal/port.go +++ b/internal/services/referal/port.go @@ -12,6 +12,7 @@ type ReferralStore interface { ProcessReferral(ctx context.Context, referredID, referralCode string) error ProcessDepositBonus(ctx context.Context, userID string, amount float64) 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 GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error) ProcessBetReferral(ctx context.Context, userPhone string, betAmount float64) error diff --git a/internal/services/referal/service.go b/internal/services/referal/service.go index 5585d74..0a812f0 100644 --- a/internal/services/referal/service.go +++ b/internal/services/referal/service.go @@ -54,16 +54,32 @@ func (s *Service) GenerateReferralCode() (string, error) { func (s *Service) CreateReferral(ctx context.Context, userID int64) error { 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() if err != nil { s.logger.Error("Failed to generate referral code", "error", err) return err } - // TODO: get the referral settings from db - var rewardAmount float64 = 100 - var expireDuration time.Time = time.Now().Add(24 * time.Hour) + settings, err := s.GetReferralSettings(ctx) + if err != nil || settings == nil { + 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{ ReferralCode: code, @@ -242,6 +258,26 @@ func (s *Service) GetReferralStats(ctx context.Context, userPhone string) (*doma 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 { 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 } - s.logger.Info("Referral settings retrieved successfully", "settingsID", settings.ID) + s.logger.Info("Referral settings retrieved successfully", "settings", settings) return settings, nil } diff --git a/internal/web_server/handlers/referal_handlers.go b/internal/web_server/handlers/referal_handlers.go index d978e0b..a2fe09e 100644 --- a/internal/web_server/handlers/referal_handlers.go +++ b/internal/web_server/handlers/referal_handlers.go @@ -21,6 +21,38 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error { 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 // @Summary Get referral statistics // @Description Retrieves referral statistics for the authenticated user @@ -112,11 +144,12 @@ func (h *Handler) UpdateReferralSettings(c *fiber.Ctx) error { // @Security Bearer // @Router /referral/settings [get] func (h *Handler) GetReferralSettings(c *fiber.Ctx) error { - userID, ok := c.Locals("user_id").(int64) - if !ok || userID == 0 { - h.logger.Error("Invalid user ID in context") - return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") - } + // userID, ok := c.Locals("user_id").(int64) + // if !ok || userID == 0 { + // h.logger.Error("Invalid user ID in context") + // return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") + // } + userID := int64(2) user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 8e6e4aa..cf0ad4c 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -109,7 +109,8 @@ func (a *App) initAppRoutes() { // Referral Routes a.fiber.Post("/referral/create", a.authMiddleware, h.CreateReferralCode) 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) // Bonus Routes