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

193 lines
5.4 KiB
Go

package arifpay
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/AnaniyaBelew/ArifpayGoPlugin"
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
"github.com/google/uuid"
)
type ArifpayService struct {
cfg *config.Config
transferStore wallet.TransferStore
httpClient *http.Client
}
func NewArifpayService(cfg *config.Config, transferStore wallet.TransferStore, httpClient *http.Client) *ArifpayService {
return &ArifpayService{
cfg: cfg,
transferStore: transferStore,
httpClient: httpClient,
}
}
func (s *ArifpayService) CreateCheckoutSession(req domain.CreateCheckoutSessionRequest) (string, error) {
// Create SDK-compatible payload
paymentPayload := ArifpayGoPlugin.PaymentRequest{
CancelUrl: s.cfg.ARIFPAY.CancelUrl,
Phone: req.Phone,
Email: req.Email,
Nonce: req.Nonce,
ErrorUrl: s.cfg.ARIFPAY.ErrorUrl,
NotifyUrl: s.cfg.ARIFPAY.NotifyUrl,
SuccessUrl: s.cfg.ARIFPAY.SuccessUrl,
PaymentMethods: req.PaymentMethods,
Lang: req.Lang,
}
// Convert items
for _, item := range req.Items {
paymentPayload.Items = append(paymentPayload.Items, domain.Item{
Name: item.Name,
Quantity: item.Quantity,
Price: item.Price,
Description: item.Description,
Image: item.Image,
})
}
// Convert beneficiaries
for _, b := range req.Beneficiaries {
paymentPayload.Beneficiaries = append(paymentPayload.Beneficiaries, domain.Beneficiary{
AccountNumber: b.AccountNumber,
Bank: b.Bank,
Amount: b.Amount,
})
}
// Instantiate payment client
expireDate := time.Now().AddDate(2, 0, 0) // 2 months from now
paymentClient := ArifpayGoPlugin.NewPayment(s.cfg.ARIFPAY.APIKey, expireDate)
// Create checkout session
response, err := paymentClient.MakePayment(paymentPayload)
if err != nil {
return "", err
}
transfer := domain.CreateTransfer{
Amount: domain.Currency(req.Beneficiaries[0].Amount),
Verified: false,
Type: domain.DEPOSIT,
ReferenceNumber: uuid.NewString(),
Status: string(domain.PaymentStatusPending),
}
if _, err := s.transferStore.CreateTransfer(context.Background(), transfer); err != nil {
return "", err
}
return response, nil
}
func (s *ArifpayService) B2CTransfer(ctx context.Context, req domain.ArifPayB2CRequest, endpoint string) (*map[string]interface{}, error) {
// endpoint := c.baseURL + "/api/Telebirr/b2c/transfer"
payloadBytes, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("failed to marshal request payload: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewBuffer(payloadBytes))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("x-arifpay-key", s.cfg.ARIFPAY.APIKey)
resp, err := s.httpClient.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("request to Telebirr B2C failed: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Telebirr API returned status %d: %s", resp.StatusCode, string(body))
}
var response map[string]interface{}
if err := json.Unmarshal(body, &response); err != nil {
return nil, fmt.Errorf("failed to parse response body: %w", err)
}
return &response, nil
}
func (s *ArifpayService) VerifyByTransactionID(transactionID string, paymentType int) ([]byte, error) {
url := "https://gateway.arifpay.org/api/checkout/getSessionByTransactionId"
var payload domain.ArifpayVerifyByTransactionIDRequest
bodyBytes, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyBytes))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-arifpay-key", s.cfg.ARIFPAY.APIKey)
resp, err := s.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("non-200 response from Arifpay: %s", string(respBody))
}
return respBody, nil
}
func (s *ArifpayService) VerifyBySessionID(sessionID string) ([]byte, error) {
url := "https://gateway.arifpay.org/api/ms/transaction/status/" + sessionID
// Create GET request without body
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-arifpay-key", s.cfg.ARIFPAY.APIKey)
resp, err := s.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("non-200 response from Arifpay: %s", string(respBody))
}
return respBody, nil
}