parent
37d968698b
commit
a5eac5f7cb
73 changed files with 2328 additions and 1881 deletions
@ -0,0 +1,36 @@ |
||||
package base |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"time" |
||||
|
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
// status=1时,属于不知道第三方是什么情况的报错,不能当成业务中断
|
||||
// status=0时,可以根据返回判断是否是业务错误
|
||||
func Request(req *http.Request, ret interface{}) int { |
||||
client := &http.Client{ |
||||
Timeout: 30 * time.Second, |
||||
Transport: &http.Transport{ |
||||
DisableKeepAlives: true, |
||||
}, |
||||
} |
||||
req.Close = true |
||||
log.Debug("req:%+v", req) |
||||
resp, err := client.Do(req) |
||||
if err != nil { |
||||
log.Error("http post call err:%v", err) |
||||
return 1 |
||||
} |
||||
defer resp.Body.Close() |
||||
body, _ := ioutil.ReadAll(resp.Body) |
||||
log.Debug("response Body:%v", string(body)) |
||||
if err := json.Unmarshal(body, ret); err != nil { |
||||
log.Error("unmarshal fail err:%v", err) |
||||
return 1 |
||||
} |
||||
return 0 |
||||
} |
||||
@ -0,0 +1,148 @@ |
||||
package base |
||||
|
||||
import ( |
||||
"bytes" |
||||
"crypto/aes" |
||||
"crypto/cipher" |
||||
"crypto/hmac" |
||||
"crypto/sha512" |
||||
"encoding/base64" |
||||
"encoding/hex" |
||||
"strings" |
||||
|
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
func SignCBC(dataStr string, key []byte, iv ...byte) string { |
||||
data := []byte(dataStr) |
||||
// 创建cipher.Block接口
|
||||
block, err := aes.NewCipher(key) |
||||
if err != nil { |
||||
return "" |
||||
} |
||||
// 填充
|
||||
blockSize := block.BlockSize() |
||||
if iv == nil { |
||||
iv = make([]byte, blockSize) |
||||
} |
||||
data = pad(data, blockSize) |
||||
// CBC模式加密
|
||||
ciphertext := make([]byte, len(data)) |
||||
mode := cipher.NewCBCEncrypter(block, iv) |
||||
mode.CryptBlocks(ciphertext, data) |
||||
|
||||
return base64.StdEncoding.EncodeToString(ciphertext) |
||||
} |
||||
|
||||
func SignCBCDecode(dataStr string, key []byte, iv ...byte) string { |
||||
data, err := base64.StdEncoding.DecodeString(dataStr) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
//
|
||||
// 创建cipher.Block接口
|
||||
block, err := aes.NewCipher(key) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
// 填充
|
||||
blockSize := block.BlockSize() |
||||
if iv == nil { |
||||
iv = make([]byte, blockSize) |
||||
} |
||||
|
||||
// CBC模式加密
|
||||
mode := cipher.NewCBCDecrypter(block, iv) |
||||
ciphertext := make([]byte, len(data)) |
||||
mode.CryptBlocks(ciphertext, data) |
||||
|
||||
return string(ciphertext) |
||||
} |
||||
|
||||
func SignCBCBase64(data string, okey string, aesIv string) string { |
||||
// 将Base64编码的密钥解码
|
||||
key, err := base64.StdEncoding.DecodeString(okey) |
||||
if err != nil { |
||||
return "" |
||||
} |
||||
|
||||
// 创建AES加密算法实例
|
||||
block, err := aes.NewCipher(key) |
||||
if err != nil { |
||||
return "" |
||||
} |
||||
|
||||
// 将Base64编码的IV解码
|
||||
iv, err := base64.StdEncoding.DecodeString(aesIv) |
||||
if err != nil { |
||||
return "" |
||||
} |
||||
|
||||
// 创建CBC加密模式实例
|
||||
mode := cipher.NewCBCEncrypter(block, iv) |
||||
|
||||
// 对数据进行填充操作
|
||||
paddedData := pad([]byte(data), block.BlockSize()) |
||||
|
||||
// 加密数据
|
||||
encryptedData := make([]byte, len(paddedData)) |
||||
mode.CryptBlocks(encryptedData, paddedData) |
||||
|
||||
// 将加密结果进行Base64编码
|
||||
encodedResult := base64.StdEncoding.EncodeToString(encryptedData) |
||||
|
||||
return encodedResult |
||||
} |
||||
|
||||
func pad(data []byte, blockSize int) []byte { |
||||
padLen := blockSize - len(data)%blockSize |
||||
padding := bytes.Repeat([]byte{byte(padLen)}, padLen) |
||||
return append(data, padding...) |
||||
} |
||||
|
||||
func GetApiCheckSum(saltKey string, dataString string) string { |
||||
saltKeyBytes := []byte(saltKey) |
||||
saltKeyEncoded := base64.StdEncoding.EncodeToString(saltKeyBytes) |
||||
hash := hmac.New(sha512.New, []byte(saltKeyEncoded)) |
||||
hash.Write([]byte(dataString)) |
||||
hashValue := hash.Sum(nil) |
||||
hashValueHex := hex.EncodeToString(hashValue) |
||||
hashValueHex = strings.ToUpper(hashValueHex) |
||||
return hashValueHex |
||||
} |
||||
|
||||
func SignCBCBase64Decode(data string, okey string, aesIv string) string { |
||||
d, err := base64.StdEncoding.DecodeString(data) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
key, err := base64.StdEncoding.DecodeString(okey) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
iv, err := base64.StdEncoding.DecodeString(aesIv) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
block, err := aes.NewCipher(key) // 分组秘钥
|
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
blockMode := cipher.NewCBCDecrypter(block, iv) // 加密模式
|
||||
blockMode.CryptBlocks(d, d) // 解密
|
||||
d = pkcs5UnPadding(d) // 去除补全码
|
||||
|
||||
return string(d) |
||||
} |
||||
|
||||
func pkcs5UnPadding(origData []byte) []byte { |
||||
length := len(origData) |
||||
unpadding := int(origData[length-1]) |
||||
return origData[:(length - unpadding)] |
||||
} |
||||
@ -1,181 +0,0 @@ |
||||
package bfpay |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
"server/util" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/gogo/protobuf/proto" |
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
func NewSub(b *base.Base) { |
||||
sub := &Sub{ |
||||
Base: b, |
||||
} |
||||
b.SignKey = key |
||||
b.HttpType = base.HttpTypeJson |
||||
b.ShouldSignUpper = false |
||||
if b.Opt == 1 { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = baseURL + payURL |
||||
} else if b.Opt == 2 { |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = baseURL + withdrawURL |
||||
} else if b.Opt == 3 { |
||||
b.SignPassStr = []string{"sign"} |
||||
b.CallbackResp.Msg = "SUCCESS" |
||||
b.CallbackReq = new(PayCallbackReq) |
||||
} else if b.Opt == 4 { |
||||
b.SignPassStr = []string{"sign", "msg"} |
||||
b.CallbackResp.Msg = "SUCCESS" |
||||
b.CallbackReq = new(WithdrawCallbackReq) |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
// header.Set("mchtId", mid)
|
||||
// header.Set("version", "20")
|
||||
// if s.Base.Opt == 1 {
|
||||
// header.Set("biz", "bq102")
|
||||
// } else if s.Base.Opt == 2 {
|
||||
// header.Set("biz", "df104")
|
||||
// }
|
||||
} |
||||
|
||||
func (s *Sub) PackReq() interface{} { |
||||
if s.Base.Opt == 1 { |
||||
return s.PackPayReq() |
||||
} |
||||
return s.PackWithdrawReq() |
||||
} |
||||
|
||||
func (s *Sub) GetResp() (proto.Message, error) { |
||||
if s.Base.Opt == 1 { |
||||
resp := s.Base.Resp.(*PayResp) |
||||
if resp.Head.RespCode != "0000" || resp.Body.PayUrl == "" { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: resp.Body.TradeId, URL: resp.Body.PayUrl, Channel: uint32(values.BFPay)}, nil |
||||
} |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.Head.RespCode != "0000" { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
withdrawRespBody := &WithdrawRespBody{} |
||||
err := Decode(resp.Body, withdrawRespBody) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: withdrawRespBody.TradeId, Channel: uint32(values.BFPay)}, nil |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &PayReq{ |
||||
Head: Head{ |
||||
MchtId: mid, |
||||
Version: "20", |
||||
Biz: "bq101", |
||||
}, |
||||
|
||||
Body: Body{ |
||||
OrderId: r.OrderID, |
||||
OrderTime: time.Now().Format("20060102150405"), |
||||
Amount: fmt.Sprintf("%d", r.Amount/1e6), |
||||
CurrencyType: "BRL", |
||||
Goods: "baxipix", |
||||
NotifyUrl: values.GetPayCallback(values.BFPay), |
||||
CallBackUrl: values.GetFrontCallback(), |
||||
}, |
||||
} |
||||
send.Sign = s.Base.SignMD5(send.Body) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
if common.PayType(r.PayType) == common.PayTypeCPF { |
||||
r.Number = strings.ReplaceAll(r.Number, "-", "") |
||||
r.Number = strings.ReplaceAll(r.Number, ".", "") |
||||
} |
||||
send := &WithdrawReq{ |
||||
Head: Head{ |
||||
MchtId: mid, |
||||
Version: "20", |
||||
Biz: "df104", |
||||
}, |
||||
} |
||||
amount := fmt.Sprintf("%d", r.Amount/1e6) |
||||
withdrawReqBody := WithdrawBody{ |
||||
BatchOrderNo: r.OrderID, |
||||
TotalNum: 1, |
||||
TotalAmount: amount, |
||||
NotifyUrl: values.GetWithdrawCallback(values.BFPay), |
||||
CurrencyType: "BRL", |
||||
} |
||||
detail := []Detail{{ |
||||
Seq: "0", |
||||
Amount: amount, |
||||
AccType: "0", |
||||
CertType: fmt.Sprintf("%d", r.PayType-1), |
||||
CertId: r.Number, |
||||
BankCardName: r.Name, |
||||
}} |
||||
withdrawReqBody.Detail = detail |
||||
jsonStr, _ := json.Marshal(withdrawReqBody) |
||||
encodeStr := string(jsonStr) |
||||
log.Debug("encodeStr:%s", encodeStr) |
||||
send.Body = Encode(encodeStr) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
// signStr := values.GetSignStr(str, "sign")
|
||||
s.Base.CallbackResp.Msg = "success" |
||||
if s.Base.Opt == 3 { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
log.Debug("checkSign pay:%+v", *req) |
||||
s.Base.CallbackResp.OrderID = req.Body.OrderId |
||||
s.Base.CallbackResp.Success = req.Body.Status == "SUCCESS" |
||||
return util.CalculateMD5(base.GetSignStr(req.Body)+"&key="+key) == req.Sign |
||||
} |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
log.Debug("checkSign withdraw:%+v", *req) |
||||
if req.Head.RespCode != "0000" { |
||||
return false |
||||
} |
||||
withdrawCallbackBody := &WithdrawCallbackBody{} |
||||
err := Decode(req.Body, withdrawCallbackBody) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return false |
||||
} |
||||
log.Debug("withdrawCallbackBody:%+v", withdrawCallbackBody) |
||||
if len(withdrawCallbackBody.Detail) == 0 { |
||||
return false |
||||
} |
||||
detail := withdrawCallbackBody.Detail[0] |
||||
if detail.Status == "AUDIT_DOING" || detail.Status == "AUDIT_SUCCESS" || detail.Status == "COMMITTED" || detail.Status == "COMMITTED_SUCCESS" || |
||||
detail.Status == "DOING" { |
||||
return false |
||||
} |
||||
s.Base.CallbackResp.OrderID = withdrawCallbackBody.BatchOrderNo |
||||
s.Base.CallbackResp.Success = detail.Status == "SUCCESS" |
||||
s.Base.CallbackResp.APIOrderID = withdrawCallbackBody.TradeId |
||||
s.Base.CallbackResp.FailMessage = req.Head.RespMsg |
||||
return true |
||||
} |
||||
@ -1,250 +0,0 @@ |
||||
package bfpay |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"net/url" |
||||
"server/util" |
||||
|
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
const ( |
||||
baseURL = "https://brl.bf-pay.com" |
||||
payURL = "/gateway/api/commPay" |
||||
withdrawURL = "/df/gateway/proxyrequest" |
||||
mid = "2000611000770152" |
||||
key = "afca030583d24e6faceceed3cddff3c9" |
||||
) |
||||
|
||||
var privateKeyPkCs8 = []byte(`-----BEGIN RSA PRIVATE KEY----- |
||||
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ5hQDWLXdURqCIc |
||||
Er3ID1D/ovQw2K+UaXP4vJ5t8d56gzFitOeCx92Qeu4wO8rINH599AZyiO3HuQM+ |
||||
P7ueBqJyDmv/vOAOld+PwiTk42DVHlEj/h9kuGXV8vZfsU6BhgNGlq9bsSn0olbM |
||||
kz2WX8Qw2CRnGbMZvYK73yEl83E1AgMBAAECgYA+9p6WKs+k0x4qYUq6E/yy0M4x |
||||
kfGy66d4qVwjB8ZuEfpx+bG9j+pxFO0qIBbFKQ5lcyE+Ju50yT+uIGMp7UrpTYuX |
||||
aU55OVFrUaLAt/XeyaKcOSPB9xK+ObRnKUrZ92FN/PU/tHkaRjFxPaNiZGqwbBcQ |
||||
RdtcHpo/ZkooRvbWyQJBAM/tLpvLIwnC6Gi8JhGunSDwZFxbLyLW/S3x4b6S0IaC |
||||
Uor/AsplshWs8VQ0L0edyShnyYcFpxw4t5oP0RtHCaMCQQDC/30hiwPJMfRZ/6oF |
||||
ljV4nyN47rQssHG2EYo/HfL7tZn+URlcZ5oSSoM2Qe6cmzg4Vaoo+CRWwKbjsh/n |
||||
d3dHAkA2uAV/DHuBEyEUhwdBugEx7PGMeJa0BX4FfFVbUMm9zEgquiei2hZ+q8+q |
||||
yDz1DOomTwHzHaK3w5lV2vm9wvkfAkA7or1XI9e9kWyElb8exEiIIktL8dziiffM |
||||
0eJw2Sz1tB1rfMv/yaOCEo28az+ZX5M7D1/h9bnPWk3v9wrw1EWDAkBZNzIZ47TS |
||||
Mj9ipSQDsSklZYPGquqlRsjRm7OcDZXC7zW6qs3mTPPuISRuMVhmFr3Lz3YMT1o/ |
||||
S0Agrn9Dq3fM |
||||
-----END RSA PRIVATE KEY-----`) |
||||
|
||||
// var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
// MIICXgIBAAKBgQDgIesHgi+Qj0kkhwvJdGzt/QZDYR8VFzDxVgt5KdA8Ec1WCrhv
|
||||
// GrmIEF2aKaqnPesv4/xn/0cLrXizYnF7wbgy/rrSzDmbWKEB6GZZc8Xz9iTxqoDT
|
||||
// 2TpZclSUwKjeicdnw35PDGdBKKCbfLJeg9pXMs/L9VnY/QtDp03a3760owIDAQAB
|
||||
// AoGBANQkZoA54elzJej0Bd0NXNk5x8bY04Gz7LhRGBT71cQ1mWQaS42l/vvheack
|
||||
// TwlzGvu+UDbjMgzEid1IjV908XFVAnmJQxFxsHJt3HUz9qK5caXtqzwqP7Vt0Bl/
|
||||
// Nt7wXhn1xq9gljLRuVV9+MoaF6punFuksqp4Qh/AAZ/zGVcJAkEA/ITUGawSY+AX
|
||||
// Gz1uAYadEnkA/Ce1rk/uL5OCSHxIvBLL3DmFp68E7+NTwyf2ilsnB0jtqOgBqrZ8
|
||||
// KoVfUjsxtwJBAOM46RGxijUhcDEoIZYUE+M+ugWskekdpwq4W9y1sNFULUjdXkwn
|
||||
// UKeSlwTis8zFCw8mkZDOgNQzRsd0eFjm5HUCQQCt2MipD/TtO7bMsyML++Ahepr5
|
||||
// /mCvLCpAKN62BpKQoKQm7pcclXrhqHDfV6D9KboZ4tRzx552KAIdyAqS81vLAkB7
|
||||
// CVLy+L7MvDmC9KcTG/YU499YuTQdFahg3qknXt7Kypjmzq+D7vn2cyMBSzxu0feG
|
||||
// Ea1ayubpgIZ/9CpCgWwNAkEA+f/5Ilnb3Dn9fRhGAuhttUIA9+vec3BH6rKc9oW/
|
||||
// JvLtLxuSpfg2D2D74nsZd48OVk+BJ0DqVeMb7sw6zjzH9A==
|
||||
// -----END RSA PRIVATE KEY-----`)
|
||||
var publicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrTw3IoR3Q6oRukb6q0LR6dc/GRXVh0ngRPZzRsq87j6817v4HNjfsf2gYkefWK3AcEGyZT7uqji1C0drDfVy82HE68hYjmxgyXQO2YRjNZkYNHNPHD9EO4y5fr4qQsSMCYA1a7fgWqbqZiGPQgCSUvrpbFbJh53QxOWqpkrKoowIDAQAB-----END PUBLIC KEY-----`) |
||||
var myPublicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeYUA1i13VEagiHBK9yA9Q/6L0 |
||||
MNivlGlz+LyebfHeeoMxYrTngsfdkHruMDvKyDR+ffQGcojtx7kDPj+7ngaicg5r |
||||
/7zgDpXfj8Ik5ONg1R5RI/4fZLhl1fL2X7FOgYYDRpavW7Ep9KJWzJM9ll/EMNgk |
||||
ZxmzGb2Cu98hJfNxNQIDAQAB |
||||
-----END PUBLIC KEY-----`) |
||||
|
||||
// Head represents the header of the request
|
||||
type Head struct { |
||||
MchtId string `json:"mchtId"` // 商户编号,不参与签名
|
||||
Version string `json:"version"` // 固定值“20”,不参与签名
|
||||
Biz string `json:"biz"` // 固定值,支付方式,不参与签名
|
||||
} |
||||
|
||||
// Body represents the body of the request
|
||||
type Body struct { |
||||
OrderId string `json:"orderId"` // 订单号
|
||||
OrderTime string `json:"orderTime"` // 订单时间yyyyMMddHHmmss
|
||||
Amount string `json:"amount"` // 总金额,以分为单位
|
||||
CurrencyType string `json:"currencyType"` // 货币种类,三位字母代码
|
||||
Goods string `json:"goods"` // 商品名称(不要带中文元素)
|
||||
NotifyUrl string `json:"notifyUrl"` // 接收推送通知的URL
|
||||
CallBackUrl string `json:"callBackUrl"` // 网页回调地址
|
||||
Desc string `json:"desc,omitempty"` // 商品描述,logo地址
|
||||
AppId string `json:"appId,omitempty"` // 产品标识
|
||||
AppName string `json:"appName,omitempty"` // 产品名称
|
||||
Operator string `json:"operator,omitempty"` // 印度UPI支付,用户的VPA账号
|
||||
ExpireTime string `json:"expireTime,omitempty"` // 订单超时时间yyyyMMddHHmmss
|
||||
IP string `json:"ip,omitempty"` // 请求IP地址
|
||||
Param string `json:"param,omitempty"` // 保留字段
|
||||
UserId string `json:"userId,omitempty"` // 要求:小于32位
|
||||
Phone string `json:"phone,omitempty"` // 手机号(币种是BRL,USDT,THB,PHP,USD,此参数可不传)
|
||||
Name string `json:"name,omitempty"` // 姓名(币种是BRL,USDT,THB,PHP,USD,此参数可不传)
|
||||
Email string `json:"email,omitempty"` // 邮箱(币种是BRL,USDT,THB,PHP,USD,此参数可不传)
|
||||
} |
||||
|
||||
type PayReq struct { |
||||
Head Head `json:"head"` |
||||
Body Body `json:"body"` |
||||
Sign string `json:"sign"` // 签名信息
|
||||
} |
||||
|
||||
type PayResp struct { |
||||
Head struct { |
||||
RespCode string `json:"respCode"` // 返回Code
|
||||
RespMsg string `json:"respMsg"` // 返回信息
|
||||
} `json:"head"` // 响应报文头
|
||||
Body struct { |
||||
MchtId string `json:"mchtId"` // 商户ID
|
||||
OrderId string `json:"orderId"` // 商户订单号
|
||||
PayUrl string `json:"payUrl"` // 支付URL地址
|
||||
TradeId string `json:"tradeId,omitempty"` // 支付平台返回的交易流水号
|
||||
Param string `json:"param,omitempty"` // 保留字段
|
||||
} `json:"body,omitempty"` // 响应报文体, 在respCode为"0000"时返回
|
||||
Sign string `json:"sign"` // 签名信息
|
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
Head struct { |
||||
RespCode string `json:"respCode"` // 返回Code
|
||||
RespMsg string `json:"respMsg"` // 返回信息
|
||||
} `json:"head"` // 响应报文头
|
||||
Body struct { |
||||
Amount string `json:"amount"` // 金额
|
||||
Biz string `json:"biz"` // 业务类型
|
||||
ChargeTime string `json:"chargeTime"` // 充值时间
|
||||
MchtId string `json:"mchtId"` // 商户ID
|
||||
OrderId string `json:"orderId"` // 商户订单号
|
||||
Seq string `json:"seq"` // 序号
|
||||
Status string `json:"status"` // 状态
|
||||
TradeId string `json:"tradeId"` // 交易流水号
|
||||
PayType string `json:"payType"` // 支付类型
|
||||
} `json:"body"` // 响应报文体
|
||||
Sign string `json:"sign"` // 签名信息
|
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
Head Head `json:"head"` |
||||
Body string `json:"body"` |
||||
} |
||||
|
||||
type WithdrawBody struct { |
||||
BatchOrderNo string `json:"batchOrderNo"` // 商户代付批次号,值唯一
|
||||
TotalNum int `json:"totalNum"` // 商户代付笔数,与detail代付明细集合数一致
|
||||
TotalAmount string `json:"totalAmount"` // 商户代付总金额,单位:分,为detail代付明细集合中金额总和
|
||||
NotifyUrl string `json:"notifyUrl,omitempty"` // 异步通知地址
|
||||
Detail []Detail `json:"detail"` // 代付订单明细,Json数组格式
|
||||
// AppId string `json:"appId,omitempty"` // 产品Id
|
||||
CurrencyType string `json:"currencyType"` // 币种BRL
|
||||
} |
||||
|
||||
type Detail struct { |
||||
Seq string `json:"seq"` // 序号,商户自定义
|
||||
Amount string `json:"amount"` // 金额,单位:分
|
||||
AccType string `json:"accType"` // 固定值 0
|
||||
CertType string `json:"certType"` // PIX账号类型或银行卡代付固定值
|
||||
CertId string `json:"certId"` // PIX账号或银行卡相关值
|
||||
// BankCardNo string `json:"bankCardNo,omitempty"` // 收款人的CPF或CNPJ(PIX代付必填)
|
||||
BankCardName string `json:"bankCardName"` // 收款用户姓名
|
||||
// BankCode string `json:"bankCode,omitempty"` // 银行编码(银行卡代付时必传)
|
||||
// Mobile string `json:"mobile,omitempty"` // 银行账户绑定的手机号码
|
||||
// Email string `json:"email,omitempty"` // 邮箱
|
||||
// BankCardType string `json:"bankCardType,omitempty"` // 银行卡类型,1:借记卡2:信用卡
|
||||
// CreditValid string `json:"creditValid,omitempty"` // 信用卡有效期,MMyy(信用卡时必填)
|
||||
// CreditCvv string `json:"creditCvv,omitempty"` // 卡背面后3位数字(信用卡时必填)
|
||||
// BankProvince string `json:"bankProvince,omitempty"` // 开户行所属省份
|
||||
// BankCity string `json:"bankCity,omitempty"` // 开户行所属市
|
||||
// BankLineCode string `json:"bankLineCode,omitempty"` // 联行号
|
||||
// BankName string `json:"bankName,omitempty"` // 银行名称
|
||||
// Remark string `json:"remark,omitempty"` // 备注
|
||||
// FirstName string `json:"firstName,omitempty"` // 收款人名
|
||||
// LastName string `json:"lastName,omitempty"` // 收款人姓
|
||||
// CardYear string `json:"cardYear,omitempty"` // 卡年份
|
||||
// CardMonth string `json:"cardMonth,omitempty"` // 卡月份
|
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
Head struct { |
||||
RespCode string `json:"respCode"` // 返回Code
|
||||
} `json:"head"` // 响应报文头
|
||||
Body string `json:"body,omitempty"` // 响应报文体,以字符串表示
|
||||
Sign string `json:"sign,omitempty"` // 签名信息,假设存在时
|
||||
} |
||||
|
||||
type WithdrawRespBody struct { |
||||
Status string `json:"status"` // 订单受理状态
|
||||
TradeId string `json:"tradeId"` // 平台批次号
|
||||
BatchOrderNo string `json:"batchOrderNo"` // 商户批次号
|
||||
MchtId string `json:"mchtId"` // 商户编号
|
||||
Desc string `json:"desc,omitempty"` // 描述, 可选字段
|
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
Head struct { |
||||
RespCode string `json:"respCode"` // 返回Code
|
||||
RespMsg string `json:"respMsg"` // 返回信息
|
||||
} `json:"head"` // 响应报文头
|
||||
Body string `json:"body,omitempty"` // 响应报文体,以字符串表示
|
||||
Sign string `json:"sign,omitempty"` // 签名信息,假设存在时
|
||||
} |
||||
|
||||
type WithdrawCallbackBody struct { |
||||
BatchOrderNo string `json:"batchOrderNo"` // 商户批次号
|
||||
TradeId string `json:"tradeId"` // 平台批次号
|
||||
TotalNum string `json:"totalNum"` // 代付笔数
|
||||
TotalAmount string `json:"totalAmount"` // 代付总金额
|
||||
Status string `json:"status"` // 状态
|
||||
Desc string `json:"desc,omitempty"` // 结果描述,可选字段
|
||||
Detail []WithdrawCallbackDetail `json:"detail"` // 代付明细订单详情
|
||||
|
||||
} |
||||
|
||||
type WithdrawCallbackDetail struct { |
||||
DetailId string `json:"detailId"` // 平台明细号
|
||||
Seq string `json:"seq"` // 序号
|
||||
Amount string `json:"amount"` // 金额 单位:分
|
||||
Status string `json:"status"` // 状态
|
||||
Desc string `json:"desc,omitempty"` // 结果描述
|
||||
FinishTime string `json:"finishTime,omitempty"` // 代付完成时间(币种时间)格式: yyyyMMddHHmmss
|
||||
} |
||||
|
||||
func Decode(str string, ret interface{}) error { |
||||
str2, err := url.QueryUnescape(str) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return err |
||||
} |
||||
res, err := util.NewXRsa(publicKey, privateKeyPkCs8) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return err |
||||
} |
||||
tmp, err := res.PrivateDecrypt(str2) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return err |
||||
} |
||||
err = json.Unmarshal([]byte(tmp), ret) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return err |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func Encode(str string) string { |
||||
res, err := util.NewXRsa(publicKey, privateKeyPkCs8) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
tmp, err := res.PublicEncrypt(str) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return "" |
||||
} |
||||
return url.QueryEscape(tmp) |
||||
} |
||||
@ -0,0 +1,137 @@ |
||||
package gopay |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/config" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
|
||||
"github.com/gogo/protobuf/proto" |
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
func NewSub(b *base.Base) { |
||||
sub := &Sub{ |
||||
Base: b, |
||||
} |
||||
b.SignKey = key |
||||
b.HttpType = base.HttpTypeJson |
||||
b.ShouldSignUpper = true |
||||
b.Channel = values.GoPay |
||||
if b.Opt == 1 { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = payURL |
||||
} else if b.Opt == 2 { |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = withdrawURL |
||||
} else if b.Opt == 3 { |
||||
b.SignPassStr = []string{"sign"} |
||||
b.CallbackResp.Msg = "SUCCESS" |
||||
b.CallbackReq = new(PayCallbackReq) |
||||
} else if b.Opt == 4 { |
||||
b.SignPassStr = []string{"sign", "msg"} |
||||
b.CallbackResp.Msg = "SUCCESS" |
||||
b.CallbackReq = new(WithdrawCallbackReq) |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
header.Set("Merchant-Id", config.GetConfig().Pay.IGeek.MID) |
||||
} |
||||
|
||||
func (s *Sub) PackReq() interface{} { |
||||
if s.Base.Opt == 1 { |
||||
return s.PackPayReq() |
||||
} |
||||
return s.PackWithdrawReq() |
||||
} |
||||
|
||||
func (s *Sub) GetResp() (proto.Message, error) { |
||||
if s.Base.Opt == 1 { |
||||
resp := s.Base.Resp.(*PayResp) |
||||
if resp.Code != 200 || resp.Data.PayLink == "" { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: fmt.Sprintf("%v", resp.Data.ID), URL: resp.Data.PayLink, Channel: uint32(values.GoPay)}, nil |
||||
} |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.Code != 200 { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: fmt.Sprintf("%v", resp.Data.ID), Channel: uint32(values.GoPay)}, nil |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &PayReq{ |
||||
Amount: r.Amount * 100, |
||||
Currency: "INR", |
||||
MerID: mid, |
||||
NotifyURL: values.GetPayCallback(values.GoPay), |
||||
OrderID: r.OrderID, |
||||
Type: 1, |
||||
ReturnURL: values.GetFrontCallback(), |
||||
UserName: r.Name, |
||||
Email: r.Email, |
||||
Mobile: r.Phone, |
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
if r.PayType != int64(common.PayTypeBank) { |
||||
return nil |
||||
} |
||||
send := &WithdrawReq{ |
||||
Amount: r.Amount * 100, |
||||
Currency: "INR", |
||||
MerID: mid, |
||||
NotifyURL: values.GetWithdrawCallback(values.GoPay), |
||||
OrderID: r.OrderID, |
||||
Type: 1, |
||||
BankCode: r.PayCode, |
||||
Account: r.CardNo, |
||||
UserName: r.Name, |
||||
Email: r.Email, |
||||
Mobile: r.Phone, |
||||
} |
||||
|
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
// str += "&key=" + key
|
||||
checkSign := "" |
||||
s.Base.CallbackResp.Msg = "success" |
||||
mySign := "" |
||||
if s.Base.Opt == 3 { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
log.Debug("checkSign pay:%+v", *req) |
||||
checkSign = req.Data.Sign |
||||
s.Base.CallbackResp.OrderID = req.Data.OrderID |
||||
s.Base.CallbackResp.Success = req.Code == 200 |
||||
mySign = s.Base.SignMD5(req.Data) |
||||
} else if s.Base.Opt == 4 { |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
log.Debug("checkSign withdraw:%+v", *req) |
||||
checkSign = req.Data.Sign |
||||
s.Base.CallbackResp.OrderID = req.Data.OrderID |
||||
s.Base.CallbackResp.Success = req.Code == 200 |
||||
s.Base.CallbackResp.APIOrderID = req.Data.ID |
||||
s.Base.CallbackResp.FailMessage = req.Message |
||||
mySign = s.Base.SignMD5(req.Data) |
||||
} |
||||
return mySign == checkSign |
||||
} |
||||
@ -0,0 +1,91 @@ |
||||
package gopay |
||||
|
||||
const ( |
||||
payURL = "https://gooopay.online/api/recharge/create" |
||||
withdrawURL = "https://gooopay.online/api/deposit/create" |
||||
mid = "2024100038" |
||||
key = "326eb5a2f78a4dacb4780104ba16030c" |
||||
) |
||||
|
||||
type PayReq struct { |
||||
Amount int64 `json:"amount"` // 订单金额,整数,单位分,举例:10000
|
||||
Currency string `json:"currency"` // 货币,举例:INR
|
||||
MerID string `json:"merId"` // 商户号,举例:2023100001
|
||||
NotifyURL string `json:"notifyUrl"` // 异步回调通知地址
|
||||
OrderID string `json:"orderId"` // 商户订单号
|
||||
Type int `json:"type"` // 类型,默认: 1
|
||||
ReturnURL string `json:"returnUrl"` // 订单完成同步跳转地址
|
||||
Sign string `json:"sign"` // 签名值,详情见1 签名说明
|
||||
UserName string `json:"userName,omitempty"` // 用户名 (可选)
|
||||
Email string `json:"email,omitempty"` // 邮箱 (可选)
|
||||
Mobile string `json:"mobile,omitempty"` // 手机号 (可选)
|
||||
} |
||||
|
||||
type PayResp struct { |
||||
Code int `json:"code"` // 状态码,200 表示提单成功,400 表示提单失败
|
||||
Message string `json:"message"` // 状态信息,"SUCCESS" 表示成功,"FAIL" 表示失败
|
||||
Data struct { |
||||
ID int `json:"id"` // 平台订单号
|
||||
MerID string `json:"merId"` // 商户号
|
||||
OrderID string `json:"orderId"` // 商户订单号
|
||||
Amount int `json:"amount"` // 金额
|
||||
Fee int `json:"fee"` // 手续费
|
||||
PayLink string `json:"payLink"` // 支付链接地址
|
||||
} `json:"data"` // 数据字段
|
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
Code int `json:"code"` // 状态码,200 表示支付成功
|
||||
Message string `json:"message"` // 状态信息,"SUCCESS" 表示成功,"FAIL" 表示失败
|
||||
Data struct { |
||||
MerID string `json:"merId"` // 商户号
|
||||
ID string `json:"id"` // 平台订单号
|
||||
OrderID string `json:"orderId"` // 商户订单号
|
||||
OperatorNum string `json:"operatorNum,omitempty"` // UTR,此参数有可能不参与回调,建议判空是否参与验签 (可选)
|
||||
Amount string `json:"amount"` // 金额
|
||||
Fee string `json:"fee"` // 手续费
|
||||
Currency string `json:"currency"` // 货币类型
|
||||
Sign string `json:"sign"` // 签名值,详情见1 签名说明
|
||||
} `json:"data"` // 数据字段
|
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
Amount int64 `json:"amount"` // 订单金额,整数,单位分,举例:10000
|
||||
Currency string `json:"currency"` // 货币,举例:INR
|
||||
MerID string `json:"merId"` // 商户号,举例:2023100001
|
||||
NotifyURL string `json:"notifyUrl"` // 异步回调通知地址
|
||||
OrderID string `json:"orderId"` // 商户订单号
|
||||
Type int `json:"type"` // 类型,默认: 1
|
||||
BankCode string `json:"bankCode"` // IFSC码,11位
|
||||
Account string `json:"account"` // 收款账号
|
||||
Sign string `json:"sign"` // 签名值,详情见1 签名说明
|
||||
UserName string `json:"userName"` // 用户名
|
||||
Email string `json:"email"` // 邮箱
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
Code int `json:"code"` // 状态码,200 表示提单成功,400 表示提单失败
|
||||
Message string `json:"message"` // 状态信息,"SUCCESS" 表示成功,"FAIL" 表示失败
|
||||
Data struct { |
||||
ID int `json:"id"` // 平台订单号
|
||||
MerID string `json:"merId"` // 商户号
|
||||
OrderID string `json:"orderId"` // 商户订单号
|
||||
Amount int `json:"amount"` // 金额
|
||||
Fee int `json:"fee"` // 手续费
|
||||
} `json:"data"` // 数据字段
|
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
Code int `json:"code"` // 状态码,200 表示提现成功,400 表示提现失败
|
||||
Message string `json:"message"` // 状态信息,"SUCCESS" 表示成功,"FAIL" 表示失败
|
||||
Data struct { |
||||
MerID string `json:"merId"` // 商户号
|
||||
ID string `json:"id"` // 平台订单号
|
||||
OrderID string `json:"orderId"` // 商户订单号
|
||||
Amount string `json:"amount"` // 金额
|
||||
Fee string `json:"fee"` // 手续费
|
||||
Currency string `json:"currency"` // 货币类型
|
||||
Sign string `json:"sign"` // 签名值,详情见1 签名说明
|
||||
} `json:"data"` // 数据字段
|
||||
} |
||||
@ -1,116 +1,134 @@ |
||||
package grepay |
||||
|
||||
import ( |
||||
"fmt" |
||||
"server/config" |
||||
"server/util" |
||||
"sort" |
||||
|
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
const ( |
||||
payURL = "https://api.metagopayments.com/cashier/pay.ac" |
||||
withdrawURL = "https://paypout.metagopayments.com/cashier/TX0001.ac" |
||||
oid = "8240601257" |
||||
mid = "24061200002795" |
||||
key = "1B5B3E0FE86054BD16F15C29CF4AC0B3" |
||||
payURL = "https://api.metagopayments.com/cashier/pay.ac" |
||||
payCallbackURL = "/grepay/pay/callback" |
||||
withdrawURL = "https://payout.metagopayments.com/cashier/TX0001.ac" |
||||
withdrawCallbackURL = "/grepay/withdraw/callback" |
||||
orgNo = "8220800959" |
||||
mid = "22081000002504" |
||||
// key = "FF5D557F6AC9EF26212B482B23AD7F07"
|
||||
) |
||||
|
||||
type PayReq struct { |
||||
Version string `json:"version"` // 版本号,固定值:2.1
|
||||
OrgNo string `json:"orgNo"` // 机构号,平台下发的机构编号
|
||||
CustId string `json:"custId"` // 商户编号,平台提供的商户编号
|
||||
CustOrderNo string `json:"custOrderNo"` // 商户订单编号,客户方生成的订单编号,不能重复
|
||||
TranType string `json:"tranType"` // 交易类型(传数字编码) 0512
|
||||
ClearType string `json:"clearType"` // 清算方式,传数字编码,默认为01
|
||||
PayAmt int `json:"payAmt"` // 支付金额, 单位是分(整数)
|
||||
BackUrl string `json:"backUrl"` // 后台回调地址,支付完成时回调客户方结果接收地址
|
||||
FrontUrl string `json:"frontUrl"` // 前台回调地址,支付结果同步通知到前端
|
||||
// BankCode string `json:"bankCode"` // 银行编码,可选字段
|
||||
GoodsName string `json:"goodsName"` // 商品名称,不可使用中文
|
||||
OrderDesc string `json:"orderDesc"` // 订单描述,不可使用中文
|
||||
BuyIp string `json:"buyIp"` // 购买者IP,商户提交订单的IP
|
||||
UserName string `json:"userName"` // 付款人姓名,不可用中国的用户名
|
||||
UserEmail string `json:"userEmail"` // 付款人邮箱,不可用中国的邮箱
|
||||
UserPhone string `json:"userPhone"` // 付款人手机号,不可用中国的手机号
|
||||
// UserCitizenId string `json:"userCitizenId,omitempty"` // 巴西唯一税号(CPF/CNPJ),特殊交易类型必填
|
||||
// UserDeviceId string `json:"userDeviceId,omitempty"` // 用户设备ID,可选字段
|
||||
CountryCode string `json:"countryCode"` // 国家编码,固定值: BR
|
||||
Currency string `json:"currency"` // 币种,固定值: BRL
|
||||
// City string `json:"city,omitempty"` // 商户用户的城市名称,可选字段
|
||||
// Street string `json:"street,omitempty"` // 商户用户的街道名称,可选字段
|
||||
// HouseNumber string `json:"houseNumber,omitempty"` // 商户用户的门牌号,可选字段
|
||||
Sign string `json:"sign"` // 签名,根据规则加签后的结果
|
||||
Version string `json:"version"` |
||||
OrgNo string `json:"orgNo"` |
||||
CustId string `json:"custId"` |
||||
CustOrderNo string `json:"custOrderNo"` |
||||
TranType string `json:"tranType"` |
||||
ClearType string `json:"clearType"` |
||||
PayAmt int64 `json:"payAmt"` |
||||
BackUrl string `json:"backUrl"` |
||||
FrontUrl string `json:"frontUrl"` |
||||
GoodsName string `json:"goodsName"` |
||||
OrderDesc string `json:"orderDesc"` |
||||
BuyIp string `json:"buyIp"` |
||||
UserName string `json:"userName"` |
||||
UserEmail string `json:"userEmail"` |
||||
UserPhone string `json:"userPhone"` |
||||
UserCitizenID string `json:"userCitizenId"` |
||||
CountryCode string `json:"countryCode"` |
||||
Currency string `json:"currency"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type PayResp struct { |
||||
OrgNo string `json:"orgNo"` // 机构编号,平台下发的机构编号
|
||||
OrdStatus string `json:"ordStatus,omitempty"` // 订单状态,可选字段
|
||||
Code string `json:"code"` // 请求接口状态返回码
|
||||
Msg string `json:"msg"` // 返回描述
|
||||
CustId string `json:"custId"` // 平台提供的商户编号
|
||||
CustOrderNo string `json:"custOrderNo"` // 商户订单编号
|
||||
PrdOrdNo string `json:"prdOrdNo,omitempty"` // 平台订单号,可作为查询依据的订单号,订单处理成功时返回
|
||||
ContentType string `json:"contentType,omitempty"` // 业务内容类型,可选字段
|
||||
BusContent string `json:"busContent,omitempty"` // 订单处理成功时返回的业务内容,如支付页面的URL链接
|
||||
OrdDesc string `json:"ordDesc,omitempty"` // 状态描述,订单状态存在时,描述状态代表的含义
|
||||
Sign string `json:"sign"` // 签名,根据规则加签后的结果
|
||||
OrgNo string `json:"orgNo"` |
||||
CustId string `json:"custId"` |
||||
Code string `json:"code"` // 000000 表示请求该接口正常
|
||||
Msg string `json:"msg"` |
||||
CustOrderNo string `json:"custOrderNo"` |
||||
ContentType string `json:"contentType"` |
||||
BusContent string `json:"busContent"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
Version string `json:"version"` // 版本号,返回和支付接口上送的一致
|
||||
OrgNo string `json:"orgNo"` // 机构编号,平台下发的机构编号
|
||||
CustId string `json:"custId"` // 平台提供的商户编号
|
||||
CustOrderNo string `json:"custOrderNo"` // 商户订单编号,客户方生成的订单编号, 不能重复
|
||||
PrdOrdNo string `json:"prdOrdNo"` // 平台订单号,可作为查询依据
|
||||
OrdAmt string `json:"ordAmt"` // 订单金额,单位为分
|
||||
OrdTime string `json:"ordTime"` // 订单时间,格式: yyyyMMddHHmmss
|
||||
PayAmt string `json:"payAmt"` // 支付金额,单位为分
|
||||
OrdStatus string `json:"ordStatus"` // 订单状态
|
||||
Sign string `json:"sign"` // 签名,根据规则加签以后的结果
|
||||
Version string `json:"version" form:"version"` |
||||
OrgNo string `json:"orgNo" form:"orgNo"` |
||||
CustId string `json:"custId" form:"custId"` |
||||
CustOrderNo string `json:"custOrderNo" form:"custOrderNo"` |
||||
PrdOrdNo string `json:"prdOrdNo" form:"prdOrdNo"` |
||||
OrdAmt string `json:"ordAmt" form:"ordAmt"` |
||||
OrdTime string `json:"ordTime" form:"ordTime"` |
||||
PayAmt string `json:"payAmt" form:"payAmt"` |
||||
OrdStatus string `json:"ordStatus" form:"ordStatus"` // 00:未交易01:成功02:失败03:被拒绝04:处理中05:取消支付06:未支付07:已退款08:退款中
|
||||
Sign string `json:"sign" form:"sign"` |
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
Version string `json:"version"` // 版本号,固定值:2.1
|
||||
OrgNo string `json:"orgNo"` // 机构编号,平台下发的机构编号
|
||||
CustId string `json:"custId"` // 平台提供的商户编号
|
||||
CustOrdNo string `json:"custOrdNo"` // 商户订单编号,客户方生成的订单编号,不能重复
|
||||
CasType string `json:"casType"` // 清算类型,固定值00(T0结算)
|
||||
Country string `json:"country"` // 国家编码,固定值:BR
|
||||
Currency string `json:"currency"` // 币种编码,固定值:BRL
|
||||
CasAmt int64 `json:"casAmt"` // 代付金额,单位是分
|
||||
DeductWay string `json:"deductWay"` // 手续费扣除方式,固定值02:账户余额中扣除
|
||||
CallBackUrl string `json:"callBackUrl"` // 回调地址
|
||||
Account string `json:"account"` // 代付子账户名称
|
||||
PayoutType string `json:"payoutType"` // 代付类型,可选值:Card, PIX
|
||||
AccountName string `json:"accountName"` // 收款人姓名
|
||||
// PayeeBankCode string `json:"payeeBankCode,omitempty"` // 银行编码,payoutType为Card时必填
|
||||
CardType string `json:"cardType"` // 代付类型的收款方式 cpf
|
||||
// CnapsCode string `json:"cnapsCode,omitempty"` // 巴西通道分行代码
|
||||
// CardNo string `json:"cardNo,omitempty"` // 银行卡号,payoutType为Card时必填
|
||||
PanNum string `json:"panNum"` // PAN Card 编码,必须传CPF(个人)
|
||||
WalletId string `json:"walletId"` // 电子钱包收款账号,payoutType为PIX时必填
|
||||
// UpiId string `json:"upiId,omitempty"` // UPI 的收款账号,对接巴西渠道时为空
|
||||
AccountType string `json:"accountType"` // 账户类型,默认值1:对私
|
||||
Phone string `json:"phone"` // 收款人手机号
|
||||
Email string `json:"email"` // 收款人邮箱
|
||||
CasDesc string `json:"casDesc"` // 代付备注(禁止使用中文)
|
||||
// AccountDigit string `json:"accountDigit,omitempty"` // 账户校验位,一般为银行卡最后一位校验位
|
||||
Sign string `json:"sign"` // 签名,根据规则加签以后的结果
|
||||
Version string `json:"version"` |
||||
OrgNo string `json:"orgNo"` |
||||
CustId string `json:"custId"` |
||||
CustOrderNo string `json:"custOrdNo"` |
||||
CasType string `json:"casType"` // 清算类型(请传数字编码)00(T0 结算)01(T1 结算)默认为00
|
||||
Country string `json:"country"` |
||||
Currency string `json:"currency"` |
||||
CasAmt int64 `json:"casAmt"` |
||||
DeductWay string `json:"deductWay"` |
||||
CallBackUrl string `json:"callBackUrl"` |
||||
Account string `json:"account"` |
||||
PayoutType string `json:"payoutType"` // Card: 代付到银行卡UPI: 代付到UPI 账户
|
||||
AccountName string `json:"accountName"` |
||||
PayeeBankCode string `json:"payeeBankCode"` |
||||
CardType string `json:"cardType"` // PayoutType为card时,填IMPS
|
||||
CnapsCode string `json:"cnapsCode"` // IFSC
|
||||
CardNo string `json:"cardNo"` |
||||
UpiId string `json:"upiId"` |
||||
Phone string `json:"phone"` |
||||
Email string `json:"email"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
OrgNo string `json:"orgNo"` // 机构编号,平台下发的机构编号
|
||||
OrdStatus string `json:"ordStatus,omitempty"` // 订单状态
|
||||
Code string `json:"code"` // 请求接口返回码
|
||||
Msg string `json:"msg"` // 返回描述
|
||||
CustId string `json:"custId"` // 平台提供的商户编号
|
||||
CustOrdNo string `json:"custOrdNo"` // 客户订单编号,原样返回
|
||||
CasOrdNo string `json:"casOrdNo,omitempty"` // 平台订单号,可作为查询依据
|
||||
CasAmt string `json:"casAmt"` // 代付金额,该字段值为100时则为1雷亚尔
|
||||
CasTime string `json:"casTime"` // 代付时间,格式:yyyyMMddHHmmss
|
||||
Sign string `json:"sign"` // 签名,根据规则加签以后的结果
|
||||
OrgNo string `json:"orgNo"` |
||||
OrdStatus string `json:"ordStatus"` // 00:未交易01:成功02:失败03:被拒绝04:处理中05:取消支付06:未支付07:已退款08:退款中
|
||||
Code string `json:"code"` // 000000 表示请求该接口正常
|
||||
Msg string `json:"msg"` |
||||
CustId string `json:"custId"` |
||||
CustOrderNo string `json:"custOrderNo"` |
||||
CasOrdNo string `json:"casOrdNo"` |
||||
CasAmt string `json:"casAmt"` |
||||
CasTime string `json:"casTime"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
OrgNo string `json:"orgNo"` // 机构编号,平台下发的机构编号
|
||||
CustId string `json:"custId"` // 平台提供的商户编号
|
||||
CustOrderNo string `json:"custOrderNo"` // 商户订单编号,客户方生成的订单编号,不能重复
|
||||
PrdOrdNo string `json:"prdOrdNo"` // 平台订单号,作为查询依据
|
||||
PayAmt string `json:"payAmt"` // 代付订单金额,单位是分
|
||||
OrdStatus string `json:"ordStatus"` // 代付订单状态
|
||||
CasDesc string `json:"casDesc"` // 代付单描述
|
||||
Sign string `json:"sign"` // 签名,根据规则加签以后的结果
|
||||
OrgNo string `json:"orgNo" form:"orgNo"` |
||||
CustId string `json:"custId" form:"custId"` |
||||
CustOrderNo string `json:"custOrderNo" form:"custOrderNo"` |
||||
PrdOrdNo string `json:"prdOrdNo" form:"prdOrdNo"` |
||||
PayAmt int64 `json:"payAmt" form:"payAmt"` |
||||
OrdStatus string `json:"ordStatus" form:"ordStatus"` // 00:未交易01:成功02:失败03:被拒绝04:处理中05:取消支付06:未支付07:已退款08:退款中
|
||||
CasDesc string `json:"casDesc" form:"casDesc"` |
||||
Sign string `json:"sign" form:"sign"` |
||||
} |
||||
|
||||
func Sign(m map[string]interface{}) string { |
||||
str := []string{} |
||||
for i := range m { |
||||
if i == "sign" { |
||||
continue |
||||
} |
||||
str = append(str, i) |
||||
} |
||||
sort.Strings(str) |
||||
signStr := "" |
||||
for _, v := range str { |
||||
mv := m[v] |
||||
signStr += fmt.Sprintf("%v=%v", v, mv) |
||||
signStr += "&" |
||||
} |
||||
signStr += "key=" + config.GetConfig().Pay.GrePay.Key |
||||
log.Debug("signStr:%v", signStr) |
||||
return util.CalculateMD5(signStr) |
||||
} |
||||
|
||||
@ -1,147 +0,0 @@ |
||||
package igeekpay |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/config" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
"server/util" |
||||
"strings" |
||||
|
||||
"github.com/gogo/protobuf/proto" |
||||
) |
||||
|
||||
func NewSub(b *base.Base) { |
||||
sub := &Sub{ |
||||
Base: b, |
||||
} |
||||
b.SignKey = config.GetConfig().Pay.IGeek.Key |
||||
b.HttpType = base.HttpTypeJson |
||||
b.ShouldSignUpper = true |
||||
if b.Opt == 1 { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = config.GetConfig().Pay.IGeek.APIURL + payURL |
||||
} else if b.Opt == 2 { |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = config.GetConfig().Pay.IGeek.APIURL + withdrawURL |
||||
} else if b.Opt == 3 { |
||||
b.CallbackResp.Msg = "success" |
||||
b.CallbackReq = new(PayCallbackReq) |
||||
} else if b.Opt == 4 { |
||||
b.CallbackResp.Msg = "success" |
||||
b.CallbackReq = new(WithdrawCallbackReq) |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
header.Set("Merchant-Id", config.GetConfig().Pay.IGeek.MID) |
||||
} |
||||
|
||||
func (s *Sub) PackReq() interface{} { |
||||
if s.Base.Opt == 1 { |
||||
return s.PackPayReq() |
||||
} |
||||
return s.PackWithdrawReq() |
||||
} |
||||
|
||||
func (s *Sub) GetResp() (proto.Message, error) { |
||||
if s.Base.Opt == 1 { |
||||
resp := s.Base.Resp.(*PayResp) |
||||
if resp.Status != 200 { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: resp.Data.TradeNo, URL: resp.Data.CashierUrl, Channel: uint32(values.IGeekPay)}, nil |
||||
} |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.Status != 200 { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: resp.Data.TradeNo, Channel: uint32(values.IGeekPay)}, nil |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &PayReq{ |
||||
Version: "V1", |
||||
BizType: "LOCAL", |
||||
AppId: config.GetConfig().Pay.IGeek.APPID, |
||||
OrderNo: r.OrderID, |
||||
ProductCode: "CASHIER", |
||||
Currency: "BRL", |
||||
Amount: util.Decimal(float64(r.Amount)/common.DecimalDigits, 2), |
||||
PaymentDetail: PaymentDetail{ |
||||
PayMode: "PIX", |
||||
}, |
||||
ProductName: fmt.Sprintf("goods%v", r.Amount), |
||||
UserDetail: UserDetail{ |
||||
ID: fmt.Sprintf("%v", r.UID), |
||||
Name: r.Name, |
||||
Mobile: r.Phone, |
||||
Email: r.Email, |
||||
CpfNumber: util.CheckCPF(r.Number), |
||||
}, |
||||
FrontCallUrl: values.GetFrontCallback(), |
||||
BackCallUrl: values.GetPayCallback(values.IGeekPay), |
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
if common.PayType(r.PayType) == common.PayTypeCPF { |
||||
r.Number = strings.ReplaceAll(r.Number, "-", "") |
||||
r.Number = strings.ReplaceAll(r.Number, ".", "") |
||||
} |
||||
send := &WithdrawReq{ |
||||
Version: "V1", |
||||
BizType: "LOCAL", |
||||
AppId: config.GetConfig().Pay.IGeek.APPID, |
||||
OrderNo: r.OrderID, |
||||
ProductCode: "PAYOUT", |
||||
Currency: "BRL", |
||||
Amount: util.Decimal(float64(r.Amount)/common.DecimalDigits, 2), |
||||
PayMode: "PIX", |
||||
PayeeName: r.Name, |
||||
IDType: common.PayType(r.PayType).String(), |
||||
IDNumber: r.Number, |
||||
PayeeMobile: "55" + r.Phone, |
||||
UserId: fmt.Sprintf("%v", r.UID), |
||||
PayeeEmail: r.Email, |
||||
CpfNumber: r.Number, |
||||
PayeeAddress: r.Address, |
||||
BackCallUrl: values.GetWithdrawCallback(values.IGeekPay), |
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
str = values.GetSignStrNull(str, "sign") |
||||
str += "&key=" + config.GetConfig().Pay.IGeek.Key |
||||
checkSign := "" |
||||
s.Base.CallbackResp.Msg = "success" |
||||
if s.Base.Opt == 3 { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
checkSign = req.Sign |
||||
s.Base.CallbackResp.OrderID = req.OrderNo |
||||
s.Base.CallbackResp.Success = req.PayStatus == "Success" |
||||
} else if s.Base.Opt == 4 { |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
checkSign = req.Sign |
||||
s.Base.CallbackResp.OrderID = req.OrderNo |
||||
s.Base.CallbackResp.Success = req.PayStatus == "Success" |
||||
s.Base.CallbackResp.APIOrderID = req.TradeNo |
||||
s.Base.CallbackResp.FailMessage = req.FailMessage |
||||
} |
||||
return strings.ToUpper(util.CalculateMD5(str)) == checkSign |
||||
} |
||||
@ -1,126 +0,0 @@ |
||||
package igeekpay |
||||
|
||||
const ( |
||||
payURL = "/collect/v1/order" |
||||
withdrawURL = "/payout/v1/brl" |
||||
) |
||||
|
||||
type PayReq struct { |
||||
Version string `json:"version,omitempty"` |
||||
BizType string `json:"bizType,omitempty"` |
||||
AppId string `json:"appId,omitempty"` |
||||
OrderNo string `json:"orderNo,omitempty"` |
||||
ProductCode string `json:"productCode,omitempty"` |
||||
Currency string `json:"currency,omitempty"` |
||||
Amount float64 `json:"amount,omitempty"` |
||||
// PaymentDetail PaymentDetail `json:"paymentDetail,omitempty"`
|
||||
ProductName string `json:"productName,omitempty"` |
||||
ProductDesc string `json:"productDesc,omitempty"` |
||||
PaymentDetail PaymentDetail `json:"paymentDetail,omitempty"` |
||||
UserDetail UserDetail `json:"userDetail,omitempty"` |
||||
FrontCallUrl string `json:"frontCallUrl,omitempty"` |
||||
BackCallUrl string `json:"backCallUrl,omitempty"` |
||||
Lang string `json:"lang,omitempty"` |
||||
AttachField string `json:"attachField,omitempty"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type PaymentDetail struct { |
||||
PayMode string `json:"payMode,omitempty"` // 支付模式 UPI/IMPS/WALLET
|
||||
// AccountNo string `json:"accountNo,omitempty"` // 支付账户
|
||||
// BankIfsc string `json:"bankIfsc,omitempty"` // 银行ifsc编码
|
||||
} |
||||
|
||||
type UserDetail struct { |
||||
ID string `json:"id,omitempty"` // 用户uid
|
||||
Name string `json:"name,omitempty"` // 名字
|
||||
Mobile string `json:"mobile,omitempty"` // 手机号
|
||||
Email string `json:"email,omitempty"` // 邮箱
|
||||
Address string `json:"address,omitempty"` // 地址
|
||||
IP string `json:"ip,omitempty"` |
||||
DeviceId string `json:"deviceId,omitempty"` |
||||
CpfNumber string `json:"cpfNumber,omitempty"` |
||||
} |
||||
|
||||
type PayResp struct { |
||||
Status int `json:"status,omitempty"` |
||||
Rel bool `json:"rel,omitempty"` |
||||
Data struct { |
||||
TradeNo string `json:"tradeNo,omitempty"` |
||||
OrderNo string `json:"orderNo,omitempty"` |
||||
ApplicationId string `json:"applicationId,omitempty"` // 商户appid
|
||||
CashierUrl string `json:"cashierUrl,omitempty"` // 支付地址
|
||||
Sign string `json:"sign,omitempty"` |
||||
} `json:"data"` |
||||
Message string `json:"message"` |
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
MerchantId string `json:"merchantId,omitempty"` |
||||
ApplicationId string `json:"applicationId,omitempty"` |
||||
TradeNo string `json:"tradeNo,omitempty"` |
||||
OrderNo string `json:"orderNo,omitempty"` |
||||
PayStatus string `json:"payStatus,omitempty"` |
||||
Amount float64 `json:"amount,omitempty"` |
||||
Currency string `json:"currency,omitempty"` |
||||
PayAmount float64 `json:"payAmount,omitempty"` |
||||
ServiceFee float64 `json:"serviceFee,omitempty"` |
||||
FailMessage string `json:"failMessage,omitempty"` |
||||
PayCurrency string `json:"payCurrency,omitempty"` |
||||
PayTime string `json:"payTime,omitempty"` |
||||
PayTimestamp int64 `json:"payTimestamp,omitempty"` |
||||
Attach string `json:"attach,omitempty"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
Version string `json:"version,omitempty"` |
||||
BizType string `json:"bizType,omitempty"` |
||||
AppId string `json:"appId,omitempty"` |
||||
OrderNo string `json:"orderNo,omitempty"` |
||||
ProductCode string `json:"productCode,omitempty"` |
||||
Currency string `json:"currency,omitempty"` |
||||
Amount float64 `json:"amount,omitempty"` |
||||
PayMode string `json:"payMode,omitempty"` // PIX
|
||||
PayeeName string `json:"payeeName,omitempty"` |
||||
IDType string `json:"idType,omitempty"` |
||||
IDNumber string `json:"idNumber,omitempty"` |
||||
PayeeMobile string `json:"payeeMobile,omitempty"` |
||||
UserId string `json:"userId,omitempty"` |
||||
PayeeEmail string `json:"payeeEmail,omitempty"` |
||||
CpfNumber string `json:"cpfNumber,omitempty"` |
||||
PayeeAddress string `json:"payeeAddress,omitempty"` |
||||
BackCallUrl string `json:"backCallUrl,omitempty"` |
||||
// AttachField string `json:"attachField,omitempty"`
|
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
Status int `json:"status,omitempty"` |
||||
Rel bool `json:"rel,omitempty"` |
||||
Data struct { |
||||
ApplicationId string `json:"applicationId,omitempty"` |
||||
TradeNo string `json:"tradeNo,omitempty"` |
||||
OrderNo string `json:"orderNo,omitempty"` |
||||
Sign string `json:"sign,omitempty"` |
||||
} `json:"data,omitempty"` |
||||
Message string `json:"message,omitempty"` |
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
MerchantId string `json:"merchantId,omitempty"` |
||||
ApplicationId string `json:"applicationId,omitempty"` |
||||
TradeNo string `json:"tradeNo,omitempty"` |
||||
OrderNo string `json:"orderNo,omitempty"` |
||||
PayStatus string `json:"payStatus,omitempty"` |
||||
Amount float64 `json:"amount,omitempty"` |
||||
Currency string `json:"currency,omitempty"` |
||||
PayAmount float64 `json:"payAmount,omitempty"` |
||||
ServiceFee float64 `json:"serviceFee,omitempty"` |
||||
FailMessage string `json:"failMessage,omitempty"` |
||||
PayCurrency string `json:"payCurrency,omitempty"` |
||||
PayTime string `json:"payTime,omitempty"` |
||||
PayTimestamp int64 `json:"payTimestamp,omitempty"` |
||||
Attach string `json:"attach,omitempty"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
@ -1,147 +0,0 @@ |
||||
package luckinpay |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/config" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
"server/util" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/gogo/protobuf/proto" |
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
func NewSub(b *base.Base) { |
||||
sub := &Sub{ |
||||
Base: b, |
||||
} |
||||
b.SignKey = key |
||||
b.HttpType = base.HttpTypeJson |
||||
// b.ShouldSignUpper = true
|
||||
if b.Opt == 1 { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = payURL |
||||
} else if b.Opt == 2 { |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = withdrawURL |
||||
} else if b.Opt == 3 { |
||||
// b.SignPassStr = []string{"sign"}
|
||||
b.CallbackResp.Msg = "success" |
||||
b.CallbackReq = new(PayCallbackReq) |
||||
} else if b.Opt == 4 { |
||||
// b.SignPassStr = []string{"sign", "msg"}
|
||||
b.CallbackResp.Msg = "success" |
||||
b.CallbackReq = new(WithdrawCallbackReq) |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
header.Set("Merchant-Id", config.GetConfig().Pay.IGeek.MID) |
||||
} |
||||
|
||||
func (s *Sub) PackReq() interface{} { |
||||
if s.Base.Opt == 1 { |
||||
return s.PackPayReq() |
||||
} |
||||
return s.PackWithdrawReq() |
||||
} |
||||
|
||||
func (s *Sub) GetResp() (proto.Message, error) { |
||||
if s.Base.Opt == 1 { |
||||
resp := s.Base.Resp.(*PayResp) |
||||
if resp.Code != "00000" || resp.Data.PayData == "" { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: resp.Data.PayOrderNo, URL: resp.Data.PayData, Channel: uint32(values.LuckinPay)}, nil |
||||
} |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.Code != "00000" { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: resp.Data.PayOrderNo, Channel: uint32(values.LuckinPay)}, nil |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &PayReq{ |
||||
MchNo: mid, |
||||
MchOrderNo: r.OrderID, |
||||
Currency: "BRL", |
||||
PayAmount: util.RoundFloat(float64(r.Amount)/common.DecimalDigits, 2), |
||||
AccountName: r.Name, |
||||
AccountEmail: r.Email, |
||||
AccountPhone: r.Phone, |
||||
CustomerIP: r.IP, |
||||
NotifyUrl: values.GetPayCallback(values.LuckinPay), |
||||
SuccessPageUrl: values.GetFrontCallback(), |
||||
ReqTime: fmt.Sprintf("%d", time.Now().UnixMilli()), |
||||
} |
||||
send.Sign, _ = base.SignWithSHA256([]byte(base.GetSignStr(send)), string(privateKey)) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
if common.PayType(r.PayType) == common.PayTypeCPF { |
||||
r.Number = strings.ReplaceAll(r.Number, "-", "") |
||||
r.Number = strings.ReplaceAll(r.Number, ".", "") |
||||
} |
||||
send := &WithdrawReq{ |
||||
MchNo: mid, |
||||
MchOrderNo: r.OrderID, |
||||
Currency: "BRL", |
||||
PayAmount: util.RoundFloat(float64(r.Amount)/common.DecimalDigits, 2), |
||||
AccountType: common.PayType(r.PayType).String(), |
||||
AccountCode: r.Number, |
||||
AccountNo: r.Number, |
||||
AccountName: r.Name, |
||||
AccountEmail: r.Email, |
||||
AccountPhone: r.Phone, |
||||
CustomerIP: r.IP, |
||||
NotifyUrl: values.GetWithdrawCallback(values.LuckinPay), |
||||
ReqTime: fmt.Sprintf("%d", time.Now().UnixMilli()), |
||||
} |
||||
send.Sign, _ = base.SignWithSHA256([]byte(base.GetSignStr(send)), string(privateKey)) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
signStr := values.GetSignStr(str, "sign") |
||||
checkSign := "" |
||||
s.Base.CallbackResp.Msg = "success" |
||||
if s.Base.Opt == 3 { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
log.Debug("checkSign pay:%+v", *req) |
||||
checkSign = req.Sign |
||||
s.Base.CallbackResp.OrderID = req.MchOrderNo |
||||
s.Base.CallbackResp.Success = req.PayState == 2 |
||||
} else if s.Base.Opt == 4 { |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
log.Debug("checkSign withdraw:%+v", *req) |
||||
if req.PayState == 1 { |
||||
return false |
||||
} |
||||
checkSign = req.Sign |
||||
s.Base.CallbackResp.OrderID = req.MchOrderNo |
||||
s.Base.CallbackResp.Success = req.PayState == 2 |
||||
s.Base.CallbackResp.APIOrderID = req.PayOrderNo |
||||
s.Base.CallbackResp.FailMessage = req.ErrMsg |
||||
} |
||||
pass, err := base.VerifyWithSHA256([]byte(signStr), checkSign, string(publicKey)) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
return false |
||||
} |
||||
return pass |
||||
} |
||||
@ -1,147 +0,0 @@ |
||||
package luckinpay |
||||
|
||||
const ( |
||||
payURL = "https://api.luckyinpay.online/api/pay/createPayinOrder" |
||||
withdrawURL = "https://api.luckyinpay.online/api/pay/createPayoutOrder" |
||||
mid = "M1704341111" |
||||
key = "O4HWRE7LH3HFDU6YTZJJKW7AGCIEICBR2KT1BR8JJVSNBBVUGLV6RA8ECGR82RMLDAOW8SUZW5YHPARCZQVRQE8MS8GGNWQ3PCIDKNIIIS7MOT8AEKESTMCUTRVZYQW7" |
||||
) |
||||
|
||||
var privateKeyPkCs8 = []byte(`-----BEGIN RSA PRIVATE KEY----- |
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdQYMybS8v6qy9uqTycOH2mRK4aLh4Pzvv530u5eBwY42I+bZO63fUXkXBnecPMgVnlcovPMpPtKa6ocQSAgW2vYmxO+gX0MKPPHcv7UfdmgtC8nUtNoJTfvNOgmElZD64lSJqSGSp2bEE1s6BLH9rLFAr61FzHCHvJFHBlycabXLbByDpLgU/aIDSc0Q8fvSUoS5TacUPSoyAnFZw6k4yX8IAgPZXO3I99CcjsgFjR0b5dXUDaGY4luU13Rg5s7n3iE6mDakiAQ8DJYQNc+I10EgFvoxuviWndiW3zoa1+VLGPsiif7E6X8nfqgOPaexd3E0H7JmUd6JRD0ge8HtXAgMBAAECggEAaI0J4Rjeaokn1+yjhdyvHviejaRyIOBJxTKu8+M52P8XNp5vKwE6ZiNXVWbaHCwxk7Du/4D3MQ72Wtb6OM7HZbuWNBOUN2FAOWMGCwNC6H5mRlhUt36qH0EkGmpslCOV37qnauo+ov5sxr7aBN/Ex0hq9Qg62sE1fn0zLfaEtPhMRqbHHJ9+Jfz7J2Fp69nSxpMfs0h/gOg2Eu2eX+tkgK6G99UJgN+D60XEWqofeUtTu/FVVrKYBLXY1Lzb0nv9XpYXtN4MJa+Xdct2FtHMDUgebCzlVZN/sVlLoSqm+nxdGJD6IbZB0GghW+YZMnimDZ47o+KD7CRXk3fjcvBnYQKBgQDUxvcyfmlcxQdwvOqxXcVW1YvgPSQTFpOc8LEZGwjzs+NjfAbS7tJE7mLImZwon8wHMzuZ2LGwSN+CdpgXiUlTAbcwkyKE9BT4X0GHwp/WD0MPl82EQR6M2bN/71zg+PQc4Sh03JgSC57YGIqVkT55OLlIF3xyriKuApZWMCuVgwKBgQC9M0cOGbJhnOJcRfdl+ZyxslubjocDNRdYH+nSZTddqpR7z04o00/6miCuvzURQ6QorULlh9+WSMB+xOBd4DHn5Zqmw4VN2UujW6dgUvXfXMqtmvldtWK+lsLsge0xbHAq5Ap9fuGnvrYfmvGGbk6m1a1XOnpmUHBVxIXUhBLunQKBgQCZ33Ew4N4NKqdgzh3jOm7VhwTqmwyViUQiwKUyBK0KoFKWxUCiFfeVxddGPmABuN3xbwlxDpYhZ/HLBTyj+LJABwOVazIRd/oaS7i2FvdD9DGI+zyyoe0X6u+2W0GNqDvRDrsVF9oZYrHykHzYAPtu6qiDDAkBXhDSSiiyF4/NRQKBgB59IekqyO0j+/JEsB51wAN+q3aA3E7vAkkIM4TdHLPyZiUhfgXkL5JBvhyK4YFbtht7+DjG0YgFR0fmcAWQuFoXTPmsrlGiP6cegPVryQVqjZq2S5MHRNdTsiussE1znQu8XdhlVvXSLMUhEeTI59HIwzs4SDsuoTuhBLP/aJGdAoGBAJ8ZCNGThSVcQijk1J1Sw0ZelGe2tsgb+2rTl8kiLDOQOgnGKaErGGAyzZBmESqq677vXwbQ+Xn7HWz6HnC+WVoAhxZCLTKXs4YdiMzOiCKeDNWky899OK3qG/6E9CqaO2Pn5F1xlYKVxIUfkwt7aQedFEIcSVN6op2V+JK4fEFX |
||||
-----END RSA PRIVATE KEY-----`) |
||||
var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY----- |
||||
MIIEpAIBAAKCAQEAnUGDMm0vL+qsvbqk8nDh9pkSuGi4eD877+d9LuXgcGONiPm2 |
||||
Tut31F5FwZ3nDzIFZ5XKLzzKT7SmuqHEEgIFtr2JsTvoF9DCjzx3L+1H3ZoLQvJ1 |
||||
LTaCU37zToJhJWQ+uJUiakhkqdmxBNbOgSx/ayxQK+tRcxwh7yRRwZcnGm1y2wcg |
||||
6S4FP2iA0nNEPH70lKEuU2nFD0qMgJxWcOpOMl/CAID2VztyPfQnI7IBY0dG+XV1 |
||||
A2hmOJblNd0YObO594hOpg2pIgEPAyWEDXPiNdBIBb6Mbr4lp3Ylt86GtflSxj7I |
||||
on+xOl/J36oDj2nsXdxNB+yZlHeiUQ9IHvB7VwIDAQABAoIBAGiNCeEY3mqJJ9fs |
||||
o4Xcrx74no2kciDgScUyrvPjOdj/FzaebysBOmYjV1Vm2hwsMZOw7v+A9zEO9lrW |
||||
+jjOx2W7ljQTlDdhQDljBgsDQuh+ZkZYVLd+qh9BJBpqbJQjld+6p2rqPqL+bMa+ |
||||
2gTfxMdIavUIOtrBNX59My32hLT4TEamxxyffiX8+ydhaevZ0saTH7NIf4DoNhLt |
||||
nl/rZICuhvfVCYDfg+tFxFqqH3lLU7vxVVaymAS12NS829J7/V6WF7TeDCWvl3XL |
||||
dhbRzA1IHmws5VWTf7FZS6Eqpvp8XRiQ+iG2QdBoIVvmGTJ4pg2eO6Pig+wkV5N3 |
||||
43LwZ2ECgYEA1Mb3Mn5pXMUHcLzqsV3FVtWL4D0kExaTnPCxGRsI87PjY3wG0u7S |
||||
RO5iyJmcKJ/MBzM7mdixsEjfgnaYF4lJUwG3MJMihPQU+F9Bh8Kf1g9DD5fNhEEe |
||||
jNmzf+9c4Pj0HOEodNyYEgue2BiKlZE+eTi5SBd8cq4irgKWVjArlYMCgYEAvTNH |
||||
DhmyYZziXEX3ZfmcsbJbm46HAzUXWB/p0mU3XaqUe89OKNNP+pogrr81EUOkKK1C |
||||
5YfflkjAfsTgXeAx5+WapsOFTdlLo1unYFL131zKrZr5XbVivpbC7IHtMWxwKuQK |
||||
fX7hp762H5rxhm5OptWtVzp6ZlBwVcSF1IQS7p0CgYEAmd9xMODeDSqnYM4d4zpu |
||||
1YcE6psMlYlEIsClMgStCqBSlsVAohX3lcXXRj5gAbjd8W8JcQ6WIWfxywU8o/iy |
||||
QAcDlWsyEXf6Gku4thb3Q/QxiPs8sqHtF+rvtltBjag70Q67FRfaGWKx8pB82AD7 |
||||
buqogwwJAV4Q0kooshePzUUCgYAefSHpKsjtI/vyRLAedcADfqt2gNxO7wJJCDOE |
||||
3Ryz8mYlIX4F5C+SQb4ciuGBW7Ybe/g4xtGIBUdH5nAFkLhaF0z5rK5Roj+nHoD1 |
||||
a8kFao2atkuTB0TXU7IrrLBNc50LvF3YZVb10izFIRHkyOfRyMM7OEg7LqE7oQSz |
||||
/2iRnQKBgQCfGQjRk4UlXEIo5NSdUsNGXpRntrbIG/tq05fJIiwzkDoJximhKxhg |
||||
Ms2QZhEqquu+718G0Pl5+x1s+h5wvllaAIcWQi0yl7OGHYjMzogingzVpMvPfTit |
||||
6hv+hPQqmjtj5+RdcZWClcSFH5MLe2kHnRRCHElTeqKdlfiSuHxBVw== |
||||
-----END RSA PRIVATE KEY-----`) |
||||
var publicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh/nLyajLky2rGA1rKJD/CYi0BK1onauzcjbDTth9tGeypwZoFLHIlJw3vY1KMIkayBwCVYZK+9X7FpoIcBwcd3mfzFpQA0WIE7gDH+qdtlx/NVKpSyp/6c7l+iKEwxvt8fHbrN/QHMh9xehroS/f8cKxEA8/dC/DAmQQ284ydJ81Ft8pUksWEyL4s3cqbMZSQsbam86U5aU55qWvPvMGqHx/5tfr9dyQ1Pytvr1H9oRPvVXmFRSLofY8GlYapbchSsViyGfAWERs3hYQvAOGB62TEKJfeYTiQyd7/Akn0XCS1S2kS4KllRqq1pIU0XKVjFqXuLf69z05fGZDkytAawIDAQAB |
||||
-----END PUBLIC KEY----- |
||||
`) |
||||
var myPublicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnUGDMm0vL+qsvbqk8nDh9pkSuGi4eD877+d9LuXgcGONiPm2Tut31F5FwZ3nDzIFZ5XKLzzKT7SmuqHEEgIFtr2JsTvoF9DCjzx3L+1H3ZoLQvJ1LTaCU37zToJhJWQ+uJUiakhkqdmxBNbOgSx/ayxQK+tRcxwh7yRRwZcnGm1y2wcg6S4FP2iA0nNEPH70lKEuU2nFD0qMgJxWcOpOMl/CAID2VztyPfQnI7IBY0dG+XV1A2hmOJblNd0YObO594hOpg2pIgEPAyWEDXPiNdBIBb6Mbr4lp3Ylt86GtflSxj7Ion+xOl/J36oDj2nsXdxNB+yZlHeiUQ9IHvB7VwIDAQAB |
||||
-----END PUBLIC KEY-----`) |
||||
|
||||
// var (
|
||||
// whiteIPs = []string{"52.67.100.247", "15.228.167.245", "54.207.16.136"}
|
||||
// )
|
||||
|
||||
type PayReq struct { |
||||
MchNo string `json:"mchNo"` |
||||
MchOrderNo string `json:"mchOrderNo"` |
||||
Currency string `json:"currency"` |
||||
PayAmount string `json:"payAmount"` |
||||
AccountName string `json:"accountName"` |
||||
AccountEmail string `json:"accountEmail"` |
||||
AccountPhone string `json:"accountPhone"` |
||||
CustomerIP string `json:"customerIp"` |
||||
NotifyUrl string `json:"notifyUrl"` |
||||
SuccessPageUrl string `json:"successPageUrl"` |
||||
Summary string `json:"summary,omitempty"` |
||||
ReqTime string `json:"reqTime"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type PayResp struct { |
||||
Code string `json:"code"` |
||||
Message string `json:"message"` |
||||
Sign string `json:"sign"` |
||||
Data PaymentData `json:"data"` |
||||
} |
||||
|
||||
// PaymentData 包含在支付响应中的数据体定义
|
||||
type PaymentData struct { |
||||
PayOrderNo string `json:"payOrderNo"` |
||||
MchOrderNo string `json:"mchOrderNo"` |
||||
MchNo string `json:"mchNo"` |
||||
Currency string `json:"currency"` |
||||
PayAmount string `json:"payAmount"` |
||||
PayInitiateTime string `json:"payInitiateTime"` |
||||
PayData string `json:"payData"` |
||||
PayReference string `json:"payReference,omitempty"` |
||||
PayState int `json:"payState"` |
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
PayOrderNo string `json:"payOrderNo"` |
||||
MchOrderNo string `json:"mchOrderNo"` |
||||
MchNo string `json:"mchNo"` |
||||
Currency string `json:"currency"` |
||||
PayAmount string `json:"payAmount"` |
||||
PayState int `json:"payState"` |
||||
PayInitiateTime string `json:"payInitiateTime"` |
||||
PayFinishTime string `json:"payFinishTime"` |
||||
ErrMsg string `json:"errMsg,omitempty"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
MchNo string `json:"mchNo"` |
||||
MchOrderNo string `json:"mchOrderNo"` |
||||
Currency string `json:"currency"` |
||||
PayAmount string `json:"payAmount"` |
||||
AccountType string `json:"accountType"` |
||||
AccountCode string `json:"accountCode"` |
||||
AccountNo string `json:"accountNo"` |
||||
AccountName string `json:"accountName"` |
||||
AccountEmail string `json:"accountEmail"` |
||||
AccountPhone string `json:"accountPhone"` |
||||
CustomerIP string `json:"customerIp"` |
||||
NotifyUrl string `json:"notifyUrl"` |
||||
Summary string `json:"summary,omitempty"` |
||||
ReqTime string `json:"reqTime"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
Code string `json:"code"` |
||||
Message string `json:"message"` |
||||
Sign string `json:"sign"` |
||||
Data PayoutData `json:"data"` |
||||
} |
||||
|
||||
type PayoutData struct { |
||||
PayOrderNo string `json:"payOrderNo"` |
||||
MchOrderNo string `json:"mchOrderNo"` |
||||
MchNo string `json:"mchNo"` |
||||
Currency string `json:"currency"` |
||||
PayAmount string `json:"payAmount"` |
||||
PayInitiateTime string `json:"payInitiateTime"` |
||||
PayState int `json:"payState"` |
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
PayOrderNo string `json:"payOrderNo"` |
||||
MchOrderNo string `json:"mchOrderNo"` |
||||
MchNo string `json:"mchNo"` |
||||
Currency string `json:"currency"` |
||||
PayAmount string `json:"payAmount"` |
||||
PayState int `json:"payState"` |
||||
PayInitiateTime string `json:"payInitiateTime"` |
||||
PayFinishTime string `json:"payFinishTime"` |
||||
ErrMsg string `json:"errMsg,omitempty"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
@ -0,0 +1,166 @@ |
||||
package mlpay |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
"server/util" |
||||
"strings" |
||||
|
||||
"github.com/gogo/protobuf/proto" |
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
func NewSub(b *base.Base) { |
||||
sub := &Sub{ |
||||
Base: b, |
||||
} |
||||
b.HttpType = base.HttpTypeForm |
||||
b.ShouldSignUpper = true |
||||
b.SignKey = key |
||||
b.Channel = values.MLPay |
||||
if b.Opt == base.OPTPay { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = baseUrl + payURL |
||||
} else if b.Opt == base.OPTWithdraw { |
||||
b.SignKey = withdrawKey |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = baseUrl + withdrawURL |
||||
} else if b.Opt == base.OPTPayCB { |
||||
b.HttpType = base.HttpTypeForm |
||||
b.CallbackReq = new(PayCallbackReq) |
||||
b.CallbackResp.Msg = "0" |
||||
} else if b.Opt == base.OPTWithdrawCB { |
||||
b.SignKey = withdrawKey |
||||
b.HttpType = base.HttpTypeForm |
||||
b.CallbackReq = new(WithdrawCallbackReq) |
||||
b.CallbackResp.Msg = "0" |
||||
// } else if b.Opt == base.OPTQueryWithdraw { // 查询
|
||||
// b.Resp = new(QueryWithdrawResp)
|
||||
// b.ReqURL = queryWithdrawURL
|
||||
// } else if b.Opt == base.OPTQueryPay { // 查询
|
||||
// b.Resp = new(QueryPayResp)
|
||||
// b.ReqURL = queryPayURL
|
||||
} else { |
||||
return |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
} |
||||
|
||||
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 == "" { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: s.Base.PayReq.OrderID, URL: resp.Data, Channel: uint32(values.MLPay)}, nil |
||||
} else if s.Base.Opt == base.OPTWithdraw { |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.Code == "0000" { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: resp.Data, Channel: uint32(values.MLPay)}, nil |
||||
} |
||||
return nil, errors.New("unknown opt") |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
userDataStr, _ := json.Marshal(UserData{UserName: r.Name, UserEmail: r.Email, UserPhone: r.Phone}) |
||||
send := &PayReq{ |
||||
PartnerID: PartnerId, |
||||
ApplicationID: ApplicationId, |
||||
PayWay: 2, |
||||
PartnerOrderNo: r.OrderID, |
||||
Amount: r.Amount * 100, |
||||
Currency: "INR", |
||||
Name: r.Name, |
||||
GameId: int(r.UID), |
||||
ClientIP: r.IP, |
||||
NotifyURL: values.GetPayCallback(values.MLPay), |
||||
Subject: "Shop", |
||||
Body: "product", |
||||
CallbackUrl: values.GetPayCallback(values.MLPay), |
||||
Extra: string(userDataStr), |
||||
Version: "1.0", |
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
send := &WithdrawReq{ |
||||
PartnerID: PartnerId, |
||||
PartnerWithdrawNo: r.OrderID, |
||||
Amount: r.Amount * 100, |
||||
Currency: "INR", |
||||
GameId: fmt.Sprintf("%d", r.UID), |
||||
NotifyURL: values.GetWithdrawCallback(values.MLPay), |
||||
AccountName: r.Name, |
||||
AccountPhone: r.Phone, |
||||
AccountEmail: r.Email, |
||||
Version: "1.0", |
||||
} |
||||
if r.PayType == int64(common.PayTypeBank) { |
||||
send.ReceiptMode = 1 |
||||
send.AccountNumber = r.CardNo |
||||
send.AccountExtra1 = r.PayCode |
||||
send.AccountExtra2 = r.PayCode[:4] |
||||
} else if r.PayType == int64(common.PayTypeUPI) { |
||||
send.ReceiptMode = 0 |
||||
send.AccountNumber = r.PayCode |
||||
} else { |
||||
return nil |
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
log.Debug("callback:%v", s.Base.CallbackReq) |
||||
sign := "" |
||||
if s.Base.Opt == base.OPTPayCB { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
s.Base.CallbackResp.OrderID = req.PartnerOrderNo |
||||
s.Base.CallbackResp.APIOrderID = req.OrderNo |
||||
// if req.Status == 1 {
|
||||
// return false
|
||||
// }
|
||||
s.Base.CallbackResp.Success = req.Status == 1 |
||||
sign = req.Sign |
||||
} else if s.Base.Opt == base.OPTWithdrawCB { |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
s.Base.CallbackResp.OrderID = req.PartnerWithdrawNo |
||||
// if req.Status == 1 {
|
||||
// return false
|
||||
// }
|
||||
s.Base.CallbackResp.Success = req.Status == 1 |
||||
sign = req.Sign |
||||
} |
||||
signStr := base.GetSignStrFormURLEncode(s.Base.C, s.Base.CallbackReq, "sign") |
||||
signStr2 := base.GetSignStrURLEncode(signStr, "sign") + "&key=" + s.Base.SignKey |
||||
return strings.ToUpper(util.CalculateMD5(signStr2)) == sign |
||||
} |
||||
@ -0,0 +1,137 @@ |
||||
package mlpay |
||||
|
||||
import ( |
||||
"fmt" |
||||
"server/util" |
||||
"sort" |
||||
"strings" |
||||
|
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
const ( |
||||
baseUrl = "https://api.lovetigervip.com" |
||||
payURL = "/pay/order" |
||||
payCallbackURL = "/mlpay/pay/callback" |
||||
withdrawURL = "/pay/withdraw" |
||||
withdrawCallbackURL = "/mlpay/withdraw/callback" |
||||
PartnerId = 1000100020003074 |
||||
ApplicationId = 69 |
||||
key = "83EF99E9E32C4B70832A4DB779BA01C7" |
||||
withdrawKey = "82BD667CE13049C4A881B52218A4F935" |
||||
) |
||||
|
||||
type PayReq struct { |
||||
PartnerID int64 `json:"partnerId"` |
||||
ApplicationID int64 `json:"applicationId"` |
||||
PayWay int `json:"payWay"` // 支付方式ID 固定值 2
|
||||
PartnerOrderNo string `json:"partnerOrderNo"` |
||||
Amount int64 `json:"amount"` |
||||
Currency string `json:"currency"` |
||||
Name string `json:"name"` |
||||
GameId int `json:"gameId"` |
||||
ClientIP string `json:"clientIp"` |
||||
NotifyURL string `json:"notifyUrl" encode:"1"` |
||||
Subject string `json:"subject"` |
||||
Body string `json:"body"` |
||||
CallbackUrl string `json:"callbackUrl" encode:"1"` |
||||
Extra string `json:"extra" encode:"1"` |
||||
Version string `json:"version"` // 接口版本号,固定:1.0
|
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type UserData struct { |
||||
UserName string `json:"userName"` |
||||
UserEmail string `json:"userEmail"` |
||||
UserPhone string `json:"userPhone"` |
||||
} |
||||
|
||||
type PayResp struct { |
||||
Code string `json:"code"` |
||||
Msg string `json:"msg"` |
||||
Data string `json:"data"` |
||||
} |
||||
|
||||
type PayData struct { |
||||
Amount string `json:"amount"` |
||||
MchOrder string `json:"mch_order"` |
||||
OrderNo string `json:"order_no"` // 平台订单号
|
||||
PayLink string `json:"pay_link"` // 支付链接
|
||||
Timestamp int64 `json:"timestamp"` // 时间戳
|
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
Status int64 `json:"status" form:"status"` // 0失败 1成功
|
||||
ApplicationID int64 `json:"applicationId" form:"applicationId"` |
||||
PayWay int64 `json:"payWay" form:"payWay"` |
||||
PartnerOrderNo string `json:"partnerOrderNo" form:"partnerOrderNo"` // 商户订单号
|
||||
OrderNo string `json:"orderNo" form:"orderNo"` // 平台订单号
|
||||
ChannelOrderNo string `json:"channelOrderNo" form:"channelOrderNo"` // 上游生成的代收号
|
||||
Amount int64 `json:"amount" form:"amount"` |
||||
Sign string `json:"sign" form:"sign"` |
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
PartnerID int64 `json:"partnerId"` |
||||
PartnerWithdrawNo string `json:"partnerWithdrawNo"` |
||||
Amount int64 `json:"amount"` |
||||
Currency string `json:"currency"` |
||||
GameId string `json:"gameId"` |
||||
NotifyURL string `json:"notifyUrl" encode:"1"` |
||||
ReceiptMode int `json:"receiptMode"` // currency=INR时收款方式0:UPI;1:IMPS;currency=BRL时收款方式 0:CPF;1:CNPJ;2:PHONE;3:EMAIL;4:EVP
|
||||
AccountNumber string `json:"accountNumber" encode:"1"` // 收款账户(URLENCODE编码,计算签名使用编码前数值)
|
||||
AccountName string `json:"accountName" encode:"1"` // 收款姓名(URLENCODE编码,计算签名使用编码前数值)
|
||||
AccountPhone string `json:"accountPhone" encode:"1"` // 收款电话(URLENCODE编码,计算签名使用编码前数值)
|
||||
AccountEmail string `json:"accountEmail" encode:"1"` // 收款邮箱(URLENCODE编码,计算签名使用编码前数值)
|
||||
AccountExtra1 string `json:"accountExtra1"` // currency=INR时,收款特殊参数1(当receiptMode为1时,此参数必填)(IFSC CODE)
|
||||
AccountExtra2 string `json:"accountExtra2"` // currency=INR时,收款特殊参数2(当receiptMode为1时,此参数在某些通道下必填,具体联系运营)(银行代码)
|
||||
Version string `json:"version"` // 接口版本号,固定:1.0
|
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
Code string `json:"code"` |
||||
Msg string `json:"msg"` |
||||
Data string `json:"data"` |
||||
} |
||||
|
||||
type WithdrawData struct { |
||||
Amount string `json:"amount"` |
||||
MchOrder string `json:"mch_order"` |
||||
OrderNo string `json:"order_no"` // 平台订单号
|
||||
Timestamp int64 `json:"timestamp"` // 时间戳
|
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
Status int64 `json:"status" form:"status"` // 0失败 1成功
|
||||
ErrorMsg int64 `json:"errorMsg" form:"errorMsg" encode:"1"` |
||||
PartnerWithdrawNo string `json:"partnerWithdrawNo" form:"partnerWithdrawNo"` // 商户订单号
|
||||
WithdrawNo string `json:"withdrawNo" form:"withdrawNo"` // 平台订单号
|
||||
ChannelWithdrawNo string `json:"channelWithdrawNo" form:"channelWithdrawNo"` // 上游生成的代收号
|
||||
Amount int64 `json:"amount" form:"amount"` |
||||
Sign string `json:"sign" form:"sign"` |
||||
} |
||||
|
||||
func Sign(m map[string]interface{}, t int) string { |
||||
str := []string{} |
||||
for i := range m { |
||||
if i == "sign" { |
||||
continue |
||||
} |
||||
str = append(str, i) |
||||
} |
||||
sort.Strings(str) |
||||
signStr := "" |
||||
for _, v := range str { |
||||
mv := m[v] |
||||
signStr += fmt.Sprintf("%v=%v", v, mv) |
||||
signStr += "&" |
||||
} |
||||
if t == 0 { |
||||
signStr += "key=" + key |
||||
} else { |
||||
signStr += "key=" + withdrawKey |
||||
} |
||||
log.Debug("signStr:%v", signStr) |
||||
return strings.ToUpper(util.CalculateMD5(signStr)) |
||||
} |
||||
@ -0,0 +1,233 @@ |
||||
package moonpay2 |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
"server/util" |
||||
"strings" |
||||
|
||||
"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 |
||||
b.Channel = values.MoonPay2 |
||||
if b.Opt == base.OPTPay { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = payURL |
||||
} else if b.Opt == base.OPTWithdraw { |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = 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 = queryWithdrawURL |
||||
} else if b.Opt == base.OPTQueryPay { // 查询
|
||||
b.Resp = new(QueryPayResp) |
||||
b.ReqURL = queryPayURL |
||||
} else { |
||||
return |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
} |
||||
|
||||
func (s *Sub) PackReq() interface{} { |
||||
if s.Base.Opt == base.OPTPay { |
||||
return s.PackPayReq() |
||||
} else if s.Base.Opt == base.OPTWithdraw { |
||||
return s.PackWithdrawReq() |
||||
} else if s.Base.Opt == base.OPTQueryWithdraw { |
||||
return s.PackQueryWithdrawReq() |
||||
} else if s.Base.Opt == base.OPTQueryPay { |
||||
return s.PackQueryPayReq() |
||||
} |
||||
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.PayURL == "" { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: resp.Data.PlatNumber, URL: resp.Data.PayURL, Channel: uint32(values.MoonPay2)}, nil |
||||
} else if s.Base.Opt == base.OPTWithdraw { |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.Code != 100 { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
data := &WithdrawData{} |
||||
tmp, ok := resp.Data.(map[string]interface{}) |
||||
if ok { |
||||
str, _ := json.Marshal(tmp) |
||||
json.Unmarshal([]byte(str), data) |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: data.PlatNumber, Channel: uint32(values.MoonPay2)}, nil |
||||
} else if s.Base.Opt == base.OPTQueryWithdraw { |
||||
resp := s.Base.Resp.(*QueryWithdrawResp) |
||||
ret := &pb.InnerQueryWithdrawResp{Msg: resp.Msg} |
||||
if len(resp.Data) == 0 { |
||||
ret.Status = 2 |
||||
return ret, nil |
||||
} |
||||
ret.OrderID = resp.Data[0].OrderNumber |
||||
s.Base.QueryWithdrawResp.OrderID = resp.Data[0].OrderNumber |
||||
// ret.APIOrderID=resp.Data[0].
|
||||
// s.Base.QueryWithdrawResp.APIOrderID = resp.Data.OrderID
|
||||
s.Base.QueryWithdrawResp.Msg = resp.Msg |
||||
if s.Base.Status != 0 { |
||||
s.Base.QueryWithdrawResp.Status = 3 |
||||
} else { |
||||
if resp.Code == 100 && resp.Data[0].Status == 4 { |
||||
s.Base.QueryWithdrawResp.Status = 1 |
||||
} else if resp.Data[0].Status == 2 || resp.Data[0].Status == 3 || resp.Data[0].Status == 5 { |
||||
s.Base.QueryWithdrawResp.Status = 2 |
||||
} else { |
||||
s.Base.QueryWithdrawResp.Status = 3 |
||||
} |
||||
} |
||||
return ret, nil |
||||
} else if s.Base.Opt == base.OPTQueryPay { |
||||
resp := s.Base.Resp.(*QueryPayResp) |
||||
ret := &pb.InnerQueryWithdrawResp{Msg: resp.Msg} |
||||
if len(resp.Data) == 0 { |
||||
ret.Status = 2 |
||||
return ret, nil |
||||
} |
||||
s.Base.QueryPayResp.APIOrderID = resp.Data[0].OrderNumber |
||||
// s.Base.QueryPayResp.OrderID = resp.Data.MOrderID
|
||||
s.Base.QueryPayResp.Msg = resp.Msg |
||||
if s.Base.Status != 0 { |
||||
s.Base.QueryPayResp.Status = 3 |
||||
} else { |
||||
if resp.Code == 100 && resp.Data[0].Status == 4 { |
||||
s.Base.QueryPayResp.Status = 1 |
||||
} else if resp.Data[0].Status == 3 { |
||||
s.Base.QueryPayResp.Status = 2 |
||||
} else { |
||||
s.Base.QueryPayResp.Status = 3 |
||||
} |
||||
} |
||||
return ret, nil |
||||
} |
||||
return nil, errors.New("unknown opt") |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &PayReq{ |
||||
MerchantID: mid, |
||||
OrderNumber: r.OrderID, |
||||
OrderAmount: fmt.Sprintf("%d", r.Amount), |
||||
Email: r.Email, |
||||
Name: r.Name, |
||||
Phone: r.Phone, |
||||
Deeplink: "0", |
||||
NotifyURL: values.GetPayCallback(values.MoonPay2), |
||||
} |
||||
send.Sign = strings.ToUpper(util.CalculateMD5(send.OrderNumber + mid + signKey)) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
send := &WithdrawReq{ |
||||
MerchantID: mid, |
||||
OrderNumber: r.OrderID, |
||||
OrderAmount: fmt.Sprintf("%d", r.Amount), |
||||
// Type: ,
|
||||
// VPA: ,
|
||||
Email: r.Email, |
||||
// Account: ,
|
||||
Name: r.Name, |
||||
// IFSC: ,
|
||||
Phone: r.Phone, |
||||
NotifyURL: values.GetWithdrawCallback(values.MoonPay2), |
||||
} |
||||
if r.PayType == int64(common.PayTypeBank) { |
||||
send.Type = "BANK" |
||||
send.Account = r.CardNo |
||||
send.IFSC = r.PayCode |
||||
} else if r.PayType == int64(common.PayTypeUPI) { |
||||
send.Type = "UPI" |
||||
send.VPA = r.PayCode |
||||
} else { |
||||
return nil |
||||
} |
||||
signData, _ := json.Marshal(send) |
||||
sign, _ := base.SignWithSHA256(signData, string(privateKey)) |
||||
send.Sign = sign |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
log.Debug("callback:%v", s.Base.CallbackReq) |
||||
if s.Base.Opt == base.OPTPayCB { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
s.Base.CallbackResp.OrderID = req.OrderNumber |
||||
s.Base.CallbackResp.APIOrderID = req.PlatNumber |
||||
if req.Status == 1 { |
||||
return false |
||||
} |
||||
s.Base.CallbackResp.Success = req.Status == 4 |
||||
|
||||
return strings.ToUpper(util.CalculateMD5(req.OrderNumber+mid+signKey)) == req.Sign |
||||
} else if s.Base.Opt == base.OPTWithdrawCB { |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
s.Base.CallbackResp.OrderID = req.OrderNumber |
||||
if req.Status == 1 { |
||||
return false |
||||
} |
||||
s.Base.CallbackResp.Success = req.Status == 4 |
||||
err := base.RsaDecode(req.Sign, string(publicKey)) |
||||
if err != nil { |
||||
log.Error("err:%v", err) |
||||
} |
||||
return err == nil |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (s *Sub) PackQueryWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
send := &QueryWithdrawReq{ |
||||
MerchantID: mid, |
||||
OrderList: []string{r.OrderID}, |
||||
} |
||||
send.Sign = strings.ToUpper(util.CalculateMD5(mid + signKey)) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackQueryPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &QueryPayReq{ |
||||
MerchantID: mid, |
||||
OrderList: []string{r.OrderID}, |
||||
} |
||||
send.Sign = strings.ToUpper(util.CalculateMD5(mid + signKey)) |
||||
return send |
||||
} |
||||
@ -0,0 +1,146 @@ |
||||
package moonpay2 |
||||
|
||||
const ( |
||||
payURL = "https://api.apayindiag.com/v1/pay/payin" |
||||
withdrawURL = "https://api.apayindiag.com/v1/payout/withdraw" |
||||
queryWithdrawURL = "https://api.apayindiag.com/v1/pay/check_payout_order" |
||||
queryPayURL = "https://api.apayindiag.com/v1/pay/check_payin_order" |
||||
signKey = "0b513f511e35dd5c3e1f6a8cdbc8db04" |
||||
mid = "190" |
||||
) |
||||
|
||||
var privateKeyPkCs8 = []byte(`-----BEGIN RSA PRIVATE KEY----- |
||||
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJpzh86YFNMBwgJehf9zOukX+4h1qvwEq2l0Vh3YQzwhGnT7xBSMG6uhXafnSSUvAa0MSFnZfvz37WsavL8d5BgI0+7mZT/CHGL6jKJul5go3thQAuNW3odBfhCy+zOMV7BSt6PgY580cuNesMCYGQGPodMI+a6nQ6jMWp+xMeW9AgMBAAECgYBZ3tupFMkZNq6jHkkuKOigdToBXyaM2lK7W9w4JXyJ4mE4rL6djiETryOF7YicQEvjW4BF985yd/kIF1i4hDYR9C0UR3V+gh++1h0ko1KpzgMlGxef2BNhYjFxy7gKat2uYic91+PeHaqfYkR50FK8cgHEeoYP+r0+19nJrtx56QJBAOaa2wdSo16xUz8MQqNkQ8rskE0ADAbDnOnN5yOY7QSFBV/Yc8JQr0tTUbgTf2xEVtPD3mJqqnlDAjb5KK1zwhsCQQCrdcZpRYKnEmMxBbgz+/32xaUHIMn4GccdW8qTCXWY4xtNKp39tHuZ9OgLGRJck/yyWKfdCgL6uBj7Y8pxCDUHAkEAnr4W7JGMeJDk10/fR46rxDLYmsjffoCFscTVygFpl2TicDoWZbsZEGdIp8h0PNlGU/xPR7xZoaPpEGKwB8bZ5QJAX00wQlUjgM+kmJvwPdzD1YUX7DVabW+OkA/0MfQhDCC3jRWyCVFnHjTVQU3nOdP7sfm7HA4zh74KDLjzzg3cwwJBAOaCNF7gkvFTdcJgnplBqSlJjPJuGcKcoD6obVD1iSLFa70y9OrAErFLeOrME5bkWuD7FKjajytV7vXmGfQLtAM=-----END RSA PRIVATE KEY-----`) |
||||
var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY----- |
||||
MIICXQIBAAKBgQCac4fOmBTTAcICXoX/czrpF/uIdar8BKtpdFYd2EM8IRp0+8QU |
||||
jBuroV2n50klLwGtDEhZ2X789+1rGry/HeQYCNPu5mU/whxi+oyibpeYKN7YUALj |
||||
Vt6HQX4QsvszjFewUrej4GOfNHLjXrDAmBkBj6HTCPmup0OozFqfsTHlvQIDAQAB |
||||
AoGAWd7bqRTJGTauox5JLijooHU6AV8mjNpSu1vcOCV8ieJhOKy+nY4hE68jhe2I |
||||
nEBL41uARffOcnf5CBdYuIQ2EfQtFEd1foIfvtYdJKNSqc4DJRsXn9gTYWIxccu4 |
||||
CmrdrmInPdfj3h2qn2JEedBSvHIBxHqGD/q9PtfZya7ceekCQQDmmtsHUqNesVM/ |
||||
DEKjZEPK7JBNAAwGw5zpzecjmO0EhQVf2HPCUK9LU1G4E39sRFbTw95iaqp5QwI2 |
||||
+Sitc8IbAkEAq3XGaUWCpxJjMQW4M/v99sWlByDJ+BnHHVvKkwl1mOMbTSqd/bR7 |
||||
mfToCxkSXJP8slin3QoC+rgY+2PKcQg1BwJBAJ6+FuyRjHiQ5NdP30eOq8Qy2JrI |
||||
336AhbHE1coBaZdk4nA6FmW7GRBnSKfIdDzZRlP8T0e8WaGj6RBisAfG2eUCQF9N |
||||
MEJVI4DPpJib8D3cw9WFF+w1Wm1vjpAP9DH0IQwgt40VsglRZx401UFN5znT+7H5 |
||||
uxwOM4e+Cgy4884N3MMCQQDmgjRe4JLxU3XCYJ6ZQakpSYzybhnCnKA+qG1Q9Yki |
||||
xWu9MvTqwBKxS3jqzBOW5Frg+xSo2o8rVe715hn0C7QD |
||||
-----END RSA PRIVATE KEY----- |
||||
`) |
||||
var publicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpsjT2KM439eEZteEsejLVS8phCvPbFb93UvS6KdAPt+381Bvdbff3AejQs5n3+089DnG5e8n53udNxftd+OEnSO3bMmYX/ylN9ul0oXpybUM1wXAfzfXmWeb5rIelSgxy8RoGQGP9o/iOr3n+eFJdvzoYTZvGDrcEjPGIZP9N4wIDAQAB |
||||
-----END PUBLIC KEY-----`) |
||||
var myPublicKey = []byte(`-----BEGIN PUBLIC KEY----- |
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCac4fOmBTTAcICXoX/czrpF/uIdar8BKtpdFYd2EM8IRp0+8QUjBuroV2n50klLwGtDEhZ2X789+1rGry/HeQYCNPu5mU/whxi+oyibpeYKN7YUALjVt6HQX4QsvszjFewUrej4GOfNHLjXrDAmBkBj6HTCPmup0OozFqfsTHlvQIDAQAB |
||||
-----END PUBLIC KEY-----`) |
||||
|
||||
type PayReq struct { |
||||
MerchantID string `json:"merchant_id"` |
||||
OrderNumber string `json:"order_number"` |
||||
OrderAmount string `json:"order_amount"` |
||||
Email string `json:"email"` |
||||
Name string `json:"name"` |
||||
Phone string `json:"phone"` |
||||
Deeplink string `json:"deeplink"` |
||||
NotifyURL string `json:"notify_url"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type PayResp struct { |
||||
Code int `json:"code"` // code=100时 为响应成功
|
||||
Data struct { |
||||
PayURL string `json:"pay_url"` |
||||
PlatNumber string `json:"plat_number"` |
||||
OrderNumber string `json:"order_number"` |
||||
OrderAmount string `json:"order_amount"` |
||||
} `json:"data"` |
||||
Msg string `json:"msg"` |
||||
Time int64 `json:"time"` |
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
Status int `json:"status"` // 状态1=处理中,3=失败,4=成功
|
||||
Message string `json:"message"` |
||||
Money string `json:"money"` |
||||
PlatNumber string `json:"plat_number"` |
||||
OrderNumber string `json:"order_number"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type QueryPayReq struct { |
||||
MerchantID string `json:"merchant_id"` |
||||
OrderList []string `json:"order_list"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type QueryPayResp struct { |
||||
Code int `json:"code"` |
||||
Data []QueryPayData `json:"data"` |
||||
Msg string `json:"msg"` |
||||
Time int64 `json:"time"` |
||||
} |
||||
|
||||
type QueryPayData struct { |
||||
Status int `json:"status"` // 状态:0是待处理,1=处理中,3=失败,4=成功(代付订单状态以此为准吗,切勿以code值做订单状态判断)
|
||||
OrderNumber string `json:"order_number"` |
||||
Utr string `json:"utr"` |
||||
OrderAmount string `json:"order_amount"` |
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
MerchantID string `json:"merchant_id"` |
||||
OrderNumber string `json:"order_number"` |
||||
OrderAmount string `json:"order_amount"` |
||||
Type string `json:"type"` |
||||
VPA string `json:"vpa"` |
||||
Email string `json:"email"` |
||||
Account string `json:"account"` |
||||
Name string `json:"name"` |
||||
IFSC string `json:"ifsc"` |
||||
Phone string `json:"phone"` |
||||
NotifyURL string `json:"notify_url"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
Code int `json:"code"` // code=100即为成功;其他值为失败(若万一出现无返回值的情况,请将您的订单状态转换为处理中,以免引起不必要的损失)
|
||||
Data interface{} `json:"data"` |
||||
Msg string `json:"msg"` |
||||
Time int `json:"time"` |
||||
} |
||||
|
||||
type WithdrawData struct { |
||||
Status int `json:"status"` |
||||
PlatNumber string `json:"plat_number"` |
||||
OrderNumber string `json:"order_number"` |
||||
OrderAmount string `json:"order_amount"` |
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
Status int `json:"status"` |
||||
Message string `json:"message"` |
||||
Money string `json:"money"` |
||||
PlatNumber string `json:"plat_number"` |
||||
OrderNumber string `json:"order_number"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type QueryWithdrawReq struct { |
||||
MerchantID string `json:"merchant_id"` |
||||
OrderList []string `json:"order_list"` |
||||
Sign string `json:"sign"` |
||||
} |
||||
|
||||
type QueryWithdrawResp struct { |
||||
Code int `json:"code"` |
||||
Data []QueryWithdrawData `json:"data"` |
||||
Msg string `json:"msg"` |
||||
Time int64 `json:"time"` |
||||
} |
||||
|
||||
type QueryWithdrawData struct { |
||||
Status int `json:"status"` // 状态:0是待处理,1=处理中,2=拒绝,3=失败,4=成功,5=撤销(代付订单状态以此为准吗,切勿以code值做订单状态判断)
|
||||
OrderNumber string `json:"order_number"` |
||||
Utr string `json:"utr"` |
||||
OrderAmount string `json:"order_amount"` |
||||
} |
||||
@ -1,139 +0,0 @@ |
||||
package pluspay |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"server/common" |
||||
"server/config" |
||||
"server/modules/pay/base" |
||||
"server/modules/pay/values" |
||||
"server/pb" |
||||
"server/util" |
||||
"strings" |
||||
|
||||
"github.com/gogo/protobuf/proto" |
||||
"github.com/liangdas/mqant/log" |
||||
) |
||||
|
||||
func NewSub(b *base.Base) { |
||||
sub := &Sub{ |
||||
Base: b, |
||||
} |
||||
b.SignKey = key |
||||
b.HttpType = base.HttpTypeForm |
||||
b.ShouldSignUpper = true |
||||
b.WhiteIPs = whiteIPs |
||||
if b.Opt == 1 { |
||||
b.Resp = new(PayResp) |
||||
b.ReqURL = payURL |
||||
} else if b.Opt == 2 { |
||||
b.Resp = new(WithdrawResp) |
||||
b.ReqURL = withdrawURL |
||||
} else if b.Opt == 3 { |
||||
b.SignPassStr = []string{"sign"} |
||||
b.CallbackResp.Msg = "success" |
||||
b.CallbackReq = new(PayCallbackReq) |
||||
} else if b.Opt == 4 { |
||||
b.SignPassStr = []string{"sign", "msg"} |
||||
b.CallbackResp.Msg = "success" |
||||
b.CallbackReq = new(WithdrawCallbackReq) |
||||
} |
||||
b.Sub = sub |
||||
} |
||||
|
||||
type Sub struct { |
||||
Base *base.Base |
||||
} |
||||
|
||||
func (s *Sub) PackHeader(header http.Header) { |
||||
header.Set("Merchant-Id", config.GetConfig().Pay.IGeek.MID) |
||||
} |
||||
|
||||
func (s *Sub) PackReq() interface{} { |
||||
if s.Base.Opt == 1 { |
||||
return s.PackPayReq() |
||||
} |
||||
return s.PackWithdrawReq() |
||||
} |
||||
|
||||
func (s *Sub) GetResp() (proto.Message, error) { |
||||
if s.Base.Opt == 1 { |
||||
resp := s.Base.Resp.(*PayResp) |
||||
if resp.RetCode != "SUCCESS" || resp.PayURL == "" { |
||||
return nil, errors.New("pay fail") |
||||
} |
||||
return &pb.InnerRechargeResp{APIOrderID: resp.PlatOrder, URL: resp.PayURL, Channel: uint32(values.PlusPay)}, nil |
||||
} |
||||
resp := s.Base.Resp.(*WithdrawResp) |
||||
if s.Base.Status == 0 && resp.RetCode != "SUCCESS" { |
||||
return nil, errors.New("withdraw fail") |
||||
} |
||||
return &pb.InnerWithdrawResp{APIOrderID: resp.PlatOrder, Channel: uint32(values.PlusPay)}, nil |
||||
} |
||||
|
||||
func (s *Sub) PackPayReq() interface{} { |
||||
r := s.Base.PayReq |
||||
send := &PayReq{ |
||||
MchID: mid, |
||||
OrderNo: r.OrderID, |
||||
Amount: util.RoundFloat(float64(r.Amount)/common.DecimalDigits, 2), |
||||
Product: "baxipix", |
||||
BankCode: "all", |
||||
Goods: fmt.Sprintf("email:%v/name:%v/phone:%v", r.Email, r.Name, r.Phone), // email:520155@gmail.com/name:tom/phone:7894561230
|
||||
// Goods: "testtests",
|
||||
NotifyURL: values.GetPayCallback(values.PlusPay), |
||||
// NotifyURL: "asdasd",
|
||||
// ReturnURL: "testtest",
|
||||
ReturnURL: values.GetFrontCallback(), |
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) PackWithdrawReq() interface{} { |
||||
r := s.Base.WithdrawReq |
||||
if common.PayType(r.PayType) == common.PayTypeCPF { |
||||
r.Number = strings.ReplaceAll(r.Number, "-", "") |
||||
r.Number = strings.ReplaceAll(r.Number, ".", "") |
||||
} |
||||
bc := strings.ToLower(common.PayType(r.PayType).String()) |
||||
send := &WithdrawReq{ |
||||
Type: "api", |
||||
MchID: mid, |
||||
MchTransNo: r.OrderID, |
||||
Amount: util.RoundFloat(float64(r.Amount)/common.DecimalDigits, 2), |
||||
NotifyURL: values.GetWithdrawCallback(values.PlusPay), |
||||
AccountName: r.Name, |
||||
AccountNo: r.Number, |
||||
BankCode: bc, |
||||
RemarkInfo: fmt.Sprintf("email:%v/phone:%v/mode:pix/%v:%v", r.Email, r.Phone, bc, r.Number), // email:520155@gmail.com/phone:9784561230/mode:pix/cpf:555555555(必须是真实的)
|
||||
} |
||||
send.Sign = s.Base.SignMD5(send) |
||||
return send |
||||
} |
||||
|
||||
func (s *Sub) CheckSign(str string) bool { |
||||
str += "&key=" + key |
||||
checkSign := "" |
||||
s.Base.CallbackResp.Msg = "success" |
||||
if s.Base.Opt == 3 { |
||||
req := s.Base.CallbackReq.(*PayCallbackReq) |
||||
log.Debug("checkSign pay:%+v", *req) |
||||
checkSign = req.Sign |
||||
s.Base.CallbackResp.OrderID = req.OrderNo |
||||
s.Base.CallbackResp.Success = req.Status == "2" |
||||
} else if s.Base.Opt == 4 { |
||||
req := s.Base.CallbackReq.(*WithdrawCallbackReq) |
||||
log.Debug("checkSign withdraw:%+v", *req) |
||||
if req.Status == "1" { |
||||
return false |
||||
} |
||||
checkSign = req.Sign |
||||
s.Base.CallbackResp.OrderID = req.MchTransNo |
||||
s.Base.CallbackResp.Success = req.Status == "2" |
||||
s.Base.CallbackResp.APIOrderID = req.MchTransNo |
||||
s.Base.CallbackResp.FailMessage = req.Msg |
||||
} |
||||
return strings.ToUpper(util.CalculateMD5(str)) == checkSign |
||||
} |
||||
@ -1,73 +0,0 @@ |
||||
package pluspay |
||||
|
||||
const ( |
||||
payURL = "http://api.fatpag.org/apipay" |
||||
withdrawURL = "http://api.fatpag.org/apitrans" |
||||
mid = "1686993516524" |
||||
key = "O4HWRE7LH3HFDU6YTZJJKW7AGCIEICBR2KT1BR8JJVSNBBVUGLV6RA8ECGR82RMLDAOW8SUZW5YHPARCZQVRQE8MS8GGNWQ3PCIDKNIIIS7MOT8AEKESTMCUTRVZYQW7" |
||||
) |
||||
|
||||
var ( |
||||
whiteIPs = []string{"52.67.100.247", "15.228.167.245", "54.207.16.136"} |
||||
) |
||||
|
||||
type PayReq struct { |
||||
MchID string `json:"mchId"` // 商户号,必填,填写商户的开户号。巴西 baxipix
|
||||
OrderNo string `json:"orderNo"` // 订单号,必填,至少6位字符,最多22位。
|
||||
Amount string `json:"amount"` // 金额,必填,单位为元,保留两位小数。
|
||||
Product string `json:"product"` // 产品号,必填,支付产品说明。
|
||||
BankCode string `json:"bankcode"` // 银行代号(小写),必填,没有明确说明填写"all",具体填写见1.3订单说明。
|
||||
Goods string `json:"goods"` // 物品说明,必填,本字段是扩展字段,参考后面的说明进行对应格式要求进行字符串拼接。一般情况下提交email、name、phone等参数,格式举例:email:520155@gmail.com/name:tom/phone:7894561230。特殊情况在1.3订单说明中有具体描述。
|
||||
NotifyURL string `json:"notifyUrl"` // 异步通知,必填,支持HTTP和HTTPS通知,通知方式为POST。
|
||||
ReturnURL string `json:"returnUrl"` // 同步通知,必填,支持HTTP和HTTPS通知,通知方式为POST。
|
||||
Sign string `json:"sign"` // 签名,必填,MD5签名,签名顺序是字典排序。
|
||||
} |
||||
|
||||
type PayResp struct { |
||||
RetCode string `json:"retCode"` |
||||
PayURL string `json:"payUrl"` |
||||
OrderNo string `json:"orderNo"` |
||||
PlatOrder string `json:"platOrder"` |
||||
Code string `json:"code"` |
||||
} |
||||
|
||||
type PayCallbackReq struct { |
||||
MchID string `json:"mchId"` // 商户号,商户的开户号。
|
||||
OrderNo string `json:"orderNo"` // 订单号,至少6位字符,最多22位。
|
||||
Amount string `json:"amount"` // 金额,单位为元,保留两位小数。
|
||||
Product string `json:"product"` // 产品号,参考product支付产品说明。
|
||||
PaySuccTime string `json:"paySuccTime"` // 支付成功时间。
|
||||
Status string `json:"status"` // 成功状态,1:支付中,2:成功,5:失效,-1:失败。
|
||||
Sign string `json:"sign"` // 签名,商户返回数据得到签名与返回的签名进行验签名。
|
||||
} |
||||
|
||||
type WithdrawReq struct { |
||||
Type string `json:"type"` // 转账类型,必填,必填字符小写固定字符"api"。
|
||||
MchID string `json:"mchId"` // 商户号,必填,填写商户的开户号。
|
||||
MchTransNo string `json:"mchTransNo"` // 转账订单号,必填,至少6位字符,最多22位。
|
||||
Amount string `json:"amount"` // 金额,必填,单位为元,保留两位小数。
|
||||
NotifyURL string `json:"notifyUrl"` // 通知地址,必填,支持HTTP和HTTPS通知,通知方式为POST。
|
||||
AccountName string `json:"accountName"` // 账户名,必填,持卡人姓名。
|
||||
AccountNo string `json:"accountNo"` // 账号,必填,持卡人卡号。
|
||||
BankCode string `json:"bankCode"` // 银行代号(驼峰法),必填,见章节五各个国家银行代号。
|
||||
RemarkInfo string `json:"remarkInfo"` // 备注,必填,见章节五具体说明。
|
||||
Sign string `json:"sign"` // 签名,必填,MD5签名,签名顺序是字典排序。
|
||||
} |
||||
|
||||
type WithdrawResp struct { |
||||
RetCode string `json:"retCode"` // 成功 SUCCESS 失败 FAIL
|
||||
RetMsg string `json:"retMsg"` |
||||
MchTransNo string `json:"mchTransNo"` |
||||
PlatOrder string `json:"platOrder"` |
||||
Status string `json:"status"` |
||||
} |
||||
|
||||
type WithdrawCallbackReq struct { |
||||
MchID string `json:"mchId"` // 商户号,商户的开户号。
|
||||
MchTransNo string `json:"mchTransNo"` // 转账订单号,至少6位字符,最多22位。
|
||||
Amount string `json:"amount"` // 金额,单位为元,保留两位小数。
|
||||
Status string `json:"status"` // 状态,1:处理中,2:成功,3:失败。
|
||||
TransSuccTime string `json:"transSuccTime"` // 成功时间。
|
||||
Sign string `json:"sign"` // 签名,商户返回数据得到签名与返回的签名进行验签名。
|
||||
Msg string `json:"msg"` // 信息描述,不参与签名,信息描述。
|
||||
} |
||||
Loading…
Reference in new issue