You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
9.4 KiB
359 lines
9.4 KiB
|
3 months ago
|
package robuspay
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"errors"
|
||
|
|
"fmt"
|
||
|
|
"net/http"
|
||
|
|
"server/modules/pay/base"
|
||
|
|
"server/modules/pay/values"
|
||
|
|
"server/pb"
|
||
|
|
"server/util"
|
||
|
|
"sort"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/gogo/protobuf/proto"
|
||
|
|
jsoniter "github.com/json-iterator/go"
|
||
|
|
"github.com/liangdas/mqant/log"
|
||
|
|
)
|
||
|
|
|
||
|
|
func NewSub(b *base.Base) {
|
||
|
|
sub := &Sub{
|
||
|
|
Base: b,
|
||
|
|
}
|
||
|
|
b.HttpType = base.HttpTypeJson
|
||
|
|
if b.Opt == base.OPTPay {
|
||
|
|
b.Resp = new(PayResp)
|
||
|
|
b.ReqURL = baseURL + payUrl
|
||
|
|
} else if b.Opt == base.OPTWithdraw {
|
||
|
|
b.Resp = new(WithdrawResp)
|
||
|
|
b.ReqURL = baseURL + withdrawUrl
|
||
|
|
} else if b.Opt == base.OPTPayCB {
|
||
|
|
b.CallbackReq = new(PayCallbackReq)
|
||
|
|
b.CallbackResp.Msg = "OK"
|
||
|
|
b.HttpType = base.HttpTypeForm
|
||
|
|
} else if b.Opt == base.OPTWithdrawCB {
|
||
|
|
b.CallbackReq = new(WithdrawCallbackReq)
|
||
|
|
b.CallbackResp.Msg = "OK"
|
||
|
|
b.HttpType = base.HttpTypeForm
|
||
|
|
} else if b.Opt == base.OPTQueryWithdraw { // 查询
|
||
|
|
b.Resp = new(QueryWithdrawResp)
|
||
|
|
b.ReqURL = baseURL + queryWithdrawUrl
|
||
|
|
} else if b.Opt == base.OPTQueryPay { // 查询
|
||
|
|
b.Resp = new(QueryPayResp)
|
||
|
|
b.ReqURL = baseURL + queryPayUrl
|
||
|
|
} else {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
b.Sub = sub
|
||
|
|
}
|
||
|
|
|
||
|
|
type Sub struct {
|
||
|
|
Base *base.Base
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) PackHeader(header http.Header) {
|
||
|
|
}
|
||
|
|
|
||
|
|
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 s.Base.Status == 0 && resp.RetCode != "0000" { // 错误
|
||
|
|
log.Error("robus pay err, %+v", resp)
|
||
|
|
return nil, errors.New("pay fail")
|
||
|
|
}
|
||
|
|
var payurl string
|
||
|
|
if resp.Data.Type == "" || resp.Data.Type == "payurl" {
|
||
|
|
payurl = resp.Data.PayUrl
|
||
|
|
} else {
|
||
|
|
payurl = resp.Data.PayData
|
||
|
|
}
|
||
|
|
if resp.Data.PayUrl == "" {
|
||
|
|
log.Error("robus pay link is nil, %+v", resp)
|
||
|
|
return nil, errors.New("pay fail")
|
||
|
|
}
|
||
|
|
return &pb.InnerRechargeResp{APIOrderID: resp.Data.OrderNo, URL: payurl, Channel: uint32(values.RobusPay)}, nil
|
||
|
|
} else if s.Base.Opt == base.OPTWithdraw {
|
||
|
|
resp := s.Base.Resp.(*WithdrawResp)
|
||
|
|
// notice: 提现的时候,未知错误不能当做错误返回
|
||
|
|
if s.Base.Status == 0 && resp.RetCode != "0000" {
|
||
|
|
log.Error("robus withdraw err, %+v", resp)
|
||
|
|
return nil, errors.New("withdraw fail")
|
||
|
|
}
|
||
|
|
return &pb.InnerWithdrawResp{APIOrderID: resp.Data.OrderNo, Channel: uint32(values.RobusPay)}, nil
|
||
|
|
} else if s.Base.Opt == base.OPTQueryWithdraw {
|
||
|
|
resp := s.Base.Resp.(*QueryWithdrawResp)
|
||
|
|
ret := &pb.InnerQueryWithdrawResp{}
|
||
|
|
if resp.RetCode != "0000" { // 错误
|
||
|
|
log.Error("robus query withdraw err, %+v", resp)
|
||
|
|
s.Base.QueryWithdrawResp.Status = base.QueryStatusUnknown
|
||
|
|
return ret, nil
|
||
|
|
}
|
||
|
|
s.Base.QueryWithdrawResp.OrderID = resp.Data.MerchantOrderNo
|
||
|
|
if s.Base.Status != 0 {
|
||
|
|
s.Base.QueryWithdrawResp.Status = base.QueryStatusUnknown
|
||
|
|
} else {
|
||
|
|
if resp.Data.Success == 1 {
|
||
|
|
s.Base.QueryWithdrawResp.Status = base.QueryStatusOrderSuccess
|
||
|
|
} else if resp.Data.Success == -1 {
|
||
|
|
s.Base.QueryWithdrawResp.Status = base.QueryStatusFail
|
||
|
|
} else {
|
||
|
|
s.Base.QueryWithdrawResp.Status = base.QueryStatusUnknown
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return ret, nil
|
||
|
|
} else if s.Base.Opt == base.OPTQueryPay {
|
||
|
|
resp := s.Base.Resp.(*QueryPayResp)
|
||
|
|
ret := &pb.InnerQueryWithdrawResp{}
|
||
|
|
if resp.RetCode != "0000" { // 错误
|
||
|
|
log.Error("robus query pay err, %+v", resp)
|
||
|
|
s.Base.QueryPayResp.Status = base.QueryStatusUnknown
|
||
|
|
return ret, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
s.Base.QueryWithdrawResp.OrderID = resp.Data.MerchantOrderNo
|
||
|
|
if s.Base.Status != 0 {
|
||
|
|
s.Base.QueryPayResp.Status = base.QueryStatusUnknown
|
||
|
|
} else {
|
||
|
|
if resp.Data.Success == 1 {
|
||
|
|
s.Base.QueryPayResp.Status = base.QueryStatusOrderSuccess
|
||
|
|
} else if resp.Data.Success == -1 {
|
||
|
|
s.Base.QueryPayResp.Status = base.QueryStatusFail
|
||
|
|
} else {
|
||
|
|
s.Base.QueryPayResp.Status = base.QueryStatusUnknown
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return ret, nil
|
||
|
|
}
|
||
|
|
return nil, errors.New("unknown opt")
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) PackPayReq() interface{} {
|
||
|
|
r := s.Base.PayReq
|
||
|
|
send := &PayReq{
|
||
|
|
MerchantNo: merchantId,
|
||
|
|
MerchantOrderNo: r.OrderID,
|
||
|
|
Amount: fmt.Sprintf("%d.00", r.Amount),
|
||
|
|
Name: r.Name,
|
||
|
|
Email: r.Email,
|
||
|
|
Mobile: r.Phone,
|
||
|
|
RequestTime: time.Now().Format(time.DateTime),
|
||
|
|
Method: "121001",
|
||
|
|
AsyncCallbackUrl: s.Base.GetPayCallbackURL(),
|
||
|
|
SyncCallbackUrl: s.Base.GetPayCallbackURL(),
|
||
|
|
SignType: "MD5",
|
||
|
|
Country: "IN",
|
||
|
|
}
|
||
|
|
signValue, err := s.GetSign(send)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("get sign err, %s", err.Error())
|
||
|
|
}
|
||
|
|
send.Sign = signValue
|
||
|
|
return send
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) PackWithdrawReq() interface{} {
|
||
|
|
r := s.Base.WithdrawReq
|
||
|
|
paramBytes, _ := json.Marshal(map[string]string{
|
||
|
|
"accountName": r.Name,
|
||
|
|
"accountNo": r.CardNo,
|
||
|
|
"bankCode": r.PayCode,
|
||
|
|
})
|
||
|
|
send := &WithdrawReq{
|
||
|
|
MerchantNo: merchantId,
|
||
|
|
MerchantOrderNo: r.OrderID,
|
||
|
|
Amount: fmt.Sprintf("%d.00", r.Amount),
|
||
|
|
Name: r.Name,
|
||
|
|
Email: r.Email,
|
||
|
|
Mobile: r.Phone,
|
||
|
|
RequestTime: time.Now().Format(time.DateTime),
|
||
|
|
AsyncCallbackUrl: s.Base.GetWithdrawCallbackURL(),
|
||
|
|
Method: "121002",
|
||
|
|
WithdrawCode: "1002",
|
||
|
|
WithdrawParam: string(paramBytes),
|
||
|
|
SignType: "MD5",
|
||
|
|
Country: "IN",
|
||
|
|
}
|
||
|
|
signValue, err := s.GetSign(send)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("get sign err, %s", err.Error())
|
||
|
|
}
|
||
|
|
send.Sign = signValue
|
||
|
|
return send
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) GetSignStr(body interface{}) (sign, signStr string) {
|
||
|
|
bodyBytes, err := jsoniter.Marshal(body)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("marshal err, %s", err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
var (
|
||
|
|
paramsMap map[string]interface{}
|
||
|
|
params []string
|
||
|
|
paramsValue []string
|
||
|
|
)
|
||
|
|
err = jsoniter.Unmarshal(bodyBytes, ¶msMap)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("unmarshal err, %s", err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
for k, v := range paramsMap {
|
||
|
|
if k == "sign" {
|
||
|
|
sign = v.(string)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
params = append(params, k)
|
||
|
|
}
|
||
|
|
sort.Strings(params)
|
||
|
|
for _, v := range params {
|
||
|
|
value := fmt.Sprintf("%+v", paramsMap[v])
|
||
|
|
switch (paramsMap[v]).(type) {
|
||
|
|
case float32:
|
||
|
|
value = fmt.Sprintf("%d", int(paramsMap[v].(float32)))
|
||
|
|
case float64:
|
||
|
|
value = fmt.Sprintf("%d", int(paramsMap[v].(float64)))
|
||
|
|
}
|
||
|
|
paramsValue = append(paramsValue, fmt.Sprintf("%s=%+v", v, value))
|
||
|
|
}
|
||
|
|
signStr = strings.Join(paramsValue, "&")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) GetSign(body interface{}) (sign string, err error) {
|
||
|
|
bodyBytes, err := jsoniter.Marshal(body)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("marshal err, %s", err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
var paramsMap map[string]interface{}
|
||
|
|
err = jsoniter.Unmarshal(bodyBytes, ¶msMap)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("unmarshal err, %s", err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
params := make([]string, 0)
|
||
|
|
for k, v := range paramsMap {
|
||
|
|
if k == "sign" || v == nil || v == "" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
params = append(params, k)
|
||
|
|
}
|
||
|
|
sort.Strings(params)
|
||
|
|
|
||
|
|
paramsValue := make([]string, 0)
|
||
|
|
for _, k := range params {
|
||
|
|
paramsValue = append(paramsValue, fmt.Sprintf("%s=%v", k, paramsMap[k]))
|
||
|
|
}
|
||
|
|
|
||
|
|
paramsValue = append(paramsValue, "key="+key)
|
||
|
|
signStr := strings.Join(paramsValue, "&")
|
||
|
|
sign = strings.ToUpper(util.CalculateMD5(signStr))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) checkSign(body string) (pass bool, err error) {
|
||
|
|
var sign string
|
||
|
|
mySign, err := s.GetSign(s.Base.CallbackReq)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("robus get sign err, %s", err.Error())
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
var (
|
||
|
|
paramsMap map[string]interface{}
|
||
|
|
)
|
||
|
|
err = jsoniter.UnmarshalFromString(body, ¶msMap)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("unmarshal err, %s", err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if paramsMap["sign"] == nil {
|
||
|
|
return false, errors.New("sign is nil")
|
||
|
|
} else {
|
||
|
|
sign = paramsMap["sign"].(string)
|
||
|
|
}
|
||
|
|
return sign == mySign, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) CheckSign(str string) bool {
|
||
|
|
log.Debug("callback:%v", s.Base.CallbackReq)
|
||
|
|
data, _ := json.Marshal(s.Base.CallbackReq)
|
||
|
|
pass, err := s.checkSign(string(data))
|
||
|
|
if err != nil {
|
||
|
|
log.Error("check sign err, %s", err.Error())
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
if s.Base.Opt == base.OPTPayCB {
|
||
|
|
req := s.Base.CallbackReq.(*PayCallbackReq)
|
||
|
|
s.Base.CallbackResp.OrderID = req.MerchantOrderNo
|
||
|
|
s.Base.CallbackResp.APIOrderID = req.OrderNo
|
||
|
|
s.Base.CallbackResp.Success = req.Success == "1"
|
||
|
|
if req.Success != "1" {
|
||
|
|
s.Base.CallbackResp.FailMessage = fmt.Sprintf("返回结果不为1")
|
||
|
|
}
|
||
|
|
return pass
|
||
|
|
} else if s.Base.Opt == base.OPTWithdrawCB {
|
||
|
|
req := s.Base.CallbackReq.(*WithdrawCallbackReq)
|
||
|
|
s.Base.CallbackResp.OrderID = req.MerchantOrderNo
|
||
|
|
s.Base.CallbackResp.APIOrderID = req.OrderNo
|
||
|
|
s.Base.CallbackResp.Success = req.Success == "1"
|
||
|
|
if req.Success != "1" {
|
||
|
|
s.Base.CallbackResp.FailMessage = fmt.Sprintf("返回结果不为1")
|
||
|
|
}
|
||
|
|
return pass
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) PackQueryWithdrawReq() interface{} {
|
||
|
|
r := s.Base.QueryWithdrawReq
|
||
|
|
send := &QueryWithdrawReq{
|
||
|
|
MerchantNo: merchantId,
|
||
|
|
MerchantOrderNo: r.OrderID,
|
||
|
|
SignType: "MD5",
|
||
|
|
Sign: "",
|
||
|
|
}
|
||
|
|
signValue, err := s.GetSign(send)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("get sign err, %s", err.Error())
|
||
|
|
}
|
||
|
|
send.Sign = signValue
|
||
|
|
|
||
|
|
return send
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Sub) PackQueryPayReq() interface{} {
|
||
|
|
r := s.Base.QueryPayReq
|
||
|
|
send := &QueryPayReq{
|
||
|
|
MerchantNo: merchantId,
|
||
|
|
MerchantOrderNo: r.OrderID,
|
||
|
|
SignType: "MD5",
|
||
|
|
Sign: "",
|
||
|
|
}
|
||
|
|
signValue, err := s.GetSign(send)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("get sign err, %s", err.Error())
|
||
|
|
}
|
||
|
|
send.Sign = signValue
|
||
|
|
|
||
|
|
return send
|
||
|
|
}
|