Merge branch 'dev-lwl/wechat'
This commit is contained in:
commit
ccf4417659
|
@ -28,6 +28,12 @@ const (
|
|||
PayTypeOp = "op" // op直冲
|
||||
PayTypeAlipay = "alipay" // 支付宝
|
||||
PayTypeAlipayH5 = "alipay_h5" // 支付宝 h5
|
||||
PayTypeWxpayNative = "wxpay_native" // 微信native
|
||||
)
|
||||
|
||||
const (
|
||||
CallBackPayTypeAlipay = "alipay"
|
||||
CallBackPayTypeWxpay = "wxpay"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -56,6 +62,7 @@ type CreateOrderData struct {
|
|||
OrderId string `json:"order_id"` // 订单id
|
||||
AlipayParamStr string `json:"alipay_param_str"` // 支付宝 app支付参数
|
||||
AlipayH5ParamStr string `json:"alipay_h5_param_str"` // 支付宝 h5支付参数
|
||||
WxpayNativeParamStr string `json:"wxpay_native_param_str"` // 微信支付 native支付参数
|
||||
}
|
||||
|
||||
// 预解锁联系方式
|
||||
|
@ -136,6 +143,7 @@ type H5DirectUnlockWechatData struct {
|
|||
OrderId string `json:"order_id"` // 订单id
|
||||
AlipayParamStr string `json:"alipay_param_str"` // 支付宝 app支付参数
|
||||
AlipayH5ParamStr string `json:"alipay_h5_param_str"` // 支付宝 h5支付参数
|
||||
WxpayNativeParamStr string `json:"wxpay_native_param_str"` // 微信支付 native支付参数
|
||||
}
|
||||
|
||||
// 支付宝回调参数
|
||||
|
@ -144,6 +152,13 @@ type AlipayCallbackParamIn struct {
|
|||
AlipayOrderId string `json:"alipay_order_id"` // 支付宝订单id
|
||||
}
|
||||
|
||||
// 支付回调参数
|
||||
type PayCallbackParamIn struct {
|
||||
OrderId string `json:"order_id"` // 我们自己服务的订单id
|
||||
OutOrderId string `json:"out_order_id"` // 外部订单id,比如支付宝、微信
|
||||
CallbackPayType string `json:"callback_pay_type"` // 支付类型
|
||||
}
|
||||
|
||||
// 解锁会员资格
|
||||
type UnlockMembershipReq struct {
|
||||
base.BaseRequest
|
||||
|
|
|
@ -19,9 +19,10 @@ func AlipayCallback(ctx *gin.Context) {
|
|||
}
|
||||
|
||||
if bm.GetString("trade_status") == "TRADE_SUCCESS" {
|
||||
service.DefaultService.AlipayCallback(ctx, &vasproto.AlipayCallbackParamIn{
|
||||
service.DefaultService.PayCallback(ctx, &vasproto.PayCallbackParamIn{
|
||||
OrderId: bm.GetString("out_trade_no"),
|
||||
AlipayOrderId: bm.GetString("trade_no"),
|
||||
OutOrderId: bm.GetString("trade_no"),
|
||||
CallbackPayType: vasproto.CallBackPayTypeAlipay,
|
||||
})
|
||||
}
|
||||
ctx.String(200, "success")
|
||||
|
|
|
@ -226,6 +226,7 @@ func Init(r *gin.Engine) {
|
|||
|
||||
extVasPayGroup := r.Group("/ext/vas")
|
||||
extVasPayGroup.POST("alipay_callback", AlipayCallback)
|
||||
extVasPayGroup.POST("wxpay_callback", WxpayCallback)
|
||||
|
||||
opVasPayGroup := r.Group("/op/vas", PrepareOp())
|
||||
opVasPayGroup.POST("create_order", middleware.JSONParamValidator(vasproto.OpCreateOrderReq{}), OpCreateOrder)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
wxpay "github.com/go-pay/gopay/wechat/v3"
|
||||
vasproto "service/api/proto/vas/proto"
|
||||
"service/app/mix/service"
|
||||
"service/bizcommon/util"
|
||||
"service/library/logger"
|
||||
"service/library/payclients/wxpaycli"
|
||||
)
|
||||
|
||||
func WxpayCallback(ctx *gin.Context) {
|
||||
notify, err := wxpaycli.GetDefaultWxpayClient().ParseNotify(ctx.Request)
|
||||
if err != nil {
|
||||
logger.Error("ParseNotify fail, req: %v, err: %v", util.ToJson(notify), err)
|
||||
return
|
||||
}
|
||||
if notify == nil {
|
||||
logger.Error("ParseNotify nil, req: %v, err: %v", util.ToJson(notify), err)
|
||||
return
|
||||
}
|
||||
logger.Info("WxpayCallback, notify: %v", util.ToJson(notify))
|
||||
|
||||
if notify.TradeState == wxpay.TradeStateSuccess {
|
||||
service.DefaultService.PayCallback(ctx, &vasproto.PayCallbackParamIn{
|
||||
OrderId: notify.OutTradeNo,
|
||||
OutOrderId: notify.TransactionId,
|
||||
CallbackPayType: vasproto.CallBackPayTypeWxpay,
|
||||
})
|
||||
}
|
||||
ctx.String(200, "success")
|
||||
}
|
|
@ -20,6 +20,7 @@ import (
|
|||
"service/library/idgenerator"
|
||||
"service/library/logger"
|
||||
"service/library/payclients/alipaycli"
|
||||
"service/library/payclients/wxpaycli"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
|
@ -95,6 +96,7 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
|
|||
var (
|
||||
alipayParamStr string
|
||||
alipayH5ParamStr string
|
||||
wxpayNativeParamStr string
|
||||
)
|
||||
|
||||
defer func() {
|
||||
|
@ -180,16 +182,29 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
|
|||
}
|
||||
case vasproto.PayTypeAlipayH5:
|
||||
alipayCli := alipaycli.GetDefaultAlipayClient()
|
||||
appPayParam := &alipaycli.WapPayParam{
|
||||
wapPayParam := &alipaycli.WapPayParam{
|
||||
OutTradeNo: orderId,
|
||||
Subject: product.Subject,
|
||||
TotalAmount: product.RealPrice,
|
||||
TimeOutSeconds: 900,
|
||||
ReturnUrl: req.ReturnUrl,
|
||||
}
|
||||
alipayH5ParamStr, err = alipayCli.WapPay(ctx, appPayParam)
|
||||
alipayH5ParamStr, err = alipayCli.WapPay(ctx, wapPayParam)
|
||||
if err != nil {
|
||||
logger.Error("alipay WapPay fail, req: %v, wapPayParam: %v, err: %v", util.ToJson(req), util.ToJson(appPayParam), err)
|
||||
logger.Error("alipay WapPay fail, req: %v, wapPayParam: %v, err: %v", util.ToJson(req), util.ToJson(wapPayParam), err)
|
||||
return
|
||||
}
|
||||
case vasproto.PayTypeWxpayNative:
|
||||
wxpayCli := wxpaycli.GetDefaultWxpayClient()
|
||||
nativePayParam := &wxpaycli.NativePayParam{
|
||||
Description: product.Subject,
|
||||
OutTradeNo: orderId,
|
||||
TotalAmount: product.RealPrice,
|
||||
TimeOutSeconds: 900,
|
||||
}
|
||||
wxpayNativeParamStr, err = wxpayCli.NativePay(ctx, nativePayParam)
|
||||
if err != nil {
|
||||
logger.Error("wxpay NativePay fail, req: %v, wapPayParam: %v, err: %v", util.ToJson(req), util.ToJson(nativePayParam), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -233,6 +248,7 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
|
|||
OrderId: orderId,
|
||||
AlipayParamStr: alipayParamStr,
|
||||
AlipayH5ParamStr: alipayH5ParamStr,
|
||||
WxpayNativeParamStr: wxpayNativeParamStr,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -1500,6 +1516,7 @@ func (v *Vas) H5DirectUnlockWechat(ctx *gin.Context, req *vasproto.H5DirectUnloc
|
|||
OrderId: cData.OrderId,
|
||||
AlipayParamStr: cData.AlipayParamStr,
|
||||
AlipayH5ParamStr: cData.AlipayH5ParamStr,
|
||||
WxpayNativeParamStr: cData.WxpayNativeParamStr,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -1524,13 +1541,14 @@ func (v *Vas) GetUserWechatUnlock(ctx *gin.Context, mid, uid int64) (uu *dbstruc
|
|||
return
|
||||
}
|
||||
|
||||
// 支付宝【支付】回调
|
||||
func (v *Vas) AlipayCallback(ctx *gin.Context, p *vasproto.AlipayCallbackParamIn) {
|
||||
// 【支付】回调
|
||||
func (v *Vas) PayCallback(ctx *gin.Context, p *vasproto.PayCallbackParamIn) {
|
||||
var (
|
||||
orderId = p.OrderId
|
||||
alipayOrderId = p.AlipayOrderId
|
||||
outOrderId = p.OutOrderId
|
||||
afterStatus int32
|
||||
)
|
||||
logger.Info("PayCallback, param: %v", util.ToJson(p))
|
||||
|
||||
// 获取订单
|
||||
checkOrder, err := v.store.GetOrderById(ctx, nil, orderId)
|
||||
|
@ -1548,8 +1566,8 @@ func (v *Vas) AlipayCallback(ctx *gin.Context, p *vasproto.AlipayCallbackParamIn
|
|||
return
|
||||
}
|
||||
|
||||
// ali_order_id检查
|
||||
outOrder, err := v.store.GetOrderByOutOrderId(ctx, nil, alipayOrderId)
|
||||
// out_order_id检查
|
||||
outOrder, err := v.store.GetOrderByOutOrderId(ctx, nil, outOrderId)
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
err = nil
|
||||
|
@ -1665,8 +1683,8 @@ func (v *Vas) AlipayCallback(ctx *gin.Context, p *vasproto.AlipayCallbackParamIn
|
|||
}
|
||||
afterStatus = dbstruct.VasOrderStatusPaySuccess
|
||||
|
||||
// 更新支付宝订单
|
||||
err = v.store.UpdateOutOrderId(ctx, tx, orderId, alipayOrderId)
|
||||
// 更新外部订单
|
||||
err = v.store.UpdateOutOrderId(ctx, tx, orderId, outOrderId)
|
||||
if err != nil {
|
||||
logger.Error("UpdateOutOrderId fail, p: %v", util.ToJson(p))
|
||||
return
|
||||
|
@ -2062,8 +2080,11 @@ func (v *Vas) DealOneOrder(ctx *gin.Context, orderId string) (err error) {
|
|||
}
|
||||
|
||||
// 支付宝查询订单
|
||||
switch order.GetPayType() {
|
||||
case vasproto.PayTypeAlipayH5:
|
||||
alipayCli := alipaycli.GetDefaultAlipayClient()
|
||||
alipayResp, err := alipayCli.QueryOrder(ctx, &alipaycli.QueryOrderParam{
|
||||
var alipayResp *alipay.TradeQueryResponse
|
||||
alipayResp, err = alipayCli.QueryOrder(ctx, &alipaycli.QueryOrderParam{
|
||||
OutTradeNo: orderId,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -2086,6 +2107,10 @@ func (v *Vas) DealOneOrder(ctx *gin.Context, orderId string) (err error) {
|
|||
err = errors.New("closed order")
|
||||
return
|
||||
}
|
||||
case vasproto.CallBackPayTypeWxpay:
|
||||
err = errors.New("暂不处理微信订单")
|
||||
return
|
||||
}
|
||||
|
||||
// 判断时间,小于7天不处理
|
||||
if time.Now().Unix()-order.GetCt() < 7*86400 {
|
||||
|
|
|
@ -49,6 +49,7 @@ import (
|
|||
"service/library/melody"
|
||||
"service/library/mycrypto"
|
||||
"service/library/payclients/alipaycli"
|
||||
"service/library/payclients/wxpaycli"
|
||||
"service/library/redis"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
|
@ -129,7 +130,13 @@ func (s *Service) Init(c any) (err error) {
|
|||
|
||||
err = alipaycli.Init(cfg.Alipay)
|
||||
if err != nil {
|
||||
logger.Error("alipaycli.Init fail, cfg: %v, err: %v", util.ToJson(cfg), err)
|
||||
logger.Error("alipaycli.Init fail, cfg: %v, err: %v", util.ToJson(cfg.Alipay), err)
|
||||
return
|
||||
}
|
||||
|
||||
err = wxpaycli.Init(cfg.Wxpay)
|
||||
if err != nil {
|
||||
logger.Error("wxpaycli.Init fail, cfg: %v, err: %v", util.ToJson(cfg.Wxpay), err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -369,9 +369,9 @@ func (s *Service) H5DirectUnlockWechat(ctx *gin.Context, req *vasproto.H5DirectU
|
|||
return
|
||||
}
|
||||
|
||||
// 支付宝回调
|
||||
func (s *Service) AlipayCallback(ctx *gin.Context, req *vasproto.AlipayCallbackParamIn) (data *vasproto.H5DirectUnlockWechatData, ec errcode.ErrCode) {
|
||||
_DefaultVas.AlipayCallback(ctx, req)
|
||||
// 支付回调
|
||||
func (s *Service) PayCallback(ctx *gin.Context, req *vasproto.PayCallbackParamIn) (data *vasproto.H5DirectUnlockWechatData, ec errcode.ErrCode) {
|
||||
_DefaultVas.PayCallback(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -27,11 +27,6 @@ mix_mysql:
|
|||
read_timeout_s: 5
|
||||
write_timeout_s: 3
|
||||
|
||||
wxpay:
|
||||
mchid: "1111"
|
||||
serial_no: "1111"
|
||||
apiv3_key: "1111"
|
||||
private_key: "af21aw65aw23efwa132f1waef56wa56awef"
|
||||
|
||||
crypto:
|
||||
aes:
|
||||
|
@ -48,6 +43,14 @@ alipay:
|
|||
private_key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtj6Nu2olEB8c8SDSANExaPbmk8LoYPEGB/APZDskhezO/w4OwPmG1Ak79XDpUUIihdmTZ8i2nBLhhRpFZGU4MMdil4X7a5nYHBm5dkGo3isIInn/qV7AYDqek4pGpMUPI6fbR05NWnUTZ+3AvMjTNBa979MgLyqS3jzpvuK6yXM5RinKVv8IF9KgthRKjH4LHyyRXBGu2cJSA5utjzFCL9KIu/T4XXZ09HOgz+JKPxXDj25Ob5eTtcBDsoJfXChcOvwCA7nxb1jzvGDrkqF36H1CC8KT1aoLRLisBsM+7sjEfNcB4RG5pGHSDGQJwZ0stGAhXf/fuWiLmI/zMOXODAgMBAAECggEAEL7CAuj8w16Iv20r+46QK0i3R42eNsZhf5wD9wYxK5TKal7/rppmLOObIWCrlATtGb7lfg2aj/mpnGEFlvYVDKImh+KYrZ/8lTLupQJQ7SjrDY/VQZPSPo/zZrohWZSSOKkyEg56samcwfc7XKJYa8t3odr9Df4wJDGibrL/z99xrJrz85le+NHBISXUyddS5ojuDNfGwE39wgLu52P74QYxv6s0xZKj2aALXaLXyTzF4ys34nVhhv75gXFtENiUet5/PVRYe7OE4cndcOP9WI3nXP5ojak8N4fY15S0YOm/0NZP8w6nWUemFjUNRXYRY42J+W+/myW8RIppaGuwkQKBgQDYH263Lh8C9EkjGA2po68LUTBhM2fT2L3batzHjXo0jvLT0IR88/9V7xhC3ZQZNcxQCK0xaCYfzFx3UV9veC1zeVRW0i/hyJ8B40w3WXCoGDiHgzQ/kcu/Iaw2qmJyhEFzOwAfrxIgco9EiZBaY7fXyy7YkZLGqXNFcLsuWR5qWwKBgQDNlc19CESIukT31Ap2QBe6t9YNXHZuKTePBRaIUCan3vZwPfZePLJQCgtoVhnCGoHZJ+ZlNhYri9x6DNLZpxCSHZNjccmqFGj3N7xWBqU38gu2dcPdMAxT1ERwf2gdlhgWAhVzD56hsWyrbP9YZACXy7TlevSj7s/5GaNaVuHT+QKBgQC2VZZ3zt51BJnrlLB6LVFRz/ZsGw1+qj5LLpYDeXXff7aYQzRzovsJigVC7GO0/TFZWGid5Us8ypI8TBejGJXn9TXVZdDlwPd9hUFY9QlZl82hbm0XMK7fms4K9KbIDJKXX/CTyoUVgPEkFpcF21lQIuhr6C0XlABfVmNlD+TcPwKBgHJuot2ov3UXsZH8/gHKNSsibswrHmS9HobGPz+K1al1Stk5NCxKPrqcjLL70gSf+ozkT7MggwCkLgnln2u1OV0Lh2HAEY9RIwgQhw2fT1GvseNS873no8T5j0rLMCnfxPJjIItWM2cvOhzFY/BQYaAcrElbwlaJdEvkgG+lkrgJAoGBAInYRdHo9V1exDUS0ucQuraoEtuvgOrqatnCbuNZ9EpgjFJxDbHXOIJYPvgfpyws4amdksNQL0Ux9+p+esJOS+JYYkE1nmCTCrfb6SNKr+PdeUteKtTiHJb4zJhGVC2Lk4uBg9AGa/d7j5apWw4RsZ/R1ky1S6KQUkqItbVrhC8l"
|
||||
notify_url: "https://api.tiefen.fun/ext/vas/alipay_callback"
|
||||
|
||||
wxpay:
|
||||
mchid: "1665016206"
|
||||
appid: "wxc28fd8aaf31984b6"
|
||||
serial_no: "51D8E75620B9569F10FF5363022F3C9D2152DF50"
|
||||
apiv3_key: "UoaswgnuKYwIadqxCVag1IZlq5n9USvt"
|
||||
private_key_path: "/app/wishpal-ironfan/etc/mix/wxpaycert/apiclient_key.pem"
|
||||
notify_url: "https://api.tiefen.fun/ext/vas/wxpay_callback"
|
||||
|
||||
apollo:
|
||||
app_id: "wishpal_live_service"
|
||||
cluster: "dev"
|
||||
|
|
|
@ -28,10 +28,12 @@ mix_mysql:
|
|||
write_timeout_s: 3
|
||||
|
||||
wxpay:
|
||||
mchid: "1111"
|
||||
serial_no: "1111"
|
||||
apiv3_key: "1111"
|
||||
private_key: "af21aw65aw23efwa132f1waef56wa56awef"
|
||||
mchid: "1665016206"
|
||||
appid: "wxc28fd8aaf31984b6"
|
||||
serial_no: "51D8E75620B9569F10FF5363022F3C9D2152DF50"
|
||||
apiv3_key: "UoaswgnuKYwIadqxCVag1IZlq5n9USvt"
|
||||
private_key_path: "/app/wishpal-ironfan/etc/mix/wxpaycert/apiclient_key.pem"
|
||||
notify_url: "https://api.wishpal.cn/ext/vas/wxpay_callback"
|
||||
|
||||
crypto:
|
||||
aes:
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEKDCCAxCgAwIBAgIUUdjnViC5Vp8Q/1NjAi88nSFS31AwDQYJKoZIhvcNAQEL
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||
Q0EwHhcNMjQwMTMwMDIxMDEyWhcNMjkwMTI4MDIxMDEyWjCBgTETMBEGA1UEAwwK
|
||||
MTY2NTAxNjIwNjEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQL
|
||||
DCTmiJDpg73lv4PmhI/liLDkuobnp5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYT
|
||||
AkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAODFaaohlVkRV079c07NzrpSTJgBLr8vNMBY/pZb/Ah+KVoNIMB732NS
|
||||
ykUqXVia5smQMnljZZodw7KKuB9hfcYcyuvXHu+2o43p5A+IZKGV/0eU5AJ2LXOZ
|
||||
SsF4xaPlNyWX6V3JrNhqpHjIbpqGGPUGeypn5bpJr3G1N8y1NSsG8m4ebh1YBBHr
|
||||
YDZN562T1g31zGI7AvsFdomjmFhq6Y2hvPukjPpceoGASEEfpC/yRrvjo05HVQVK
|
||||
8x6oda/67IHNS2F0goUsJESBCYVOhezugmy4XaeyFkqcw+1rde+LzBs9sBlzhvgr
|
||||
Asu/1LEEqJGHO1qAXwqpifWThEHyYUMCAwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsG
|
||||
A1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2Y2Eu
|
||||
aXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRC
|
||||
MDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdB
|
||||
OUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQAcaVb/
|
||||
Eg+fOt1qPr9we38kzUwVRktgamFB3hRfKvZpva3hx4lh8ZC3Et7bIP/r4IV5qCNC
|
||||
wzN1Niq0aBXtnehOWL+mnnBmmW5QnB80UX1/yFxtaBEK+6R6IObAj7ClUSb0F8ak
|
||||
0fRkCyWGl985sAUyZVE5g0jQEEcWFhdV9lpwPdprY4S9vck+cCfjPi4EyxEzRh7z
|
||||
knsvZbjoj/0oTSKgg39D4UEQl6X0e3YR74kIXfKmFK08WxoKKet201pL3bzJKBAY
|
||||
s+8VBqAKsTvNZJ1/GYPqax7ArpACX4LjgmzCv7/rrM75ce6rXWlkIOBSAz2dHuF0
|
||||
Q6iPI92vMh32p19Q
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDgxWmqIZVZEVdO
|
||||
/XNOzc66UkyYAS6/LzTAWP6WW/wIfilaDSDAe99jUspFKl1YmubJkDJ5Y2WaHcOy
|
||||
irgfYX3GHMrr1x7vtqON6eQPiGShlf9HlOQCdi1zmUrBeMWj5Tcll+ldyazYaqR4
|
||||
yG6ahhj1BnsqZ+W6Sa9xtTfMtTUrBvJuHm4dWAQR62A2Teetk9YN9cxiOwL7BXaJ
|
||||
o5hYaumNobz7pIz6XHqBgEhBH6Qv8ka746NOR1UFSvMeqHWv+uyBzUthdIKFLCRE
|
||||
gQmFToXs7oJsuF2nshZKnMPta3Xvi8wbPbAZc4b4KwLLv9SxBKiRhztagF8KqYn1
|
||||
k4RB8mFDAgMBAAECggEAFfMxXmvpKcmHvS8DE68FgSyITk/PQNxbSm1mb0iMVEf9
|
||||
wc2GZUWziv+KwTZh50U5RHXQeAo84dAGTGk/kdDzd2VYa6+WVdKAJluw6dNoAF+l
|
||||
jlf77EGeLqvJoRsqMdcwi3tKTt5jAr9nUGRCaNSvmz4GyR1cUdTgTTplOJh5mLnm
|
||||
GGZQPVR87pex00QCTtQ7dggG/vg8QM+XbBeSAkWByeUDsrCo4pKbsY+kxKGCkhV0
|
||||
3hxgHz2v7QZ8kanbgVPZzB76tOxRf9ghUQ5TFPc9kjgtQmn5ViqzMTXdotFXlE/u
|
||||
n82BreEK03E9kWE3Uvt9jf21oJkQGQsRqTNYd8uIAQKBgQDyNOIIOnOgwt3coiZk
|
||||
LYmo+F/zQQm6R8gebYWO1XCKLkMto9JaeJyEpehZQngMJvJc4r+4tWNFv8rcOHu5
|
||||
/7SnteVUJK4RBXpKosLqswqD0ySEXzNLloumvxXz8HnXIiTSQ3rtISQSHzp0uunq
|
||||
fkTzezc9ZRT08Jx6rmLvpKsJ3QKBgQDtklbus1fRQ/zbdddKbTfYMZsWSi7qQiA3
|
||||
AKM7rY6wrS1gUJtVk9mhNgUe0uIvkkdQvtm/QKiSrtgGkre59g9sekZppCyWId6a
|
||||
i1tlFvkG16Oc/TsAJDBNJgtWrkPDsjjHSx2VExTeRJ30XGd8lx3EEWHEbSboGPbf
|
||||
G3gxm9a1nwKBgAdH06uPpj4k3WpubV0BiWvM24WCZPp2get4O1WJ0PI2ZcqPbBlQ
|
||||
GtRZ8FwOhXFIEmz8W+r/eNZ153ErOXzj1NhdvWEEIT9dvMlVjypi62P/Cs/31KDn
|
||||
C5edktlcVy1CV30CjkVmg6EP00ADBlkIJqZzA7wSt8iNGwcNCuhNON75AoGBAOGA
|
||||
GXIj24RwM1Agr8UenHZix6HFsnh7YdazjT11RU7gYoTcnkUBvP5vpzaV10puX7D+
|
||||
JvOJrTjmK3k5xJkIPaWq/rEBu6yZ45DwHEV9I81h3BSErX852nswVGznprzXq1tI
|
||||
KoE5BoLfwMqU90nkqsVT9mgbb2W5ZINrsI/uK0RjAoGBAL+9L8iJx6/M4yQosTrQ
|
||||
IL6SOxPU3HlfkqZzObiQ8vs7VdIpGhB1EMc9UEKe8RcnpTUeLsVeNHdiDZzRHtJ3
|
||||
RxZS/AsjJtYAZ2f/maJhgQsh6JN1AceDhMhx1iTsjr/ockyUZuXKiCr5Q43tzrMJ
|
||||
tMrOrkquEUSn+XDIomat7Bnw
|
||||
-----END PRIVATE KEY-----
|
|
@ -64,9 +64,11 @@ type RedisConfig struct {
|
|||
// 微信支付客户端配置
|
||||
type WxpayClientConfig struct {
|
||||
MchId string `json:"mchid" yaml:"mchid"` // 商户id
|
||||
AppId string `json:"appid" yaml:"appid"` // appid
|
||||
SerialNo string `json:"serial_no" yaml:"serial_no"` // 商户API证书的证书序列号
|
||||
ApiV3Key string `json:"apiv3_key" yaml:"apiv3_key"` // APIv3Key,商户平台获取
|
||||
PrivateKey string `json:"private_key" yaml:"private_key"` // 商户API证书下载后,私钥 apiclient_key.pem 读取后的字符串内容
|
||||
PrivateKeyPath string `json:"private_key_path" yaml:"private_key_path"` // 商户API证书下载后,私钥 apiclient_key.pem 读取后的字符串内容
|
||||
NotifyUrl string `json:"notify_url" yaml:"notify_url"` // 回调地址
|
||||
}
|
||||
|
||||
// 账号相关验密配置
|
||||
|
|
|
@ -1,24 +1,117 @@
|
|||
package wxpaycli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
wxpay "github.com/go-pay/gopay/wechat/v3"
|
||||
|
||||
"service/bizcommon/util"
|
||||
"service/library/configcenter"
|
||||
"service/library/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultOrderTimeoutSeconds = 900 // 默认订单超时时间,单位: s
|
||||
)
|
||||
|
||||
var defaultWxpayClient *WxpayClient
|
||||
|
||||
type WxpayClient struct {
|
||||
*wxpay.ClientV3
|
||||
AppId string `json:"app_id"`
|
||||
NotifyUrl string `json:"notify_url"`
|
||||
}
|
||||
|
||||
func NewWxpayClient(cfg *configcenter.WxpayClientConfig) (cli *WxpayClient, err error) {
|
||||
wxPayCli, err := wxpay.NewClientV3(cfg.MchId, cfg.SerialNo, cfg.ApiV3Key, cfg.PrivateKey)
|
||||
func GetDefaultWxpayClient() *WxpayClient {
|
||||
return defaultWxpayClient
|
||||
}
|
||||
|
||||
func Init(cfg *configcenter.WxpayClientConfig) (err error) {
|
||||
// private key
|
||||
bs, err := os.ReadFile(cfg.PrivateKeyPath)
|
||||
if err != nil {
|
||||
logger.Error("real PrivateKeyPath fail, cfg: %v, err: %v", util.ToJson(cfg), err)
|
||||
return
|
||||
}
|
||||
privateKey := string(bs)
|
||||
|
||||
wxpayCli, err := wxpay.NewClientV3(cfg.MchId, cfg.SerialNo, cfg.ApiV3Key, privateKey)
|
||||
if err != nil {
|
||||
logger.Error("NewClientV3 fail, cfg: %v, err: %v", util.ToJson(cfg), err)
|
||||
return
|
||||
}
|
||||
cli = &WxpayClient{
|
||||
wxPayCli,
|
||||
|
||||
defaultWxpayClient = &WxpayClient{
|
||||
ClientV3: wxpayCli,
|
||||
AppId: cfg.AppId,
|
||||
NotifyUrl: cfg.NotifyUrl,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 验签
|
||||
func (c *WxpayClient) ParseNotify(req *http.Request) (notify *wxpay.V3DecryptResult, err error) {
|
||||
notifyReq, err := wxpay.V3ParseNotify(req)
|
||||
if err != nil {
|
||||
logger.Error("V3ParseNotify fail, notifyReq: %v, err: %v", util.ToJson(notifyReq), err)
|
||||
return
|
||||
}
|
||||
if notifyReq == nil {
|
||||
logger.Error("V3ParseNotify nil, err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
notifyTmp, err := notifyReq.DecryptCipherText(string(c.ApiV3Key))
|
||||
if err != nil {
|
||||
logger.Error("DecryptCipherText fail, notifyTmp: %v, err: %v", util.ToJson(notifyTmp), err)
|
||||
return
|
||||
}
|
||||
if notifyTmp == nil {
|
||||
logger.Error("DecryptCipherText nil, err: %v", err)
|
||||
return
|
||||
}
|
||||
logger.Info("Wxpay ParseNotify, %v", util.ToJson(notifyTmp))
|
||||
|
||||
notify = notifyTmp
|
||||
return
|
||||
}
|
||||
|
||||
// 微信支付 native支付
|
||||
type NativePayParam struct {
|
||||
Description string
|
||||
OutTradeNo string // 商家订单id,我们自己的订单id
|
||||
TotalAmount int64 // 金额,单位:分
|
||||
TimeOutSeconds int // 订单有效时间,单位:秒
|
||||
}
|
||||
|
||||
func (c *WxpayClient) NativePay(ctx context.Context, param *NativePayParam) (wxpayNativeParamStr string, err error) {
|
||||
if param.TimeOutSeconds <= 0 {
|
||||
param.TimeOutSeconds = DefaultOrderTimeoutSeconds
|
||||
}
|
||||
bm := gopay.BodyMap{
|
||||
"appid": c.AppId,
|
||||
"description": param.Description,
|
||||
"out_trade_no": param.OutTradeNo,
|
||||
"time_expire": time.Now().Add(time.Second * time.Duration(param.TimeOutSeconds)).Format(time.RFC3339),
|
||||
"notify_url": c.NotifyUrl,
|
||||
"amount": gopay.BodyMap{
|
||||
"total": param.TotalAmount,
|
||||
"currency": "CNY",
|
||||
},
|
||||
}
|
||||
resp, err := c.V3TransactionNative(ctx, bm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.Code != wxpay.Success {
|
||||
logger.Info("wxpay NativePay fail, code: %v, error: %v, response: %v", resp.Code, resp.Error, util.ToJson(resp.Response))
|
||||
return
|
||||
}
|
||||
wxpayNativeParamStr = resp.Response.CodeUrl
|
||||
logger.Info("wxpay NativePay success, code: %v, error: %v, response: %v", resp.Code, resp.Error, util.ToJson(resp.Response))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package wxpaycli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"service/app/mix/conf"
|
||||
"service/library/configcenter"
|
||||
"service/library/idgenerator"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := new(conf.ConfigSt)
|
||||
err := configcenter.LoadConfig("/Users/erwin/wishpalv2/service/etc/mix/mix-test.yaml", cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
}
|
||||
|
||||
err = Init(cfg.Wxpay)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestWxpayClient_NativePay(t *testing.T) {
|
||||
cli := GetDefaultWxpayClient()
|
||||
resp, err := cli.NativePay(context.Background(), &NativePayParam{
|
||||
Description: "测试哈哈",
|
||||
OutTradeNo: idgenerator.GenOrderId(),
|
||||
TotalAmount: 1,
|
||||
TimeOutSeconds: 3600 * 24,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
t.Log(fmt.Sprintf("%#v", resp))
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue