支付调起+订单查询
This commit is contained in:
parent
0b844afa5f
commit
c1e354e4ab
|
@ -4,6 +4,7 @@ const (
|
||||||
TOKEN_PRE = "player_token_"
|
TOKEN_PRE = "player_token_"
|
||||||
TOKEN_Admin = "Admin_token_"
|
TOKEN_Admin = "Admin_token_"
|
||||||
ADMIN_V1 = "/admin/pay/api/v1"
|
ADMIN_V1 = "/admin/pay/api/v1"
|
||||||
|
FRONT_API_V1 = "/v1"
|
||||||
|
|
||||||
// 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
// 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||||
PAY_CHANNEL_UNKNOWN = 0
|
PAY_CHANNEL_UNKNOWN = 0
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package data
|
|
||||||
|
|
||||||
import "PaymentCenter/app/models/ordersmodel"
|
|
||||||
|
|
||||||
func GetOrderInfoById(id int64) (orderInfo ordersmodel.Orders, err error) {
|
|
||||||
_, err = ordersmodel.GetInstance().GetDb().Where("Id = ?", id).Get(&orderInfo)
|
|
||||||
if err != nil {
|
|
||||||
return ordersmodel.Orders{}, err
|
|
||||||
}
|
|
||||||
return orderInfo, nil
|
|
||||||
}
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package front
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-pay/gopay/alipay"
|
||||||
|
"github.com/go-pay/xlog"
|
||||||
|
"github.com/qit-team/snow-core/log/logger"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WxCallback 微信支付回调
|
||||||
|
//func WxCallback(c *gin.Context) {
|
||||||
|
// notifyReq, err := wechat.V3ParseNotify(c.Request)
|
||||||
|
// if err != nil {
|
||||||
|
// xlog.Error(err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// paymentService.WxPayCallBack(notifyReq)
|
||||||
|
//
|
||||||
|
// // ====↓↓↓====异步通知应答====↓↓↓====
|
||||||
|
// // 退款通知http应答码为200且返回状态码为SUCCESS才会当做商户接收成功,否则会重试。
|
||||||
|
// // 注意:重试过多会导致微信支付端积压过多通知而堵塞,影响其他正常通知。
|
||||||
|
//
|
||||||
|
// // 此写法是 gin 框架返回微信的写法
|
||||||
|
// c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
|
||||||
|
//}
|
||||||
|
|
||||||
|
// AliCallback 支付宝支付回调
|
||||||
|
func AliCallback(c *gin.Context) {
|
||||||
|
notifyReq, err := alipay.ParseNotifyToBodyMap(c.Request) // c.Request 是 gin 框架的写法
|
||||||
|
logger.Info(c, "AliCallback-回调数据", c.Request)
|
||||||
|
if err != nil {
|
||||||
|
xlog.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appId := notifyReq.Get("app_id")
|
||||||
|
if appId == "" {
|
||||||
|
c.String(http.StatusBadRequest, "%s", "fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo 查询支付宝公钥证书信息,进行验证签名
|
||||||
|
alipayPublicCert := ""
|
||||||
|
ok, err := alipay.VerifySignWithCert([]byte(alipayPublicCert), notifyReq)
|
||||||
|
if !ok {
|
||||||
|
logger.Error(c, "AliCallback-回调数据,验签失败")
|
||||||
|
c.String(http.StatusBadRequest, "%s", "fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo 拼装数据触发下游回调,数据待定
|
||||||
|
|
||||||
|
c.String(http.StatusOK, "%s", "success")
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package front
|
||||||
|
|
||||||
|
type WxRequest struct {
|
||||||
|
TradeNo string `json:"tradeNo" validate:"required"` // 交易流水号
|
||||||
|
VoucherId string `json:"voucherId"` // 制码批次号
|
||||||
|
VoucherCode string `json:"voucherCode"` // 串码
|
||||||
|
CnclSt string `json:"cnclSt"` // 核销状态,4-已核销
|
||||||
|
RedeemResult string `json:"redeemResult"` // 核销结果,00-成功,09- 失败
|
||||||
|
MrchntNo string `json:"mrchntNo"` // 商户号
|
||||||
|
Sign string `json:"sign"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AliRequest struct {
|
||||||
|
MerchantId int `form:"merchantId" validate:"required"`
|
||||||
|
OutTradeNo string `form:"outTradeNo" validate:"required"`
|
||||||
|
Status string `form:"status" validate:"required"`
|
||||||
|
RechargeAccount string `form:"rechargeAccount"`
|
||||||
|
CardCode string `form:"cardCode"`
|
||||||
|
Sign string `form:"sign" validate:"required"`
|
||||||
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
package requestmapping
|
package requestmapping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"PaymentCenter/app/constants/common"
|
||||||
|
"PaymentCenter/app/http/entities/front"
|
||||||
|
)
|
||||||
|
|
||||||
var FrontRequestMap = map[string]func() interface{}{
|
var FrontRequestMap = map[string]func() interface{}{
|
||||||
//"/v1/login": func() interface{} {
|
common.FRONT_API_V1 + "/notify/wx": func() interface{} { return new(front.WxRequest) },
|
||||||
// return new(front.LoginRequest)
|
common.FRONT_API_V1 + "/notify/ali": func() interface{} { return new(front.AliRequest) },
|
||||||
//},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ package routes
|
||||||
*/
|
*/
|
||||||
import (
|
import (
|
||||||
"PaymentCenter/app/http/controllers"
|
"PaymentCenter/app/http/controllers"
|
||||||
|
"PaymentCenter/app/http/controllers/front"
|
||||||
"PaymentCenter/app/http/middlewares"
|
"PaymentCenter/app/http/middlewares"
|
||||||
"PaymentCenter/app/http/trace"
|
"PaymentCenter/app/http/trace"
|
||||||
"PaymentCenter/app/utils/metric"
|
"PaymentCenter/app/utils/metric"
|
||||||
|
@ -49,6 +50,16 @@ func RegisterRoute(router *gin.Engine) {
|
||||||
//
|
//
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
v1 := router.Group("/v1", middlewares.ValidateRequest())
|
||||||
|
{
|
||||||
|
//回调处理
|
||||||
|
notify := v1.Group("/notify")
|
||||||
|
{
|
||||||
|
notify.POST("/wx", front.WxCallback)
|
||||||
|
notify.POST("/ali", front.AliCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||||
|
|
||||||
//router.GET("/hello", controllers.HelloHandler)
|
//router.GET("/hello", controllers.HelloHandler)
|
||||||
|
|
|
@ -14,7 +14,7 @@ func SingleTalk(tag uint64, ch interface{}, msg []byte) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// if !sendOk {
|
// if !sendOk {
|
||||||
// common.PikaTool.Zadd(utils.GetRealKey(common2.USER_MSG)+data.Msg.To, data, time.Now().Unix())
|
// payCommon.PikaTool.Zadd(utils.GetRealKey(common2.USER_MSG)+data.Msg.To, data, time.Now().Unix())
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"PaymentCenter/app/constants/common"
|
|
||||||
"PaymentCenter/app/constants/errorcode"
|
|
||||||
"PaymentCenter/app/data"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"github.com/go-pay/gopay"
|
|
||||||
"github.com/go-pay/gopay/wechat/v3"
|
|
||||||
"github.com/go-pay/xlog"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ActivityGoodsCreateService(orderId int64) (err error) {
|
|
||||||
// 获取订单信息
|
|
||||||
orderInfo, err := data.GetOrderInfoById(orderId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if orderInfo.PayId == 0 {
|
|
||||||
return errors.New("缺少订单信息,无法进行支付")
|
|
||||||
}
|
|
||||||
// 获取支付渠道
|
|
||||||
payChannelInfo, err := data.GetPayChannelById(orderInfo.PayId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch payChannelInfo.ChannelType {
|
|
||||||
case common.PAYCHANNEL_WX_H5:
|
|
||||||
//todo 微信H5支付
|
|
||||||
wxH5PayInfo()
|
|
||||||
break
|
|
||||||
case common.PAYCHANNEL_ALI_H5:
|
|
||||||
//todo 支付宝H5支付
|
|
||||||
aLiH5PayInfo()
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return errors.New("暂不支持该支付渠道,请后续再使用")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func wxH5PayInfo(c context.Context) {
|
|
||||||
// NewClientV3 初始化微信客户端 v3
|
|
||||||
// mchid:商户ID 或者服务商模式的 sp_mchid
|
|
||||||
// serialNo:商户证书的证书序列号
|
|
||||||
// apiV3Key:apiV3Key,商户平台获取
|
|
||||||
// privateKey:私钥 apiclient_key.pem 读取后的内容
|
|
||||||
client, err := wechat.NewClientV3(MchId, SerialNo, APIv3Key, PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置微信平台API证书和序列号(推荐开启自动验签,无需手动设置证书公钥等信息)
|
|
||||||
//client.SetPlatformCert([]byte(""), "")
|
|
||||||
|
|
||||||
// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
|
|
||||||
err = client.AutoVerifySign()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义配置http请求接收返回结果body大小,默认 10MB
|
|
||||||
client.SetBodySize(10) // 没有特殊需求,可忽略此配置
|
|
||||||
|
|
||||||
// 打开Debug开关,输出日志,默认是关闭的
|
|
||||||
client.DebugSwitch = gopay.DebugOn
|
|
||||||
expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
|
|
||||||
// 初始化 BodyMap
|
|
||||||
bm := make(gopay.BodyMap)
|
|
||||||
bm.Set("sp_appid", "sp_appid").
|
|
||||||
Set("sp_mchid", "sp_mchid").
|
|
||||||
Set("sub_mchid", "sub_mchid").
|
|
||||||
Set("description", "测试Jsapi支付商品").
|
|
||||||
Set("out_trade_no", tradeNo).
|
|
||||||
Set("time_expire", expire).
|
|
||||||
Set("notify_url", "https://www.fmm.ink").
|
|
||||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
|
||||||
bm.Set("total", 1).
|
|
||||||
Set("currency", "CNY")
|
|
||||||
}).
|
|
||||||
SetBodyMap("payer", func(bm gopay.BodyMap) {
|
|
||||||
bm.Set("sp_openid", "asdas")
|
|
||||||
})
|
|
||||||
|
|
||||||
wxRsp, err := client.V3TransactionH5(c, bm)
|
|
||||||
if err != nil {
|
|
||||||
xlog.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if wxRsp.Code == errorcode.Success {
|
|
||||||
xlog.Debugf("wxRsp: %#v", wxRsp.Response)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
xlog.Errorf("wxRsp:%s", wxRsp.Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func aLiH5PayInfo() {
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
package paymentService
|
||||||
|
|
||||||
|
import (
|
||||||
|
"PaymentCenter/app/third/paymentService/payCommon"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-pay/gopay"
|
||||||
|
"github.com/go-pay/gopay/alipay"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
aliClient *alipay.Client
|
||||||
|
aliClientErr error
|
||||||
|
aliOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// AliInitClient 使用提供的支付请求参数初始化支付宝客户端
|
||||||
|
func AliInitClient(aliConfig AliPay) {
|
||||||
|
aliOnce.Do(func() {
|
||||||
|
// 初始化支付宝客户端
|
||||||
|
// appid:应用ID
|
||||||
|
// privateKey:应用私钥,支持PKCS1和PKCS8
|
||||||
|
// isProd:是否是正式环境,沙箱环境请选择新版沙箱应用。
|
||||||
|
aliClient, aliClientErr = alipay.NewClient(aliConfig.AppId, aliConfig.PrivateKey, true)
|
||||||
|
})
|
||||||
|
// 自定义配置http请求接收返回结果body大小,默认 10MB
|
||||||
|
aliClient.SetBodySize(10) // 没有特殊需求,可忽略此配置
|
||||||
|
|
||||||
|
// 打开Debug开关,输出日志,默认关闭
|
||||||
|
aliClient.DebugSwitch = gopay.DebugOn
|
||||||
|
|
||||||
|
// 设置支付宝请求 公共参数
|
||||||
|
// 注意:具体设置哪些参数,根据不同的方法而不同,此处列举出所有设置参数
|
||||||
|
aliClient.SetLocation(alipay.LocationShanghai). // 设置时区,不设置或出错均为默认服务器时间
|
||||||
|
SetCharset(alipay.UTF8). // 设置字符编码,不设置默认 utf-8
|
||||||
|
SetSignType(alipay.RSA2) // 设置签名类型,不设置默认 RSA2
|
||||||
|
|
||||||
|
// 自动同步验签(只支持证书模式)
|
||||||
|
// 传入 alipayPublicCert.crt 内容
|
||||||
|
aliClient.AutoVerifySign(aliConfig.AlipayPublicCert)
|
||||||
|
|
||||||
|
// 证书内容
|
||||||
|
aliClientErr = aliClient.SetCertSnByContent(aliConfig.AppPublicCert, aliConfig.AlipayRootCert, aliConfig.AlipayPublicCert)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAliClient 获取已经初始化的支付宝客户端
|
||||||
|
func GetAliClient() (*alipay.Client, error) {
|
||||||
|
if aliClient == nil {
|
||||||
|
return nil, errors.New("client not initialized")
|
||||||
|
}
|
||||||
|
if aliClientErr != nil {
|
||||||
|
return nil, aliClientErr
|
||||||
|
}
|
||||||
|
return aliClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALiH5PayInfo 支付宝手机网站支付
|
||||||
|
func ALiH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
|
||||||
|
// 初始化支付宝客户端
|
||||||
|
AliInitClient(payOrderRequest.Ali)
|
||||||
|
|
||||||
|
// 获取支付宝客户端
|
||||||
|
aliClient, err := GetAliClient()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to get client:", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// 初始化 BodyMap
|
||||||
|
amount := float64(payOrderRequest.Amount) / 100.0
|
||||||
|
|
||||||
|
bm := make(gopay.BodyMap)
|
||||||
|
bm.Set("out_trade_no", payOrderRequest.OrderId).
|
||||||
|
Set("total_amount", amount).
|
||||||
|
Set("subject", payOrderRequest.Description).
|
||||||
|
Set("notify_url", payCommon.ALI_NOTIFY_URL)
|
||||||
|
|
||||||
|
aliRsp, err := aliClient.TradeWapPay(c, bm)
|
||||||
|
if err != nil {
|
||||||
|
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||||
|
return "", bizErr
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return aliRsp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALiOrderQuery 查询支付宝订单
|
||||||
|
func ALiOrderQuery(ctx context.Context, aliConfig AliPay, OrderNo string) (PayOrderQueryInfo, error) {
|
||||||
|
// 初始化支付宝客户端
|
||||||
|
AliInitClient(aliConfig)
|
||||||
|
|
||||||
|
// 获取支付宝客户端
|
||||||
|
aliClient, err := GetAliClient()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to get client:", err)
|
||||||
|
return PayOrderQueryInfo{}, err
|
||||||
|
}
|
||||||
|
// 请求参数
|
||||||
|
bm := make(gopay.BodyMap)
|
||||||
|
bm.Set("out_trade_no", OrderNo)
|
||||||
|
|
||||||
|
// 查询订单
|
||||||
|
aliRsp, err := aliClient.TradeQuery(ctx, bm)
|
||||||
|
if err != nil {
|
||||||
|
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||||
|
return PayOrderQueryInfo{}, bizErr
|
||||||
|
}
|
||||||
|
return PayOrderQueryInfo{}, err
|
||||||
|
}
|
||||||
|
// 同步返回验签
|
||||||
|
ok, err := alipay.VerifySyncSignWithCert(aliConfig.AlipayPublicCert, aliRsp.SignData, aliRsp.Sign)
|
||||||
|
if err != nil || !ok {
|
||||||
|
return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("验签失败,失败原因:%s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 映射交易状态
|
||||||
|
tradeState := ""
|
||||||
|
tradeStateDesc := ""
|
||||||
|
switch aliRsp.Response.TradeStatus {
|
||||||
|
case "TRADE_SUCCESS":
|
||||||
|
tradeState = "SUCCESS"
|
||||||
|
tradeStateDesc = "交易支付成功"
|
||||||
|
case "REFUND":
|
||||||
|
tradeState = "REFUND"
|
||||||
|
case "WAIT_BUYER_PAY":
|
||||||
|
tradeState = "NOTPAY"
|
||||||
|
tradeStateDesc = "交易创建,等待买家付款"
|
||||||
|
case "TRADE_CLOSED":
|
||||||
|
tradeState = "CLOSED"
|
||||||
|
tradeStateDesc = "未付款交易超时关闭,或支付完成后全额退款"
|
||||||
|
}
|
||||||
|
|
||||||
|
amountTotal, _ := strconv.Atoi(aliRsp.Response.TotalAmount)
|
||||||
|
payerTotal, _ := strconv.Atoi(aliRsp.Response.BuyerPayAmount)
|
||||||
|
// 构建数据
|
||||||
|
return PayOrderQueryInfo{
|
||||||
|
AppId: aliConfig.AppId,
|
||||||
|
OutTradeNo: aliRsp.Response.OutTradeNo,
|
||||||
|
TransactionId: aliRsp.Response.TradeNo,
|
||||||
|
TradeState: tradeState,
|
||||||
|
TradeStateDesc: tradeStateDesc,
|
||||||
|
SuccessTime: aliRsp.Response.SendPayDate,
|
||||||
|
AmountTotal: int64(amountTotal * 100),
|
||||||
|
PayerTotal: int64(payerTotal * 100),
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package payCommon
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||||
|
PAY_CHANNEL_UNKNOWN = 0
|
||||||
|
PAY_CHANNEL_WECHAT_JSAPI = 1
|
||||||
|
PAY_CHANNEL_WECHAT_H5 = 2
|
||||||
|
PAY_CHANNEL_WECHAT_APP = 3
|
||||||
|
PAY_CHANNEL_WECHAT_NATIVE = 4
|
||||||
|
PAY_CHANNEL_WECHAT_MINI = 5
|
||||||
|
PAY_CHANNEL_ALIPAY_WEB = 6
|
||||||
|
PAY_CHANNEL_ALIPAY_MINI = 7
|
||||||
|
PAY_CHANNEL_ALIPAY_JSAPI = 8
|
||||||
|
|
||||||
|
PAY_SUCCESS_CODE = 200 // 支付响应成功
|
||||||
|
PAY_ERROR_CODE = 500 // 支付响应失败
|
||||||
|
PAY_NOT_FOUND_CODE = 404 // 未找到支付渠道
|
||||||
|
|
||||||
|
WX_SUCCESS_CODE = 200 // 微信状态码返回成功
|
||||||
|
WX_NOTIFY_URL = "" // 微信支付回调地址
|
||||||
|
|
||||||
|
ALI_NOTIFY_URL = "" // 支付宝支付回调地址
|
||||||
|
|
||||||
|
ORDER_NO_TYPE_ORDER_NO = 2
|
||||||
|
|
||||||
|
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
|
||||||
|
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
|
||||||
|
)
|
|
@ -0,0 +1,130 @@
|
||||||
|
package paymentService
|
||||||
|
|
||||||
|
import (
|
||||||
|
"PaymentCenter/app/third/paymentService/payCommon"
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PayOrderRequest struct {
|
||||||
|
OrderId int64 `json:"order_id"` // 平台订单号
|
||||||
|
ChannelType int `json:"channel_type"` // 支付方式
|
||||||
|
Description string `json:"description"` // 商品描述
|
||||||
|
Amount int `json:"amount"` // 金额单位为分
|
||||||
|
PayerClientIp string `json:"payer_client_ip"` // 终端IP
|
||||||
|
Wx WxPay `json:"wx"`
|
||||||
|
Ali AliPay `json:"ali"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WxPay struct {
|
||||||
|
AppId string `json:"app_id"` // 应用ID
|
||||||
|
MchId string `json:"mch_id"` // 商户ID 或者服务商模式的 sp_mchid
|
||||||
|
SerialNo string `json:"serial_no"` // 商户证书的证书序列号
|
||||||
|
ApiV3Key string `json:"api_v_3_key"` // apiV3Key,商户平台获取
|
||||||
|
PrivateKey string `json:"private_key"` // 私钥 apiclient_key.pem 读取后的内容
|
||||||
|
}
|
||||||
|
|
||||||
|
type AliPay struct {
|
||||||
|
AppId string `json:"app_id"` // 应用ID
|
||||||
|
PrivateKey string `json:"private_key"` // 应用私钥
|
||||||
|
AppPublicCert []byte `json:"app_public_cert"` // 应用公钥
|
||||||
|
AlipayRootCert []byte `json:"alipay_root_cert"` // 支付宝根证书
|
||||||
|
AlipayPublicCert []byte `json:"alipay_public_cert"` // 支付宝公钥
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayOrderResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
ErrorMsg string `json:"error_msg"`
|
||||||
|
Result string `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentService 统一发起支付
|
||||||
|
func PaymentService(c context.Context, payOrderRequest PayOrderRequest) (payOrderResponse PayOrderResponse) {
|
||||||
|
switch payOrderRequest.ChannelType {
|
||||||
|
case payCommon.PAY_CHANNEL_WECHAT_H5:
|
||||||
|
// 微信H5支付
|
||||||
|
info, err := WxH5PayInfo(c, payOrderRequest)
|
||||||
|
if err != nil {
|
||||||
|
return PayOrderResponse{
|
||||||
|
Code: payCommon.PAY_ERROR_CODE,
|
||||||
|
ErrorMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PayOrderResponse{
|
||||||
|
Code: payCommon.PAY_SUCCESS_CODE,
|
||||||
|
ErrorMsg: "",
|
||||||
|
Result: info,
|
||||||
|
}
|
||||||
|
case payCommon.PAY_CHANNEL_ALIPAY_WEB:
|
||||||
|
// 支付宝H5支付
|
||||||
|
info, err := ALiH5PayInfo(c, payOrderRequest)
|
||||||
|
if err != nil {
|
||||||
|
return PayOrderResponse{
|
||||||
|
Code: payCommon.PAY_ERROR_CODE,
|
||||||
|
ErrorMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PayOrderResponse{
|
||||||
|
Code: payCommon.PAY_SUCCESS_CODE,
|
||||||
|
ErrorMsg: "",
|
||||||
|
Result: info,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return PayOrderResponse{
|
||||||
|
Code: payCommon.PAY_NOT_FOUND_CODE,
|
||||||
|
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayOrderQueryRequest struct {
|
||||||
|
OrderId int64 `json:"order_id"` // 商户订单号
|
||||||
|
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||||
|
Wx WxPay `json:"wx"`
|
||||||
|
Ali AliPay `json:"ali"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayOrderQueryResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
ErrorMsg string `json:"error_msg"`
|
||||||
|
Result PayOrderQueryInfo `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayOrderQueryInfo struct {
|
||||||
|
AppId string `json:"app_id"` // 应用ID
|
||||||
|
OutTradeNo string `json:"out_trade_no"` // 商家订单号
|
||||||
|
TransactionId string `json:"transaction_id"` // 第三方订单号
|
||||||
|
TradeState string `json:"trade_state"` // 交易状态 SUCCESS:成功、REFUND:转入退款、NOTPAY:未支付、CLOSED:已关闭
|
||||||
|
TradeStateDesc string `json:"trade_state_desc"` // 交易描述
|
||||||
|
SuccessTime string `json:"success_time"` // 交易完成时间
|
||||||
|
AmountTotal int64 `json:"amount_total"` // 订单总金额,单位:分
|
||||||
|
PayerTotal int64 `json:"payer_total"` // 支付总金额,单位:分
|
||||||
|
}
|
||||||
|
|
||||||
|
// PayOrderQuery 查询订单状态
|
||||||
|
func PayOrderQuery(c context.Context, payOrderQueryRequest PayOrderQueryRequest) PayOrderQueryResponse {
|
||||||
|
var err error
|
||||||
|
var info PayOrderQueryInfo
|
||||||
|
switch payOrderQueryRequest.PayChannel {
|
||||||
|
case payCommon.PAY_CHANNLE_TYPE_WECHAT:
|
||||||
|
// 微信H5支付
|
||||||
|
info, err = WxOrderQuery(c, payOrderQueryRequest.Wx, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||||
|
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||||
|
info, err = ALiOrderQuery(c, payOrderQueryRequest.Ali, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||||
|
default:
|
||||||
|
return PayOrderQueryResponse{
|
||||||
|
Code: payCommon.PAY_ERROR_CODE,
|
||||||
|
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return PayOrderQueryResponse{
|
||||||
|
Code: payCommon.PAY_ERROR_CODE,
|
||||||
|
ErrorMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PayOrderQueryResponse{
|
||||||
|
Code: payCommon.PAY_SUCCESS_CODE,
|
||||||
|
Result: info,
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,169 @@
|
||||||
|
package paymentService
|
||||||
|
|
||||||
|
import (
|
||||||
|
"PaymentCenter/app/third/paymentService/payCommon"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-pay/gopay"
|
||||||
|
"github.com/go-pay/gopay/wechat/v3"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
wxClient *wechat.ClientV3
|
||||||
|
clientErr error
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitClient 使用提供的支付请求参数初始化微信客户端
|
||||||
|
func InitClient(wxConfig WxPay) {
|
||||||
|
once.Do(func() {
|
||||||
|
// NewClientV3 初始化微信客户端 v3
|
||||||
|
// mchid:商户ID 或者服务商模式的 sp_mchid
|
||||||
|
// serialNo:商户证书的证书序列号
|
||||||
|
// apiV3Key:apiV3Key,商户平台获取
|
||||||
|
// privateKey:私钥 apiclient_key.pem 读取后的内容
|
||||||
|
wxClient, clientErr = wechat.NewClientV3(
|
||||||
|
wxConfig.MchId,
|
||||||
|
wxConfig.SerialNo,
|
||||||
|
wxConfig.ApiV3Key,
|
||||||
|
wxConfig.PrivateKey,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
|
||||||
|
clientErr = wxClient.AutoVerifySign()
|
||||||
|
|
||||||
|
// 自定义配置http请求接收返回结果body大小,默认 10MB
|
||||||
|
wxClient.SetBodySize(10) // 没有特殊需求,可忽略此配置
|
||||||
|
|
||||||
|
// 打开Debug开关,输出日志,默认是关闭的
|
||||||
|
wxClient.DebugSwitch = gopay.DebugOn
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClient 获取已经初始化的微信客户端
|
||||||
|
func GetClient() (*wechat.ClientV3, error) {
|
||||||
|
if wxClient == nil {
|
||||||
|
return nil, errors.New("client not initialized")
|
||||||
|
}
|
||||||
|
if clientErr != nil {
|
||||||
|
return nil, clientErr
|
||||||
|
}
|
||||||
|
return wxClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WxH5PayInfo 微信H5支付
|
||||||
|
func WxH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
|
||||||
|
// 初始化微信客户端
|
||||||
|
InitClient(payOrderRequest.Wx)
|
||||||
|
|
||||||
|
// 获取微信客户端
|
||||||
|
wxClient, err := GetClient()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to get client:", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
|
||||||
|
// 初始化 BodyMap
|
||||||
|
bm := make(gopay.BodyMap)
|
||||||
|
bm.Set("appid", payOrderRequest.Wx.AppId).
|
||||||
|
Set("mchid", payOrderRequest.Wx.MchId).
|
||||||
|
Set("description", payOrderRequest.Description).
|
||||||
|
Set("out_trade_no", payOrderRequest.OrderId).
|
||||||
|
Set("time_expire", expire).
|
||||||
|
Set("notify_url", payCommon.WX_NOTIFY_URL).
|
||||||
|
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||||
|
bm.Set("total", payOrderRequest.Amount).
|
||||||
|
Set("currency", "CNY")
|
||||||
|
}).
|
||||||
|
SetBodyMap("scene_info", func(bm gopay.BodyMap) {
|
||||||
|
bm.Set("payer_client_ip", payOrderRequest.PayerClientIp).
|
||||||
|
SetBodyMap("h5_info", func(bm gopay.BodyMap) {
|
||||||
|
bm.Set("type", "common")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
wxRsp, err := wxClient.V3TransactionH5(c, bm)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if wxRsp.Code != wechat.Success || wxRsp.Response.H5Url == "" {
|
||||||
|
return "", errors.New(fmt.Sprintf("发起支付失败,失败状态码:%d, 失败原因:%s", wxRsp.Code, wxRsp.Error))
|
||||||
|
}
|
||||||
|
return wxRsp.Response.H5Url, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//func WxPayCallBack(notifyReq *wechat.V3NotifyReq) error {
|
||||||
|
// // 获取附加数据中的信息
|
||||||
|
// appId := notifyReq.Resource.AssociatedData
|
||||||
|
//
|
||||||
|
// payOrderRequest := PayOrderRequest{}
|
||||||
|
// // 初始化微信客户端
|
||||||
|
// InitClient(payOrderRequest)
|
||||||
|
//
|
||||||
|
// // 获取微信客户端
|
||||||
|
// wxClient, err := GetClient()
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Println("Failed to get client:", err)
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 获取微信平台证书
|
||||||
|
// certMap := wxClient.WxPublicKeyMap()
|
||||||
|
// // 验证异步通知的签名
|
||||||
|
// err = notifyReq.VerifySignByPKMap(certMap)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// objPtr := ""
|
||||||
|
// // 通用通知解密(推荐此方法)
|
||||||
|
// result := notifyReq.DecryptCipherTextToStruct(apiV3Key, objPtr)
|
||||||
|
//}
|
||||||
|
|
||||||
|
// WxOrderQuery 查询微信订单
|
||||||
|
func WxOrderQuery(ctx context.Context, wxConfig WxPay, orderNo string) (PayOrderQueryInfo, error) {
|
||||||
|
// 初始化微信客户端
|
||||||
|
InitClient(wxConfig)
|
||||||
|
|
||||||
|
// 获取微信客户端
|
||||||
|
wxClient, err := GetClient()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to get client:", err)
|
||||||
|
return PayOrderQueryInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
wxRsp, err := wxClient.V3TransactionQueryOrder(ctx, payCommon.ORDER_NO_TYPE_ORDER_NO, orderNo)
|
||||||
|
if err != nil {
|
||||||
|
return PayOrderQueryInfo{}, err
|
||||||
|
}
|
||||||
|
if wxRsp.Code != wechat.Success {
|
||||||
|
return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("查询订单接口错误,错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 映射交易状态
|
||||||
|
tradeState := ""
|
||||||
|
switch wxRsp.Response.TradeState {
|
||||||
|
case "SUCCESS":
|
||||||
|
tradeState = "SUCCESS"
|
||||||
|
case "REFUND":
|
||||||
|
tradeState = "REFUND"
|
||||||
|
case "NOTPAY":
|
||||||
|
tradeState = "NOTPAY"
|
||||||
|
case "CLOSED":
|
||||||
|
tradeState = "CLOSED"
|
||||||
|
}
|
||||||
|
amountTotal := wxRsp.Response.Amount.Total
|
||||||
|
payerTotal := wxRsp.Response.Amount.PayerTotal
|
||||||
|
|
||||||
|
return PayOrderQueryInfo{
|
||||||
|
AppId: wxRsp.Response.Appid,
|
||||||
|
OutTradeNo: wxRsp.Response.OutTradeNo,
|
||||||
|
TransactionId: wxRsp.Response.TransactionId,
|
||||||
|
TradeState: tradeState,
|
||||||
|
TradeStateDesc: wxRsp.Response.TradeStateDesc,
|
||||||
|
SuccessTime: wxRsp.Response.SuccessTime,
|
||||||
|
AmountTotal: int64(amountTotal),
|
||||||
|
PayerTotal: int64(payerTotal),
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -23,8 +23,8 @@ type CMqManager struct {
|
||||||
|
|
||||||
func (this *CMqManager) InitMq() {
|
func (this *CMqManager) InitMq() {
|
||||||
this.mqs = make(map[string]Imq)
|
this.mqs = make(map[string]Imq)
|
||||||
//this.mqs[common.MQ_RABBIT] = RabbitMq{}
|
//this.mqs[payCommon.MQ_RABBIT] = RabbitMq{}
|
||||||
//this.mqs[common.MQ_NSQ] = NsqMq{}
|
//this.mqs[payCommon.MQ_NSQ] = NsqMq{}
|
||||||
this.mqs[common3.MQ_NATS] = mq.NatsMq{}
|
this.mqs[common3.MQ_NATS] = mq.NatsMq{}
|
||||||
this.mqs[common3.MQ_KFK] = mq.KafkaMq{}
|
this.mqs[common3.MQ_KFK] = mq.KafkaMq{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*事件触发
|
*事件触发
|
||||||
event.EventManger.TrigerEvent(common.Event_USER_LOG_IN, param)
|
event.EventManger.TrigerEvent(payCommon.Event_USER_LOG_IN, param)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var EventManger *EventManagerFactory
|
var EventManger *EventManagerFactory
|
||||||
|
|
Loading…
Reference in New Issue