185 lines
6.0 KiB
Go
185 lines
6.0 KiB
Go
|
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
|
|||
|
}
|