feat: referal completed
This commit is contained in:
parent
f796b97afe
commit
8670fba6a4
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||||
|
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
|
|
@ -63,13 +64,15 @@ func main() {
|
||||||
transactionSvc := transaction.NewService(store)
|
transactionSvc := transaction.NewService(store)
|
||||||
|
|
||||||
notificationRepo := repository.NewNotificationRepository(store)
|
notificationRepo := repository.NewNotificationRepository(store)
|
||||||
|
referalRepo := repository.NewReferralRepository(store)
|
||||||
|
|
||||||
notificationSvc := notificationservice.New(notificationRepo, logger, cfg)
|
notificationSvc := notificationservice.New(notificationRepo, logger, cfg)
|
||||||
|
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
|
||||||
|
|
||||||
app := httpserver.NewApp(cfg.Port, v, authSvc, logger, jwtutil.JwtConfig{
|
app := httpserver.NewApp(cfg.Port, v, authSvc, logger, jwtutil.JwtConfig{
|
||||||
JwtAccessKey: cfg.JwtKey,
|
JwtAccessKey: cfg.JwtKey,
|
||||||
JwtAccessExpiry: cfg.AccessExpiry,
|
JwtAccessExpiry: cfg.AccessExpiry,
|
||||||
}, userSvc, ticketSvc, betSvc, walletSvc, transactionSvc, notificationSvc,
|
}, userSvc, ticketSvc, betSvc, walletSvc, transactionSvc, notificationSvc, referalSvc)
|
||||||
)
|
|
||||||
logger.Info("Starting server", "port", cfg.Port)
|
logger.Info("Starting server", "port", cfg.Port)
|
||||||
|
|
||||||
if err := app.Run(); err != nil {
|
if err := app.Run(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,13 @@ SET
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateReferralCode :exec
|
||||||
|
UPDATE users
|
||||||
|
SET
|
||||||
|
referral_code = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: GetReferralStats :one
|
-- name: GetReferralStats :one
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) as total_referrals,
|
COUNT(*) as total_referrals,
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,24 @@ func (q *Queries) UpdateReferral(ctx context.Context, arg UpdateReferralParams)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateReferralCode = `-- name: UpdateReferralCode :exec
|
||||||
|
UPDATE users
|
||||||
|
SET
|
||||||
|
referral_code = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateReferralCodeParams struct {
|
||||||
|
ID int64
|
||||||
|
ReferralCode pgtype.Text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateReferralCode(ctx context.Context, arg UpdateReferralCodeParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateReferralCode, arg.ID, arg.ReferralCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const UpdateReferralSettings = `-- name: UpdateReferralSettings :one
|
const UpdateReferralSettings = `-- name: UpdateReferralSettings :one
|
||||||
UPDATE referral_settings
|
UPDATE referral_settings
|
||||||
SET
|
SET
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,8 @@ type UpdateUserReq struct {
|
||||||
LastName ValidString
|
LastName ValidString
|
||||||
Suspended ValidBool
|
Suspended ValidBool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateUserReferalCode struct {
|
||||||
|
UserID int64
|
||||||
|
Code string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ type ReferralRepository interface {
|
||||||
UpdateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
UpdateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
||||||
CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
CreateSettings(ctx context.Context, settings *domain.ReferralSettings) error
|
||||||
GetReferralByReferredID(ctx context.Context, referredID string) (*domain.Referral, error) // New method
|
GetReferralByReferredID(ctx context.Context, referredID string) (*domain.Referral, error) // New method
|
||||||
|
UpdateUserReferalCode(ctx context.Context, codedata domain.UpdateUserReferalCode) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReferralRepo struct {
|
type ReferralRepo struct {
|
||||||
|
|
@ -29,6 +30,18 @@ func NewReferralRepository(store *Store) ReferralRepository {
|
||||||
return &ReferralRepo{store: store}
|
return &ReferralRepo{store: store}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ReferralRepo) UpdateUserReferalCode(ctx context.Context, codedata domain.UpdateUserReferalCode) error {
|
||||||
|
params := dbgen.UpdateReferralCodeParams{
|
||||||
|
ID: codedata.UserID,
|
||||||
|
ReferralCode: pgtype.Text{
|
||||||
|
String: codedata.Code,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.store.queries.UpdateReferralCode(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *ReferralRepo) CreateReferral(ctx context.Context, referral *domain.Referral) error {
|
func (r *ReferralRepo) CreateReferral(ctx context.Context, referral *domain.Referral) error {
|
||||||
rewardAmount := pgtype.Numeric{}
|
rewardAmount := pgtype.Numeric{}
|
||||||
if err := rewardAmount.Scan(referral.RewardAmount); err != nil {
|
if err := rewardAmount.Scan(referral.RewardAmount); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,11 @@ import (
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
repo repository.NotificationRepository
|
repo repository.NotificationRepository
|
||||||
logger *slog.Logger
|
|
||||||
connections sync.Map
|
connections sync.Map
|
||||||
notificationCh chan *domain.Notification
|
notificationCh chan *domain.Notification
|
||||||
stopCh chan struct{}
|
stopCh chan struct{}
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(repo repository.NotificationRepository, logger *slog.Logger, cfg *config.Config) NotificationStore {
|
func New(repo repository.NotificationRepository, logger *slog.Logger, cfg *config.Config) NotificationStore {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
type ReferralStore interface {
|
type ReferralStore interface {
|
||||||
GenerateReferralCode() (string, error)
|
GenerateReferralCode() (string, error)
|
||||||
CreateReferral(ctx context.Context, userID string) (*domain.Referral, error)
|
CreateReferral(ctx context.Context, userID int64) error
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
|
@ -17,13 +19,17 @@ type Service struct {
|
||||||
repo repository.ReferralRepository
|
repo repository.ReferralRepository
|
||||||
walletSvc wallet.Service
|
walletSvc wallet.Service
|
||||||
store *repository.Store
|
store *repository.Store
|
||||||
|
config *config.Config
|
||||||
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(repo repository.ReferralRepository, walletSvc wallet.Service, store *repository.Store) *Service {
|
func New(repo repository.ReferralRepository, walletSvc wallet.Service, store *repository.Store, cfg *config.Config, logger *slog.Logger) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
walletSvc: walletSvc,
|
walletSvc: walletSvc,
|
||||||
store: store,
|
store: store,
|
||||||
|
config: cfg,
|
||||||
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,77 +43,57 @@ var (
|
||||||
func (s *Service) GenerateReferralCode() (string, error) {
|
func (s *Service) GenerateReferralCode() (string, error) {
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
if _, err := rand.Read(b); err != nil {
|
if _, err := rand.Read(b); err != nil {
|
||||||
|
s.logger.Error("Failed to generate random bytes for referral code", "error", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return base32.StdEncoding.EncodeToString(b)[:10], nil
|
code := base32.StdEncoding.EncodeToString(b)[:10]
|
||||||
}
|
s.logger.Debug("Generated referral code", "code", code)
|
||||||
|
return code, nil
|
||||||
func (s *Service) CreateReferral(ctx context.Context, userPhone string) (*domain.Referral, error) {
|
|
||||||
settings, err := s.repo.GetSettings(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateReferral(ctx context.Context, userID int64) error {
|
||||||
|
s.logger.Info("Creating referral code for user", "userID", userID)
|
||||||
code, err := s.GenerateReferralCode()
|
code, err := s.GenerateReferralCode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
s.logger.Error("Failed to generate referral code", "error", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
userID, err := strconv.ParseInt(userPhone, 10, 64)
|
if err := s.repo.UpdateUserReferalCode(ctx, domain.UpdateUserReferalCode{
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("invalid phone number format")
|
|
||||||
}
|
|
||||||
|
|
||||||
wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(wallets) == 0 {
|
|
||||||
_, err = s.walletSvc.CreateWallet(ctx, domain.CreateWallet{
|
|
||||||
IsWithdraw: true,
|
|
||||||
IsBettable: true,
|
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
})
|
Code: code,
|
||||||
if err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
referral := &domain.Referral{
|
return nil
|
||||||
ReferrerID: userPhone,
|
|
||||||
ReferralCode: code,
|
|
||||||
Status: domain.ReferralPending,
|
|
||||||
RewardAmount: settings.ReferralRewardAmount,
|
|
||||||
ExpiresAt: time.Now().Add(time.Duration(settings.ExpiresAfterDays) * 24 * time.Hour),
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.repo.CreateReferral(ctx, referral); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return referral, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCode string) error {
|
func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCode string) error {
|
||||||
|
s.logger.Info("Processing referral", "referredPhone", referredPhone, "referralCode", referralCode)
|
||||||
|
|
||||||
referral, err := s.repo.GetReferralByCode(ctx, referralCode)
|
referral, err := s.repo.GetReferralByCode(ctx, referralCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get referral by code", "referralCode", referralCode, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if referral == nil || referral.Status != domain.ReferralPending || referral.ExpiresAt.Before(time.Now()) {
|
if referral == nil || referral.Status != domain.ReferralPending || referral.ExpiresAt.Before(time.Now()) {
|
||||||
|
s.logger.Warn("Invalid or expired referral", "referralCode", referralCode, "status", referral.Status)
|
||||||
return ErrInvalidReferral
|
return ErrInvalidReferral
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := s.store.GetUserByPhone(ctx, referredPhone)
|
user, err := s.store.GetUserByPhone(ctx, referredPhone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, domain.ErrUserNotFound) {
|
if errors.Is(err, domain.ErrUserNotFound) {
|
||||||
|
s.logger.Warn("User not found for referral", "referredPhone", referredPhone)
|
||||||
return ErrUserNotFound
|
return ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
s.logger.Error("Failed to get user by phone", "referredPhone", referredPhone, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !user.PhoneVerified {
|
if !user.PhoneVerified {
|
||||||
|
s.logger.Warn("Phone not verified for referral", "referredPhone", referredPhone)
|
||||||
return ErrInvalidReferralSignup
|
return ErrInvalidReferralSignup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,99 +102,166 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo
|
||||||
referral.UpdatedAt = time.Now()
|
referral.UpdatedAt = time.Now()
|
||||||
|
|
||||||
if err := s.repo.UpdateReferral(ctx, referral); err != nil {
|
if err := s.repo.UpdateReferral(ctx, referral); err != nil {
|
||||||
|
s.logger.Error("Failed to update referral", "referralCode", referralCode, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
referrerID, err := strconv.ParseInt(referral.ReferrerID, 10, 64)
|
referrerID, err := strconv.ParseInt(referral.ReferrerID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Invalid referrer phone number format", "referrerID", referral.ReferrerID, "error", err)
|
||||||
return errors.New("invalid referrer phone number format")
|
return errors.New("invalid referrer phone number format")
|
||||||
}
|
}
|
||||||
|
|
||||||
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referrerID)
|
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referrerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get wallets for referrer", "referrerID", referrerID, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(wallets) == 0 {
|
if len(wallets) == 0 {
|
||||||
|
s.logger.Error("Referrer has no wallet", "referrerID", referrerID)
|
||||||
return errors.New("referrer has no wallet")
|
return errors.New("referrer has no wallet")
|
||||||
}
|
}
|
||||||
|
|
||||||
walletID := wallets[0].ID
|
walletID := wallets[0].ID
|
||||||
currentBonus := float64(wallets[0].Balance)
|
currentBonus := float64(wallets[0].Balance)
|
||||||
return s.walletSvc.Add(ctx, walletID, domain.Currency(int64((currentBonus+referral.RewardAmount)*100)))
|
err = s.walletSvc.Add(ctx, walletID, domain.Currency(int64((currentBonus+referral.RewardAmount)*100)))
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to add referral reward to wallet", "walletID", walletID, "referrerID", referrerID, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Referral processed successfully", "referredPhone", referredPhone, "referralCode", referralCode, "rewardAmount", referral.RewardAmount)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error {
|
func (s *Service) ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error {
|
||||||
|
s.logger.Info("Processing deposit bonus", "userPhone", userPhone, "amount", amount)
|
||||||
|
|
||||||
settings, err := s.repo.GetSettings(ctx)
|
settings, err := s.repo.GetSettings(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get referral settings", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
userID, err := strconv.ParseInt(userPhone, 10, 64)
|
userID, err := strconv.ParseInt(userPhone, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Invalid phone number format", "userPhone", userPhone, "error", err)
|
||||||
return errors.New("invalid phone number format")
|
return errors.New("invalid phone number format")
|
||||||
}
|
}
|
||||||
|
|
||||||
wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID)
|
wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get wallets for user", "userID", userID, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(wallets) == 0 {
|
if len(wallets) == 0 {
|
||||||
|
s.logger.Error("User has no wallet", "userID", userID)
|
||||||
return errors.New("user has no wallet")
|
return errors.New("user has no wallet")
|
||||||
}
|
}
|
||||||
|
|
||||||
walletID := wallets[0].ID
|
walletID := wallets[0].ID
|
||||||
bonus := amount * (settings.CashbackPercentage / 100)
|
bonus := amount * (settings.CashbackPercentage / 100)
|
||||||
currentBonus := float64(wallets[0].Balance)
|
currentBonus := float64(wallets[0].Balance)
|
||||||
return s.walletSvc.Add(ctx, walletID, domain.Currency(int64((currentBonus+bonus)*100)))
|
err = s.walletSvc.Add(ctx, walletID, domain.Currency(int64((currentBonus+bonus)*100)))
|
||||||
|
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, userPhone string, betAmount float64) error {
|
func (s *Service) ProcessBetReferral(ctx context.Context, userPhone string, betAmount float64) error {
|
||||||
|
s.logger.Info("Processing bet referral", "userPhone", userPhone, "betAmount", betAmount)
|
||||||
|
|
||||||
settings, err := s.repo.GetSettings(ctx)
|
settings, err := s.repo.GetSettings(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get referral settings", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
referral, err := s.repo.GetReferralByReferredID(ctx, userPhone)
|
referral, err := s.repo.GetReferralByReferredID(ctx, userPhone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get referral by referred ID", "userPhone", userPhone, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if referral == nil || referral.Status != domain.ReferralCompleted {
|
if referral == nil || referral.Status != domain.ReferralCompleted {
|
||||||
|
s.logger.Warn("No valid referral found", "userPhone", userPhone, "status", referral.Status)
|
||||||
return ErrNoReferralFound
|
return ErrNoReferralFound
|
||||||
}
|
}
|
||||||
|
|
||||||
referrerID, err := strconv.ParseInt(referral.ReferrerID, 10, 64)
|
referrerID, err := strconv.ParseInt(referral.ReferrerID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Invalid referrer phone number format", "referrerID", referral.ReferrerID, "error", err)
|
||||||
return errors.New("invalid referrer phone number format")
|
return errors.New("invalid referrer phone number format")
|
||||||
}
|
}
|
||||||
|
|
||||||
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referrerID)
|
wallets, err := s.walletSvc.GetWalletsByUser(ctx, referrerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get wallets for referrer", "referrerID", referrerID, "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(wallets) == 0 {
|
if len(wallets) == 0 {
|
||||||
|
s.logger.Error("Referrer has no wallet", "referrerID", referrerID)
|
||||||
return errors.New("referrer has no wallet")
|
return errors.New("referrer has no wallet")
|
||||||
}
|
}
|
||||||
|
|
||||||
bonusPercentage := settings.BetReferralBonusPercentage
|
bonusPercentage := settings.BetReferralBonusPercentage
|
||||||
if bonusPercentage == 0 {
|
if bonusPercentage == 0 {
|
||||||
bonusPercentage = 5.0
|
bonusPercentage = 5.0
|
||||||
|
s.logger.Debug("Using default bet referral bonus percentage", "percentage", bonusPercentage)
|
||||||
}
|
}
|
||||||
bonus := betAmount * (bonusPercentage / 100)
|
bonus := betAmount * (bonusPercentage / 100)
|
||||||
|
|
||||||
walletID := wallets[0].ID
|
walletID := wallets[0].ID
|
||||||
currentBalance := float64(wallets[0].Balance)
|
currentBalance := float64(wallets[0].Balance)
|
||||||
return s.walletSvc.Add(ctx, walletID, domain.Currency(int64((currentBalance+bonus)*100)))
|
err = s.walletSvc.Add(ctx, walletID, domain.Currency(int64((currentBalance+bonus)*100)))
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referrerID, "bonus", bonus, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Bet referral processed successfully", "userPhone", userPhone, "referrerID", referrerID, "bonus", bonus)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetReferralStats(ctx context.Context, userPhone string) (*domain.ReferralStats, error) {
|
func (s *Service) GetReferralStats(ctx context.Context, userPhone string) (*domain.ReferralStats, error) {
|
||||||
return s.repo.GetReferralStats(ctx, userPhone)
|
s.logger.Info("Fetching referral stats", "userPhone", userPhone)
|
||||||
|
|
||||||
|
stats, err := s.repo.GetReferralStats(ctx, userPhone)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to get referral stats", "userPhone", userPhone, "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Referral stats retrieved successfully", "userPhone", userPhone, "totalReferrals", stats.TotalReferrals)
|
||||||
|
return stats, 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)
|
||||||
|
|
||||||
settings.UpdatedAt = time.Now()
|
settings.UpdatedAt = time.Now()
|
||||||
return s.repo.UpdateSettings(ctx, settings)
|
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) {
|
func (s *Service) GetReferralSettings(ctx context.Context) (*domain.ReferralSettings, error) {
|
||||||
return s.repo.GetSettings(ctx)
|
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", "settingsID", settings.ID)
|
||||||
|
return settings, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,26 +6,19 @@ import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) CreateReferral(c *fiber.Ctx) error {
|
func (h *Handler) CreateReferralCode(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")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
if err := h.referralSvc.CreateReferral(c.Context(), userID); err != nil {
|
||||||
if err != nil {
|
|
||||||
h.logger.Error("Failed to get user", "userID", userID, "error", err)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
|
||||||
}
|
|
||||||
|
|
||||||
referral, err := h.referralSvc.CreateReferral(c.Context(), user.PhoneNumber)
|
|
||||||
if err != nil {
|
|
||||||
h.logger.Error("Failed to create referral", "userID", userID, "error", err)
|
h.logger.Error("Failed to create referral", "userID", userID, "error", err)
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", referral, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReferralStats godoc
|
// GetReferralStats godoc
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Patch("/wallet/:id", h.UpdateWalletActive)
|
a.fiber.Patch("/wallet/:id", h.UpdateWalletActive)
|
||||||
|
|
||||||
// Referral Routes
|
// Referral Routes
|
||||||
a.fiber.Post("/referral/create", a.authMiddleware, h.CreateReferral)
|
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.Get("/referral/settings", h.GetReferralSettings)
|
||||||
a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
|
a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user