129 lines
3.2 KiB
Go
129 lines
3.2 KiB
Go
package chapa
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
type Service struct {
|
|
transactionStore transaction.TransactionStore
|
|
walletStore wallet.WalletStore
|
|
store *repository.Store
|
|
}
|
|
|
|
func (s *Service) HandleChapaTransferWebhook(ctx context.Context, req domain.ChapaWebHookTransfer) error {
|
|
tx, err := s.store.Begin(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback(ctx)
|
|
|
|
// 1. Fetch transaction
|
|
referenceID, err := strconv.ParseInt(req.Reference, 10, 64)
|
|
txn, err := s.transactionStore.GetTransactionByID(ctx, referenceID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if txn.Verified {
|
|
return nil // already processed
|
|
}
|
|
|
|
// 2. Compare amount
|
|
webhookAmount, _ := decimal.NewFromString(req.Amount)
|
|
storedAmount, _ := decimal.NewFromString(txn.Amount.String())
|
|
if !webhookAmount.Equal(storedAmount) {
|
|
return fmt.Errorf("amount mismatch")
|
|
}
|
|
|
|
// 3. Update transaction
|
|
txn.Verified = true
|
|
|
|
if err := s.transactionStore.UpdateTransactionVerified(ctx, txn.ID, txn.Verified, txn.ApprovedBy.Value, txn.ApproverName.Value); err != nil {
|
|
return err
|
|
}
|
|
|
|
return tx.Commit(ctx)
|
|
}
|
|
|
|
func (s *Service) HandleChapaPaymentWebhook(ctx context.Context, req domain.ChapaWebHookPayment) error {
|
|
tx, err := s.store.Begin(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback(ctx)
|
|
|
|
if req.Status != "success" {
|
|
return fmt.Errorf("payment status not successful")
|
|
}
|
|
|
|
// 1. Parse reference ID
|
|
referenceID, err := strconv.ParseInt(req.TxRef, 10, 64)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid tx_ref: %w", err)
|
|
}
|
|
|
|
// 2. Fetch transaction
|
|
txn, err := s.transactionStore.GetTransactionByID(ctx, referenceID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if txn.Verified {
|
|
return nil // already processed
|
|
}
|
|
|
|
// 3. Amount validation
|
|
webhookAmount, _ := decimal.NewFromString(req.Amount)
|
|
storedAmount := txn.Amount // assuming it's domain.Currency (decimal.Decimal alias)
|
|
|
|
if webhookAmount.LessThan(storedAmount) {
|
|
return fmt.Errorf("webhook amount is less than expected")
|
|
}
|
|
|
|
// 4. Fetch wallet
|
|
wallet, err := s.walletStore.GetWalletByID(ctx, txn.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 5. Update wallet balance
|
|
newBalance := wallet.Balance.Add(storedAmount)
|
|
if err := s.walletStore.UpdateBalance(ctx, wallet.ID, newBalance); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 6. Mark transaction as verified
|
|
if err := s.transactionStore.UpdateTransactionVerified(ctx, txn.ID, true, txn.ApprovedBy.Value, txn.ApproverName.Value); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 7. Check & generate referral code
|
|
hasCode, err := s.userStore.HasReferralCode(ctx, wallet.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !hasCode {
|
|
code := misc.GenerateReferralCode(req.FirstName)
|
|
|
|
if err := s.userStore.SetReferralCode(ctx, wallet.UserID, code); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := s.referralStore.CreateReferralCode(ctx, domain.ReferralCode{
|
|
Code: code,
|
|
Amount: config.ReferralRewardBase,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit(ctx)
|
|
}
|