Merge remote-tracking branch 'origin/main' into feat-20240117-001-Robin

This commit is contained in:
Leufolium 2024-02-07 13:51:00 +08:00
commit 5079d25bb3
20 changed files with 409 additions and 92 deletions

View File

@ -146,7 +146,7 @@ var ErrCodeMsgMap = map[ErrCode]string{
ErrCodeMomentCreateTimesSrvFail: "动态创建频次表服务错误",
ErrCodeMomentCreateTimesNotExist: "动态创建频次表不存在",
ErrCodeMomentCreateTimesReachedDailyUpperbound: "动态创建次数已达每日上限",
ErrCodeMomentCreateTimesReachedDailyUpperbound: "每天仅可发布三条动态",
ErrCodeAlignedAuditTaskSrvFail: "已对齐审核任务服务错误",
ErrCodeAlignedAuditTaskNotExist: "已对齐审核任务不存在",

View File

@ -25,9 +25,15 @@ type GetMembershipProductListData struct {
// 创建订单
const (
PayTypeOp = "op" // op直冲
PayTypeAlipay = "alipay" // 支付宝
PayTypeAlipayH5 = "alipay_h5" // 支付宝 h5
PayTypeOp = "op" // op直冲
PayTypeAlipay = "alipay" // 支付宝
PayTypeAlipayH5 = "alipay_h5" // 支付宝 h5
PayTypeWxpayNative = "wxpay_native" // 微信native
)
const (
CallBackPayTypeAlipay = "alipay"
CallBackPayTypeWxpay = "wxpay"
)
const (
@ -53,9 +59,10 @@ type CreateOrderReq struct {
}
type CreateOrderData struct {
OrderId string `json:"order_id"` // 订单id
AlipayParamStr string `json:"alipay_param_str"` // 支付宝 app支付参数
AlipayH5ParamStr string `json:"alipay_h5_param_str"` // 支付宝 h5支付参数
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支付参数
}
// 预解锁联系方式
@ -132,10 +139,11 @@ type H5DirectUnlockWechatReq struct {
}
type H5DirectUnlockWechatData struct {
CoinEnough int32 `json:"coin_enough"` // 0:不够(用下面的支付宝参数)1:够
OrderId string `json:"order_id"` // 订单id
AlipayParamStr string `json:"alipay_param_str"` // 支付宝 app支付参数
AlipayH5ParamStr string `json:"alipay_h5_param_str"` // 支付宝 h5支付参数
CoinEnough int32 `json:"coin_enough"` // 0:不够(用下面的支付宝参数)1:够
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

View File

@ -19,9 +19,10 @@ func AlipayCallback(ctx *gin.Context) {
}
if bm.GetString("trade_status") == "TRADE_SUCCESS" {
service.DefaultService.AlipayCallback(ctx, &vasproto.AlipayCallbackParamIn{
OrderId: bm.GetString("out_trade_no"),
AlipayOrderId: bm.GetString("trade_no"),
service.DefaultService.PayCallback(ctx, &vasproto.PayCallbackParamIn{
OrderId: bm.GetString("out_trade_no"),
OutOrderId: bm.GetString("trade_no"),
CallbackPayType: vasproto.CallBackPayTypeAlipay,
})
}
ctx.String(200, "success")

View File

@ -227,6 +227,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)

View File

@ -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")
}

View File

@ -287,6 +287,7 @@ func (l *AuthBusinessValidator) EnsureMomentCreateTimesNotReachedDailyUpperbound
return
}
logger.Info("momentCreateTimes: %v, maxDailyMomentCreateTimes : %v", l.momentCreateTimes.CreateTimes, maxDailyMomentCreateTimes)
if l.momentCreateTimes.CreateTimes >= int64(maxDailyMomentCreateTimes) {
logger.Error("the moment create times of this mid has reached its daily upperbound")
l.ec = errcode.ErrCodeMomentCreateTimesReachedDailyUpperbound

View File

@ -191,14 +191,23 @@ func (m *Media) saveImage(ctx *gin.Context, image *dbstruct.Image) (*dbstruct.Im
}
id := mediaSeqId.Seq
doc := &dbstruct.Image{
Id: id,
Ct: time.Now().Unix(),
Ut: time.Now().Unix(),
SrcId: image.SrcId,
MD5: image.MD5,
W: image.W,
H: image.H,
Fmt: image.Fmt,
Id: id,
Ct: time.Now().Unix(),
Ut: time.Now().Unix(),
SrcId: image.SrcId,
SizeSrc: 0,
SrcId720: "",
Size720: 0,
SrcId1080: "",
Size1080: 0,
SrcId1440: "",
Size1440: 0,
Status: 0,
ResizeT: 0,
MD5: image.MD5,
W: image.W,
H: image.H,
Fmt: image.Fmt,
}
err = m.store.SaveImage(ctx, doc)
if err != nil {

View File

@ -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"
@ -93,8 +94,9 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
orderId = idgenerator.GenOrderId() // 订单id
)
var (
alipayParamStr string
alipayH5ParamStr string
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
}
}
@ -230,9 +245,10 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
}
data = &vasproto.CreateOrderData{
OrderId: orderId,
AlipayParamStr: alipayParamStr,
AlipayH5ParamStr: alipayH5ParamStr,
OrderId: orderId,
AlipayParamStr: alipayParamStr,
AlipayH5ParamStr: alipayH5ParamStr,
WxpayNativeParamStr: wxpayNativeParamStr,
}
return
}
@ -1497,9 +1513,10 @@ func (v *Vas) H5DirectUnlockWechat(ctx *gin.Context, req *vasproto.H5DirectUnloc
return
}
data = &vasproto.H5DirectUnlockWechatData{
OrderId: cData.OrderId,
AlipayParamStr: cData.AlipayParamStr,
AlipayH5ParamStr: cData.AlipayH5ParamStr,
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
afterStatus int32
orderId = p.OrderId
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,28 +2080,35 @@ func (v *Vas) DealOneOrder(ctx *gin.Context, orderId string) (err error) {
}
// 支付宝查询订单
alipayCli := alipaycli.GetDefaultAlipayClient()
alipayResp, err := alipayCli.QueryOrder(ctx, &alipaycli.QueryOrderParam{
OutTradeNo: orderId,
})
if err != nil {
logger.Error("alipayCli.QueryOrder fail, id: %v, err: %v", orderId, err)
return
}
if alipayResp == nil {
err = errors.New("alipayCli.QueryOrder resp nil")
logger.Error("alipayCli.QueryOrder nil, id: %v, err: %v", orderId, err)
return
}
// 已退款
if alipayResp.Response.TradeStatus == "TRADE_CLOSED" {
// 更新订单状态
err = v.store.UpdateOrderStatus(ctx, nil, order.GetID(), dbstruct.VasOrderStatusPaySuccess, dbstruct.VasOrderStatusRefund)
switch order.GetPayType() {
case vasproto.PayTypeAlipayH5:
alipayCli := alipaycli.GetDefaultAlipayClient()
var alipayResp *alipay.TradeQueryResponse
alipayResp, err = alipayCli.QueryOrder(ctx, &alipaycli.QueryOrderParam{
OutTradeNo: orderId,
})
if err != nil {
logger.Error("UpdateOrderStatus fail, orderId: %v, err: %v", order.GetID(), err)
logger.Error("alipayCli.QueryOrder fail, id: %v, err: %v", orderId, err)
return
}
err = errors.New("closed order")
if alipayResp == nil {
err = errors.New("alipayCli.QueryOrder resp nil")
logger.Error("alipayCli.QueryOrder nil, id: %v, err: %v", orderId, err)
return
}
// 已退款
if alipayResp.Response.TradeStatus == "TRADE_CLOSED" {
// 更新订单状态
err = v.store.UpdateOrderStatus(ctx, nil, order.GetID(), dbstruct.VasOrderStatusPaySuccess, dbstruct.VasOrderStatusRefund)
if err != nil {
logger.Error("UpdateOrderStatus fail, orderId: %v, err: %v", order.GetID(), err)
return
}
err = errors.New("closed order")
return
}
case vasproto.CallBackPayTypeWxpay:
err = errors.New("暂不处理微信订单")
return
}

View File

@ -48,6 +48,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
}

View File

@ -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
}

View File

@ -6,15 +6,40 @@ import (
)
// 图片
const (
ImageStatusResizeInit = 0
ImageStatusResizeDone = 100
ImageStatusResizeFail = 101
)
type Image struct {
Id int64 `json:"id" bson:"_id"` // 图片id
Ct int64 `json:"ct" bson:"ct"` // 创建时间
Ut int64 `json:"ut" bson:"ut"` // 更新时间
SrcId string `json:"src_id" bson:"src_id"` // 源id
MD5 string `json:"md5" bson:"md5"` // 视频md5
W int64 `json:"w" bson:"w"` // 宽
H int64 `json:"h" bson:"h"` // 高
Fmt string `json:"fmt" bson:"fmt"` // 图片格式
Id int64 `json:"id" bson:"_id"` // 图片id
Ct int64 `json:"ct" bson:"ct"` // 创建时间
Ut int64 `json:"ut" bson:"ut"` // 更新时间
SrcId string `json:"src_id" bson:"src_id"` // 源id
SizeSrc int64 `json:"size_src" bson:"size_src"` // 原图片大小
SrcId720 string `json:"src_id_720" bson:"src_id_720"` // 720P图片
Size720 int64 `json:"size_720" bson:"size_720"` // 720P图片大小
SrcId1080 string `json:"src_id_1080" bson:"src_id_1080"` // 1080P图片
Size1080 int64 `json:"size_1080" bson:"size_1080"` // 1080P图片大小
SrcId1440 string `json:"src_id_1440" bson:"src_id_1440"` // 1440P图片
Size1440 int64 `json:"size_1440" bson:"size_1440"` // 1440P图片大小
Status int `json:"status" bson:"status"` // 状态
ResizeT int64 `json:"resize_t" bson:"resize_t"` // 压缩时间
MD5 string `json:"md5" bson:"md5"` // 视频md5
W int64 `json:"w" bson:"w"` // 宽
H int64 `json:"h" bson:"h"` // 高
Fmt string `json:"fmt" bson:"fmt"` // 图片格式
}
func (i *Image) SelectMinSizeOssId() string {
if i == nil {
return ""
}
if len(i.SrcId720) > 0 && i.Size720 < i.SizeSrc {
return i.SrcId720
}
return i.SrcId
}
type ToCImage struct {

View File

@ -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"

View File

@ -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.

View File

@ -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-----

View File

@ -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-----

View File

@ -63,10 +63,12 @@ type RedisConfig struct {
// 微信支付客户端配置
type WxpayClientConfig struct {
MchId string `json:"mchid" yaml:"mchid"` // 商户id
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 读取后的字符串内容
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商户平台获取
PrivateKeyPath string `json:"private_key_path" yaml:"private_key_path"` // 商户API证书下载后私钥 apiclient_key.pem 读取后的字符串内容
NotifyUrl string `json:"notify_url" yaml:"notify_url"` // 回调地址
}
// 账号相关验密配置

View File

@ -46,12 +46,16 @@ func transToCImage(image *dbstruct.Image) *dbstruct.ToCImage {
if image == nil {
return nil
}
// 选择内存最小的图片
imgSrcId := image.SelectMinSizeOssId()
return &dbstruct.ToCImage{
Id: image.Id,
W: image.W,
H: image.H,
Fmt: image.Fmt,
Urls: []string{defaultMediaFiller.fileServerDomainName + image.SrcId},
Urls: []string{defaultMediaFiller.fileServerDomainName + imgSrcId},
}
}
@ -70,7 +74,8 @@ func transToCVideo(video *dbstruct.Video, coverImg *dbstruct.Image) *dbstruct.To
ret.CoverW = coverImg.W
ret.CoverH = coverImg.H
ret.CoverFmt = coverImg.Fmt
ret.CoverUrls = []string{defaultMediaFiller.fileServerDomainName + coverImg.SrcId}
imgSrcId := coverImg.SelectMinSizeOssId()
ret.CoverUrls = []string{defaultMediaFiller.fileServerDomainName + imgSrcId}
}
return ret
}

View File

@ -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
}

View File

@ -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
}