package wxpay import ( "bytes" "context" "crypto/md5" "encoding/json" "encoding/xml" "errors" "fmt" "github.com/codinl/go-logger" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/core/option" "github.com/wechatpay-apiv3/wechatpay-go/services/certificates" "github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi" "github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic" wechatpayutils "github.com/wechatpay-apiv3/wechatpay-go/utils" "io/ioutil" "log" "mh-server/config" "mh-server/lib/utils" //"mh-server/model" "net/http" "sort" "strconv" "strings" "time" ) const ( //clientIp = "120.229.60.77" clientIp = "39.108.188.218" domain = "switch.deovo.com:8001" //wxPayNotifyUrl = "api/v1/wxpay/notice" wxPayNotifyUrl = "/api/v1/wxpay/notice" WxPayMember = "member_pay" // 会员 WxPayRentCard = "rent_card_pay" // 租卡 WxPayDeposit = "deposit_pay" // 押金 WxPayExchangeGoods = "exchange_goods" // 兑换商品 WxPayUpgradeMember = "upgrade_member" // 多级会员 WxPayMemberExpireDelay = "member_expire_delay" // 会员过期滞纳金 WxPayShareCardRetrieve = "share_card_retrieve" // //NotifyUrl = "https://switch.deovo.com:8001/api/v1/wxpay/notice" // 数据库配置 生产 //NotifyUrl = "https://dev.switch.deovo.com:8004/api/v1/wxpay/notice" // 测试 wxPayOrderRefundsUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds" ) //web 微信支付 func WebPay(orderId string, totalFee uint32, openId, profitSharing, attach, notifyUrl string) (*Sextuple, error) { now := time.Now().Local() strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) nonce := utils.GenRandStr(NonceStringLength) //configInfo, err := model.PayConfigInfo() //if err != nil { // logger.Error(err) // return nil, err //} //if configInfo.NotifyUrl == "" { // logger.Error("NotifyUrl is null") // return nil, errors.New("NotifyUrl is null") //} if notifyUrl == "" { logger.Error("NotifyUrl is null") return nil, errors.New("NotifyUrl is null") } logger.Info("MchId:", config.AppConfig.WxMchID) logger.Info("AppId:", config.AppConfig.WxAppId) logger.Info("MchSecret:", config.AppConfig.WxMchSecret) unifiedOrderReq := UnifiedOrderReq{ DeviceInfo: "WEB", NonceStr: nonce, Sign: "", SignType: "MD5", Body: "创建订单", OutTradeNo: orderId, FeeType: "CNY", TotalFee: strconv.Itoa(int(totalFee)), //SpbillCreateIp: config.AppConfig.IP, SpbillCreateIp: clientIp, //NotifyUrl: "https://" + config.AppConfig.Domain + config.AppConfig.WxPayNotifyUrl, //NotifyUrl: "https://" + domain + wxPayNotifyUrl, //NotifyUrl: configInfo.NotifyUrl, NotifyUrl: notifyUrl, TradeType: "JSAPI", MchId: config.AppConfig.WxMchID, AppId: config.AppConfig.WxAppId, OpenId: openId, TimeStart: strTime, ProfitSharing: profitSharing, Attach: attach, } fmt.Println("OutTradeNo:", unifiedOrderReq.OutTradeNo) m, err := struct2Map(unifiedOrderReq) if err != nil { logger.Error(err) return nil, err } //mJson, _ := json.MarshalIndent(&m, "", " ") //fmt.Println("mJson:", string(mJson)) sign, err := GenWxPaySign(m, config.AppConfig.WxMchSecret) if err != nil { logger.Error(err) return nil, err } unifiedOrderReq.Sign = strings.ToUpper(sign) //unifiedOrderReqJson, _ := json.Marshal(&unifiedOrderReq) //fmt.Println("unifiedOrderReqJson:", string(unifiedOrderReqJson)) unifiedOrderResp, err := WxUnifiedOrder(unifiedOrderReq) if err != nil { logger.Errorf("WxUnifiedOrder unified order error %#v", err) return nil, err } var sextuple Sextuple sextuple.NonceStr = unifiedOrderResp.NonceStr sextuple.AppId = unifiedOrderResp.AppId sextuple.Timestamp = fmt.Sprintf("%d", time.Now().Unix()) sextuple.Package = "prepay_id=" + unifiedOrderResp.PrepayId sextuple.SignType = "MD5" //logger.Debugf("unified order sextuple: %#v", sextuple) m, err = struct2Map(sextuple) if err != nil { logger.Errorf("struct to map error %#v", err) return nil, err } sextuple.PaySign, err = GenWxPaySign(m, config.AppConfig.WxMchSecret) if err != nil { logger.Errorf("GenWxPaySign gen response sign error: %#v", err) return nil, err } return &sextuple, nil } const ( NonceStringLength = 32 UnifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder" ) type ( //根据调用微信统一支付接口返回数据组装五元组 Sextuple struct { AppId string `json:"appId"` NonceStr string `json:"nonceStr,omitempty"` Timestamp string `json:"timeStamp,omitempty"` Package string `json:"package,omitempty"` SignType string `json:"signType,omitempty"` PaySign string `json:"paySign,omitempty"` } UnifiedOrderReq struct { XMLName xml.Name `xml:"xml"` //xml标签 AppId string `xml:"appid" json:"appid"` //微信分配的小程序ID,必须 MchId string `xml:"mch_id" json:"mch_id"` //微信支付分配的商户号,必须 DeviceInfo string `xml:"device_info" json:"device_info"` //微信支付填"WEB",必须 NonceStr string `xml:"nonce_str" json:"nonce_str"` //随机字符串,必须 Sign string `xml:"sign" json:"sign"` //签名,必须 SignType string `xml:"sign_type" json:"sign_type"` //"HMAC-SHA256"或者"MD5",非必须,默认MD5 Body string `xml:"body" json:"body"` //商品简单描述,必须 Detail string `xml:"detail,omitempty" json:"detail,omitempty"` //商品详细列表,使用json格式 Attach string `xml:"attach" json:"attach"` //附加数据,如"贵阳分店",非必须 OutTradeNo string `xml:"out_trade_no" json:"out_trade_no"` //CRS订单号,必须 FeeType string `xml:"fee_type,omitempty" json:"fee_type,omitempty"` //默认人民币:CNY,非必须 TotalFee string `xml:"total_fee" json:"total_fee"` //订单金额,单位分,必须 SpbillCreateIp string `xml:"spbill_create_ip" json:"spbill_create_ip"` //支付提交客户端IP,如“123.123.123.123”,必须 TimeStart string `xml:"time_start,omitempty" json:"time_start,omitempty"` //订单生成时间,格式为yyyyMMddHHmmss,如20170324094700,非必须 TimeExpire string `xml:"time_expire,omitempty" json:"time_expire,omitempty"` //订单结束时间,格式同上,非必须 GoodsTag string `xml:"goods_tag,omitempty" json:"goods_tag,omitempty"` //商品标记,代金券或立减优惠功能的参数,非必须 NotifyUrl string `xml:"notify_url" json:"notify_url"` //接收微信支付异步通知回调地址,不能携带参数,必须 TradeType string `xml:"trade_type" json:"trade_type"` //交易类型,小程序写"JSAPI",必须 LimitPay string `xml:"limit_pay,omitempty" json:"limit_pay,omitempty"` //限制某种支付方式,非必须 OpenId string `xml:"openid" json:"openid"` //微信用户唯一标识,必须 ProfitSharing string `xml:"profit_sharing" json:"profit_sharing"` //是否需要分账 } ZFWechatUnifiedOrderReq struct { XMLName xml.Name `xml:"xml"` //xml标签 AppId string `xml:"appid" json:"appid"` //微信分配的小程序ID,必须 MchId string `xml:"mch_id" json:"mch_id"` //微信支付分配的商户号,必须 NonceStr string `xml:"nonce_str" json:"nonce_str"` //随机字符串,必须 Sign string `xml:"sign" json:"sign"` //签名,必须 Body string `xml:"body" json:"body"` //商品简单描述,必须 OutTradeNo string `xml:"out_trade_no" json:"out_trade_no"` //CRS订单号,必须 TotalFee string `xml:"total_fee" json:"total_fee"` //订单金额,单位分,必须 SpbillCreateIp string `xml:"spbill_create_ip" json:"spbill_create_ip"` //支付提交客户端IP,如“123.123.123.123”,必须 NotifyUrl string `xml:"notify_url" json:"notify_url"` //接收微信支付异步通知回调地址,不能携带参数,必须 TradeType string `xml:"trade_type" json:"trade_type"` //交易类型,小程序写"JSAPI",必须 OpenId string `xml:"openid" json:"openid"` //微信用户唯一标识,必须 Attach string `xml:"attach" json:"attach"` } UnifiedOrderResp struct { ReturnCode string `xml:"return_code"` ReturnMsg string `xml:"return_msg"` AppId string `xml:"appid"` MchId string `xml:"mch_id"` DeviceInfo string `xml:"device_info"` NonceStr string `xml:"nonce_str"` Sign string `xml:"sign"` ResultCode string `xml:"result_code"` ErrCode string `xml:"err_code"` ErrCodeDes string `xml:"err_code_des"` TradeType string `xml:"trade_type"` PrepayId string `xml:"prepay_id"` } WechatNotifyInfo struct { ReturnCode string `xml:"return_code,CDATA" json:"return_code"` ReturnMsg string `xml:"return_msg,CDATA" json:"return_msg"` Appid string `xml:"appid,CDATA" json:"appid"` MchId string `xml:"mch_id,CDATA" json:"mch_id"` DeviceInfo string `xml:"device_info,CDATA" json:"device_info"` NonceStr string `xml:"nonce_str,CDATA" json:"nonce_str"` Sign string `xml:"sign,CDATA" json:"sign"` // 默认MD5 SignType string `xml:"sign_type,CDATA" json:"sign_type"` //可选 ResultCode string `xml:"result_code,CDATA" json:"result_code"` ErrCode string `xml:"err_code,CDATA" json:"err_code"` ErrCodeDes string `xml:"err_code_des,CDATA" json:"err_code_des"` Openid string `xml:"openid,CDATA" json:"openid"` IsSubscribe string `xml:"is_subscribe,CDATA" json:"is_subscribe"` TradeType string `xml:"trade_type,CDATA" json:"trade_type"` BankType string `xml:"bank_type,CDATA" json:"bank_type"` TotalFee uint `xml:"total_fee,CDATA" json:"total_fee"` SettlementTotalFee uint `xml:"settlement_total_fee" json:"settlement_total_fee"` FeeType string `xml:"fee_type,CDATA" json:"fee_type"` CashFee uint `xml:"cash_fee,CDATA" json:"cash_fee"` CashFeeType string `xml:"cash_fee_type,CDATA" json:"cash_fee_type"` CouponFee uint `xml:"coupon_fee,CDATA" json:"coupon_fee"` CouponCount uint `xml:"coupon_count,CDATA" json:"coupon_count"` CouponType0 uint `xml:"coupon_type_0,CDATA" json:"coupon_type_0"` CouponId0 string `xml:"coupon_id_0,CDATA" json:"coupon_id_0"` CouponFee0 uint `xml:"coupon_fee_0,CDATA" json:"coupon_fee_0"` CouponFee1 uint `xml:"coupon_fee_1,CDATA" json:"coupon_fee_1"` CouponId1 string `xml:"coupon_id_1,CDATA" json:"coupon_id_1"` CouponFee2 uint `xml:"coupon_fee_2,CDATA" json:"coupon_fee_2"` CouponId2 string `xml:"coupon_id_2,CDATA" json:"coupon_id_2"` CouponFee3 uint `xml:"coupon_fee_3,CDATA" json:"coupon_fee_3"` CouponId3 string `xml:"coupon_id_3,CDATA" json:"coupon_id_3"` CouponFee4 uint `xml:"coupon_fee_4,CDATA" json:"coupon_fee_4"` CouponId4 string `xml:"coupon_id_4,CDATA" json:"coupon_id_4"` CouponFee5 uint `xml:"coupon_fee_5,CDATA" json:"coupon_fee_5"` CouponId5 string `xml:"coupon_id_5,CDATA" json:"coupon_id_5"` TransactionId string `xml:"transaction_id,CDATA" json:"transaction_id"` OutTradeNo string `xml:"out_trade_no,CDATA" json:"out_trade_no"` Attach string `xml:"attach,CDATA" json:"attach"` TimeEnd string `xml:"time_end,CDATA" json:"time_end"` } WechatNotify struct { ReturnCode string `xml:"return_code"` ReturnMsg string `xml:"return_msg"` //签名失败 或者 参数格式校验错误 } NotifyResponseObject struct { XMLName xml.Name `xml:"xml"` WechatNotify } AppWxPayRet struct { AppId string `json:"appid,omitempty"` PartnerId string `json:"partnerid,omitempty"` PrepayId string `json:"prepayid,omitempty"` Package string `json:"package,omitempty"` NonceStr string `json:"noncestr,omitempty"` Timestamp string `json:"timestamp,omitempty"` Sign string `json:"sign,omitempty"` } ) type T struct { CouponFee0 string `json:"coupon_fee_0"` CouponFee1 string `json:"coupon_fee_1"` CouponFee2 string `json:"coupon_fee_2"` CouponFee3 string `json:"coupon_fee_3"` CouponId0 string `json:"coupon_id_0"` CouponId1 string `json:"coupon_id_1"` CouponId2 string `json:"coupon_id_2"` CouponId3 string `json:"coupon_id_3"` } //type T struct { // Xml struct { // Appid string `json:"appid"` // Attach string `json:"attach"` // BankType string `json:"bank_type"` // CashFee string `json:"cash_fee"` // // // CouponCount string `json:"coupon_count"` // CouponFee string `json:"coupon_fee"` // CouponFee0 string `json:"coupon_fee_0"` // CouponFee1 string `json:"coupon_fee_1"` // CouponId0 string `json:"coupon_id_0"` // CouponId1 string `json:"coupon_id_1"` // // // DeviceInfo string `json:"device_info"` // FeeType string `json:"fee_type"` // IsSubscribe string `json:"is_subscribe"` // MchId string `json:"mch_id"` // NonceStr string `json:"nonce_str"` // Openid string `json:"openid"` // OutTradeNo string `json:"out_trade_no"` // ResultCode string `json:"result_code"` // ReturnCode string `json:"return_code"` // Sign string `json:"sign"` // TimeEnd string `json:"time_end"` // TotalFee string `json:"total_fee"` // TradeType string `json:"trade_type"` // TransactionId string `json:"transaction_id"` // } `json:"xml"` //} ////app 微信支付 ////totalFee 单位是分 //func AppPay(totalFee int, openId string) (*AppWxPayRet, string, error) { // now := time.Now() // strTime := fmt.Sprintf("%04d%02d%02d%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) // tradeNO := strTime + utils.RandomNumString(100000, 999999) // nonce := utils.GenRandStr(NonceStringLength) // unifiedOrderReq := UnifiedOrderReq{ // DeviceInfo: "WEB", // NonceStr: nonce, // Sign: "", // SignType: "MD5", // Body: "升级会员", // OutTradeNo: tradeNO, // FeeType: "CNY", // TotalFee: strconv.Itoa(int(totalFee)), // //SpbillCreateIp: config.AppConfig.IP, // SpbillCreateIp: clientIp, // //NotifyUrl: config.AppConfig.WxPayNotifyUrl, // TradeType: "APP", // AppId: "WechatAppId", // MchId: "WechatMchId", // OpenId: openId, // TimeStart: strTime, // } // // //生成签名 // m, err := struct2Map(unifiedOrderReq) // if err != nil { // logger.Error(err) // return nil, "", err // } // sign, err := GenWxPaySign(m, config.AppConfig.WxMchSecret) // if err != nil { // logger.Error(err) // return nil, "", err // } // unifiedOrderReq.Sign = strings.ToUpper(sign) // // unifiedOrderResp, err := WxUnifiedOrder(unifiedOrderReq) // if err != nil { // logger.Errorf("WxUnifiedOrder unified order error %#v", err) // return nil, "", err // } // // var payret AppWxPayRet // payret.AppId = unifiedOrderResp.AppId // payret.PartnerId = unifiedOrderResp.MchId // payret.PrepayId = unifiedOrderResp.PrepayId // payret.Package = "Sign=WXPay" // payret.NonceStr = unifiedOrderResp.NonceStr // payret.Timestamp = fmt.Sprintf("%d", time.Now().Unix()) // // m, err = struct2Map(payret) // if err != nil { // logger.Errorf("Pay struct to map error %#v", err) // return nil, "", err // } // // payret.Sign, err = GenWxPaySign(m, config.AppConfig.WxMchSecret) // if err != nil { // logger.Errorf("GenWxPaySign gen response sign error: %#v", err) // return nil, "", err // } // // return &payret, tradeNO, nil //} func struct2Map(r interface{}) (s map[string]string, err error) { var temp map[string]interface{} var result = make(map[string]string) bin, err := json.Marshal(r) if err != nil { logger.Error(err) return result, err } if err := json.Unmarshal(bin, &temp); err != nil { return nil, err } for k, v := range temp { switch v2 := v.(type) { case string: result[k] = v2 case uint, int8, uint8, int, int16, uint16, int32, uint32, int64, uint64: result[k] = fmt.Sprintf("%d", v2) case float32, float64: result[k] = fmt.Sprintf("%.0f", v2) } } return result, nil } func GenWxPaySign(m map[string]string, payKey string) (string, error) { delete(m, "sign") var signData []string for k, v := range m { if k == "openid" { fmt.Println(k, ":", v) } if v != "" && v != "0" { signData = append(signData, fmt.Sprintf("%s=%s", k, v)) } } signDataJson, _ := json.MarshalIndent(&signData, "", " ") fmt.Println("signDataJson1", string(signDataJson)) sort.Strings(signData) signDataJson2, _ := json.MarshalIndent(&signData, "", " ") fmt.Println("signDataJson2", string(signDataJson2)) signStr := strings.Join(signData, "&") signStr = signStr + "&key=" + payKey logger.Info("签字符串1 :", signStr) c := md5.New() _, err := c.Write([]byte(signStr)) if err != nil { logger.Error(err) return "", err } signByte := c.Sum(nil) return fmt.Sprintf("%x", signByte), nil } func WxUnifiedOrder(r UnifiedOrderReq) (UnifiedOrderResp, error) { var payResp UnifiedOrderResp data, err := xml.Marshal(r) if err != nil { logger.Error(err) return payResp, err } //logger.Error(" xml data: ", string(data)) //fmt.Println("xml:", string(data)) logger.Error("xml:", string(data)) client := http.Client{} req, err := http.NewRequest("POST", UnifiedOrderUrl, bytes.NewBuffer(data)) if err != nil { logger.Error(err) return payResp, err } req.Header.Set("Content-Type", "application/xml; charset=utf-8") resp, err := client.Do(req) if err != nil { logger.Error(err) return payResp, err } //fmt.Println("err:", err) body, err := ioutil.ReadAll(resp.Body) if err != nil { logger.Error(err) return payResp, err } //fmt.Println("err:", err) fmt.Println("body:", string(body)) defer resp.Body.Close() err = xml.Unmarshal(body, &payResp) if err != nil { logger.Error(err) return payResp, err } if payResp.ReturnCode != "SUCCESS" { return payResp, errors.New(payResp.ReturnMsg) } return payResp, nil } func WxPayTransactionOrderClose(outTradeNo, mchid string) error { // url := fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close", outTradeNo) // para := map[string]interface{}{ // "mchid": mchid, // } // data, err := json.Marshal(para) // logger.Error("json:", string(data)) // client := http.Client{} // req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) // if err != nil { // logger.Error(err) // return err // } // req.Header.Set("Content-Type", "application/json") // req.Header.Set("Accept", "application/json") //// Content-Type: application/json // resp, err := client.Do(req) // if err != nil { // logger.Error(err) // return err // } // // //fmt.Println("err:", err) // body, err := ioutil.ReadAll(resp.Body) // if err != nil { // logger.Error(err) // return err // } // //fmt.Println("err:", err) // fmt.Println("body:", string(body)) // // defer resp.Body.Close() var ( mchID string = "1609877389" // 商户号 mchCertificateSerialNumber string = "7540301D8FD52CCF7D6267DCF7CD2BC0AB467EFF" // 商户证书序列号 mchAPIv3Key string = "DeovoMingHuiRengTianTang45675123" // 商户APIv3密钥 ) // 微信商户 // 商户ID:1609877389 // 操作密码:456755 // 密钥API:DeovoMingHuiRengTianTang45675456 //密钥APIv3: DeovoMingHuiRengTianTang45675123 // 证书序列号:7540301D8FD52CCF7D6267DCF7CD2BC0AB467EFF // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := wechatpayutils.LoadPrivateKeyWithPath("/Users/li/mh/mh_server/pack/configs/merchant/apiclient_key.pem") if err != nil { log.Fatal("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.Fatalf("new wechat pay client err:%s", err) } // 发送请求,以下载微信支付平台证书为例 // https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay5_1.shtml svc := certificates.CertificatesApiService{Client: client} resp, result, err := svc.DownloadCertificates(ctx) log.Printf("status=%d resp=%s", result.Response.StatusCode, resp) svcClient := jsapi.JsapiApiService{Client: client} apiResult, err := svcClient.CloseOrder(ctx, jsapi.CloseOrderRequest{ OutTradeNo: &outTradeNo, Mchid: &mchid, }) if err != nil { fmt.Println("err:", err) logger.Error(err) return err } fmt.Println("StatusCode:", (*apiResult).Response.StatusCode) //bodyCloseOrder,_ := ioutil.ReadAll((*apiResult.Response.Body)) fmt.Println("apiResult:", (*apiResult).Response.StatusCode) return nil } func PayNotifyHandle(notify WechatNotifyInfo) (string, error) { m, err := struct2Map(notify) if err != nil { logger.Error(err.Error()) return "", err } sign, err := GenWxPaySign(m, config.AppConfig.WxMchSecret) if err != nil { logger.Error(err.Error()) return "", err } sign = strings.ToUpper(sign) logger.Error("微信推送支付通知 sign : payKey", sign, config.AppConfig.WxMchSecret) return sign, err } func TransactionOrderRefund(orderRefund OrderRefund) error { var ( mchID string = "1609877389" // 商户号 mchCertificateSerialNumber string = "7540301D8FD52CCF7D6267DCF7CD2BC0AB467EFF" // 商户证书序列号 mchAPIv3Key string = "DeovoMingHuiRengTianTang45675123" // 商户APIv3密钥 ) // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 mchPrivateKey, err := wechatpayutils.LoadPrivateKeyWithPath("./configs/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 := refunddomestic.RefundsApiService{Client: client} resp, result, err := svc.Create(ctx, refunddomestic.CreateRequest{ OutTradeNo: core.String(orderRefund.OutTradeNo), OutRefundNo: core.String(orderRefund.OutRefundNo), Reason: core.String("取消订单"), //NotifyUrl: core.String("https://weixin.qq.com/api/v1/wxpay/notice"), NotifyUrl: core.String(orderRefund.NotifyUrl), Amount: &refunddomestic.AmountReq{ Currency: core.String("CNY"), Refund: core.Int64(int64(orderRefund.Amount.Refund)), Total: core.Int64(int64(orderRefund.Amount.Total)), }, }, ) if err != nil { // 处理错误 log.Printf("call Create err:%s", err) } else { // 处理返回结果 log.Printf("status=%d resp=%s", result.Response.StatusCode, resp) } return nil } func PayOrderRefund(orderRefund OrderRefund) error { para, err := json.Marshal(&orderRefund) if err != nil { logger.Error("err:", err) return err } client := http.Client{} req, err := http.NewRequest("POST", wxPayOrderRefundsUrl, bytes.NewBuffer(para)) if err != nil { logger.Error(err) return err } req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Accept", "application/json") resp, err := client.Do(req) if err != nil { logger.Error(err) return err } //fmt.Println("err:", err) body, err := ioutil.ReadAll(resp.Body) if err != nil { logger.Error(err) return err } //fmt.Println("err:", err) fmt.Println("body:", string(body)) defer resp.Body.Close() fmt.Println("") return nil } type OrderRefund struct { OutTradeNo string `json:"out_trade_no"` OutRefundNo string `json:"out_refund_no"` NotifyUrl string `json:"notify_url"` Amount OrderRefundAmount `json:"amount"` } type OrderRefundAmount struct { Refund uint32 `json:"refund"` Total uint32 `json:"total"` Currency string `json:"currency"` }