igp-sep-example/service/sep.go

183 lines
5.2 KiB
Go

package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log/slog"
"net/http"
"strconv"
)
type SepTokenResponse struct {
Status int `json:"status"`
ErrorCode string `json:"errorCode"`
ErrorDesc string `json:"errorDesc"`
Token string `json:"token"`
}
type VerifyTransactionResponse struct {
TransactionDetail TransactionDetail `json:"TransactionDetail"`
ResultCode int `json:"ResultCode"`
ResultDescription string `json:"ResultDescription"`
Success bool `json:"Success"`
}
type TransactionDetail struct {
RRN string `json:"RRN"`
RefNum string `json:"RefNum"`
MaskedPan string `json:"MaskedPan"`
HashedPan string `json:"HashedPan"`
TerminalNumber int `json:"TerminalNumber"`
OrginalAmount int64 `json:"OrginalAmount"`
AffectiveAmount int64 `json:"AffectiveAmount"`
StraceDate string `json:"StraceDate"`
StraceNo string `json:"StraceNo"`
}
type ReverseTransactionResponse struct {
TransactionDetail TransactionDetail `json:"TransactionDetail"`
ResultCode int `json:"ResultCode"`
ResultDescription string `json:"ResultDescription"`
Success bool `json:"Success"`
}
func (p *PaymentService) RealInitialize(ctx context.Context, credential, phone, resNum string, amount int64) (*SepTokenResponse, error) {
description := p.generateDescription()
message := SepTokenRequest{
Action: "token",
TerminalId: credential,
Amount: amount,
ResNum: resNum,
RedirectUrl: p.Cfg.CallbackURL,
CellNumber: phone,
TokenExpiryInMin: 20,
}
if len(description) > 0 {
if len(description) <= 50 {
message.ResNum1 = description
} else if len(description) <= 100 {
message.ResNum1 = description[:50]
message.ResNum2 = description[50:]
} else if len(description) <= 150 {
message.ResNum1 = description[:50]
message.ResNum2 = description[50:100]
message.ResNum3 = description[100:]
} else {
message.ResNum1 = description[:50]
message.ResNum2 = description[50:100]
message.ResNum3 = description[100:150]
message.ResNum4 = description[150:]
}
}
bodyBytes, err := json.Marshal(message)
if err != nil {
return nil, fmt.Errorf("marshal error: %v", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", p.Cfg.PaymentGetToken, bytes.NewReader(bodyBytes))
if err != nil {
return nil, fmt.Errorf("request creation error: %v", err)
}
req.Header.Set("Content-Type", "application/json")
slog.Info("SEP Token Request", "endpoint", p.Cfg.PaymentGetToken, "body", message)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request error: %v", err)
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read body error: %v", err)
}
slog.Info("SEP Token Response", "status_code", resp.StatusCode, "body", string(responseBody))
var parsed SepTokenResponse
if err := json.Unmarshal(responseBody, &parsed); err != nil {
return nil, fmt.Errorf("unmarshal error: %v", err)
}
if parsed.Status == 1 && parsed.Token != "" {
slog.Info("sep payment initialized", "token", parsed.Token)
return &parsed, nil
}
return nil, fmt.Errorf("sep init error (code %s): %s", parsed.ErrorCode, parsed.ErrorDesc)
}
func (p *PaymentService) RealVerifyTransaction(ctx context.Context, refNum string) (*VerifyTransactionResponse, error) {
terminalNumber, err := strconv.Atoi(p.Cfg.Credential)
if err != nil {
return nil, fmt.Errorf("خطا در تبدیل TerminalId: %v", err)
}
requestBody := map[string]interface{}{
"RefNum": refNum,
"TerminalNumber": terminalNumber,
}
bodyBytes, err := json.Marshal(requestBody)
if err != nil {
return nil, fmt.Errorf("marshal error: %v", err)
}
verifyURL := p.Cfg.PaymentVerifyURL
if verifyURL == "" {
verifyURL = "https://sep.shaparak.ir/verifyTxnRandomSessionkey/ipg/VerifyTransaction"
}
req, err := http.NewRequestWithContext(ctx, "POST", verifyURL, bytes.NewReader(bodyBytes))
if err != nil {
return nil, fmt.Errorf("request creation error: %v", err)
}
req.Header.Set("Content-Type", "application/json")
slog.Info("SEP VerifyTransaction Request",
"endpoint", verifyURL,
"refNum", refNum,
"terminalNumber", terminalNumber)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request error: %v", err)
}
defer resp.Body.Close()
respBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read body error: %v", err)
}
slog.Info("SEP VerifyTransaction Response",
"status_code", resp.StatusCode,
"body", string(respBytes))
var verifyResp VerifyTransactionResponse
if err := json.Unmarshal(respBytes, &verifyResp); err != nil {
return nil, fmt.Errorf("unmarshal error: %v", err)
}
slog.Info("VerifyTransaction Result",
"success", verifyResp.Success,
"resultCode", verifyResp.ResultCode,
"resultDescription", verifyResp.ResultDescription)
return &verifyResp, nil
}
func (p *PaymentService) generateDescription() string {
description := "سفارش از درگاه"
if p.IPGTransaction != nil {
description += " : " + p.IPGTransaction.ID
}
return description
}