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 }