package internal import ( "context" "errors" "fmt" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/core/option" "github.com/wechatpay-apiv3/wechatpay-go/services/payments/app" "github.com/wechatpay-apiv3/wechatpay-go/utils" "goutil/logUtilPlus" "log" _ "paycenter/internal/pay" "paycenter/internal/wxpaycofnig" _ "paycenter/internal/wxpaycofnig" "strconv" "time" ) var ( mchID string = wxpaycofnig.GetWxPayConfig().MchID // 商户号 mchCertificateSerialNumber string = wxpaycofnig.GetWxPayConfig().MchCertificateSerialNumber // 商户证书序列号 mchAPIv3Key string = wxpaycofnig.GetWxPayConfig().MchAPIv3Key // 商户APIv3密钥 appId string = wxpaycofnig.GetWxPayConfig().AppId // 应用ID Address string = "成都市XXXXXXXXXXXXXXXXXXXXXXX" //公司地址 wxPayApiUrl string = wxpaycofnig.GetWxPayConfig().NotifyUrl //支付成功回调地址 ) // Prepay 函数用于发起预支付请求。 // 参数: // // outTradeNo: 商户订单号。 // currency: 订单金额,单位为分。 // storeId: 商户门店编号。 // clientIp: 用户的客户端IP。 // description: 订单描述。 // // 返回值: // // 成功时返回预支付ID和nil错误。 // 失败时返回空字符串和错误对象。 func Prepay(outTradeNo int64, currency int64, storeId string, clientIp string, description string) (string, error) { // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem") if err != nil { logUtilPlus.ErrorLog("load merchant private key error") return "", err } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { logUtilPlus.ErrorLog("new wechat pay client err:%s", err) return "", err } svc := app.AppApiService{Client: client} resp, result, err := svc.Prepay(ctx, app.PrepayRequest{ Appid: core.String(appId), Mchid: core.String(mchID), Description: core.String(description), OutTradeNo: core.String(strconv.FormatInt(outTradeNo, 10)), TimeExpire: core.Time(time.Now().Add(time.Hour * 2)), //支付时效时间 2 小时后失效 Attach: core.String(""), //附加数据 这里不需要,有个订单id 可以获取订单详细信息 NotifyUrl: core.String(fmt.Sprintf(wxPayApiUrl, strconv.FormatInt(outTradeNo, 10))), //回调地址 //GoodsTag: core.String("WXG"),//优惠标记 这里没用 //LimitPay: []string{"LimitPay_example"}, SupportFapiao: core.Bool(false), Amount: &app.Amount{ Currency: core.String("CNY"), Total: core.Int64(currency), }, Detail: &app.Detail{ //CostPrice: core.Int64(608800), GoodsDetail: []app.GoodsDetail{app.GoodsDetail{ GoodsName: core.String(storeId), //商品编号 MerchantGoodsId: core.String(description), Quantity: core.Int64(1), UnitPrice: core.Int64(currency), //WechatpayGoodsId: core.String("1001"), }}, //InvoiceId: core.String("wx123"), }, SceneInfo: &app.SceneInfo{ //DeviceId: core.String("013467007045764"), PayerClientIp: core.String(clientIp), StoreInfo: &app.StoreInfo{ Address: core.String(Address), //AreaCode: core.String("440305"), //Id: core.String("0001"), //Name: core.String("腾讯大厦分店"), }, }, SettleInfo: &app.SettleInfo{ ProfitSharing: core.Bool(false), }, }, ) if err != nil { // 处理错误 logUtilPlus.ErrorLog("call Prepay err:%s", err.Error()) return "", err } if result.Response.StatusCode != 200 { errStr := fmt.Sprintf("status=%d resp=%s", result.Response.StatusCode, resp) logUtilPlus.ErrorLog(errStr) return "", errors.New(errStr) } return *resp.PrepayId, nil } // CloseOrder 关闭订单 func CloseOrder(outTradeNo int64) error { // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem") if err != nil { log.Print("加载商家私钥错误") } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { log.Printf("新的 WeChat Pay 客户端 Err:%s", err) } svc := app.AppApiService{Client: client} _, err = svc.CloseOrder(ctx, app.CloseOrderRequest{ //商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯 OutTradeNo: core.String(strconv.FormatInt(outTradeNo, 10)), //直连商户的商户号,由微信支付生成并下发。 Mchid: core.String(mchID), }, ) if err != nil { // 处理错误 logUtilPlus.ErrorLog("call CloseOrder err:%s", err) return err } return nil } // QueryOrderById 根据商户订单号查询订单 func QueryOrderById() { // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem") if err != nil { log.Print("load merchant private key error") } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { log.Printf("new wechat pay client err:%s", err) } svc := app.AppApiService{Client: client} resp, result, err := svc.QueryOrderById(ctx, app.QueryOrderByIdRequest{ TransactionId: core.String("TransactionId_example"), Mchid: core.String("Mchid_example"), }, ) if err != nil { // 处理错误 log.Printf("call QueryOrderById err:%s", err) } else { // 处理返回结果 log.Printf("status=%d resp=%s", result.Response.StatusCode, resp) } } // QueryOrderByOutTradeNo 根据商户订单号查询订单 func QueryOrderByOutTradeNo(outTradeNo int64) (string, error) { //循环查询次数 var count int = 0 loop: // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem") if err != nil { log.Print("load merchant private key error") return "", err } ctx := context.Background() // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 opts := []core.ClientOption{ option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), } client, err := core.NewClient(ctx, opts...) if err != nil { log.Printf("new wechat pay client err:%s", err) return "", err } svc := app.AppApiService{Client: client} resp, result, err := svc.QueryOrderByOutTradeNo(ctx, app.QueryOrderByOutTradeNoRequest{ OutTradeNo: core.String(strconv.FormatInt(outTradeNo, 10)), Mchid: &mchID, }, ) if err != nil { // 处理错误 log.Printf("call QueryOrderByOutTradeNo err:%s", err) return "", err } else { // 处理返回结果 log.Printf("status=%d resp=%s", result.Response.StatusCode, resp) //支付成功 if resp.TradeState == core.String("SUCCESS") { return "SUCCESS", nil } else if resp.TradeState == core.String("NOTPAY") && count < 3 { //未支付,循环查找订单 //休息200毫秒 time.Sleep(200 * time.Millisecond) count++ goto loop } //支付失败 return *resp.TradeState, nil } }