182 lines
5.5 KiB
Go
182 lines
5.5 KiB
Go
package payCenter
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"videoweb/pub/common/httputil"
|
|
"videoweb/pub/common/log"
|
|
"videoweb/pub/common/srvdef"
|
|
)
|
|
|
|
// Recharge 使用新支付中心的元字符串金额和商户 MD5 签名协议。
|
|
type Recharge struct {
|
|
Ctx context.Context `json:"-"`
|
|
Time string `json:"time"`
|
|
Sign string `json:"sign"`
|
|
MercID string `json:"mercId"`
|
|
Type string `json:"type"`
|
|
Money string `json:"money"`
|
|
TradeNo string `json:"tradeNo"`
|
|
NotifyUrl string `json:"notifyUrl"`
|
|
CancelNotifyUrl string `json:"cancelNotifyUrl,omitempty"`
|
|
Info PayInfo `json:"info"`
|
|
SignType string `json:"signType"`
|
|
Mode string `json:"mode"`
|
|
Payload string `json:"payload"`
|
|
}
|
|
|
|
type PayInfo struct {
|
|
App string `json:"app"`
|
|
PlayerId string `json:"playerId"`
|
|
PlayerIp string `json:"playerIp"`
|
|
DeviceType string `json:"deviceType"`
|
|
DeviceId string `json:"deviceId"`
|
|
Name string `json:"name"`
|
|
Tel string `json:"tel"`
|
|
AlipayAct string `json:"alipayAct"`
|
|
}
|
|
|
|
type PayResp struct {
|
|
Code srvdef.CodeType `json:"code"`
|
|
OID string `json:"oid"`
|
|
PayUrl string `json:"payUrl"`
|
|
Mode string `json:"mode"`
|
|
Rebate string `json:"rebate"`
|
|
Sign string `json:"sign"`
|
|
}
|
|
|
|
type RechargeResp struct {
|
|
Code int `json:"code"`
|
|
Info string `json:"info"`
|
|
Err string `json:"err"`
|
|
Msg PayResp `json:"msg"`
|
|
Tip string `json:"tip"`
|
|
}
|
|
|
|
type RechargeCallbackResp struct {
|
|
Code int `json:"code" binding:"required"`
|
|
MercID string `json:"mercId" binding:"required"`
|
|
OID string `json:"oid" binding:"required"`
|
|
PayMoney string `json:"payMoney" binding:"required"`
|
|
TradeNo string `json:"tradeNo" binding:"required"`
|
|
Sign string `json:"sign" binding:"required"`
|
|
}
|
|
|
|
type RefundCallbackResp struct {
|
|
Code int `json:"code"`
|
|
MercID string `json:"mercId"`
|
|
OID string `json:"oid"`
|
|
TradeNo string `json:"tradeNo"`
|
|
Sign string `json:"sign"`
|
|
}
|
|
|
|
type rechargePostFunc func(context.Context, *Recharge, *RechargeResp) (int, error)
|
|
|
|
func (in *Recharge) ToPayNew() (PayResp, error) {
|
|
return in.toPayNew(func(ctx context.Context, request *Recharge, response *RechargeResp) (int, error) {
|
|
return httputil.NewCtx(ctx).POSTJsonWithJResp(response, request.GetURL(), nil, request)
|
|
})
|
|
}
|
|
|
|
func (in *Recharge) toPayNew(post rechargePostFunc) (result PayResp, err error) {
|
|
defer func() {
|
|
if recovered := recover(); recovered != nil {
|
|
result = PayResp{}
|
|
err = fmt.Errorf("pay center request panic: %v", recovered)
|
|
if in != nil {
|
|
log.Error("【新支付中心 /api/shark/topay】请求异常", log.Any("tradeNo", in.TradeNo), log.E(err))
|
|
}
|
|
}
|
|
if in != nil {
|
|
if err != nil {
|
|
log.Error("【新支付中心 /api/shark/topay】下单失败", log.Any("tradeNo", in.TradeNo), log.E(err))
|
|
} else {
|
|
log.Info("【新支付中心 /api/shark/topay】下单成功", log.Any("tradeNo", in.TradeNo), log.Any("oid", result.OID))
|
|
}
|
|
}
|
|
}()
|
|
if in == nil {
|
|
return result, errors.New("pay center request: nil recharge")
|
|
}
|
|
if post == nil {
|
|
return result, errors.New("pay center request: nil poster")
|
|
}
|
|
if err := validateConfig(true); err != nil {
|
|
return result, err
|
|
}
|
|
amount, err := ParseYuanToFen(in.Money)
|
|
if err != nil || amount <= 0 || in.TradeNo == "" || in.Type == "" {
|
|
return result, errors.New("新支付中心下单参数错误:订单号、支付方式和正数金额不能为空")
|
|
}
|
|
in.fill()
|
|
|
|
var response RechargeResp
|
|
code, requestErr := post(in.Ctx, in, &response)
|
|
if requestErr != nil {
|
|
return result, fmt.Errorf("post pay center order: %w", requestErr)
|
|
}
|
|
if code != http.StatusOK {
|
|
return result, fmt.Errorf("pay center returned HTTP status %d", code)
|
|
}
|
|
if response.Code != http.StatusOK {
|
|
return result, fmt.Errorf("pay center returned provider code %d", response.Code)
|
|
}
|
|
if response.Err != "" {
|
|
return result, fmt.Errorf("pay center rejected order: %s", response.Err)
|
|
}
|
|
// 外层成功但没有订单号/支付链接不能落为处理中订单。
|
|
if response.Msg.OID == "" || response.Msg.PayUrl == "" {
|
|
return result, errors.New("新支付中心下单结果缺少订单号或支付链接")
|
|
}
|
|
return response.Msg, nil
|
|
}
|
|
|
|
func (in *Recharge) fill() {
|
|
in.MercID = in.GetMercID()
|
|
in.Time = Generate13DigitString()
|
|
in.Info.App = payCenterConf.AppName
|
|
in.NotifyUrl = in.GetNotifyURL()
|
|
in.SignType = "1"
|
|
in.Sign = in.sign()
|
|
}
|
|
|
|
func (in *Recharge) GetNotifyURL() string {
|
|
return payCenterConf.CallbackUrl + "/api/web/third/newpaycenter/recharge/callback"
|
|
}
|
|
|
|
func (in *Recharge) GetCancelNotifyURL() string {
|
|
return payCenterConf.CallbackUrl + "/api/web/third/newpaycenter/refund/callback"
|
|
}
|
|
|
|
func (in *Recharge) sign() string {
|
|
// 字段顺序必须与 girl 及支付中心约定一致,金额使用原始元字符串。
|
|
var body bytes.Buffer
|
|
body.WriteString(in.MercID)
|
|
body.WriteString(in.Money)
|
|
body.WriteString(in.NotifyUrl)
|
|
body.WriteString(in.TradeNo)
|
|
body.WriteString(in.Type)
|
|
body.WriteString(in.GetAppSecret())
|
|
return md5Sign(body.String())
|
|
}
|
|
|
|
func (in *Recharge) GetURL() string {
|
|
return payCenterConf.ApiUrl + "/api/shark/topay"
|
|
}
|
|
|
|
func (in *Recharge) Success() string {
|
|
return "success"
|
|
}
|
|
|
|
func (in *Recharge) GetAppSecret() string {
|
|
return payCenterConf.MercSecret
|
|
}
|
|
|
|
func (in *Recharge) GetMercID() string {
|
|
return payCenterConf.MercID
|
|
}
|