package qyweixin import ( "bytes" "context" "crypto/tls" "errors" "fmt" butil "git.u8t.cn/open/gosdk/util" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" "github.com/spf13/cast" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/core/option" "github.com/wechatpay-apiv3/wechatpay-go/utils" "io/ioutil" "net/http" "os" "time" ) type PayReq struct { TotalAmount int64 Title string Openid string BillNo string } type PayConfig struct { Corpid string Secret string Agent string CertPem string KeyPem string MchId string ApiKey string SerialNumber string } type AppPay struct { App cli *core.Client tlsClient *http.Client stdClient *http.Client config *PayConfig } func NewAppPay(cfg *PayConfig) *AppPay { payCertPem, _ := os.ReadFile(cfg.CertPem) payKeyPem, _ := os.ReadFile(cfg.KeyPem) pay := &AppPay{} client, err := pay.withCert(payCertPem, payKeyPem) if err != nil { log.Errorf("with cert error :%s", err.Error()) return nil } pay.tlsClient = client pay.App = *NewApp(&AppConfig{Corpid: cfg.Corpid, Secret: cfg.Secret, Agent: cfg.Agent}) pay.config = cfg return pay } // 附着商户证书 func (c *AppPay) withCert(cert, key []byte) (*http.Client, error) { tlsCert, err := tls.X509KeyPair(cert, key) if err != nil { return nil, err } conf := &tls.Config{ Certificates: []tls.Certificate{tlsCert}, } trans := &http.Transport{ TLSClientConfig: conf, } return &http.Client{ Transport: trans, }, nil } // 发送请求 func (c *AppPay) post(url string, params butil.Params, tls bool) ([]byte, error) { var httpc *http.Client if tls { if c.tlsClient == nil { return nil, errors.New("tls wepay is not initialized") } httpc = c.tlsClient } else { httpc = c.stdClient } buf := bytes.NewBuffer(params.Encode()) resp, err := httpc.Post(url, "application/xml; charset=utf-8", buf) if err != nil { return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } return body, nil } func (w *AppPay) initPay() error { // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := utils.LoadPrivateKeyWithPath(w.config.KeyPem) if err != nil { return err } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(w.config.MchId, w.config.SerialNumber, mchPrivateKey, w.config.ApiKey), } client, err := core.NewClient(ctx, opts...) if err != nil { return err } w.cli = client return nil } func (p *AppPay) PayMoney(req *PayReq) error { if p.cli == nil { if err := p.initPay(); err != nil { return err } } param := butil.NewParams() if req.BillNo == "" { req.BillNo = fmt.Sprintf("QY%s", time.Now().Format("20060102150405")) } param.Set("nonce_str", goutil.RandomStr(32)) param.Set("mch_billno", req.BillNo) param.Set("mch_id", p.config.MchId) param.Set("wxappid", p.config.Corpid) param.Set("agentid", p.config.Agent) param.Set("re_openid", req.Openid) param.Set("total_amount", cast.ToString(req.TotalAmount)) param.Set("wishing", req.Title) param.Set("act_name", "企业红包") param.Set("remark", "企业红包") param.Set("workwx_sign", param.QySignMd5(p.config.Secret)) param.Set("sign", param.SignMd5(p.config.ApiKey)) reqUrl := "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendworkwxredpack" rspBody, err := p.post(reqUrl, param, true) if err != nil { log.Errorf("Post [%s] [%s] error :%s", reqUrl, string(param.Encode()), err.Error()) return err } respParam := butil.NewParams() respParam.Decode(rspBody) returnCode := respParam.GetString("return_code") resultCoce := respParam.GetString("result_code") if resultCoce == "SUCCESS" && returnCode == "SUCCESS" { return nil } return errors.New(string(respParam.Encode())) }