138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
package chapa
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||
"github.com/shopspring/decimal"
|
||
)
|
||
|
||
type Service struct {
|
||
transactionStore transaction.TransactionStore
|
||
walletStore wallet.WalletStore
|
||
userStore user.UserStore
|
||
referralStore referralservice.ReferralStore
|
||
store *repository.Store
|
||
}
|
||
|
||
func NewService(
|
||
txStore transaction.TransactionStore,
|
||
walletStore wallet.WalletStore,
|
||
userStore user.UserStore,
|
||
referralStore referralservice.ReferralStore,
|
||
store *repository.Store,
|
||
) *Service {
|
||
return &Service{
|
||
transactionStore: txStore,
|
||
walletStore: walletStore,
|
||
userStore: userStore,
|
||
referralStore: referralStore,
|
||
store: store,
|
||
}
|
||
}
|
||
|
||
func (s *Service) HandleChapaTransferWebhook(ctx context.Context, req domain.ChapaWebHookTransfer) error {
|
||
_, tx, err := s.store.BeginTx(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer tx.Rollback(ctx)
|
||
|
||
// Use your services normally (they don’t use the transaction, unless you wire `q`)
|
||
referenceID, err := strconv.ParseInt(req.Reference, 10, 64)
|
||
if err != nil {
|
||
return fmt.Errorf("invalid reference ID: %w", err)
|
||
}
|
||
|
||
txn, err := s.transactionStore.GetTransactionByID(ctx, referenceID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if txn.Verified {
|
||
return nil
|
||
}
|
||
|
||
webhookAmount, _ := decimal.NewFromString(req.Amount)
|
||
storedAmount, _ := decimal.NewFromString(txn.Amount.String())
|
||
if !webhookAmount.Equal(storedAmount) {
|
||
return fmt.Errorf("amount mismatch")
|
||
}
|
||
|
||
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.BeginTx(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
|
||
}
|
||
|
||
webhookAmount, _ := strconv.ParseFloat(req.Amount, 32)
|
||
if webhookAmount < float64(txn.Amount) {
|
||
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 + txn.Amount
|
||
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 & Create Referral
|
||
stats, err := s.referralStore.GetReferralStats(ctx, string(wallet.UserID))
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if stats == nil {
|
||
if err := s.referralStore.CreateReferral(ctx, wallet.UserID); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return tx.Commit(ctx)
|
||
}
|