Compare commits
15 Commits
67265ef3fc
...
cfec0f5fca
Author | SHA1 | Date |
---|---|---|
|
cfec0f5fca | |
|
964a0808b9 | |
|
cacfbccbcf | |
|
24c0c6d36a | |
|
c2fd9e68f9 | |
|
ebcb3a9d7f | |
|
81dfd00cf9 | |
|
5c32d74165 | |
|
7588991d54 | |
|
de1f1d01fc | |
|
a03d0947a5 | |
|
1d3288acca | |
|
96aa3b16da | |
|
fd57130499 | |
|
99aa763357 |
Dockerfile
app
constants
data
http
controllers/front
entities/front
middlewares
requestmapping
routes
services
third/paymentService
utils
front/templates
go.modgo.sum
|
@ -36,6 +36,7 @@ WORKDIR /app
|
|||
COPY /server .
|
||||
#COPY --from=builder /app/server .
|
||||
COPY .env .
|
||||
COPY ./front ./front
|
||||
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
|
|
@ -6,6 +6,8 @@ const (
|
|||
ADMIN_V1 = "/pay/admin/api/v1"
|
||||
FRONT_V1 = "/pay/front/api/v1"
|
||||
|
||||
WXCodeRedirectAddress = FRONT_V1 + "/wx/payurl" // 微信支付,授权code后 重定向地址
|
||||
|
||||
// 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
PAY_CHANNEL_UNKNOWN = 0
|
||||
PAY_CHANNEL_WECHAT_JSAPI = 1
|
||||
|
|
|
@ -52,7 +52,10 @@ const (
|
|||
AppAesEncryptFail = 1234
|
||||
AppDeEncryptFail = 1250
|
||||
// 加密方式不存在
|
||||
EncryptTypeNotFound = 1241
|
||||
EncryptTypeNotFound = 1241
|
||||
PayChannelConfigNotFound = 1242
|
||||
// 加密参数异常
|
||||
PayEncryptParamFail = 1243
|
||||
|
||||
//渠道
|
||||
PayChannelNotFound = 1300
|
||||
|
@ -74,6 +77,7 @@ const (
|
|||
OrderNotSupportRefundPart = 1413
|
||||
OrderRefundAmountError = 1414
|
||||
OrderPayChannelChange = 1415
|
||||
OrderPayRequestLogNotExist = 1416
|
||||
// 关闭订单
|
||||
CloseOrderPayed = 1420
|
||||
|
||||
|
@ -93,6 +97,10 @@ const (
|
|||
|
||||
// 退款
|
||||
RefundOutTradeNoSame = 1801
|
||||
|
||||
// 微信授权
|
||||
WechatAuthFail = 1901
|
||||
WechatAuthSignFail = 1902
|
||||
)
|
||||
|
||||
var MsgEN = map[int]string{
|
||||
|
@ -138,7 +146,9 @@ var MsgZH = map[int]string{
|
|||
|
||||
AppAesEncryptFail: "aes 加密失败",
|
||||
|
||||
EncryptTypeNotFound: "加密方式不存在",
|
||||
EncryptTypeNotFound: "加密方式不存在",
|
||||
PayChannelConfigNotFound: "secret支付方式配置不存在",
|
||||
PayEncryptParamFail: "加密参数错误,解析失败",
|
||||
|
||||
AppDeEncryptFail: "未知原因导致解密失败,请检查加密数据是和app加密配置",
|
||||
|
||||
|
@ -150,15 +160,16 @@ var MsgZH = map[int]string{
|
|||
RequestLogNotFound: "未找到日志信息",
|
||||
RequestResponseValid: "上游返回格式无效",
|
||||
|
||||
OrdersNotFound: "未找到订单",
|
||||
OrdersExist: "订单已存在",
|
||||
OrderTypeNotFount: "未知的支付方式",
|
||||
OrderIsDelete: "订单已删除",
|
||||
OrderStatusErr: "订单状态错误",
|
||||
OrderClosed: "订单已关闭,无法继续支付",
|
||||
OrderFailed: "订单支付失败,请重新发起",
|
||||
OrderPayed: "订单已支付成功,请勿重复支付",
|
||||
OrderPayChannelChange: "支付方式不一致,切换支付方式请关闭原订单生成新订单",
|
||||
OrdersNotFound: "未找到订单",
|
||||
OrdersExist: "订单已存在",
|
||||
OrderTypeNotFount: "未知的支付方式",
|
||||
OrderIsDelete: "订单已删除",
|
||||
OrderStatusErr: "订单状态错误",
|
||||
OrderClosed: "订单已关闭,无法继续支付",
|
||||
OrderFailed: "订单支付失败,请重新发起",
|
||||
OrderPayed: "订单已支付成功,请勿重复支付",
|
||||
OrderPayChannelChange: "支付方式不一致,切换支付方式请关闭原订单生成新订单",
|
||||
OrderPayRequestLogNotExist: "订单下单数据不存在",
|
||||
|
||||
NotifySendFail: "回调发送失败",
|
||||
RefundOrderNotFound: "退款订单未找到",
|
||||
|
@ -173,6 +184,9 @@ var MsgZH = map[int]string{
|
|||
CloseOrderPayed: "订单已支付成功,无法关闭",
|
||||
|
||||
ThirdRefundFail: "第三方退款失败",
|
||||
|
||||
WechatAuthFail: "微信授权失败",
|
||||
WechatAuthSignFail: "微信签名失败",
|
||||
}
|
||||
var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH}
|
||||
|
||||
|
|
|
@ -49,3 +49,8 @@ func (m *OrderRequestLogRepo) OrderRequestLogBackendList(conn builder.Cond, page
|
|||
repo.Join("left", "orders", "orders.app_id = order_request_log.app_id and orders.out_trade_no = order_request_log.out_trade_no")
|
||||
return repo.Desc("order_request_log.create_time").FindAndCount(orderLogList)
|
||||
}
|
||||
|
||||
// 查询订单日志
|
||||
func (m *OrderRequestLogRepo) OrderRequestLogGet(orderLog *orderrequestlogmodel.OrderRequestLog, conn builder.Cond) (bool, error) {
|
||||
return m.repo.Where(conn).Get(orderLog)
|
||||
}
|
||||
|
|
|
@ -3,9 +3,13 @@ package front
|
|||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"PaymentCenter/app/utils"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -39,7 +43,7 @@ func WxCallback(c *gin.Context) {
|
|||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
if payChannelModel.ChannelType != common.PAY_CHANNEL_WECHAT_H5 {
|
||||
if !(payChannelModel.ChannelType == common.PAY_CHANNEL_WECHAT_H5 || payChannelModel.ChannelType == common.PAY_CHANNEL_WECHAT_JSAPI) {
|
||||
logger.Error(c, "WxCallback-回调数据解析支付配置错误,查询的数据不是当前渠道")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
|
@ -189,3 +193,70 @@ func BrokerWechatUrl(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 拼接微信授权链接
|
||||
func GetWxAuthUrl(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*front.GetWxAuthUrlRequest)
|
||||
|
||||
url, code := thirdpay.GetWxAuthUrl(*req)
|
||||
controllers.HandCodeRes(c, url, code)
|
||||
}
|
||||
|
||||
// 通过code获取授权,openid
|
||||
func GetWxAuth(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*front.GetWxAuthRequest)
|
||||
rsp, code := thirdpay.GetWxAuth(*req)
|
||||
controllers.HandCodeRes(c, rsp, code)
|
||||
}
|
||||
|
||||
// 接收code
|
||||
func GetWxCode(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*front.GetWxAuthRequest)
|
||||
//rsp, code := thirdpay.GetWxAuth(*req)
|
||||
controllers.HandCodeRes(c, req, 200)
|
||||
}
|
||||
|
||||
// 微信JSAPI 支付接口
|
||||
/*
|
||||
预支付接口实现如下功能:
|
||||
1.订单请求参数
|
||||
2.订单信息存数据
|
||||
3.返回用户授权地址
|
||||
wxjsapi接口实现如下功能:
|
||||
4.用户授权后获取code,statu传的是订单号
|
||||
5.通过code获取openid
|
||||
6.通过openid请求微信下单,返回支付参数
|
||||
7.支付参数聚合,签名,返回支付参数给前端
|
||||
*/
|
||||
func WxJsApiPay(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*front.WxJsApiPayRequest)
|
||||
req.ClientIp = c.ClientIP()
|
||||
|
||||
rsp, code := thirdpay.WxJsApiPay(*req)
|
||||
if code == errorcode.Success {
|
||||
c.HTML(http.StatusOK, "success.html", gin.H{
|
||||
"appId": rsp.AppId,
|
||||
"timeStamp": rsp.TimeStamp,
|
||||
"nonceStr": rsp.NonceStr,
|
||||
"package": rsp.Package,
|
||||
"signType": rsp.SignType,
|
||||
"paySign": rsp.PaySign,
|
||||
"returnUrl": rsp.ReturnUrl,
|
||||
})
|
||||
} else {
|
||||
utils.Log(c, "", "WxJsApiPay,支付失败code=", code, "msg=", rsp.ThirdMsg)
|
||||
errmsg := rsp.ThirdMsg
|
||||
data := make(map[string]interface{})
|
||||
_ = json.Unmarshal([]byte(rsp.ThirdMsg), &data)
|
||||
if message, ok := data["message"]; ok {
|
||||
errmsg = message.(string)
|
||||
}
|
||||
if errmsg == "" {
|
||||
errmsg = errorcode.GetMsg(code, "")
|
||||
}
|
||||
|
||||
c.HTML(http.StatusOK, "fail.html", gin.H{
|
||||
"errmsg": errmsg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ type PayCommonReqBody struct {
|
|||
ExtJson string `json:"ext_json" label:"扩展参数"`
|
||||
Desc string `json:"desc" validate:"max=100" label:"商品描述"`
|
||||
ReturnUrl string `json:"return_url" validate:"max=1024" label:"支付成功后跳转的地址"`
|
||||
OpenId string `json:"open_id" label:"用户openid"`
|
||||
}
|
||||
|
||||
type PayReqs struct {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package front
|
||||
|
||||
type GetWxAuthUrlRequest struct {
|
||||
PayChannelId string `json:"pay_channel_id" form:"pay_channel_id" validate:"required"`
|
||||
}
|
||||
|
||||
type GetWxAuthRequest struct {
|
||||
Code string `json:"code" form:"code" `
|
||||
PayChannelId string `json:"state" form:"state"`
|
||||
}
|
||||
|
||||
// 获取微信用户信息
|
||||
type GetWxAuthResponse struct {
|
||||
AccessToken string `json:"access_token"` //网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
|
||||
ExpiresIn int `json:"expires_in"` //access_token接口调用凭证超时时间,单位(秒)
|
||||
RefreshToken string `json:"refresh_token"` //用户刷新access_token
|
||||
Openid string `json:"openid"` //用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
|
||||
Scope string `json:"scope"` //用户授权的作用域,使用逗号(,)分隔
|
||||
IsSnapshotuser int `json:"is_snapshotuser"`
|
||||
Unionid string `json:"unionid"` // 用户统一标识(针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的),只有当scope为"snsapi_userinfo"时返回
|
||||
}
|
||||
|
||||
// jsapi支付
|
||||
type WxJsApiPayRequest struct {
|
||||
Code string `json:"code" form:"code" `
|
||||
State string `json:"state" form:"state"` // 支付中心的订单id
|
||||
ClientIp string `json:"client_ip" form:"client_ip"`
|
||||
}
|
||||
|
||||
//// jsapi支付返回
|
||||
//type WxJsApiPayResponse struct {
|
||||
// Url string
|
||||
// ThirdMsg string
|
||||
//}
|
||||
|
||||
// jsapi支付返回
|
||||
type WxJsApiPayResponse struct {
|
||||
AppId string `json:"appId"`
|
||||
TimeStamp string `json:"timeStamp"`
|
||||
NonceStr string `json:"nonceStr"`
|
||||
Package string `json:"package"`
|
||||
SignType string `json:"signType"`
|
||||
PaySign string `json:"paySign"`
|
||||
ThirdMsg string `json:"third_msg"`
|
||||
ReturnUrl string
|
||||
}
|
|
@ -107,6 +107,7 @@ func ValidateRequest() gin.HandlerFunc {
|
|||
return func(c *gin.Context) {
|
||||
var path = c.FullPath()
|
||||
var handler func() interface{}
|
||||
var logId int64
|
||||
|
||||
if strings.Index(path, "admin") >= 0 {
|
||||
handler = requestmapping.BackendRequestMap[path]
|
||||
|
@ -126,6 +127,17 @@ func ValidateRequest() gin.HandlerFunc {
|
|||
c.Abort()
|
||||
}
|
||||
c.Set("request", v)
|
||||
//表单验证
|
||||
logHandler := requestmapping.FrontRequestMap[path]
|
||||
if logHandler != nil {
|
||||
_, isSaveLog := logHandler()
|
||||
if isSaveLog {
|
||||
logContent, _ := json.Marshal(v)
|
||||
//记录请求日志
|
||||
logId, _ = services.AddRequestLog(logContent, c.ClientIP(), path)
|
||||
}
|
||||
c.Set("log", logId)
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
|
|
@ -33,10 +33,10 @@ func ServerRecovery() gin.HandlerFunc {
|
|||
}
|
||||
|
||||
c.JSON(500, gin.H{
|
||||
"code": 500,
|
||||
"msg": "system error",
|
||||
"request_uri": c.Request.URL.Path,
|
||||
"data": make(map[string]string),
|
||||
"code": 500,
|
||||
"msg": "system error",
|
||||
//"request_uri": c.Request.URL.Path,
|
||||
//"data": make(map[string]string),
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -2,6 +2,7 @@ package requestmapping
|
|||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
)
|
||||
|
||||
|
@ -10,12 +11,19 @@ var FrontRequestMap = map[string]func() (validForm interface{}, isSaveLog bool){
|
|||
common.FRONT_V1 + "/pay/refund": func() (interface{}, bool) { return new(front.RefundReqs), true },
|
||||
common.FRONT_V1 + "/pay/query": func() (interface{}, bool) { return new(front.QueryReqs), false },
|
||||
common.FRONT_V1 + "/pay/close": func() (interface{}, bool) { return new(front.CloseReqs), true },
|
||||
common.FRONT_V1 + "/wx/payurl": func() (interface{}, bool) { return new(front.WxJsApiPayRequest), true },
|
||||
}
|
||||
|
||||
var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{
|
||||
|
||||
common.FRONT_V1 + "/pay/url": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/refund": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/query": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/close": func() interface{} { return new(front.CloseReqs) },
|
||||
common.FRONT_V1 + "/pay/url": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/refund": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/query": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/close": func() interface{} { return new(front.CloseReqs) },
|
||||
common.FRONT_V1 + "/wx/index": func() interface{} { return new(entities.PageRequest) },
|
||||
common.FRONT_V1 + "/wx/getWxAuthUrl": func() interface{} { return new(front.GetWxAuthUrlRequest) },
|
||||
common.FRONT_V1 + "/wx/getWxAuth": func() interface{} { return new(front.GetWxAuthRequest) },
|
||||
common.FRONT_V1 + "/wx/getCode": func() interface{} { return new(front.GetWxAuthRequest) },
|
||||
|
||||
common.WXCodeRedirectAddress: func() interface{} { return new(front.WxJsApiPayRequest) },
|
||||
}
|
||||
|
|
|
@ -67,6 +67,18 @@ func RegisterRoute(router *gin.Engine) {
|
|||
v1.GET("/brokerWechatUrl", front.BrokerWechatUrl)
|
||||
}
|
||||
|
||||
// 微信获取授权相关
|
||||
router.LoadHTMLGlob("./front/templates/*")
|
||||
wx := v1.Group("/wx", middlewares.ValidateRequest())
|
||||
{
|
||||
wx.POST("/getWxAuthUrl", front.GetWxAuthUrl) // 获取授权codeUrl
|
||||
wx.GET("/getWxAuth", front.GetWxAuth) // 获取openId
|
||||
wx.GET("/getCode", front.GetWxCode) // 接收微信code
|
||||
}
|
||||
|
||||
// 微信jsapi支付链接
|
||||
router.GET(common.WXCodeRedirectAddress, middlewares.ValidateRequest(), front.WxJsApiPay)
|
||||
|
||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func (a *AppCheck) Crypt() (cryptFunc func(app *appmodel.App) apicrypt.ApiCrypt)
|
|||
func (a *AppCheck) ReCheckAfterDecrypt(data []byte, requestData *front.RequestBody) bool {
|
||||
var requestCommonData front.ApiCommonBody
|
||||
if err := sonic.Unmarshal(data, &requestCommonData); err != nil {
|
||||
a.Code = errorcode.ParamError
|
||||
a.Code = errorcode.PayEncryptParamFail
|
||||
return false
|
||||
}
|
||||
if requestCommonData.AppId != requestData.AppId || requestCommonData.Timestamp != requestData.Timestamp {
|
||||
|
|
|
@ -149,3 +149,17 @@ func PayOrderCheckRepeat(order *ordersmodel.Orders, conn builder.Cond) (exist bo
|
|||
}
|
||||
return true, code
|
||||
}
|
||||
|
||||
// 商户请求日志
|
||||
func OrderRequestLogs(req *orderrequestlogmodel.OrderRequestLog) (bool, error) {
|
||||
requestRepo := data.NewOrderRequestLogRepo(paychannelmodel.GetInstance().GetDb())
|
||||
conn := builder.NewCond()
|
||||
if req.OutTradeNo != "" {
|
||||
conn = conn.And(builder.Eq{"out_trade_no": req.OutTradeNo})
|
||||
}
|
||||
if req.AppId > 0 {
|
||||
conn = conn.And(builder.Eq{"app_id": req.AppId})
|
||||
}
|
||||
|
||||
return requestRepo.OrderRequestLogGet(req, conn)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ import (
|
|||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"xorm.io/builder"
|
||||
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
|
@ -25,6 +28,7 @@ type PayParam struct {
|
|||
Desc string
|
||||
ClientIp string
|
||||
ReturnUrl string
|
||||
OpenId string
|
||||
}
|
||||
|
||||
type Pay struct {
|
||||
|
@ -50,6 +54,7 @@ func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
|
|||
Desc: paycheck.Reqs.Desc,
|
||||
ClientIp: paycheck.AppCheck.Ip,
|
||||
ReturnUrl: paycheck.Reqs.ReturnUrl,
|
||||
OpenId: paycheck.Reqs.OpenId,
|
||||
},
|
||||
RelationOrder: paycheck.OldOrder,
|
||||
PayCode: errorcode.Success,
|
||||
|
@ -97,6 +102,7 @@ func (w *Pay) PayUrl() (url string) {
|
|||
var (
|
||||
payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error
|
||||
ok bool
|
||||
res paymentService.PayOrderResponse
|
||||
)
|
||||
thirdPay := &paymentService.PayOrderRequest{
|
||||
PayChannelId: w.PayParam.Channel.Id,
|
||||
|
@ -106,7 +112,9 @@ func (w *Pay) PayUrl() (url string) {
|
|||
Amount: w.Order.Amount,
|
||||
PayerClientIp: w.PayParam.ClientIp,
|
||||
ReturnUrl: w.PayParam.ReturnUrl,
|
||||
OpenId: w.PayParam.OpenId,
|
||||
}
|
||||
// 判断是否是支持的支付渠道,找到对应的配置
|
||||
if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok {
|
||||
w.PayCode = errorcode.PayChannelNotBuild
|
||||
return
|
||||
|
@ -116,7 +124,26 @@ func (w *Pay) PayUrl() (url string) {
|
|||
w.PayCode = errorcode.PayChannelExtJsonError
|
||||
return
|
||||
}
|
||||
res := paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
switch w.PayParam.Channel.ChannelType {
|
||||
// 微信公众号支付,返回的是用户授权链接
|
||||
case common.PAY_CHANNEL_WECHAT_JSAPI:
|
||||
// 获取授权链接
|
||||
res.Result, res.Code = w.GetWxAuthUrl(w.PayParam.Channel.AppId, w.Order.Id)
|
||||
case common.PAY_CHANNEL_ALIPAY_WEB:
|
||||
// 支付宝h5
|
||||
res = paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
case common.PAY_CHANNEL_WECHAT_H5:
|
||||
// 微信h5支付
|
||||
res = paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
if res.Result != "" {
|
||||
res.Result = config.GetConf().PayService.Host + "/pay/front/api/v1/brokerWechatUrl" + "?url=" + res.Result
|
||||
}
|
||||
default:
|
||||
w.PayCode = errorcode.PayChannelNotBuild
|
||||
return
|
||||
}
|
||||
|
||||
//res := paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
|
||||
if res.Code == payCommon.PAY_SUCCESS_CODE {
|
||||
w.Order.Status = common.ORDER_STATUS_PAYING
|
||||
|
@ -204,3 +231,20 @@ func (w *Pay) CloseOrder() {
|
|||
w.ThirdMsg = res.ErrorMsg
|
||||
w.PayCode = res.Code
|
||||
}
|
||||
|
||||
// appid:微信的公众号appid
|
||||
func (w *Pay) GetWxAuthUrl(appid string, orderId int64) (targetUrl string, code int) {
|
||||
var (
|
||||
// 重定向地址
|
||||
redirectUri = config.GetConf().PayService.Host + common.WXCodeRedirectAddress
|
||||
)
|
||||
baseUrl := "https://open.weixin.qq.com/connect/oauth2/authorize"
|
||||
redirectUri = url.QueryEscape(redirectUri)
|
||||
responseType := "code"
|
||||
scope := "snsapi_base"
|
||||
order := strconv.Itoa(int(orderId))
|
||||
|
||||
targetUrl = baseUrl + "?appid=" + appid + "&redirect_uri=" + redirectUri + "&response_type=" + responseType + "&scope=" + scope + "&state=" + order + "#wechat_redirect"
|
||||
code = errorcode.Success
|
||||
return
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@ import (
|
|||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
// 支持的支付方式
|
||||
var PayWayList = map[int]func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error{
|
||||
common.PAY_CHANNEL_WECHAT_H5: WechatH5,
|
||||
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWeb,
|
||||
common.PAY_CHANNEL_WECHAT_H5: WechatH5,
|
||||
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWeb,
|
||||
common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPI,
|
||||
}
|
||||
|
||||
func WechatH5(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
|
||||
|
@ -29,3 +31,11 @@ func AlipayWeb(commonPayInfo *paymentService.PayOrderRequest, channel *paychanne
|
|||
commonPayInfo.Ali.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
func WechatJSAPI(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonPayInfo.Wx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonPayInfo.Wx.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ import (
|
|||
)
|
||||
|
||||
var RefundWayList = map[int]func(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error{
|
||||
common.PAY_CHANNEL_WECHAT_H5: WechatH5Refund,
|
||||
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWebRefund,
|
||||
common.PAY_CHANNEL_WECHAT_H5: WechatH5Refund,
|
||||
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWebRefund,
|
||||
common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPIRefund,
|
||||
}
|
||||
|
||||
func WechatH5Refund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
|
||||
|
@ -31,3 +32,13 @@ func AlipayWebRefund(commonRefundInfo *paymentService.OrderRefundRequest, channe
|
|||
commonRefundInfo.Ali.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
||||
func WechatJSAPIRefund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
|
||||
commonRefundInfo.PayChannel = common.PAY_CHANNLE_TYPE_WECHAT
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonRefundInfo.Wx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonRefundInfo.Wx.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,359 @@
|
|||
package thirdpay
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/app/utils/httpclient"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// 获取授权链接
|
||||
func GetWxAuthUrl(param front.GetWxAuthUrlRequest) (targetUrl string, code int) {
|
||||
var (
|
||||
// 重定向地址
|
||||
redirectUri = config.GetConf().PayService.Host + common.WXCodeRedirectAddress
|
||||
)
|
||||
baseUrl := "https://open.weixin.qq.com/connect/oauth2/authorize"
|
||||
|
||||
// 获取支付渠道的配置
|
||||
id, err := strconv.Atoi(param.PayChannelId)
|
||||
if err != nil {
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
payChannel := paychannelmodel.PayChannel{Id: int64(id)}
|
||||
code = services.PayChannelGet(&payChannel)
|
||||
if code != 200 {
|
||||
return
|
||||
}
|
||||
|
||||
appid := payChannel.AppId
|
||||
redirectUri = url.QueryEscape(redirectUri)
|
||||
responseType := "code"
|
||||
scope := "snsapi_base"
|
||||
|
||||
targetUrl = baseUrl + "?appid=" + appid + "&redirect_uri=" + redirectUri + "&response_type=" + responseType + "&scope=" + scope + "&state=" + param.PayChannelId + "#wechat_redirect"
|
||||
return
|
||||
}
|
||||
|
||||
// // 通过code换取网页授权access_token,openid
|
||||
func GetWxAuth(param front.GetWxAuthRequest) (rsp front.GetWxAuthResponse, code int) {
|
||||
|
||||
// 获取支付渠道的配置
|
||||
id, err := strconv.Atoi(param.PayChannelId)
|
||||
if err != nil {
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
payChannel := paychannelmodel.PayChannel{Id: int64(id)}
|
||||
code = services.PayChannelGet(&payChannel)
|
||||
if code != 200 {
|
||||
return
|
||||
}
|
||||
|
||||
//// 配置支付的解析
|
||||
wxConfig := make(map[string]interface{})
|
||||
err = json.Unmarshal([]byte(payChannel.ExtJson), &wxConfig)
|
||||
if err != nil {
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
sk := wxConfig["secret"].(string)
|
||||
if sk == "" {
|
||||
code = errorcode.PayChannelConfigNotFound
|
||||
return
|
||||
}
|
||||
|
||||
targetUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
|
||||
payChannel.AppId,
|
||||
sk,
|
||||
param.Code,
|
||||
)
|
||||
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
body := map[string]string{}
|
||||
response, err := httpclient.FastHttpGet(targetUrl, header, body, 0)
|
||||
if err != nil {
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
utils.Log(nil, "获取微信授权信息", string(response), targetUrl)
|
||||
|
||||
// 解析返回数据
|
||||
err = json.Unmarshal(response, &rsp)
|
||||
if err != nil {
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
if rsp.Openid == "" {
|
||||
code = errorcode.WechatAuthFail
|
||||
return
|
||||
}
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 微信JSAPI 支付接口
|
||||
/*
|
||||
1.获取订单请求参数
|
||||
2.订单信息存数据
|
||||
3.返回用户授权地址
|
||||
4.用户授权后获取code
|
||||
5.通过code获取openid
|
||||
6.通过openid请求微信下单,返回支付参数
|
||||
7.支付参数聚合,签名,返回支付参数给前端
|
||||
*/
|
||||
type wxJsapiPay struct {
|
||||
code int
|
||||
msg string
|
||||
param front.WxJsApiPayRequest
|
||||
order *ordersmodel.Orders
|
||||
payChannel paychannelmodel.PayChannel
|
||||
wxConfig paymentService.WxPay
|
||||
orderPayRequest front.PayReqs
|
||||
|
||||
openId string // 用户openid
|
||||
}
|
||||
|
||||
func newWxJsapiPay(param front.WxJsApiPayRequest) *wxJsapiPay {
|
||||
return &wxJsapiPay{param: param}
|
||||
}
|
||||
|
||||
func (this *wxJsapiPay) getOrder() {
|
||||
order := new(ordersmodel.Orders)
|
||||
this.order, this.code = services.OrderFindOne(order, builder.Eq{"id": this.param.State})
|
||||
if this.code != errorcode.Success {
|
||||
return
|
||||
}
|
||||
switch this.order.Status {
|
||||
case common.ORDER_STATUS_PAYED:
|
||||
this.code = errorcode.OrderPayed
|
||||
case common.ORDER_STATUS_CLOSE:
|
||||
this.code = errorcode.OrderClosed
|
||||
}
|
||||
}
|
||||
func (this *wxJsapiPay) getPayChannel() {
|
||||
payChannel := paychannelmodel.PayChannel{Id: this.order.PayChannelId}
|
||||
this.code = services.PayChannelGet(&payChannel)
|
||||
this.payChannel = payChannel
|
||||
}
|
||||
|
||||
// 获取下单的请求参数
|
||||
func (this *wxJsapiPay) getOrderRequestLogs() {
|
||||
orderRequestLog := orderrequestlogmodel.OrderRequestLog{
|
||||
OutTradeNo: this.order.OutTradeNo,
|
||||
AppId: this.order.AppId,
|
||||
}
|
||||
has, err := services.OrderRequestLogs(&orderRequestLog)
|
||||
if err != nil {
|
||||
this.code = handErr(err)
|
||||
return
|
||||
}
|
||||
if !has {
|
||||
this.code = errorcode.OrderPayRequestLogNotExist
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(orderRequestLog.MerchantRequest), &this.orderPayRequest)
|
||||
if err != nil {
|
||||
this.code = handErr(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (this *wxJsapiPay) getOpenId() {
|
||||
var err error
|
||||
//// 配置支付的解析
|
||||
wxConfig := paymentService.WxPay{}
|
||||
err = json.Unmarshal([]byte(this.payChannel.ExtJson), &wxConfig)
|
||||
if err != nil {
|
||||
this.code = handErr(err)
|
||||
return
|
||||
}
|
||||
sk := wxConfig.Secret
|
||||
if sk == "" {
|
||||
this.code = errorcode.PayChannelConfigNotFound
|
||||
return
|
||||
}
|
||||
this.wxConfig = wxConfig
|
||||
|
||||
targetUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
|
||||
this.payChannel.AppId,
|
||||
sk,
|
||||
this.param.Code,
|
||||
)
|
||||
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
body := map[string]string{}
|
||||
response, err := httpclient.FastHttpGet(targetUrl, header, body, 0)
|
||||
if err != nil {
|
||||
this.code = handErr(err)
|
||||
return
|
||||
}
|
||||
utils.Log(nil, "获取微信授权信息", string(response), targetUrl)
|
||||
|
||||
// 解析返回数据
|
||||
var rsp front.GetWxAuthResponse
|
||||
err = json.Unmarshal(response, &rsp)
|
||||
if err != nil {
|
||||
this.code = handErr(err)
|
||||
return
|
||||
}
|
||||
if rsp.Openid == "" {
|
||||
this.code = errorcode.WechatAuthFail
|
||||
this.msg = string(response)
|
||||
return
|
||||
}
|
||||
this.openId = rsp.Openid
|
||||
this.code = handErr(err)
|
||||
}
|
||||
|
||||
func (this *wxJsapiPay) Sign(AppId, TimeStamp, NonceStr, Package string) (res string, err error) {
|
||||
//组装被加密的字符串
|
||||
|
||||
targetStr := AppId + "\n" + TimeStamp + "\n" + NonceStr + "\n" + Package + "\n"
|
||||
//加密
|
||||
sign, err := this.SHA256WithRsaBase64(targetStr)
|
||||
|
||||
return sign, err
|
||||
}
|
||||
|
||||
func (this *wxJsapiPay) SHA256WithRsaBase64(origData string) (sign string, err error) {
|
||||
//var keypath = "商户证书私钥地址"
|
||||
//key, err := ioutil.ReadFile(keypath)
|
||||
var key []byte
|
||||
if this.wxConfig.PrivateKey == "" {
|
||||
return "", errors.New("配置的私钥不存在")
|
||||
}
|
||||
key = []byte(this.wxConfig.PrivateKey)
|
||||
|
||||
blocks, _ := pem.Decode(key)
|
||||
if blocks == nil || blocks.Type != "PRIVATE KEY" {
|
||||
utils.Log(nil, "failed to decode PRIVATE KEY")
|
||||
return
|
||||
|
||||
}
|
||||
privateKey, err := x509.ParsePKCS8PrivateKey(blocks.Bytes)
|
||||
|
||||
h := sha256.New()
|
||||
h.Write([]byte(origData))
|
||||
digest := h.Sum(nil)
|
||||
s, _ := rsa.SignPKCS1v15(nil, privateKey.(*rsa.PrivateKey), crypto.SHA256, digest)
|
||||
sign = base64.StdEncoding.EncodeToString(s)
|
||||
|
||||
return sign, err
|
||||
}
|
||||
|
||||
func WxJsApiPay(param front.WxJsApiPayRequest) (response front.WxJsApiPayResponse, code int) {
|
||||
var ctx = context.Background()
|
||||
task := newWxJsapiPay(param)
|
||||
|
||||
// 1 获取订单
|
||||
task.getOrder()
|
||||
if task.code != errorcode.Success {
|
||||
return response, task.code
|
||||
}
|
||||
|
||||
// 获取支付渠道配置
|
||||
task.getPayChannel()
|
||||
if task.code != errorcode.Success {
|
||||
return response, task.code
|
||||
}
|
||||
// 获取下单的请求参数
|
||||
task.getOrderRequestLogs()
|
||||
if task.code != errorcode.Success {
|
||||
return response, task.code
|
||||
}
|
||||
// 2 通过code获取openid
|
||||
task.getOpenId()
|
||||
if task.code != errorcode.Success {
|
||||
response.ThirdMsg = task.msg
|
||||
return response, task.code
|
||||
}
|
||||
task.wxConfig.AppId = task.payChannel.AppId
|
||||
|
||||
order := task.order
|
||||
// 通过openid,订单数据,请求微信下单, 获取prepay_id
|
||||
orderRequest := paymentService.PayOrderRequest{
|
||||
PayChannelId: order.PayChannelId,
|
||||
OrderId: order.Id,
|
||||
ChannelType: task.payChannel.ChannelType,
|
||||
Description: order.Desc,
|
||||
Amount: order.Amount,
|
||||
PayerClientIp: param.ClientIp,
|
||||
ReturnUrl: task.orderPayRequest.ReturnUrl,
|
||||
Wx: task.wxConfig,
|
||||
Ali: paymentService.AliPay{},
|
||||
OpenId: task.openId,
|
||||
}
|
||||
res := paymentService.PaymentService(ctx, orderRequest)
|
||||
// 下单失败
|
||||
if res.Code != payCommon.PAY_SUCCESS_CODE {
|
||||
task.code = errorcode.PrePayFail
|
||||
response.ThirdMsg = res.ErrorMsg
|
||||
return response, task.code
|
||||
}
|
||||
// 更新订单状态
|
||||
order.Status = common.ORDER_STATUS_PAYING
|
||||
task.code = services.OrderUpdate(order, "status")
|
||||
if task.code != errorcode.Success {
|
||||
utils.Log(nil, "成功下单,更新订单状态失败", order)
|
||||
}
|
||||
|
||||
// 3 组装返回数据
|
||||
response = front.WxJsApiPayResponse{
|
||||
AppId: task.payChannel.AppId,
|
||||
TimeStamp: strconv.Itoa(int(time.Now().Unix())),
|
||||
NonceStr: strconv.Itoa(int(time.Now().Unix())),
|
||||
Package: "prepay_id=" + res.Result,
|
||||
SignType: "RSA",
|
||||
PaySign: "",
|
||||
ThirdMsg: "",
|
||||
}
|
||||
|
||||
// 4 签名
|
||||
signValue, err := task.Sign(response.AppId, response.TimeStamp, response.NonceStr, response.Package)
|
||||
if err != nil {
|
||||
utils.Log(nil, "签名失败", err)
|
||||
return response, errorcode.WechatAuthFail
|
||||
}
|
||||
response.PaySign = signValue
|
||||
response.ReturnUrl = task.orderPayRequest.ReturnUrl
|
||||
|
||||
return response, task.code
|
||||
}
|
||||
|
||||
func handErr(err error) int {
|
||||
if err != nil {
|
||||
utils.Log(nil, "sys err", err.Error())
|
||||
return errorcode.SystemError
|
||||
} else {
|
||||
return errorcode.Success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
package services
|
||||
|
||||
//import (
|
||||
// "PaymentCenter/app/constants/common"
|
||||
// "PaymentCenter/app/constants/errorcode"
|
||||
// "PaymentCenter/app/http/entities/front"
|
||||
// "PaymentCenter/app/models/ordersmodel"
|
||||
// "PaymentCenter/app/models/paychannelmodel"
|
||||
// "PaymentCenter/app/third/paymentService"
|
||||
// "PaymentCenter/app/third/paymentService/payCommon"
|
||||
// "PaymentCenter/app/utils"
|
||||
// "PaymentCenter/app/utils/httpclient"
|
||||
// "PaymentCenter/config"
|
||||
// "context"
|
||||
// "crypto"
|
||||
// "crypto/rsa"
|
||||
// "crypto/sha256"
|
||||
// "crypto/x509"
|
||||
// "encoding/base64"
|
||||
// "encoding/json"
|
||||
// "encoding/pem"
|
||||
// "errors"
|
||||
// "fmt"
|
||||
// "net/url"
|
||||
// "strconv"
|
||||
// "time"
|
||||
// "xorm.io/builder"
|
||||
//)
|
||||
//
|
||||
//// 获取授权链接
|
||||
//func GetWxAuthUrl(param front.GetWxAuthUrlRequest) (targetUrl string, code int) {
|
||||
// var (
|
||||
// // 重定向地址
|
||||
// redirectUri = config.GetConf().PayService.Host + common.FRONT_V1 + "/wx/getWxAuth"
|
||||
// )
|
||||
// baseUrl := "https://open.weixin.qq.com/connect/oauth2/authorize"
|
||||
//
|
||||
// // 获取支付渠道的配置
|
||||
// id, err := strconv.Atoi(param.PayChannelId)
|
||||
// if err != nil {
|
||||
// code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// payChannel := paychannelmodel.PayChannel{Id: int64(id)}
|
||||
// code = PayChannelGet(&payChannel)
|
||||
// if code != 200 {
|
||||
// return
|
||||
// }
|
||||
// //// 配置解析
|
||||
// //wxConfig := paymentService.WxPay{}
|
||||
// //err = json.Unmarshal([]byte(payChannel.ExtJson), &wxConfig)
|
||||
// //if err != nil {
|
||||
// // code = handErr(err)
|
||||
// // return
|
||||
// //}
|
||||
//
|
||||
// appid := payChannel.AppId
|
||||
// redirectUri = url.QueryEscape(redirectUri)
|
||||
// responseType := "code"
|
||||
// scope := "snsapi_base"
|
||||
//
|
||||
// targetUrl = baseUrl + "?appid=" + appid + "&redirect_uri=" + redirectUri + "&response_type=" + responseType + "&scope=" + scope + "&state=" + param.PayChannelId + "#wechat_redirect"
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// // 通过code换取网页授权access_token,openid
|
||||
//func GetWxAuth(param front.GetWxAuthRequest) (rsp front.GetWxAuthResponse, code int) {
|
||||
//
|
||||
// // 获取支付渠道的配置
|
||||
// id, err := strconv.Atoi(param.PayChannelId)
|
||||
// if err != nil {
|
||||
// code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// payChannel := paychannelmodel.PayChannel{Id: int64(id)}
|
||||
// code = PayChannelGet(&payChannel)
|
||||
// if code != 200 {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// //// 配置支付的解析
|
||||
// wxConfig := make(map[string]interface{})
|
||||
// err = json.Unmarshal([]byte(payChannel.ExtJson), &wxConfig)
|
||||
// if err != nil {
|
||||
// code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// sk := wxConfig["secret"].(string)
|
||||
// if sk == "" {
|
||||
// code = errorcode.PayChannelConfigNotFound
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// targetUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
|
||||
// payChannel.AppId,
|
||||
// sk,
|
||||
// param.Code,
|
||||
// )
|
||||
//
|
||||
// header := map[string]string{
|
||||
// "Content-Type": "application/json",
|
||||
// }
|
||||
// body := map[string]string{}
|
||||
// response, err := httpclient.FastHttpGet(targetUrl, header, body, 0)
|
||||
// if err != nil {
|
||||
// code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// utils.Log(nil, "获取微信授权信息", string(response), targetUrl)
|
||||
//
|
||||
// // 解析返回数据
|
||||
// err = json.Unmarshal(response, &rsp)
|
||||
// if err != nil {
|
||||
// code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// if rsp.Openid == "" {
|
||||
// code = errorcode.WechatAuthFail
|
||||
// return
|
||||
// }
|
||||
// code = handErr(err)
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 微信JSAPI 支付接口
|
||||
///*
|
||||
//1.获取订单请求参数
|
||||
//2.订单信息存数据
|
||||
//3.返回用户授权地址
|
||||
//4.用户授权后获取code
|
||||
//5.通过code获取openid
|
||||
//6.通过openid请求微信下单,返回支付参数
|
||||
//7.支付参数聚合,签名,返回支付参数给前端
|
||||
//*/
|
||||
//type wxJsapiPay struct {
|
||||
// code int
|
||||
// msg string
|
||||
// param front.WxJsApiPayRequest
|
||||
// order *ordersmodel.Orders
|
||||
// payChannel paychannelmodel.PayChannel
|
||||
// wxConfig map[string]interface{}
|
||||
//
|
||||
// openId string // 用户openid
|
||||
//}
|
||||
//
|
||||
//func newWxJsapiPay(param front.WxJsApiPayRequest) *wxJsapiPay {
|
||||
// return &wxJsapiPay{param: param}
|
||||
//}
|
||||
//
|
||||
//func (this *wxJsapiPay) getOrder() {
|
||||
// order := new(ordersmodel.Orders)
|
||||
// this.order, this.code = OrderFindOne(order, builder.Eq{"id": this.param.State})
|
||||
//}
|
||||
//func (this *wxJsapiPay) getPayChannel() {
|
||||
// payChannel := paychannelmodel.PayChannel{Id: this.order.PayChannelId}
|
||||
// this.code = PayChannelGet(&payChannel)
|
||||
// this.payChannel = payChannel
|
||||
//}
|
||||
//
|
||||
//func (this *wxJsapiPay) getOpenId() {
|
||||
// var err error
|
||||
// //// 配置支付的解析
|
||||
// wxConfig := make(map[string]interface{})
|
||||
// err = json.Unmarshal([]byte(this.payChannel.ExtJson), &wxConfig)
|
||||
// if err != nil {
|
||||
// this.code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// sk := wxConfig["secret"].(string)
|
||||
// if sk == "" {
|
||||
// this.code = errorcode.PayChannelConfigNotFound
|
||||
// return
|
||||
// }
|
||||
// this.wxConfig = wxConfig
|
||||
//
|
||||
// targetUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
|
||||
// this.payChannel.AppId,
|
||||
// sk,
|
||||
// this.param.Code,
|
||||
// )
|
||||
//
|
||||
// header := map[string]string{
|
||||
// "Content-Type": "application/json",
|
||||
// }
|
||||
// body := map[string]string{}
|
||||
// response, err := httpclient.FastHttpGet(targetUrl, header, body, 0)
|
||||
// if err != nil {
|
||||
// this.code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// utils.Log(nil, "获取微信授权信息", string(response), targetUrl)
|
||||
//
|
||||
// // 解析返回数据
|
||||
// var rsp front.GetWxAuthResponse
|
||||
// err = json.Unmarshal(response, &rsp)
|
||||
// if err != nil {
|
||||
// this.code = handErr(err)
|
||||
// return
|
||||
// }
|
||||
// if rsp.Openid == "" {
|
||||
// this.code = errorcode.WechatAuthFail
|
||||
// return
|
||||
// }
|
||||
// this.openId = rsp.Openid
|
||||
// this.code = handErr(err)
|
||||
//}
|
||||
//
|
||||
//func (this *wxJsapiPay) Sign(AppId, TimeStamp, NonceStr, Package string) (res string, err error) {
|
||||
// //组装被加密的字符串
|
||||
//
|
||||
// targetStr := AppId + "\n" + TimeStamp + "\n" + NonceStr + "\n" + Package + "\n"
|
||||
// //加密
|
||||
// sign, err := this.SHA256WithRsaBase64(targetStr)
|
||||
//
|
||||
// return sign, err
|
||||
//}
|
||||
//
|
||||
//func (this *wxJsapiPay) SHA256WithRsaBase64(origData string) (sign string, err error) {
|
||||
// //var keypath = "商户证书私钥地址"
|
||||
// //key, err := ioutil.ReadFile(keypath)
|
||||
// var key []byte
|
||||
// if pri, ok := this.wxConfig["private_key"].(string); ok {
|
||||
// key = []byte(pri)
|
||||
// } else {
|
||||
// return "", errors.New("配置的私钥不存在")
|
||||
// }
|
||||
//
|
||||
// blocks, _ := pem.Decode(key)
|
||||
// if blocks == nil || blocks.Type != "PRIVATE KEY" {
|
||||
// utils.Log(nil, "failed to decode PRIVATE KEY")
|
||||
// return
|
||||
//
|
||||
// }
|
||||
// privateKey, err := x509.ParsePKCS8PrivateKey(blocks.Bytes)
|
||||
//
|
||||
// h := sha256.New()
|
||||
// h.Write([]byte(origData))
|
||||
// digest := h.Sum(nil)
|
||||
// s, _ := rsa.SignPKCS1v15(nil, privateKey.(*rsa.PrivateKey), crypto.SHA256, digest)
|
||||
// sign = base64.StdEncoding.EncodeToString(s)
|
||||
//
|
||||
// return sign, err
|
||||
//}
|
||||
//
|
||||
//func WxJsApiPay(param front.WxJsApiPayRequest) (response front.WxJsApiPayResponse, code int) {
|
||||
// var ctx = context.Background()
|
||||
// task := newWxJsapiPay(param)
|
||||
//
|
||||
// // 1 获取订单
|
||||
// task.getOrder()
|
||||
// if task.code != errorcode.Success {
|
||||
// return response, task.code
|
||||
// }
|
||||
//
|
||||
// // 获取支付渠道配置
|
||||
// task.getPayChannel()
|
||||
// if task.code != errorcode.Success {
|
||||
// return response, task.code
|
||||
// }
|
||||
//
|
||||
// // 2 通过code获取openid
|
||||
// task.getOpenId()
|
||||
// if task.code != errorcode.Success {
|
||||
// return response, task.code
|
||||
// }
|
||||
//
|
||||
// order := task.order
|
||||
// // 通过openid,订单数据,请求微信下单, 获取prepay_id
|
||||
// orderRequest := paymentService.PayOrderRequest{
|
||||
// PayChannelId: order.PayChannelId,
|
||||
// OrderId: order.Id,
|
||||
// ChannelType: task.payChannel.ChannelType,
|
||||
// Description: order.Desc,
|
||||
// Amount: order.Amount,
|
||||
// PayerClientIp: param.ClientIp,
|
||||
// ReturnUrl: "",
|
||||
// //Wx: paymentService.WxPay{},
|
||||
// //Ali: paymentService.AliPay{},
|
||||
// OpenId: task.openId,
|
||||
// }
|
||||
// res := paymentService.PaymentService(ctx, orderRequest)
|
||||
// // 下单失败
|
||||
// if res.Code != payCommon.PAY_SUCCESS_CODE {
|
||||
// task.code = errorcode.PrePayFail
|
||||
// task.msg = res.ErrorMsg
|
||||
// return response, task.code
|
||||
// }
|
||||
// // 更新订单状态
|
||||
// order.Status = common.ORDER_STATUS_PAYING
|
||||
// task.code = OrderUpdate(order, "status")
|
||||
// if task.code != errorcode.Success {
|
||||
// utils.Log(nil, "成功下单,更新订单状态失败", order)
|
||||
// }
|
||||
//
|
||||
// // 3 组装返回数据
|
||||
// response = front.WxJsApiPayResponse{
|
||||
// AppId: task.payChannel.AppId,
|
||||
// TimeStamp: strconv.Itoa(int(time.Now().Unix())),
|
||||
// NonceStr: strconv.Itoa(int(time.Now().Unix())),
|
||||
// Package: "prepay_id=" + res.Result,
|
||||
// SignType: "RSA",
|
||||
// PaySign: "",
|
||||
// ThirdMsg: "",
|
||||
// }
|
||||
//
|
||||
// // 4 签名
|
||||
// // 4.1 签名数据
|
||||
// signValue, err := task.Sign(response.AppId, response.TimeStamp, response.NonceStr, response.Package)
|
||||
// if err != nil {
|
||||
// utils.Log(nil, "签名失败", err)
|
||||
// return response, errorcode.WechatAuthFail
|
||||
// }
|
||||
// response.PaySign = signValue
|
||||
//
|
||||
// return response, task.code
|
||||
//}
|
|
@ -14,13 +14,14 @@ import (
|
|||
type PayOrderRequest struct {
|
||||
PayChannelId int64 `json:"pay_channel_id"` // 支付方式ID
|
||||
OrderId int64 `json:"order_id"` // 平台订单号
|
||||
ChannelType int `json:"channel_type"` // 支付方式
|
||||
ChannelType int `json:"channel_type"` // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
Description string `json:"description"` // 商品描述
|
||||
Amount int `json:"amount"` // 金额单位为分
|
||||
PayerClientIp string `json:"payer_client_ip"` // 终端IP
|
||||
ReturnUrl string `json:"return_url"` // 支付成功后回调地址
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
Wx WxPay `json:"wx"` // 微信支付参数
|
||||
Ali AliPay `json:"ali"` // 支付宝参数
|
||||
OpenId string `json:"open_id"` // 支付者信息。 openid
|
||||
}
|
||||
|
||||
type WxPay struct {
|
||||
|
@ -29,6 +30,7 @@ type WxPay struct {
|
|||
SerialNo string `json:"serial_no"` // 商户证书的证书序列号
|
||||
ApiV3Key string `json:"api_v_3_key"` // apiV3Key,商户平台获取
|
||||
PrivateKey string `json:"private_key"` // 私钥 apiclient_key.pem 读取后的内容
|
||||
Secret string `json:"secret"` // 商户私钥,读取后的内容
|
||||
}
|
||||
|
||||
type AliPay struct {
|
||||
|
@ -58,6 +60,10 @@ func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrder
|
|||
case payCommon.PAY_CHANNEL_ALIPAY_WEB:
|
||||
// 支付宝H5支付
|
||||
info, err = ALiH5PayInfo(c, payOrderRequest)
|
||||
case payCommon.PAY_CHANNEL_WECHAT_JSAPI:
|
||||
// 微信JSAPI支付
|
||||
info, err = WxJsApiPayInfo(c, payOrderRequest)
|
||||
|
||||
default:
|
||||
payOrderResponse = PayOrderResponse{
|
||||
Code: payCommon.PAY_NOT_FOUND_CODE,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -31,14 +31,14 @@ func InitClient(wxConfig WxPay) (*wechat.ClientV3, error) {
|
|||
wxConfig.ApiV3Key,
|
||||
wxConfig.PrivateKey,
|
||||
)
|
||||
if clientErr != nil {
|
||||
return nil, clientErr
|
||||
}
|
||||
// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
|
||||
clientErr = wxClient.AutoVerifySign()
|
||||
if wxClient == nil {
|
||||
return nil, errors.New("client not initialized")
|
||||
}
|
||||
if clientErr != nil {
|
||||
return nil, clientErr
|
||||
}
|
||||
|
||||
// 自定义配置http请求接收返回结果body大小,默认 10MB
|
||||
wxClient.SetBodySize(10) // 没有特殊需求,可忽略此配置
|
||||
|
@ -95,6 +95,52 @@ func WxH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, er
|
|||
return wxRsp.Response.H5Url, nil
|
||||
}
|
||||
|
||||
// 微信JSAPI支付
|
||||
func WxJsApiPayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
|
||||
if payOrderRequest.OpenId == "" {
|
||||
return "", errors.New("jsapi方式openId不能为空")
|
||||
}
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(payOrderRequest.Wx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
|
||||
// 初始化 BodyMap
|
||||
envConfig := config.GetConf()
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("appid", payOrderRequest.Wx.AppId).
|
||||
Set("mchid", payOrderRequest.Wx.MchId).
|
||||
Set("description", payOrderRequest.Description).
|
||||
Set("out_trade_no", strconv.FormatInt(payOrderRequest.OrderId, 10)).
|
||||
Set("time_expire", expire).
|
||||
Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.WX_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)).
|
||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||
bm.Set("total", payOrderRequest.Amount).
|
||||
Set("currency", "CNY")
|
||||
}).
|
||||
SetBodyMap("payer", func(bm gopay.BodyMap) {
|
||||
bm.Set("openid", payOrderRequest.OpenId)
|
||||
})
|
||||
|
||||
wxRsp, err := wxClient.V3TransactionJsapi(c, bm)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if wxRsp.Code != wechat.Success || wxRsp.Response.PrepayId == "" {
|
||||
logger.Error(c, "WxJsApiPayInfo 发生错误", fmt.Sprintf("错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||
return "", errors.New(wxRsp.Error)
|
||||
}
|
||||
//if payOrderRequest.ReturnUrl != "" {
|
||||
// values := url.Values{}
|
||||
// values.Set("redirect_url", payOrderRequest.ReturnUrl)
|
||||
// encodedStr := values.Encode()
|
||||
// //wxRsp.Response.H5Url = wxRsp.Response.H5Url + "&" + encodedStr
|
||||
//}
|
||||
return wxRsp.Response.PrepayId, nil
|
||||
}
|
||||
|
||||
// WxPayCallBack 微信支付回调
|
||||
func WxPayCallBack(notifyReq *wechat.V3NotifyReq, wxConfig WxPay) error {
|
||||
// 初始化微信客户端
|
||||
|
|
|
@ -8,9 +8,12 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
PRI = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmjK6SPkrP03ssex5Dxn4KZeVm9rQoJMslru13GNgoGKJAq13xwUGl6lpGlhzM9IMzg0ldOO2a0SQPPjc0fLrDjIgHPfIT6H1hDGkZdPaF4D0OfiHGzlLwXq7FyyyGc2JXILsniMBXcCxNFhbW0jAaJyYrBJb3q84a5y5AtK3IC+eDV6Bj2J4HlQVGKgW9u2ic6Jxl23sacXY6iifi+KEuoXNCJrmYlgRWTaQovLmTCLkErkzxzG9DFRDWGoz25LthDPqcCSUmWEbJ+obwIGB4r2WCbFXvaeVBQORlyVRyNUvYMItjHBQIKinDWZ6y8KzA0YKOoxEfr0KfE8Uk4PQBAgMBAAECggEABTAX0PzelN4uyvTT0sMi/R0YRKPgepP40vtBsNvF10E7Lp4ClAupHpYFSrJq178xu1/2dVBXEGM9hw8GUQd7RCjuD3cFwcp/EKU+Zy6uQ38iZRTskEDa3bC+q3EXzuFXDxqOfIhai262UTlkATw0sjUwJRdkbMxoeWHkSNuH7UBVddxFL8Bq1DKaPzRCqQ8zlkMZHy8Xbf2b8rFoi1oPBoPjHyxCo33zcnSg5xntIoA5pkD6x4z5cAnU55aBoYUiRv7jmG+MVp1jpDvAmJLfUayVZNakgX1r74bMPsl9kpA7dVdgOlWrIkbJE1plVXXswBb8QKN0/Yx2vv/YASSi0QKBgQDaO9BkRjvht/lrsQEur1wXf5ITnsVWsqlUhYQKGHihzOj7e0rGO9QICM4eQZH9ssHfxEXhmEoFdkaqo3Fo47NI+yinpWm+KruwrRFkCGejlKZ4bhn9zWPb8L1qJbN4UD1c5jUNk1B0EEdnLRFg0/O7xm602bGilvY5x2nf0v95+QKBgQDDXyiiGNV7GO4h8OQYJwq0IqenPyIanRgYI3rw//tg147mhWcxT6ms6dMUh9nEXEFali2J1En+aVvx1Xn47CuGrRmZOLaGkw9ESFA/4ngYdea+xgttbKMXm0QwIwvATq2jxxrYEKmnr/+EUUWzIWioM1zQffAhVlkLFVnImquMSQKBgDe7qNfC/A4ELwWqubOTg0BZCxRJqvoePJJiWrs9Tql7rFB1Rz5jDx5SKVmew0r4OP0Nog8gFl9YumlfvlncNPBBfDt8SgoP3ckcGeHjJ5ymHPGKpMaliogj7ivKnw/t5g3wmMHzyksp0SJvZw3Ec22UGrfDFNOCHDXbUJWhzC75AoGBALbM6rAAnH65LNcFFeajYRh69HNAVyCfrFOpnvawDPzntAVs/MjeyNvJTH8BPXjE+UFREvrLbxBkdGsqWx3VnEQ+4pzCu8XfA4HYR33+4G/CoUwO8dJIu7DyzjJcGDqvYzjCqxNPQ+5qdqHPiW+56rq2lDlgHLaUnGwKZh+U2L5BAoGAeogtSQbnZaLQofSGcUOol2fyG24NU1JK3My+N1ypkSpD+y1KiFQeM5kg7UcJB6LBKZ/lRCKcjEMaxMyj57ETMkbRVKBLvsIL5QYolJLIHYqBul0AeFJ4K51SKK2Xk5rFvyuJKkJBux26WodtCXTnEzP1KRZGlSxJeN/V1yXjSEU="
|
||||
//PRI = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmjK6SPkrP03ssex5Dxn4KZeVm9rQoJMslru13GNgoGKJAq13xwUGl6lpGlhzM9IMzg0ldOO2a0SQPPjc0fLrDjIgHPfIT6H1hDGkZdPaF4D0OfiHGzlLwXq7FyyyGc2JXILsniMBXcCxNFhbW0jAaJyYrBJb3q84a5y5AtK3IC+eDV6Bj2J4HlQVGKgW9u2ic6Jxl23sacXY6iifi+KEuoXNCJrmYlgRWTaQovLmTCLkErkzxzG9DFRDWGoz25LthDPqcCSUmWEbJ+obwIGB4r2WCbFXvaeVBQORlyVRyNUvYMItjHBQIKinDWZ6y8KzA0YKOoxEfr0KfE8Uk4PQBAgMBAAECggEABTAX0PzelN4uyvTT0sMi/R0YRKPgepP40vtBsNvF10E7Lp4ClAupHpYFSrJq178xu1/2dVBXEGM9hw8GUQd7RCjuD3cFwcp/EKU+Zy6uQ38iZRTskEDa3bC+q3EXzuFXDxqOfIhai262UTlkATw0sjUwJRdkbMxoeWHkSNuH7UBVddxFL8Bq1DKaPzRCqQ8zlkMZHy8Xbf2b8rFoi1oPBoPjHyxCo33zcnSg5xntIoA5pkD6x4z5cAnU55aBoYUiRv7jmG+MVp1jpDvAmJLfUayVZNakgX1r74bMPsl9kpA7dVdgOlWrIkbJE1plVXXswBb8QKN0/Yx2vv/YASSi0QKBgQDaO9BkRjvht/lrsQEur1wXf5ITnsVWsqlUhYQKGHihzOj7e0rGO9QICM4eQZH9ssHfxEXhmEoFdkaqo3Fo47NI+yinpWm+KruwrRFkCGejlKZ4bhn9zWPb8L1qJbN4UD1c5jUNk1B0EEdnLRFg0/O7xm602bGilvY5x2nf0v95+QKBgQDDXyiiGNV7GO4h8OQYJwq0IqenPyIanRgYI3rw//tg147mhWcxT6ms6dMUh9nEXEFali2J1En+aVvx1Xn47CuGrRmZOLaGkw9ESFA/4ngYdea+xgttbKMXm0QwIwvATq2jxxrYEKmnr/+EUUWzIWioM1zQffAhVlkLFVnImquMSQKBgDe7qNfC/A4ELwWqubOTg0BZCxRJqvoePJJiWrs9Tql7rFB1Rz5jDx5SKVmew0r4OP0Nog8gFl9YumlfvlncNPBBfDt8SgoP3ckcGeHjJ5ymHPGKpMaliogj7ivKnw/t5g3wmMHzyksp0SJvZw3Ec22UGrfDFNOCHDXbUJWhzC75AoGBALbM6rAAnH65LNcFFeajYRh69HNAVyCfrFOpnvawDPzntAVs/MjeyNvJTH8BPXjE+UFREvrLbxBkdGsqWx3VnEQ+4pzCu8XfA4HYR33+4G/CoUwO8dJIu7DyzjJcGDqvYzjCqxNPQ+5qdqHPiW+56rq2lDlgHLaUnGwKZh+U2L5BAoGAeogtSQbnZaLQofSGcUOol2fyG24NU1JK3My+N1ypkSpD+y1KiFQeM5kg7UcJB6LBKZ/lRCKcjEMaxMyj57ETMkbRVKBLvsIL5QYolJLIHYqBul0AeFJ4K51SKK2Xk5rFvyuJKkJBux26WodtCXTnEzP1KRZGlSxJeN/V1yXjSEU="
|
||||
|
||||
PUB = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoyukj5Kz9N7LHseQ8Z+CmXlZva0KCTLJa7tdxjYKBiiQKtd8cFBpepaRpYczPSDM4NJXTjtmtEkDz43NHy6w4yIBz3yE+h9YQxpGXT2heA9Dn4hxs5S8F6uxcsshnNiVyC7J4jAV3AsTRYW1tIwGicmKwSW96vOGucuQLStyAvng1egY9ieB5UFRioFvbtonOicZdt7GnF2Ooon4vihLqFzQia5mJYEVk2kKLy5kwi5BK5M8cxvQxUQ1hqM9uS7YQz6nAklJlhGyfqG8CBgeK9lgmxV72nlQUDkZclUcjVL2DCLYxwUCCopw1mesvCswNGCjqMRH69CnxPFJOD0AQIDAQAB"
|
||||
//PUB = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoyukj5Kz9N7LHseQ8Z+CmXlZva0KCTLJa7tdxjYKBiiQKtd8cFBpepaRpYczPSDM4NJXTjtmtEkDz43NHy6w4yIBz3yE+h9YQxpGXT2heA9Dn4hxs5S8F6uxcsshnNiVyC7J4jAV3AsTRYW1tIwGicmKwSW96vOGucuQLStyAvng1egY9ieB5UFRioFvbtonOicZdt7GnF2Ooon4vihLqFzQia5mJYEVk2kKLy5kwi5BK5M8cxvQxUQ1hqM9uS7YQz6nAklJlhGyfqG8CBgeK9lgmxV72nlQUDkZclUcjVL2DCLYxwUCCopw1mesvCswNGCjqMRH69CnxPFJOD0AQIDAQAB"
|
||||
|
||||
PRI = "MIIEoAIBAAKCAQEAnSSVbidsHYZ46XcAo3eDXYKidzPZ/0W8UKZyHSLthZ0oMlkpC9gfPNKWA1DqiGH22MjRNzX2xz3WdE+bsC+MVWCWjq988PtEX/H+ahpbxKAMHHm4jWSjSLhjrnDCCbYUraG7++uiTzx/Qcef4bq9PAA64ckZLtTfywQdkzi5iWhTzggA6I1gEMKxsoJB+wljyTufmFj12/cHOSrl8wXoHJtODEwC70maH0e2SKT0ZSCFN3G7f7iLgQEDsAl9jZYrC1x9WK9kWtzm4V1ej2wn2MFa5DuE4AzLvBJDyKQN8PHI1lMuTn2QBFDtNyCb53y2qylU7azUn6yq1LNMwsjuPQIDAQABAoIBAH2kFXHYRUIqFRydUD5ivP6UBzAFniPS7ukQ26ZeGci9ybjPvtjAeOFZgiWumYZnxUS480YQeHn/ACtIxzMMIUjWDCqTNvM6AwYvZvoQjxTb3jMaQyuRrlfjTZfYgdvf4BKfgLzAPqrZtOm0ISoK82g4ytthvSfLfg9FAByIuxeXuJtzHuy7jTRqD9t7D6QBtweMEYGpjpHuMtrGTfk5fkRmvRoFIbRLhVo68hTgl/7ha5OujmRtlS45W12ayA3HceIfCyHliCMohaAkUR4AsmbFc3Sk1Fi/lQdJry+a8SfSkmGQ8Jc55d4nXldLJ1j5eLyl5/tQakqhDNleF6KFA4UCgYEAzzAVkrVJCpyQiaKEBhgFpHT/A3KCxJDRnnzE7hO8K05S4hmPgRQk0bB8iLXwdoAgelt9oJ2Epb4u7n7xQx+x/HohLUgJq7mz+gwqkiPkVi2idSQypSn6O9XXvjYNb29bjRUsIYixRZjcbvp9//TnP8W/mxuicmQme7gmwrgjFpMCgYEAwiowbUDP9ZlKeILFSXLnPWLAWX/5uqyG3i+FhUczxj7JyOSP5zXbs31OqtDmcpKChQXaCP9erDlwq8fN+U02zcLwIw8sbTAR5UCD/GjdKdTdJ+aKntoppwnCDPNszLhbCyMn6LOXh+AVKv9yFlX7Z1b/8yRbHXj2smKgzzzzme8CgYBVbh9HGgcfIAWdKuzDUn5pHHDWbA4tnQVCE3JkNLD/LlGQtzdr4vF3oQ0IlfSr+BLsQPNhGfJLIUtave8fXV9Xmsg5Up3iODVU4lVfYvtQ6Yo2QRG89r0elQNbhBAwJbubReKnhSSLbQdfn1v7AXGk4xYpj9CA2HjhxMH+wkx9jwJ/brug4q4T6/2AezoZSco+FsQ67tANnGjIge6YN2pkHKuyaN/xMeuFYNgWBVUeGDl2Nmcf8gGx/IbFuzI4RfXDS5XhXh1JOPwxOI2SuGEVwMWlWxwf8nh5SMpH4Rry8c4yHifumsfRo6woZl1Is3RV7JmxXvlc/XH/P7z/+TDJvQKBgH+yqQHTZToSc0u4X4luHfHJMT5bRRzWYCHAo1wgj9R9hsm70uFfNmXJX1YXOYJXFA43XkZSZNaAgvtaIpOcFS/G/dwHf2JqI8MRJINT9Ixf7zmo/vPjISI2ncTUeJgguvNSSlbn9hZ/guxlhz3XWY3lmTLPHAtnAFQ7OKGoqxbw"
|
||||
PUB = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnSSVbidsHYZ46XcAo3eDXYKidzPZ/0W8UKZyHSLthZ0oMlkpC9gfPNKWA1DqiGH22MjRNzX2xz3WdE+bsC+MVWCWjq988PtEX/H+ahpbxKAMHHm4jWSjSLhjrnDCCbYUraG7++uiTzx/Qcef4bq9PAA64ckZLtTfywQdkzi5iWhTzggA6I1gEMKxsoJB+wljyTufmFj12/cHOSrl8wXoHJtODEwC70maH0e2SKT0ZSCFN3G7f7iLgQEDsAl9jZYrC1x9WK9kWtzm4V1ej2wn2MFa5DuE4AzLvBJDyKQN8PHI1lMuTn2QBFDtNyCb53y2qylU7azUn6yq1LNMwsjuPQIDAQAB"
|
||||
)
|
||||
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
|
@ -19,7 +22,9 @@ func TestRsaEncrypt(t *testing.T) {
|
|||
|
||||
func TestRsaDecrypt(t *testing.T) {
|
||||
data := "pPnAPy7v2SY9Fu0LFcQH8UBA6VQ2FCfSg3nRZdMXS7mWjBwlacKHuFnh9UhobL7mxnmMyZPP100bpjCg2kvcfOpOp3ci85p+OYWINt4Fh3qgEOTG5FUyziaagGLm882t/I36KsDTVvbMZvC5sg4gZ9JQ5yAR+nuJfr0IxI0se/iD5luV1rms1kZHggd30iXdZtbkbX7xJ4xtnIiJmZU7kL+Xmvv1rDdPLxbol65QfnM1me1IHkXJapqSBnhEEmFQyBx31vp1ccNjkza8ZWbvTPCngc1k4kvlm6lKfwsG4hMuSdXUzveDm+Oo8StAKnyVoerJ202n7Vfx1XhehineQT0TPD7bO0HCEsDXXYEWwvcax8VdzYvHk7qSbH6e154qCr4LgDRSHKwAAExinTrzxx2rtSimieBLaEpDL2v5ch45HnhjRhWTRmM61W1g6sdHaVX1mQxaXvrT4v+h+f4TbIV4r4qeGJ6rXG+yKRoYseLzyGgystoOny9P0UH15W8rWPytV2eioWT7i3Cglg04BWP9mst67LQXeFH4CA6CkwVV2w9nCHrzxX2ouYSQELUEkTlIMry2AlkZubUnupGJLmLLUyZj7pM/6cLjyAgm02/gRc4wwf7JBBq/ipmKXpkhHXWLtQDWJEZTT+ug2v9EXy5dgPNPe8ZI0MILAeipjIc="
|
||||
privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
|
||||
data = "UaUJQUa2leqvgS5Brd0jjlMC4JFfQqavzk8VVSuHurBzC0l0Kz0EUY2nm8QRKB6ndCQZo4ktk/row+V1L/Zjn+3gBDhh4rNr0JNSvY/C+7AHpugvN+V8M0aEkFvZkaEaQiwjTExP8lz5w6Q/1O7Srb3KjnKs9wX97viyUbhUS4diGPCFnXLsWYnf6qSXvwNQwjgr3QykF45E2bN6VxsO/60OVZNN/yYgREe+IuuUyGvm+FlymnpMADGpDaViIOhqA77DNV4JkAsAv1Zjxtg+DFaeW9CcUOczw2yeQHXeEP/vzWfmcHXOZq17NKfSeiVotvLTUcT21UygD4oAUBPRmUTuqqa2095NCiNxxqFnRtHaWeY/dwp4ymNiHLFPh1HFwjVtvlazrEiLflsP0CI6zqn/bL8YhcV2VSSWx4g2YTTc3Xl56QeXa1PhdjSZg/apBRb/mEXTo1WNy/NQ5hVdNhtydB10WtA3YSr5vOEXSIbue4GJDYNNyMQTVBnfn3PTHl89/unlkFNI9AD60IfUCfhxOfg5Ddqa+8thTEBj4yOod/2dh6z2Dl7GZ7Ak0gWy1iFvFQm/6Y4p7dA44foAg9MwbV1wYbrdGauC5o7VRg0x6Sklzu/z5LeU4YUMruT0cd/Ov2kXkqiDyMn3GzdmIIWFadXISTbr7s1yU4uovn8="
|
||||
|
||||
privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
|
||||
` + PRI + `
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
res, err := Decrypt(privateKeyPEM, data)
|
||||
|
@ -27,7 +32,7 @@ func TestRsaDecrypt(t *testing.T) {
|
|||
}
|
||||
|
||||
func encrypt() string {
|
||||
data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"refundOutTreadNo001\",\"amount\":1,\"desc\":\"退款\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643,\"refund_out_trade_no\":\"asdadasdas\"}"
|
||||
data := "{\"pay_channel_id\":1729382256910270476,\"out_trade_no\":\"zxp1234D56711tuikuan\",\"order_type\":1,\"amount\":1,\"desc\":\"测试支付宝退款商品zxp\",\"ext_json\":\"\",\"app_id\":8070450532247928844,\"timestamp\":1723096731}"
|
||||
pub := `-----BEGIN PUBLIC KEY-----
|
||||
` + PUB + `
|
||||
-----END PUBLIC KEY-----`
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
@ -38,7 +40,7 @@ func TestSM2Encrypt(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSM2Decrypt(t *testing.T) {
|
||||
en := "MDRkZDJkYzE1ZmIyZTdjMDRiNTlhZGM5OGM1NjBjM2RhZWVkMzhkMjljYjFkMmEyNjUzMmZlZDRkMWUxMjc5MjQxM2M5OTJiMTk5OWQ4MzgwOTdjYjhhMTU4ODA3OTNmZDNiM2FjZmE2NWNjNDAzZTgyODZjZjM5Y2NkMWU2NmJjY2EwNjU0N2NlNzM3N2M3YWViMmRmN2UzNGQ3YTIyMzI1NWJiMzU5NzljMDVlNjg2MTQzMGE4Y2VmNDZmMTU4YTYxNmI5ZjE2YTcwYzc0MTRhNmNmMWE2NWE5ZTE1YWM1ODBmODk1MWNiOWNhMzBlMDNhMjQzZmZjZWY4YjQzOWUzOGM5NmU0MGQyMTc5YjY5YThhNGQ3ZTQxMjZlMzA1MGZlNWIxZDI4Mzc0YjU3MmRiODBiMjFiMWY4NGYwNDBjYTE3NTRhN2FjMDk5Y2ZmZGI5MDM3NjIxYTE0ODAzNGIyOTU4NjA4ZDM4MzNlOGIwNDE4MWQ4NGUyMWU0OTNmZjYzNzNjMGQ4Y2M0ODVkYzM4NjZlYjZlOWZiYzVjZGFmMDExNWNiYWNiODA4Y2ZkYjczODlmZmJlZDliNmQzMDdiYTczY2EyOTVlOWNhM2RhZmNlNDk1YTZiNWI4NzFhYzdlN2U2ZTJmZWFlOGU3YTllOTFhYTE4ZGY4MzVkNWI2YjFkOGFkY2NhYWM0YjMwOTU3NzUxMmZkYWVlMmVhOWJlMTkwMWUxOTUzMzFmN2UyZjU5NmFkOGRiN2Q1ZDJmYzI2MDA5NjE4YmNhNzc="
|
||||
en := "TURRek1HUXlOemhqTkdNMVl6aGxPRFZpTURCalpHVmhaV1E1WkRSaVpqVTFOekJsWkdJMk4yVTRPR0ptWVRrME5tRTROMkkzWW1FM09EUm1aVFptWVRGak0yUTRaakV3WW1FMFlqVTBZMll6TVRBek9EZGxabVJoWVRRMk1HUmpNRFU0WkdReE9XSmhZelV6TkRaak5XSmxNVE14Wm1Wa1ltRTJZVE0yWWpnelpXWTBNbVl4T1RabU5EWXpNMlk1WVdNeE4yVXpOalZpT0RabU1qQXhZbU0wTXpjM01qRmtZV1U1WVdJeE5ESTVPVE00TmpabVpXRXhNelV5Tm1aaE5EVmhaRGxrTTJWaU4yUm1aR1U0T0dRNVpUQXpabUl3TmpabE16TTFOekl4TnpsaFpETXhOV05oWmpNMk4yRmlOVEl5TlRRM1lUVTVNakJqWW1Nek1HRXpOR1l3T1RKa00ySmpPV0ZsTVRBeVkyVm1ZVEZqTkRRM01EaG1aV1UzTnpSallqWmpZVEZtWTJVMVpUYzJOMlE0WmpoaE1UTXlOMkU1WWpVek5tUTBORGcyTjJaaFlqazJaRGd5T0RBME9ETmtZVFZqTUdFMk1qUmhZV1ptWTJSa09UZGlOemN4WlRaaFltSmhNR0kzT0RNNFpETXdOV1UyWTJGbU5tVmtZak5pTURCbU4yVTJaakkxTkRWa1pqWTBPR05rTURBeE5XTmxOamt5TkRJNE1tTmlORE14T0dRM01USXpaREkxWW1ZeE1qRmxPRFU0TlRkall6RTJPVFJoWTJWak9EbGxPV0kyTlRVeFpUYzJOemsxTTJJMU56VTNNall4T1dGbU1EWTBabU0yTkdOaVkyUXhaVFZsTUdGa09EUTBNVFZqTkdVNE5tWXlaakpsT1dVM09Ea3pZVEZsTmpJMllqRmlaakl5T1dFeE9USXpNR0pqWVRjeU1ERmpOV1V4TXprME9UbGtOemN6TWpReVkySm1ORGMxTVdObFpHUTJOR05tTlRjPQ=="
|
||||
decrypt, err := SM2Decrypt(en, SELF_PUB, SELF_PRI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -47,10 +49,28 @@ func TestSM2Decrypt(t *testing.T) {
|
|||
}
|
||||
|
||||
func encrypt() string {
|
||||
data := "{\"order_no\":5476377146882523228,\"order_type\":1,\"out_tread_no\":\"asdadasdas\",\"amount\":1,\"desc\":\"abc\",\"status\":2,\"create_time\":\"2024-08-08 14:47:35\"}"
|
||||
data := "{\"pay_channel_id\":1729382256910270476,\"out_trade_no\":\"zxp1234D56711tuikuan\",\"order_type\":1,\"amount\":1,\"desc\":\"测试支付宝退款商品zxp\",\"ext_json\":\"\",\"app_id\":1729382256910270475,\"timestamp\":1723096731}"
|
||||
|
||||
//data := "{\"refund_out_trade_no\":\"zxp1234D56711tuikuan\",\"pay_channel_id\":1729382256910270476,\"out_trade_no\":\"4123412341234\",\"order_type\":2,\"amount\":1,\"desc\":\"测试支付宝退款商品zxp\",\"ext_json\":\"\",\"app_id\":1729382256910270475,\"timestamp\":1723096731}"
|
||||
en, err := SM2Encrypt(data, SELF_PUB)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return en
|
||||
}
|
||||
|
||||
func TestSm2Decode(t *testing.T) {
|
||||
en := "TURRd1lUZGlZamt4T1RGbU9XWmhOR1pqTkRKa05HWmpORFkyTjJNd05qVmtNR1EwTTJNellUVmhPR1ZsTm1GbVpqZzFPRGMwTW1Oak5EQmtaRGszTkRrek5tRTVNREEwTkdFMFlXRXhaREl5T0RVME1ESmtObVk1TWpWaVpqYzNORGhoT1RObE0yVmtaVGc1T0dVellUZGlabU15WkRNNU1EQXpNR0ZsTm1Oa05XSTBPVEJpT1dFMU9XUTVObU15TURCaU9EVTNNR0UzWTJFNU9UYzVNalF3TnpFeVl6RTVZemd4TW1WbVpUQTNZbVV5WVRoaU1tRmtaak5tWkRjek1XVXdabVZrTlRnMVpUTXlNR0U0WldWaVlURXlNREExWWpnek1XRTBNVFk1WlRCa09ERXpaVGN6WWpJMFpEUmpOVFV5WlRRMU1HTmxNbVEwWlRkbU5tTTFaR1l5TUdZeU5XTXdNV1kwTVdFNU5EZGxaRFV3TnpjME9EWTFaVFJoWVRreU5HTm1ZVFU1WXpoa01USmxNREF3WTJOa01qRTVNell6T1RObFpXWXpNelEyTnpObU9HTTJaV00xTkdVd1ltRmhOVFZsWVRka09UQTFaRFZrTXpobVlqSTJabVEzWldFelptWmpNbU5tTldFd01tUmhOak5qTWpBeVl6azVaR0poT0RRMFpHTTJNbVJtTkdRM05Ea3dZems0TmprMk9UTmpNbVF3TnpFeE1qUmlaVFJpT1RrMk9UY3pNR0prTmpZNVpqYzFPRFJpWVRCbE5tTXdZV1JqTnpOak4yVmpaR1ExWmpJellUWmtaR1EwTVRCbE1qSTVZV1F5WW1GbFl6YzRPRGhsWXpjME5HTmlNekk0TnpRek1UZGhNak0xWVRWbFlUYzNNR1JsTVRZMU1tWmpOVEEzT1dVMllqSTNabUl5TVRNM09URmpPRFF4TXpsa09ETm1OelExWTJVNVlUTXlZams0TVRZd1pqUXdNV1k1TjJSbVpEazRZV1kxWXpZeE1USTRaREEzT0dRME5tVXlaQT09"
|
||||
|
||||
content, _ := base64.StdEncoding.DecodeString(en)
|
||||
|
||||
decrypt, err := SM2Decrypt(string(content), SELF_PUB, SELF_PRI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Log(decrypt)
|
||||
|
||||
tempMap := make(map[string]interface{})
|
||||
json.Unmarshal([]byte(decrypt), &tempMap)
|
||||
t.Log(tempMap)
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package httpclient
|
|||
|
||||
import (
|
||||
"PaymentCenter/app/utils"
|
||||
"fmt"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
"time"
|
||||
)
|
||||
|
@ -83,12 +81,11 @@ func FastHttpGet(url string, header map[string]string, body map[string]string, t
|
|||
}
|
||||
url = url[0 : len(url)-1]
|
||||
}
|
||||
fmt.Println(url)
|
||||
req.SetRequestURI(url)
|
||||
resp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(resp) // 用完需要释放资源
|
||||
var err error
|
||||
if timeout == 0 {
|
||||
if timeout <= 0 {
|
||||
if err = fasthttp.Do(req, resp); err != nil {
|
||||
utils.Log(nil, "http请求失败", err, url)
|
||||
return nil, err
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>微信支付</title>
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.success,
|
||||
.error {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#right {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 100px auto 20px;
|
||||
border-radius: 50%;
|
||||
border: 5px solid rgb(104, 225, 52);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#right::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 88px;
|
||||
height: 50px;
|
||||
border: 5px solid rgb(104, 225, 52);
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
transform: rotate(-45deg) translate(7px, -10px);
|
||||
}
|
||||
|
||||
.success-txt {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: rgb(104, 225, 52);
|
||||
}
|
||||
|
||||
#error {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 100px auto 20px;
|
||||
border-radius: 50%;
|
||||
border: 5px solid rgb(244, 57, 52);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#error::before {
|
||||
content: "\2715";
|
||||
display: block;
|
||||
color: rgb(244, 57, 52);
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.error-txt {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: rgb(244, 57, 52);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="success">
|
||||
<span id="right"></span>
|
||||
<span class="success-txt">支付成功</span>
|
||||
</div>
|
||||
<div class="error">
|
||||
<span id="error"></span>
|
||||
<span class="error-txt">支付失败 {{.errmsg}}</span>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementsByClassName('error')[0].style.display = 'block';
|
||||
document.getElementsByClassName('success')[0].style.display = 'none';
|
||||
document.getElementsByClassName('error')[0].innerHTML = res.err_msg || '支付失败';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,131 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>微信支付</title>
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.success,
|
||||
.error {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#right {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 100px auto 20px;
|
||||
border-radius: 50%;
|
||||
border: 5px solid rgb(104, 225, 52);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#right::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 88px;
|
||||
height: 50px;
|
||||
border: 5px solid rgb(104, 225, 52);
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
transform: rotate(-45deg) translate(7px, -10px);
|
||||
}
|
||||
|
||||
.success-txt {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: rgb(104, 225, 52);
|
||||
}
|
||||
|
||||
#error {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: 100px auto 20px;
|
||||
border-radius: 50%;
|
||||
border: 5px solid rgb(244, 57, 52);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#error::before {
|
||||
content: "\2715";
|
||||
display: block;
|
||||
color: rgb(244, 57, 52);
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.error-txt {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: rgb(244, 57, 52);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="success">
|
||||
<span id="right"></span>
|
||||
<span class="success-txt">支付成功</span>
|
||||
</div>
|
||||
<div class="error">
|
||||
<span id="error"></span>
|
||||
<span class="error-txt">支付失败</span>
|
||||
</div>
|
||||
<script>
|
||||
function onBridgeReady() {
|
||||
WeixinJSBridge.invoke(
|
||||
'getBrandWCPayRequest', {
|
||||
"appId": "{{.appId}}",
|
||||
"timeStamp": "{{.timeStamp}}",
|
||||
"nonceStr": "{{.nonceStr}}",
|
||||
"package": "{{.package}}",
|
||||
"signType": "{{.signType}}",
|
||||
"paySign": "{{.paySign}}"
|
||||
},
|
||||
function (res) {
|
||||
if (res.err_msg == "get_brand_wcpay_request:ok") {
|
||||
// 使用以上方式判断前端返回,微信团队郑重提示:
|
||||
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
|
||||
document.getElementsByClassName('success')[0].style.display = 'block';
|
||||
document.getElementsByClassName('error')[0].style.display = 'none';
|
||||
window.location.href = {{.returnUrl}}; // 跳转
|
||||
} else {
|
||||
document.getElementsByClassName('error')[0].style.display = 'block';
|
||||
document.getElementsByClassName('success')[0].style.display = 'none';
|
||||
document.getElementsByClassName('error')[0].innerHTML = res.err_msg || '支付失败';
|
||||
}
|
||||
});
|
||||
}
|
||||
if (typeof WeixinJSBridge == "undefined") {
|
||||
if (document.addEventListener) {
|
||||
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
|
||||
} else if (document.attachEvent) {
|
||||
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
|
||||
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
|
||||
}
|
||||
} else {
|
||||
onBridgeReady();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
17
go.mod
17
go.mod
|
@ -3,9 +3,7 @@ module PaymentCenter
|
|||
go 1.21
|
||||
|
||||
require (
|
||||
gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2
|
||||
github.com/BurntSushi/toml v0.4.1
|
||||
github.com/Shopify/sarama v1.19.0
|
||||
github.com/ZZMarquis/gm v1.3.2
|
||||
github.com/ahmetb/go-linq/v3 v3.2.0
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
|
@ -13,10 +11,12 @@ require (
|
|||
github.com/forgoer/openssl v1.6.0
|
||||
github.com/gin-gonic/gin v1.7.7
|
||||
github.com/go-pay/gopay v1.5.103
|
||||
github.com/go-pay/util v0.0.2
|
||||
github.com/go-playground/locales v0.14.0
|
||||
github.com/go-playground/universal-translator v0.18.0
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.5
|
||||
github.com/nats-io/nats.go v1.9.1
|
||||
github.com/openzipkin/zipkin-go v0.2.2
|
||||
|
@ -25,12 +25,12 @@ require (
|
|||
github.com/qit-team/snow-core v0.1.28
|
||||
github.com/qit-team/work v0.3.11
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
|
||||
github.com/swaggo/gin-swagger v1.3.3
|
||||
github.com/swaggo/swag v1.7.9
|
||||
github.com/tjfoc/gmsm v1.4.1
|
||||
github.com/valyala/fasthttp v1.31.0
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20
|
||||
google.golang.org/grpc v1.56.3
|
||||
google.golang.org/protobuf v1.30.0
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0
|
||||
|
@ -55,13 +55,8 @@ require (
|
|||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/eapache/go-resiliency v1.1.0 // indirect
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
|
||||
github.com/eapache/queue v1.1.0 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
|
@ -69,7 +64,6 @@ require (
|
|||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-pay/crypto v0.0.1 // indirect
|
||||
github.com/go-pay/errgroup v0.0.2 // indirect
|
||||
github.com/go-pay/util v0.0.2 // indirect
|
||||
github.com/go-pay/xlog v0.0.3 // indirect
|
||||
github.com/go-pay/xtime v0.0.2 // indirect
|
||||
github.com/go-playground/validator/v10 v10.9.0 // indirect
|
||||
|
@ -81,8 +75,6 @@ require (
|
|||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hetiansu5/accesslog v1.0.0 // indirect
|
||||
github.com/hetiansu5/cores v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
@ -99,14 +91,11 @@ require (
|
|||
github.com/nats-io/jwt v0.3.2 // indirect
|
||||
github.com/nats-io/nkeys v0.1.3 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
github.com/tidwall/gjson v1.12.1 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
|
|
17
go.sum
17
go.sum
|
@ -39,8 +39,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
|||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||
gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2 h1:f4Rj4jVshXYX7wl7aIrd7W9DbGfqxYrZ/c7ppoVL4a4=
|
||||
gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2/go.mod h1:OEBHFTBQOvsJGzLyMZS8K98F8aZHWg+O8Stycuh94Dk=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
|
@ -53,14 +51,14 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
|
|||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/ZZMarquis/gm v1.3.2 h1:lFtpzg5zeeVMZ/gKi0gtYcKLBEo9XTqsZDHDz6s3Gow=
|
||||
github.com/ZZMarquis/gm v1.3.2/go.mod h1:wWbjZYgruQVd7Bb8UkSN8ujU931kx2XUW6nZLCiDE0Q=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||
github.com/ahmetb/go-linq/v3 v3.2.0 h1:BEuMfp+b59io8g5wYzNoFe9pWPalRklhlhbiU3hYZDE=
|
||||
|
@ -161,11 +159,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
|
@ -188,7 +183,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=
|
||||
|
@ -393,7 +387,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
|||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
|
@ -609,7 +602,6 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP
|
|||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -655,7 +647,6 @@ github.com/qit-team/snow-core v0.1.28 h1:RrX7i6GLbcMMSVzAT1lXgS/S3M2b1OrAnsoPaRG
|
|||
github.com/qit-team/snow-core v0.1.28/go.mod h1:J9CNj6P2IRh72yVa7rut4T8ikq/4DjaisLqXZy40TNg=
|
||||
github.com/qit-team/work v0.3.11 h1:AAtLTCOJ01WMFcvviK9rDGhHzaHE3bvunMOnSZ/80k8=
|
||||
github.com/qit-team/work v0.3.11/go.mod h1:h5m1cZjn+BznChuAyMiR/+IUyWEmaMylPKRhq/AlxKw=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
|
@ -703,11 +694,9 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
|
|||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
|
@ -769,6 +758,8 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU
|
|||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20 h1:gS8oFn1bHGnyapR2Zb4aqTV6l4kJWgbtqjCq6k1L9DQ=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.20/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
Loading…
Reference in New Issue