Yimaru-BackEnd/internal/services/referal/service.go

241 lines
8.3 KiB
Go

package referralservice
import (
"context"
"crypto/rand"
"encoding/base32"
"errors"
"fmt"
"log/slog"
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
)
type Service struct {
repo repository.ReferralRepository
walletSvc wallet.Service
settingSvc settings.Service
config *config.Config
logger *slog.Logger
}
func New(repo repository.ReferralRepository, walletSvc wallet.Service, settingSvc settings.Service, cfg *config.Config, logger *slog.Logger) *Service {
return &Service{
repo: repo,
walletSvc: walletSvc,
settingSvc: settingSvc,
config: cfg,
logger: logger,
}
}
var (
ErrInvalidReferral = errors.New("invalid or expired referral")
ErrUserNotFound = errors.New("user not found")
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) {
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
s.logger.Error("Failed to generate random bytes for referral code", "error", err)
return "", err
}
code := base32.StdEncoding.EncodeToString(b)[:10]
s.logger.Debug("Generated referral code", "code", code)
return code, nil
}
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)
// check if user already has an active referral code
referralCodes, err := s.repo.GetReferralCodesByUser(ctx, userID)
if err != nil {
s.logger.Error("Failed to check if user alredy has active referral code", "error", err)
return domain.ReferralCode{}, err
}
if referralCodes != nil {
s.logger.Error("user already has an active referral code", "error", err)
return domain.ReferralCode{}, ErrUserAlreadyHasReferralCode
}
code, err := s.GenerateReferralCode()
if err != nil {
s.logger.Error("Failed to generate referral code", "error", err)
return domain.ReferralCode{}, err
}
newReferralCode, err := s.repo.CreateReferralCode(ctx, domain.CreateReferralCode{
ReferrerID: userID,
ReferralCode: code,
CompanyID: companyID,
NumberOfReferrals: settingsList.DefaultMaxReferrals,
RewardAmount: settingsList.ReferralRewardAmount,
})
if err != nil {
return domain.ReferralCode{}, err
}
return newReferralCode, nil
}
func (s *Service) ProcessReferral(ctx context.Context, referredID int64, referralCode string, companyID int64) error {
s.logger.Info("Processing referral", "referralCode", referralCode)
referral, err := s.repo.GetReferralCode(ctx, referralCode)
if err != nil {
s.logger.Error("Failed to get referral by code", "referralCode", referralCode, "error", err)
return err
}
wallets, err := s.walletSvc.GetCustomerWallet(ctx, referral.ReferrerID)
if err != nil {
s.logger.Error("Failed to get referrer wallets", "referrerId", referral.ReferrerID, "error", err)
return err
}
_, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID,
referral.RewardAmount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
fmt.Sprintf("Added %v to static wallet due to %v referral code being used", referral.RewardAmount, referral.ReferralCode),
)
if err != nil {
s.logger.Error("Failed to add referral reward to static wallet", "walletID", wallets.StaticID, "error", err)
return err
}
_, 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
}
func (s *Service) GetReferralStats(ctx context.Context, userID int64, companyID int64) (domain.ReferralStats, error) {
stats, err := s.repo.GetReferralStats(ctx, userID, companyID)
if err != nil {
s.logger.Error("Failed to get referral stats", "userID", userID, "error", err)
return domain.ReferralStats{}, err
}
s.logger.Info("Referral stats retrieved successfully", "userID", userID, "totalReferrals", stats.TotalReferrals)
return stats, nil
}
func (s *Service) GetUserReferralCount(ctx context.Context, referrerID int64) (int64, error) {
count, err := s.repo.GetUserReferralCount(ctx, referrerID)
if err != nil {
s.logger.Error("Failed to get referral count", "userID", referrerID, "error", err)
return 0, err
}
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
// }