Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 40s
feat(pay): 添加支付API基础结构 feat(miniapp): 创建支付测试小程序页面与配置 feat(wechatpay): 配置微信支付参数与证书 fix(guild): 修复成员列表查询条件 docs: 更新代码规范文档与需求文档 style: 统一前后端枚举显示与注释格式 refactor(admin): 重构用户奖励发放接口参数处理 test(title): 添加称号效果参数验证测试
120 lines
4.5 KiB
Go
120 lines
4.5 KiB
Go
package pay
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
|
||
"bindbox-game/configs"
|
||
|
||
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
||
refundsvc "github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
||
)
|
||
|
||
type WechatPayClient struct {
|
||
client *core.Client
|
||
}
|
||
|
||
// NewWechatPayClient 初始化微信支付客户端
|
||
// 入参:context.Context
|
||
// 返回:WechatPayClient实例,或错误(配置缺失/私钥加载失败/客户端创建失败)
|
||
func NewWechatPayClient(ctx context.Context) (*WechatPayClient, error) {
|
||
cfg := configs.Get()
|
||
if cfg.WechatPay.ApiV3Key == "" {
|
||
return nil, errors.New("wechat pay config incomplete")
|
||
}
|
||
var opts []core.ClientOption
|
||
if cfg.WechatPay.PublicKeyID != "" && cfg.WechatPay.PublicKeyPath != "" {
|
||
if cfg.WechatPay.MchID == "" || cfg.WechatPay.SerialNo == "" || cfg.WechatPay.PrivateKeyPath == "" {
|
||
return nil, errors.New("wechat pay config incomplete")
|
||
}
|
||
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(cfg.WechatPay.PrivateKeyPath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
pubKey, err := utils.LoadPublicKeyWithPath(cfg.WechatPay.PublicKeyPath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
opts = []core.ClientOption{option.WithWechatPayPublicKeyAuthCipher(cfg.WechatPay.MchID, cfg.WechatPay.SerialNo, mchPrivateKey, cfg.WechatPay.PublicKeyID, pubKey)}
|
||
} else {
|
||
if cfg.WechatPay.MchID == "" || cfg.WechatPay.SerialNo == "" || cfg.WechatPay.PrivateKeyPath == "" {
|
||
return nil, errors.New("wechat pay config incomplete")
|
||
}
|
||
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(cfg.WechatPay.PrivateKeyPath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
opts = []core.ClientOption{option.WithWechatPayAutoAuthCipher(cfg.WechatPay.MchID, cfg.WechatPay.SerialNo, mchPrivateKey, cfg.WechatPay.ApiV3Key)}
|
||
}
|
||
client, err := core.NewClient(ctx, opts...)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &WechatPayClient{client: client}, nil
|
||
}
|
||
|
||
// JSAPIPrepay 直连商户JSAPI预下单,返回prepay_id
|
||
// 入参:appid、mchid、描述、商户订单号、总金额(分)、openid、回调URL
|
||
// 返回:prepay_id 或错误
|
||
func (c *WechatPayClient) JSAPIPrepay(ctx context.Context, appid, mchid, description, outTradeNo string, total int64, openid, notifyURL string) (string, error) {
|
||
svc := jsapi.JsapiApiService{Client: c.client}
|
||
resp, _, err := svc.Prepay(ctx, jsapi.PrepayRequest{
|
||
Appid: core.String(appid),
|
||
Mchid: core.String(mchid),
|
||
Description: core.String(description),
|
||
OutTradeNo: core.String(outTradeNo),
|
||
NotifyUrl: core.String(notifyURL),
|
||
Amount: &jsapi.Amount{
|
||
Total: core.Int64(total),
|
||
},
|
||
Payer: &jsapi.Payer{
|
||
Openid: core.String(openid),
|
||
},
|
||
})
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
if resp == nil || resp.PrepayId == nil {
|
||
return "", errors.New("missing prepay_id in response")
|
||
}
|
||
return *resp.PrepayId, nil
|
||
}
|
||
|
||
// RefundOrder 直连商户退款
|
||
// 入参:outTradeNo(商户订单号)、refundNo(商户退款单号)、amountRefund(退款金额分)、total(原订单金额分)、reason(退款原因,可空)
|
||
// 返回:微信退款单ID与状态,或错误
|
||
func (c *WechatPayClient) RefundOrder(ctx context.Context, outTradeNo, refundNo string, amountRefund, total int64, reason string) (string, string, error) {
|
||
svc := refundsvc.RefundsApiService{Client: c.client}
|
||
req := refundsvc.CreateRequest{
|
||
OutTradeNo: core.String(outTradeNo),
|
||
OutRefundNo: core.String(refundNo),
|
||
Amount: &refundsvc.AmountReq{
|
||
Refund: core.Int64(amountRefund),
|
||
Total: core.Int64(total),
|
||
Currency: core.String("CNY"),
|
||
},
|
||
}
|
||
if reason != "" {
|
||
req.Reason = core.String(reason)
|
||
}
|
||
resp, _, err := svc.Create(ctx, req)
|
||
if err != nil {
|
||
return "", "", err
|
||
}
|
||
var refundID, status string
|
||
if resp != nil {
|
||
if resp.RefundId != nil {
|
||
refundID = *resp.RefundId
|
||
}
|
||
if resp.Status != nil {
|
||
status = string(*resp.Status)
|
||
}
|
||
}
|
||
if refundID == "" {
|
||
return "", status, errors.New("missing refund_id in response")
|
||
}
|
||
return refundID, status, nil
|
||
} |