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

181 lines
6.0 KiB
Go

package transaction
import (
"context"
"errors"
"fmt"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
)
var (
ErrBranchRequiredForRole = errors.New("branch_id is required to be passed for this role")
ErrInvalidBranchID = errors.New("invalid branch id")
ErrUnauthorizedCompanyID = errors.New("unauthorized company id")
ErrUnauthorizedBranchManager = errors.New("unauthorized branch manager")
ErrCustomerRoleNotAuthorized = errors.New("customer role not authorized")
ErrDepositCannotBeUnverified = errors.New("deposit cannot be unverified")
ErrShopBetHasExpired = errors.New("shop bet has already been expired")
)
type Service struct {
transactionStore TransactionStore
branchSvc branch.Service
betSvc bet.Service
walletSvc wallet.Service
userSvc user.Service
}
func NewService(transactionStore TransactionStore, branchSvc branch.Service, betSvc bet.Service, walletSvc wallet.Service, userSvc user.Service) *Service {
return &Service{
transactionStore: transactionStore,
branchSvc: branchSvc,
betSvc: betSvc,
walletSvc: walletSvc,
userSvc: userSvc,
}
}
func (s *Service) CreateShopTransaction(ctx context.Context, transaction domain.CreateShopTransaction) (domain.ShopTransaction, error) {
return s.transactionStore.CreateShopTransaction(ctx, transaction)
}
func (s *Service) GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransactionDetail, error) {
return s.transactionStore.GetShopTransactionByID(ctx, id)
}
func (s *Service) GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error) {
return s.transactionStore.GetAllShopTransactions(ctx, filter)
}
func (s *Service) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error) {
return s.transactionStore.GetShopTransactionByBranch(ctx, id)
}
func (s *Service) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, role domain.Role, companyID domain.ValidInt64, branchID domain.ValidInt64) error {
// TODO: Move this into a service role verification service
// Checks to make sure only the same company and branch can modify this
transaction, err := s.GetShopTransactionByID(ctx, id)
if role != domain.RoleSuperAdmin {
if !companyID.Valid || companyID.Value != transaction.CompanyID {
// s.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
return fmt.Errorf("user cannot modify another companies data")
}
if role == domain.RoleCashier {
if !branchID.Valid || branchID.Value != transaction.BranchID {
// h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", "Unauthorized")
return fmt.Errorf("user cannot modify another companies data")
}
}
}
if err != nil {
return err
}
switch transaction.Type {
case domain.TRANSACTION_BET:
if verified {
bet, err := s.GetShopBetByShopTransactionID(ctx, transaction.ID)
if err != nil {
return err
}
var firstEvent time.Time = bet.Outcomes[0].Expires
for _, outcome := range bet.Outcomes {
if outcome.Expires.Before(firstEvent) {
firstEvent = outcome.Expires
}
}
fmt.Printf("\n\n Shop bet expire %v - now %v \n\n", firstEvent, time.Now().UTC())
if firstEvent.Before(time.Now()) {
return ErrShopBetHasExpired
}
}
case domain.TRANSACTION_DEPOSIT:
if !verified {
// TODO: Figure out what to do here? Should i return the money or verify the faulty verify
return ErrDepositCannotBeUnverified
}
deposit, err := s.GetShopDepositByShopTransactionID(ctx, transaction.ID)
if err != nil {
return err
}
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, deposit.CustomerID)
if err != nil {
return ErrUserHasNoCustomerWallet
}
transfer, err := s.walletSvc.TransferToWallet(ctx,
deposit.BranchWalletID, customerWallet.RegularID, transaction.Amount, domain.TRANSFER_DIRECT, domain.ValidInt64{
Value: transaction.UserID,
Valid: true,
},
fmt.Sprintf("Transferred %v to customer wallet due to shop deposit", transaction.Amount),
)
if err != nil {
return err
}
err = s.UpdateShopDepositTransferID(ctx, deposit.ID, domain.ValidInt64{
Value: transfer.ID,
Valid: true,
})
if err != nil {
return err
}
}
return s.transactionStore.UpdateShopTransactionVerified(ctx, id, verified, approvedBy)
}
func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role domain.Role, userID int64, userCompanyID domain.ValidInt64) (*int64, *int64, error) {
// var branchID int64
// var companyID int64
switch role {
case domain.RoleAdmin, domain.RoleBranchManager, domain.RoleSuperAdmin:
if branchID == nil {
// h.logger.Error("CashoutReq Branch ID is required for this user role")
return nil, nil, ErrBranchRequiredForRole
}
branch, err := s.branchSvc.GetBranchByID(ctx, *branchID)
if err != nil {
// h.logger.Error("CashoutReq no branches")
return nil, nil, ErrInvalidBetID
}
// Check if the user has access to the company
if role != domain.RoleSuperAdmin {
if !userCompanyID.Valid || userCompanyID.Value != branch.CompanyID {
return nil, nil, ErrUnauthorizedCompanyID
}
}
if role == domain.RoleBranchManager {
if branch.BranchManagerID != userID {
return nil, nil, ErrUnauthorizedBranchManager
}
}
return &branch.ID, &branch.CompanyID, nil
case domain.RoleCashier:
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
if err != nil {
// h.logger.Error("CashoutReq failed, branch id invalid")
return nil, nil, ErrInvalidBranchID
}
return &branch.ID, &branch.CompanyID, nil
default:
return nil, nil, ErrCustomerRoleNotAuthorized
}
}