- Removed the CheckAndSendResultNotifications method from the result service. - Consolidated notification logic into a new notification.go file. - Updated email and in-app notification formatting to include event processing periods. - Added error handling for wallet operations to check if wallets are active before processing transfers. - Introduced new error for disabled wallets. - Updated cron jobs to comment out unnecessary tasks. - Added bulk update functionality for bet outcomes by odd IDs in the odd handler. - Renamed ticket handler methods for clarity and consistency. - Updated API version in routes.
288 lines
8.4 KiB
Go
288 lines
8.4 KiB
Go
package wallet
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
// "fmt"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"go.uber.org/zap"
|
|
// "github.com/SamuelTariku/FortuneBet-Backend/internal/event"
|
|
)
|
|
|
|
var (
|
|
ErrBalanceInsufficient = errors.New("wallet balance is insufficient")
|
|
ErrWalletIsDisabled = errors.New("wallet is disabled")
|
|
)
|
|
|
|
func (s *Service) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
|
|
return s.walletStore.CreateWallet(ctx, wallet)
|
|
}
|
|
|
|
func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64) (domain.CustomerWallet, error) {
|
|
|
|
regularWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
|
|
IsWithdraw: true,
|
|
IsBettable: true,
|
|
IsTransferable: true,
|
|
UserID: customerID,
|
|
Type: domain.RegularWalletType,
|
|
})
|
|
|
|
if err != nil {
|
|
return domain.CustomerWallet{}, err
|
|
}
|
|
|
|
staticWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
|
|
IsWithdraw: false,
|
|
IsBettable: true,
|
|
IsTransferable: true,
|
|
UserID: customerID,
|
|
Type: domain.StaticWalletType,
|
|
})
|
|
|
|
if err != nil {
|
|
return domain.CustomerWallet{}, err
|
|
}
|
|
|
|
return s.walletStore.CreateCustomerWallet(ctx, domain.CreateCustomerWallet{
|
|
CustomerID: customerID,
|
|
RegularWalletID: regularWallet.ID,
|
|
StaticWalletID: staticWallet.ID,
|
|
})
|
|
}
|
|
|
|
func (s *Service) GetWalletByID(ctx context.Context, id int64) (domain.Wallet, error) {
|
|
return s.walletStore.GetWalletByID(ctx, id)
|
|
}
|
|
|
|
func (s *Service) GetAllWallets(ctx context.Context) ([]domain.Wallet, error) {
|
|
return s.walletStore.GetAllWallets(ctx)
|
|
}
|
|
|
|
func (s *Service) GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error) {
|
|
return s.walletStore.GetWalletsByUser(ctx, id)
|
|
}
|
|
|
|
func (s *Service) GetCompanyByWalletID(ctx context.Context, walletID int64) (domain.Company, error) {
|
|
return s.walletStore.GetCompanyByWalletID(ctx, walletID)
|
|
}
|
|
|
|
func (s *Service) GetBranchByWalletID(ctx context.Context, walletID int64) (domain.Branch, error) {
|
|
return s.walletStore.GetBranchByWalletID(ctx, walletID)
|
|
}
|
|
|
|
func (s *Service) GetAllCustomerWallet(ctx context.Context) ([]domain.GetCustomerWallet, error) {
|
|
return s.walletStore.GetAllCustomerWallets(ctx)
|
|
}
|
|
func (s *Service) GetCustomerWallet(ctx context.Context, customerID int64) (domain.GetCustomerWallet, error) {
|
|
return s.walletStore.GetCustomerWallet(ctx, customerID)
|
|
}
|
|
|
|
func (s *Service) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error) {
|
|
return s.walletStore.GetAllBranchWallets(ctx)
|
|
}
|
|
|
|
func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
|
|
|
|
wallet, err := s.GetWalletByID(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !wallet.IsActive {
|
|
return ErrWalletIsDisabled
|
|
}
|
|
|
|
err = s.walletStore.UpdateBalance(ctx, id, balance)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// go func() {
|
|
// s.kafkaProducer.Publish(ctx, fmt.Sprint(wallet.UserID), event.WalletEvent{
|
|
// EventType: event.WalletBalanceUpdated,
|
|
// WalletID: wallet.ID,
|
|
// UserID: wallet.UserID,
|
|
// Balance: balance,
|
|
// WalletType: wallet.Type,
|
|
// Trigger: "UpdateBalance",
|
|
// })
|
|
// }()
|
|
|
|
if err := s.SendWalletUpdateNotification(ctx, wallet); err != nil {
|
|
s.mongoLogger.Info("Failed to send wallet update notification",
|
|
zap.Int64("wallet_id", wallet.ID),
|
|
zap.Error(err))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) AddToWallet(
|
|
ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, paymentDetails domain.PaymentDetails, message string) (domain.Transfer, error) {
|
|
wallet, err := s.GetWalletByID(ctx, id)
|
|
if err != nil {
|
|
return domain.Transfer{}, err
|
|
}
|
|
if !wallet.IsActive {
|
|
return domain.Transfer{}, ErrWalletIsDisabled
|
|
}
|
|
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance+amount)
|
|
if err != nil {
|
|
return domain.Transfer{}, err
|
|
}
|
|
|
|
// go func() {
|
|
// s.kafkaProducer.Publish(ctx, fmt.Sprint(wallet.ID), event.WalletEvent{
|
|
// EventType: event.WalletBalanceUpdated,
|
|
// WalletID: wallet.ID,
|
|
// UserID: wallet.UserID,
|
|
// Balance: wallet.Balance + amount,
|
|
// WalletType: wallet.Type,
|
|
// Trigger: "AddToWallet",
|
|
// })
|
|
// }()
|
|
if err := s.SendWalletUpdateNotification(ctx, wallet); err != nil {
|
|
s.mongoLogger.Info("Failed to send wallet update notification",
|
|
zap.Int64("wallet_id", wallet.ID),
|
|
zap.Error(err))
|
|
}
|
|
|
|
// Log the transfer here for reference
|
|
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
|
Message: message,
|
|
Amount: amount,
|
|
Verified: true,
|
|
ReceiverWalletID: domain.ValidInt64{
|
|
Value: wallet.ID,
|
|
Valid: true,
|
|
},
|
|
CashierID: cashierID,
|
|
PaymentMethod: paymentMethod,
|
|
Type: domain.DEPOSIT,
|
|
ReferenceNumber: paymentDetails.ReferenceNumber.Value,
|
|
})
|
|
|
|
return newTransfer, err
|
|
}
|
|
|
|
func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, message string) (domain.Transfer, error) {
|
|
wallet, err := s.GetWalletByID(ctx, id)
|
|
if err != nil {
|
|
return domain.Transfer{}, err
|
|
}
|
|
|
|
if !wallet.IsActive {
|
|
return domain.Transfer{}, ErrWalletIsDisabled
|
|
}
|
|
if wallet.Balance < amount {
|
|
// Send Wallet low to admin
|
|
if wallet.Type == domain.CompanyWalletType || wallet.Type == domain.BranchWalletType {
|
|
s.SendAdminWalletInsufficientNotification(ctx, wallet, amount)
|
|
} else {
|
|
s.SendCustomerWalletInsufficientNotification(ctx, wallet, amount)
|
|
}
|
|
return domain.Transfer{}, ErrBalanceInsufficient
|
|
}
|
|
|
|
if wallet.Type == domain.BranchWalletType || wallet.Type == domain.CompanyWalletType {
|
|
var thresholds []float32
|
|
|
|
if wallet.Type == domain.CompanyWalletType {
|
|
thresholds = []float32{100000, 50000, 25000, 10000, 5000, 3000, 1000, 500}
|
|
} else {
|
|
thresholds = []float32{5000, 3000, 1000, 500}
|
|
}
|
|
|
|
balance := wallet.Balance.Float32()
|
|
for _, thresholds := range thresholds {
|
|
if thresholds < balance && thresholds > (balance-amount.Float32()) {
|
|
s.SendAdminWalletLowNotification(ctx, wallet)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance-amount)
|
|
|
|
if err != nil {
|
|
return domain.Transfer{}, nil
|
|
}
|
|
|
|
// go func() {
|
|
// s.kafkaProducer.Publish(ctx, fmt.Sprint(wallet.ID), event.WalletEvent{
|
|
// EventType: event.WalletBalanceUpdated,
|
|
// WalletID: wallet.ID,
|
|
// UserID: wallet.UserID,
|
|
// Balance: wallet.Balance - amount,
|
|
// WalletType: wallet.Type,
|
|
// Trigger: "DeductFromWallet",
|
|
// })
|
|
// }()
|
|
|
|
if err := s.SendWalletUpdateNotification(ctx, wallet); err != nil {
|
|
s.mongoLogger.Info("Failed to send wallet update notification",
|
|
zap.Int64("wallet_id", wallet.ID),
|
|
zap.Error(err))
|
|
}
|
|
|
|
// Log the transfer here for reference
|
|
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
|
Message: message,
|
|
Amount: amount,
|
|
Verified: true,
|
|
SenderWalletID: domain.ValidInt64{
|
|
Value: wallet.ID,
|
|
Valid: true,
|
|
},
|
|
CashierID: cashierID,
|
|
PaymentMethod: paymentMethod,
|
|
Type: domain.WITHDRAW,
|
|
ReferenceNumber: "",
|
|
})
|
|
|
|
return newTransfer, err
|
|
}
|
|
|
|
// Directly Refilling wallet without
|
|
// func (s *Service) RefillWallet(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) {
|
|
// receiverWallet, err := s.GetWalletByID(ctx, transfer.ReceiverWalletID)
|
|
// if err != nil {
|
|
// return domain.Transfer{}, err
|
|
// }
|
|
|
|
// // Add to receiver
|
|
// senderWallet, err := s.GetWalletByID(ctx, transfer.SenderWalletID)
|
|
// if err != nil {
|
|
// return domain.Transfer{}, err
|
|
// } else if senderWallet.Balance < transfer.Amount {
|
|
// return domain.Transfer{}, ErrInsufficientBalance
|
|
// }
|
|
|
|
// err = s.walletStore.UpdateBalance(ctx, receiverWallet.ID, receiverWallet.Balance+transfer.Amount)
|
|
// if err != nil {
|
|
// return domain.Transfer{}, err
|
|
// }
|
|
|
|
// // Log the transfer so that if there is a mistake, it can be reverted
|
|
// newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
|
|
// CashierID: transfer.CashierID,
|
|
// ReceiverWalletID: transfer.ReceiverWalletID,
|
|
// Amount: transfer.Amount,
|
|
// Type: domain.DEPOSIT,
|
|
// PaymentMethod: transfer.PaymentMethod,
|
|
// Verified: true,
|
|
// })
|
|
// if err != nil {
|
|
// return domain.Transfer{}, err
|
|
// }
|
|
|
|
// return newTransfer, nil
|
|
// }
|
|
|
|
func (s *Service) UpdateWalletActive(ctx context.Context, id int64, isActive bool) error {
|
|
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
|
}
|