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) }