新增eanipay

fix/release
mofangmin 1 year ago
parent 6bee0e79ba
commit 19b4c3bc97
  1. 7
      common/recharge.go
  2. 3
      modules/pay/allpay/all.go
  3. 1
      modules/pay/base/base.go
  4. 184
      modules/pay/eanipay/base.go
  5. 196
      modules/pay/eanipay/values.go
  6. 1
      modules/pay/values/values.go

@ -150,6 +150,13 @@ const (
WithdrawOrderTypeAll WithdrawOrderTypeAll
) )
// 支付类型
const (
WithdrawTypeWallet = 3
WithdrawTypeUPI = 4
WithdrawTypeBank = 7
)
type WithdrawOrder struct { type WithdrawOrder struct {
ID uint `gorm:"primarykey"` ID uint `gorm:"primarykey"`
UID int `gorm:"column:uid;not null;type:int(11)"` UID int `gorm:"column:uid;not null;type:int(11)"`

@ -3,6 +3,7 @@ package allpay
import ( import (
"reflect" "reflect"
"server/modules/pay/base" "server/modules/pay/base"
"server/modules/pay/eanipay"
"server/modules/pay/gopay" "server/modules/pay/gopay"
"server/modules/pay/grepay" "server/modules/pay/grepay"
"server/modules/pay/luckyinpay" "server/modules/pay/luckyinpay"
@ -59,6 +60,7 @@ type AllPay struct {
Moonpay2 func(b *base.Base) Moonpay2 func(b *base.Base)
PayPlus func(b *base.Base) PayPlus func(b *base.Base)
LuckyinPay func(b *base.Base) LuckyinPay func(b *base.Base)
Eanipay func(b *base.Base)
} }
var All = &AllPay{} var All = &AllPay{}
@ -70,6 +72,7 @@ func init() {
All.MLPay = mlpay.NewSub All.MLPay = mlpay.NewSub
All.PayPlus = payplus.NewSub All.PayPlus = payplus.NewSub
All.LuckyinPay = luckyinpay.NewSub All.LuckyinPay = luckyinpay.NewSub
All.Eanipay = eanipay.NewSub
} }
func NewSub(b *base.Base, index int) { func NewSub(b *base.Base, index int) {

@ -62,6 +62,7 @@ type Base struct {
SignPassStr []string // 不参与签名的字段 SignPassStr []string // 不参与签名的字段
KeyName string // 有时候有些渠道签名字段不一样 KeyName string // 有时候有些渠道签名字段不一样
C *gin.Context C *gin.Context
ReqData interface{}
} }
type CallbackResp struct { type CallbackResp struct {

@ -0,0 +1,184 @@
package eanipay
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"server/common"
"server/modules/pay/base"
"server/modules/pay/values"
"server/pb"
"server/util"
"time"
"github.com/gogo/protobuf/proto"
"github.com/liangdas/mqant/log"
)
func NewSub(b *base.Base) {
sub := &Sub{
Base: b,
}
b.HttpType = base.HttpTypeJson
b.ShouldSignUpper = true
if b.Opt == base.OPTPay {
b.Resp = new(PayResp)
b.ReqURL = baseURL + payURL
} else if b.Opt == base.OPTWithdraw {
b.Resp = new(WithdrawResp)
b.ReqURL = baseURL + withdrawURL
} else if b.Opt == base.OPTPayCB {
b.CallbackReq = new(PayCallbackReq)
b.CallbackResp.Msg = "success"
} else if b.Opt == base.OPTWithdrawCB {
b.CallbackReq = new(WithdrawCallbackReq)
b.CallbackResp.Msg = "success"
} else if b.Opt == base.OPTQueryWithdraw { // 查询
b.Resp = new(QueryWithdrawResp)
b.ReqURL = baseURL + queryWithdrawURL
} else if b.Opt == base.OPTQueryPay { // 查询
b.Resp = new(QueryPayResp)
b.ReqURL = baseURL + queryPayURL
} else {
return
}
b.Sub = sub
}
type Sub struct {
Base *base.Base
}
func (s *Sub) PackHeader(header http.Header) {
header.Set("Accept", "application/json")
url := baseURL
if s.Base.Opt == base.OPTPay {
url += payURL
} else if s.Base.Opt == base.OPTWithdraw {
url += withdrawURL
} else if s.Base.Opt == base.OPTQueryWithdraw {
url += queryWithdrawURL
} else if s.Base.Opt == base.OPTQueryPay {
url += queryPayURL
}
randomStr := util.GetSimpleRandomString(10)
bodyStr, _ := json.Marshal(s.Base.ReqData)
now := time.Now().UnixMilli()
sign := Sign(string(bodyStr), fmt.Sprintf("%d", now), randomStr, url)
header.Set("Authorization", fmt.Sprintf(`V2_SHA256 appId=%s,sign=%s,timestamp=%d,nonce=%s`, appID, sign, now, randomStr))
}
func (s *Sub) PackReq() interface{} {
if s.Base.Opt == base.OPTPay {
return s.PackPayReq()
} else if s.Base.Opt == base.OPTWithdraw {
return s.PackWithdrawReq()
}
return nil
}
func (s *Sub) GetResp() (proto.Message, error) {
log.Debug("resp:%v", s.Base.Resp)
if s.Base.Opt == base.OPTPay {
resp := s.Base.Resp.(*PayResp)
if resp.Data.Action.URL == "" {
return nil, errors.New("pay fail")
}
return &pb.InnerRechargeResp{APIOrderID: resp.Data.PaymentNo, URL: resp.Data.Action.URL, Channel: uint32(values.EaniPay)}, nil
} else if s.Base.Opt == base.OPTWithdraw {
resp := s.Base.Resp.(*WithdrawResp)
if s.Base.Status == 0 && resp.Code != "OK" {
return nil, errors.New("withdraw fail")
}
return &pb.InnerWithdrawResp{APIOrderID: resp.Data.PayoutNo, Channel: uint32(values.EaniPay)}, nil
}
return nil, errors.New("unknown opt")
}
func (s *Sub) PackPayReq() interface{} {
r := s.Base.PayReq
send := &PayReq{
MerchantTradeNo: r.OrderID,
Amount: fmt.Sprintf("%d", r.Amount),
Currency: "INR",
Description: "TeenPatti",
Payer: Payer{UserID: fmt.Sprintf("%d", r.UID), Name: r.Name, Email: r.Email, Phone: r.Phone},
PayMethod: struct {
Type string `json:"type"` // UPI
}{Type: "UPI"},
TradeEnv: struct {
IP string `json:"ip"`
}{IP: r.IP},
NotifyUrl: values.GetPayCallback(values.EaniPay),
ReturnUrl: values.GetPayCallback(values.EaniPay),
}
s.Base.ReqData = send
return send
}
func (s *Sub) PackWithdrawReq() interface{} {
r := s.Base.WithdrawReq
send := &WithdrawReq{
MerchantTradeNo: r.OrderID,
Amount: fmt.Sprintf("%d", r.Amount),
Currency: "INR",
Description: "TeenPatti",
NotifyUrl: values.GetWithdrawCallback(values.EaniPay),
}
if r.PayType == common.WithdrawTypeBank {
send.PayoutMethod.Type = "BANK_ACCOUNT"
send.PayoutMethod.Mode = "IMPS"
send.PayoutMethod.BankCode = r.PayCode
send.PayoutMethod.BankName = r.BankName
send.PayoutMethod.AccountNumber = r.CardNo
send.PayoutMethod.PayeeName = r.Name
send.PayoutMethod.PayeePhone = r.Phone
send.PayoutMethod.PayeeEmail = r.Email
send.PayoutMethod.PayeeAddress = r.Address
} else {
return nil
}
s.Base.ReqData = send
return send
}
func (s *Sub) CheckSign(str string) bool {
log.Debug("callback:%v", s.Base.CallbackReq)
signStr := s.Base.C.GetHeader("Authorization")
signData := parseData(signStr)
if s.Base.Opt == base.OPTPayCB {
req := s.Base.CallbackReq.(*PayCallbackReq)
s.Base.CallbackResp.OrderID = req.Data.MerchantTradeNo
if req.Data.Status == "PENDING" || req.Data.Status == "PROCESSING" {
return false
}
s.Base.CallbackResp.APIOrderID = req.Data.PaymentNo
s.Base.CallbackResp.Success = req.Data.Status == "PAID"
return Sign(str, signData.Timestamp, signData.Nonce, values.GetPayCallback(values.EaniPay)) == signData.Sign
} else if s.Base.Opt == base.OPTWithdrawCB {
req := s.Base.CallbackReq.(*WithdrawCallbackReq)
s.Base.CallbackResp.OrderID = req.Data.MerchantTradeNo
if req.Data.Status == "PENDING" || req.Data.Status == "PROCESSING" {
return false
}
s.Base.CallbackResp.Success = req.Data.Status == "PAID"
return Sign(str, signData.Timestamp, signData.Nonce, values.GetWithdrawCallback(values.EaniPay)) == signData.Sign
}
return false
}
func Sign(bodyStr, t, ran, url string) string {
signStr := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
appID,
appSecret,
"POST",
url,
t,
ran,
bodyStr,
)
sign := util.CalculateSHA256(signStr)
log.Debug("signStr:%s,sign:%s", signStr, sign)
return sign
}

@ -0,0 +1,196 @@
package eanipay
import "strings"
const (
baseURL = "https://gateway.eanishop.com"
// baseURL = "https://gateway.eanishop.com"
payURL = "/pg/v2/payment/create"
queryPayURL = "/pg/v2/payment/query"
withdrawURL = "/pg/v2/payout/create"
queryWithdrawURL = "/pg/v2/payout/query"
appID = "c553240e3e3842ad98eb8ae23c3745b5"
appSecret = "8e77714f16d2487f9846cc6c3432ead5"
)
type PayReq struct {
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
Description string `json:"description"`
Payer Payer `json:"payer"`
PayMethod struct {
Type string `json:"type"` // UPI
} `json:"payMethod"`
TradeEnv struct {
IP string `json:"ip"`
} `json:"tradeEnv"` // 如果具体环境信息比较复杂,可以直接使用json.RawMessage
MerchantAttach string `json:"merchantAttach,omitempty"` // omitempty表示如果字段为空,则在JSON中不显示
NotifyUrl string `json:"notifyUrl"`
ReturnUrl string `json:"returnUrl"`
}
type Payer struct {
UserID string `json:"userId" validate:"required,max=64"`
Name string `json:"name" validate:"required,max=80"`
Email string `json:"email" validate:"required,email,max=80"`
Phone string `json:"phone" validate:"required,max=20"`
}
type PayResp struct {
Code string `json:"code"`
ErrorMessage string `json:"errorMessage"`
Data PaymentData `json:"data"`
}
type PaymentData struct {
PaymentNo string `json:"paymentNo"`
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
Action Action `json:"action"`
}
type Action struct {
PayMethodType string `json:"payMethodType"`
Type string `json:"type"`
URL string `json:"url"`
Method string `json:"method"`
}
type PayCallbackReq struct {
Event string `json:"event"`
Code string `json:"code"`
ErrorMessage string `json:"errorMessage"`
Data struct {
PaymentNo string `json:"paymentNo"`
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
RefundStatus string `json:"refundStatus"`
Status string `json:"status"` // PENDING 待⽀付 PROCESSING ⽀付中 PAID ⽀付成功 FAILURE ⽀付失败 CANCELLED 已取消
MerchantAttach string `json:"merchantAttach"`
CreatedTime string `json:"createdTime"`
PaidTime string `json:"paidTime"`
} `json:"data"`
}
type QueryPayReq struct {
MerchantTradeNo string `json:"merchantTradeNo"`
}
type QueryPayResp struct {
Code string `json:"code"`
ErrorMessage string `json:"errorMessage"`
Data struct {
PaymentNo string `json:"paymentNo"`
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
RefundStatus string `json:"refundStatus"`
Status string `json:"status"` // PENDING 待⽀付 PROCESSING ⽀付中 PAID ⽀付成功 FAILURE ⽀付失败 CANCELLED 已取消
MerchantAttach string `json:"merchantAttach"`
CreatedTime string `json:"createdTime"`
PaidTime string `json:"paidTime"`
} `json:"data"`
}
type WithdrawReq struct {
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
Description string `json:"description"`
PayoutMethod struct {
Type string `json:"type"` // BANK_ACCOUNT
Mode string `json:"mode"` // IMPS
BankCode string `json:"bankCode"`
BankName string `json:"bankName"`
AccountNumber string `json:"accountNumber"`
PayeeName string `json:"payeeName"`
PayeePhone string `json:"payeePhone"`
PayeeEmail string `json:"payeeEmail"`
PayeeAddress string `json:"payeeAddress"`
// VPA string `json:"vpa"`
} `json:"payoutMethod"`
MerchantAttach string `json:"merchantAttach,omitempty"`
NotifyUrl string `json:"notifyUrl"`
}
type WithdrawResp struct {
Code string `json:"code"` // OK
ErrorMessage string `json:"errorMessage"`
Data struct {
PayoutNo string `json:"payoutNo"`
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
} `json:"data"`
}
type WithdrawCallbackReq struct {
Event string `json:"event"`
Code string `json:"code"`
ErrorMessage string `json:"errorMessage"`
Data struct {
PayoutNo string `json:"payoutNo"`
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
TotalFee string `json:"totalFee"`
Status string `json:"status"` // PENDING 待处理 PROCESSING 处理中 PAID 代付成功 FAILURE 代付失败 REVERSED 代付退票 CANCELLED 代付取消
MerchantAttach string `json:"merchantAttach"`
CreatedTime string `json:"createdTime"`
PaidTime string `json:"paidTime"`
} `json:"data"`
}
type QueryWithdrawReq struct {
MerchantTradeNo string `json:"merchantTradeNo"`
}
type QueryWithdrawResp struct {
Code string `json:"code"`
ErrorMessage string `json:"errorMessage"`
Data struct {
PayoutNo string `json:"payoutNo"`
MerchantTradeNo string `json:"merchantTradeNo"`
Amount string `json:"amount"`
Currency string `json:"currency"`
TotalFee string `json:"totalFee"`
Status string `json:"status"` // PENDING 待处理 PROCESSING 处理中 PAID 代付成功 FAILURE 代付失败 REVERSED 代付退票 CANCELLED 代付取消
MerchantAttach string `json:"merchantAttach"`
CreatedTime string `json:"createdTime"`
PaidTime string `json:"paidTime"`
} `json:"data"`
}
type SignData struct {
AppId string
Sign string
Timestamp string
Nonce string
}
func parseData(input string) SignData {
input = strings.TrimPrefix(input, "V2_SHA256 ")
pairs := strings.Split(input, ",")
data := SignData{}
for _, pair := range pairs {
keyValue := strings.Split(pair, "=")
if len(keyValue) == 2 {
key := keyValue[0]
value := keyValue[1]
switch key {
case "appId":
data.AppId = value
case "sign":
data.Sign = value
case "timestamp":
data.Timestamp = value
case "nonce":
data.Nonce = value
}
}
}
return data
}

@ -69,6 +69,7 @@ const (
MoonPay2 MoonPay2
PayPlus PayPlus
LuckyinPay LuckyinPay
EaniPay
PayAll PayAll
) )

Loading…
Cancel
Save