139 lines
4.0 KiB
Go
139 lines
4.0 KiB
Go
package balance
|
|
|
|
import (
|
|
"context"
|
|
"enaklo-pos-be/internal/common/logger"
|
|
"enaklo-pos-be/internal/common/mycontext"
|
|
"enaklo-pos-be/internal/entity"
|
|
"enaklo-pos-be/internal/repository"
|
|
"errors"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type Config interface {
|
|
GetPlatformFee() int64
|
|
}
|
|
|
|
type BalanceService struct {
|
|
repo repository.WalletRepository
|
|
trx repository.Trx
|
|
crypt repository.Crypto
|
|
transaction repository.TransactionRepository
|
|
cfg Config
|
|
}
|
|
|
|
func NewBalanceService(repo repository.WalletRepository,
|
|
trx repository.Trx,
|
|
crypt repository.Crypto, cfg Config,
|
|
transaction repository.TransactionRepository) *BalanceService {
|
|
return &BalanceService{
|
|
repo: repo,
|
|
trx: trx,
|
|
crypt: crypt,
|
|
cfg: cfg,
|
|
transaction: transaction,
|
|
}
|
|
}
|
|
|
|
func (s *BalanceService) GetByID(ctx context.Context, id int64) (*entity.Balance, error) {
|
|
balanceDB, err := s.repo.GetByPartnerID(ctx, nil, id)
|
|
if err != nil {
|
|
logger.ContextLogger(ctx).Error("error when get branch by id", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
return &entity.Balance{
|
|
PartnerID: id,
|
|
Balance: balanceDB.Balance,
|
|
AuthBalance: balanceDB.AuthBalance,
|
|
}, nil
|
|
}
|
|
|
|
func (s *BalanceService) WithdrawInquiry(ctx context.Context, req *entity.BalanceWithdrawInquiry) (*entity.BalanceWithdrawInquiryResponse, error) {
|
|
balanceDB, err := s.repo.GetForUpdate(ctx, nil, req.PartnerID)
|
|
if err != nil {
|
|
logger.ContextLogger(ctx).Error("error when get branch by id", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
if float64(req.Amount) > balanceDB.Balance {
|
|
logger.ContextLogger(ctx).Error("requested amount exceeds available balance")
|
|
return nil, errors.New("insufficient balance")
|
|
}
|
|
|
|
token, err := s.crypt.GenerateJWTWithdraw(&entity.WalletWithdrawRequest{
|
|
ID: balanceDB.ID,
|
|
PartnerID: req.PartnerID,
|
|
Amount: req.Amount - s.cfg.GetPlatformFee(),
|
|
Fee: s.cfg.GetPlatformFee(),
|
|
Total: req.Amount,
|
|
})
|
|
|
|
return &entity.BalanceWithdrawInquiryResponse{
|
|
PartnerID: req.PartnerID,
|
|
Amount: req.Amount - s.cfg.GetPlatformFee(),
|
|
Token: token,
|
|
Fee: s.cfg.GetPlatformFee(),
|
|
Total: req.Amount,
|
|
}, nil
|
|
}
|
|
|
|
func (s *BalanceService) WithdrawExecute(ctx mycontext.Context, req *entity.WalletWithdrawRequest) (*entity.WalletWithdrawResponse, error) {
|
|
decodedReq, err := s.crypt.ValidateJWTWithdraw(req.Token)
|
|
if err != nil || decodedReq.PartnerID != req.PartnerID {
|
|
logger.ContextLogger(ctx).Error("invalid withdrawal token", zap.Error(err))
|
|
return nil, errors.New("invalid withdrawal token")
|
|
}
|
|
|
|
trx, _ := s.trx.Begin(ctx)
|
|
wallet, err := s.repo.GetForUpdate(ctx, trx, decodedReq.PartnerID)
|
|
if err != nil {
|
|
logger.ContextLogger(ctx).Error("error retrieving wallet by partner ID", zap.Error(err))
|
|
trx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
totalAmount := float64(decodedReq.Total)
|
|
if totalAmount > wallet.Balance {
|
|
logger.ContextLogger(ctx).Error("insufficient balance for withdrawal", zap.Float64("available", wallet.Balance), zap.Float64("requested", totalAmount))
|
|
trx.Rollback()
|
|
return nil, errors.New("insufficient balance")
|
|
}
|
|
|
|
wallet.Balance -= totalAmount
|
|
wallet.AuthBalance += totalAmount
|
|
|
|
if _, err := s.repo.Update(ctx, trx, wallet); err != nil {
|
|
logger.ContextLogger(ctx).Error("error updating wallet balance", zap.Error(err))
|
|
trx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
transaction := &entity.Transaction{
|
|
PartnerID: wallet.PartnerID,
|
|
TransactionType: "WITHDRAW",
|
|
Status: "WAITING_APPROVAL",
|
|
CreatedBy: ctx.RequestedBy(),
|
|
Amount: totalAmount,
|
|
}
|
|
|
|
transaction, err = s.transaction.Create(ctx, trx, transaction)
|
|
if err != nil {
|
|
logger.ContextLogger(ctx).Error("error creating transaction record", zap.Error(err))
|
|
trx.Rollback()
|
|
return nil, err
|
|
}
|
|
|
|
if err := trx.Commit().Error; err != nil {
|
|
logger.ContextLogger(ctx).Error("error committing transaction", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
response := &entity.WalletWithdrawResponse{
|
|
TransactionID: transaction.ID,
|
|
Status: "WAITING_APPROVAL",
|
|
}
|
|
|
|
return response, nil
|
|
}
|