kefu/lib/wechat_pay.go

185 lines
6.0 KiB
Go
Raw Permalink Normal View History

2024-12-10 02:50:12 +00:00
package lib
import (
"context"
"encoding/json"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
"io/ioutil"
"log"
"net/http"
"time"
)
type WechatPay struct {
AppId string //公众号AppID
MchID string //商户号
MchCertificateSerialNumber string //商户证书序列号
MchAPIv3Key string //商户API V3密钥
MchPrivateKey string //商户私钥
NotifyUrl string //回调地址
timeExpire time.Time //订单过期时间
Client *core.Client //client
Ctx context.Context
}
func NewWechatPay(appId, mchID, mchCertificateSerialNumber, mchAPIv3Key, mchPrivateKey, notifyUrl string) (*WechatPay, error) {
wp := &WechatPay{
AppId: appId,
MchID: mchID,
MchCertificateSerialNumber: mchCertificateSerialNumber,
MchAPIv3Key: mchAPIv3Key,
MchPrivateKey: mchPrivateKey,
NotifyUrl: notifyUrl,
timeExpire: time.Now().Add(2 * time.Hour),
}
// 使用 utils 提供的函数从私钥的文本内容中加载商户私钥,商户私钥会用来生成请求的签名
privateKey, err := utils.LoadPrivateKey(mchPrivateKey)
if err != nil {
return nil, err
}
ctx := context.Background()
// 使用商户私钥等初始化 client并使它具有自动定时获取微信支付平台证书的能力
opts := []core.ClientOption{
option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, privateKey, mchAPIv3Key),
}
client, err := core.NewClient(ctx, opts...)
if err != nil {
return nil, err
}
wp.Client = client
wp.Ctx = ctx
return wp, nil
}
// native支付下单
func (this *WechatPay) NativePayPreOrder(amount int64, description, orderSn string) (string, error) {
svc := native.NativeApiService{Client: this.Client}
resp, result, err := svc.Prepay(this.Ctx,
native.PrepayRequest{
Appid: core.String(this.AppId),
Mchid: core.String(this.MchID),
Description: core.String(description),
OutTradeNo: core.String(orderSn),
TimeExpire: core.Time(this.timeExpire),
NotifyUrl: core.String(this.NotifyUrl),
Amount: &native.Amount{
Currency: core.String("CNY"),
Total: core.Int64(amount),
},
},
)
if err != nil {
return "", err
}
// 处理返回结果
log.Println(resp, result)
return *resp.CodeUrl, nil
}
// jsapi支付下单
func (this *WechatPay) JsApiPreOrder(openId string, amount int64, description, orderSn string) (string, error) {
svc := jsapi.JsapiApiService{Client: this.Client}
resp, result, err := svc.PrepayWithRequestPayment(this.Ctx,
jsapi.PrepayRequest{
Appid: core.String(this.AppId),
Mchid: core.String(this.MchID),
Description: core.String(description),
OutTradeNo: core.String(orderSn),
TimeExpire: core.Time(this.timeExpire),
NotifyUrl: core.String(this.NotifyUrl),
Amount: &jsapi.Amount{
Currency: core.String("CNY"),
Total: core.Int64(amount),
},
Payer: &jsapi.Payer{
Openid: core.String(openId),
},
},
)
if err != nil {
return "", err
}
// 处理返回结果
log.Println(resp, result)
if err != nil {
return "", err
}
respBody, err := json.Marshal(map[string]interface{}{
"prepayId": resp.PrepayId,
"appId": resp.Appid,
"timeStamp": resp.TimeStamp,
"nonceStr": resp.NonceStr, //随机串
"package": resp.Package,
"signType": resp.SignType, //微信签名方式:
"paySign": resp.PaySign, //微信签名
})
return string(respBody), nil
}
// native支付查询
func (this *WechatPay) NativePayQueryOrder(orderSn string) (string, string, error) {
svc := native.NativeApiService{Client: this.Client}
resp, result, err := svc.QueryOrderByOutTradeNo(this.Ctx,
native.QueryOrderByOutTradeNoRequest{
OutTradeNo: core.String(orderSn),
Mchid: core.String(this.MchID),
},
)
if err != nil {
return "", "", err
}
body, _ := ioutil.ReadAll(result.Response.Body)
return string(body), *resp.TradeState, nil
}
// jsapi支付查询
func (this *WechatPay) JsApiQueryOrder(orderSn string) (string, string, error) {
svc := jsapi.JsapiApiService{Client: this.Client}
resp, result, err := svc.QueryOrderById(this.Ctx,
jsapi.QueryOrderByIdRequest{
TransactionId: core.String(orderSn),
Mchid: core.String(this.MchID),
},
)
if err != nil {
return "", "", err
}
body, _ := ioutil.ReadAll(result.Response.Body)
return string(body), *resp.TradeState, nil
}
// 解密回调
func (this *WechatPay) ParseNotifyRequest(request *http.Request) (map[string]interface{}, error) {
ctx := context.Background()
content := make(map[string]interface{})
// 1. 使用 `RegisterDownloaderWithPrivateKey` 注册下载器
// 使用 utils 提供的函数从私钥的文本内容中加载商户私钥,商户私钥会用来生成请求的签名
mchPrivateKey, err := utils.LoadPrivateKey(this.MchPrivateKey)
if err != nil {
return content, err
}
err = downloader.MgrInstance().RegisterDownloaderWithPrivateKey(ctx, mchPrivateKey, this.MchCertificateSerialNumber, this.MchID, this.MchAPIv3Key)
if err != nil {
return content, err
}
// 2. 获取商户号对应的微信支付平台证书访问器
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(this.MchID)
// 3. 使用证书访问器初始化 `notify.Handler`
handler := notify.NewNotifyHandler(this.MchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
notifyReq, err := handler.ParseNotifyRequest(ctx, request, &content)
log.Println(notifyReq, content)
return content, nil
}