kefu/lib/wechat_pay.go

185 lines
6.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}