193 lines
5.4 KiB
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
|
|
}
|