wx_pay.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package services
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/wechatpay-apiv3/wechatpay-go/core"
  8. "github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
  9. payUtils "github.com/wechatpay-apiv3/wechatpay-go/utils"
  10. "hongze/hongze_mfyx/models"
  11. "hongze/hongze_mfyx/models/order"
  12. "hongze/hongze_mfyx/utils"
  13. "time"
  14. )
  15. //const (
  16. // MchPKFileName = "./utils/cert/apiclient_key.pem"
  17. // Mchid = "1624495680"
  18. // MchCertificateSerialNumber = "5ED2719CFAE5205763034AD80BF4B8A33533C418"
  19. // MchAPIv3Key = "W1tbnzQrzQ7yRRNuQCIHjis8dgdasKVX"
  20. //)
  21. //
  22. //// 微信商户建立连接
  23. //func getWechatClient() (context.Context, *core.Client, error) {
  24. // // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
  25. // mchPrivateKey, err := payUtils.LoadPrivateKeyWithPath(MchPKFileName)
  26. // if err != nil {
  27. // log.Print("load merchant private key error")
  28. // return nil, nil, err
  29. // }
  30. // ctx := context.Background()
  31. // // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
  32. // opts := []core.ClientOption{
  33. // option.WithWechatPayAutoAuthCipher(Mchid, MchCertificateSerialNumber, mchPrivateKey, MchAPIv3Key),
  34. // }
  35. // client, err := core.NewClient(ctx, opts...)
  36. // if err != nil {
  37. // log.Printf("new wechat pay client err:%s", err)
  38. // return nil, nil, err
  39. // }
  40. // return ctx, client, nil
  41. //}
  42. // 生成预支付交易单
  43. func ExampleJsapiApiServicePrepay(orderDetail *order.CygxOrder, unionId string) (JsapiApiResp order.PrepayWithRequestPaymentResponse, err error) {
  44. //var err error
  45. defer func() {
  46. if err != nil {
  47. fmt.Println(err)
  48. go utils.SendAlarmMsg(fmt.Sprint("生成预支付交易单失败 ExampleJsapiApiServicePrepay, err:", err.Error(), "unionId:", unionId), 2)
  49. }
  50. }()
  51. userRecord, e := models.GetUserRecordByUnionId(unionId, 10)
  52. if e != nil && e.Error() != utils.ErrNoRow() {
  53. err = errors.New("GetUserRecordByUnionId, Err: " + e.Error())
  54. return
  55. }
  56. ctx := context.Background()
  57. svc := jsapi.JsapiApiService{Client: utils.WechatCertClient}
  58. // 得到prepay_id,以及调起支付所需的参数和签名
  59. resp, _, err := svc.PrepayWithRequestPayment(ctx,
  60. jsapi.PrepayRequest{
  61. Appid: core.String(utils.WxAppId),
  62. Mchid: core.String(utils.Mchid),
  63. Description: core.String(orderDetail.SourceTitle),
  64. OutTradeNo: core.String(orderDetail.OutTradeNo),
  65. Attach: core.String(""),
  66. NotifyUrl: core.String(utils.WxPayJsapiNotifyUrl),
  67. TimeExpire: core.Time(time.Now().Add(10 * time.Minute)),
  68. Amount: &jsapi.Amount{
  69. Total: core.Int64(int64(orderDetail.OrderMoney * 100)), // 分
  70. },
  71. Payer: &jsapi.Payer{
  72. Openid: core.String(userRecord.OpenId),
  73. },
  74. },
  75. )
  76. if err != nil {
  77. //log.Printf("PrepayWithRequestPayment err:%s", err)
  78. return
  79. }
  80. JsapiApiResp.PrepayId = *resp.PrepayId
  81. JsapiApiResp.Appid = *resp.Appid
  82. JsapiApiResp.TimeStamp = *resp.TimeStamp
  83. JsapiApiResp.NonceStr = *resp.NonceStr
  84. JsapiApiResp.Package = *resp.Package
  85. JsapiApiResp.SignType = *resp.SignType
  86. JsapiApiResp.PaySign = *resp.PaySign
  87. return
  88. }
  89. type WechatPayCallback struct {
  90. MchID string `json:"mchid"`
  91. AppID string `json:"appid"`
  92. OutTradeNo string `json:"out_trade_no"`
  93. TransactionID string `json:"transaction_id"`
  94. TradeType string `json:"trade_type"`
  95. TradeState string `json:"trade_state"`
  96. TradeStateDesc string `json:"trade_state_desc"`
  97. BankType string `json:"bank_type"`
  98. Attach string `json:"attach"`
  99. SuccessTime time.Time `json:"success_time"`
  100. Payer struct {
  101. OpenID string `json:"openid"`
  102. } `json:"payer"`
  103. Amount struct {
  104. Total int `json:"total"`
  105. PayerTotal int `json:"payer_total"`
  106. Currency string `json:"currency"`
  107. PayerCurrency string `json:"payer_currency"`
  108. } `json:"amount"`
  109. }
  110. // 微信支付回调内容解密
  111. func WxDecodeNotify(body []byte) (wechatPayCallback *WechatPayCallback) {
  112. var err error
  113. defer func() {
  114. if err != nil {
  115. fmt.Println(err)
  116. go utils.SendAlarmMsg(fmt.Sprint("微信支付回调内容解密失败 WxDecodeNotify, err:", err.Error()), 2)
  117. }
  118. }()
  119. var prepaymap map[string]interface{}
  120. _ = json.Unmarshal(body, &prepaymap)
  121. var prepaymap2 = prepaymap["resource"].(map[string]interface{})
  122. nonce := prepaymap2["nonce"].(string)
  123. associatedData := prepaymap2["associated_data"].(string)
  124. ciphertext := prepaymap2["ciphertext"].(string)
  125. tx, e := payUtils.DecryptAES256GCM(utils.MchAPIv3Key, associatedData, nonce, ciphertext)
  126. if e != nil {
  127. err = errors.New("DecryptAES256GCM, Err: " + e.Error())
  128. return
  129. }
  130. var datamap *WechatPayCallback
  131. _ = json.Unmarshal([]byte(tx), &datamap)
  132. wechatPayCallback = datamap
  133. return
  134. }
  135. // Transaction
  136. type Transaction struct {
  137. Amount TransactionAmount `json:"amount,omitempty"`
  138. Appid string `json:"appid,omitempty"`
  139. Attach string `json:"attach,omitempty"`
  140. BankType string `json:"bank_type,omitempty"`
  141. Mchid string `json:"mchid,omitempty"`
  142. OutTradeNo string `json:"out_trade_no,omitempty"`
  143. Payer TransactionPayer `json:"payer,omitempty"`
  144. PromotionDetail []PromotionDetail `json:"promotion_detail,omitempty"`
  145. SuccessTime time.Time `json:"success_time,omitempty"`
  146. TradeState string `json:"trade_state,omitempty"`
  147. TradeStateDesc string `json:"trade_state_desc,omitempty"`
  148. TradeType string `json:"trade_type,omitempty"`
  149. TransactionId string `json:"transaction_id,omitempty"`
  150. }
  151. // TransactionAmount
  152. type TransactionAmount struct {
  153. Currency string `json:"currency,omitempty"`
  154. PayerCurrency string `json:"payer_currency,omitempty"`
  155. PayerTotal int64 `json:"payer_total,omitempty"`
  156. Total int64 `json:"total,omitempty"`
  157. }
  158. // PromotionDetail
  159. type PromotionDetail struct {
  160. // 券ID
  161. CouponId *string `json:"coupon_id,omitempty"`
  162. // 优惠名称
  163. Name *string `json:"name,omitempty"`
  164. // GLOBAL:全场代金券;SINGLE:单品优惠
  165. Scope *string `json:"scope,omitempty"`
  166. // CASH:充值;NOCASH:预充值。
  167. Type *string `json:"type,omitempty"`
  168. // 优惠券面额
  169. Amount *int64 `json:"amount,omitempty"`
  170. // 活动ID,批次ID
  171. StockId *string `json:"stock_id,omitempty"`
  172. // 单位为分
  173. WechatpayContribute *int64 `json:"wechatpay_contribute,omitempty"`
  174. // 单位为分
  175. MerchantContribute *int64 `json:"merchant_contribute,omitempty"`
  176. // 单位为分
  177. OtherContribute *int64 `json:"other_contribute,omitempty"`
  178. // CNY:人民币,境内商户号仅支持人民币。
  179. Currency *string `json:"currency,omitempty"`
  180. GoodsDetail []PromotionGoodsDetail `json:"goods_detail,omitempty"`
  181. }
  182. // PromotionGoodsDetail
  183. type PromotionGoodsDetail struct {
  184. // 商品编码
  185. GoodsId *string `json:"goods_id"`
  186. // 商品数量
  187. Quantity *int64 `json:"quantity"`
  188. // 商品价格
  189. UnitPrice *int64 `json:"unit_price"`
  190. // 商品优惠金额
  191. DiscountAmount *int64 `json:"discount_amount"`
  192. // 商品备注
  193. GoodsRemark *string `json:"goods_remark,omitempty"`
  194. }
  195. // TransactionPayer
  196. type TransactionPayer struct {
  197. Openid string `json:"openid,omitempty"`
  198. }
  199. // 根据订单号查询订单状态
  200. func GetQueryOrderByOutTradeNo(outTradeNo string) (tradeState string, statusCode int, itemResp *Transaction) {
  201. var err error
  202. defer func() {
  203. if err != nil {
  204. fmt.Println("err", err)
  205. go utils.SendAlarmMsg(fmt.Sprint("根据订单号查询订单状态 失败 GetQueryOrderByOutTradeNo, err:", err.Error(), "outTradeNo", outTradeNo), 2)
  206. }
  207. }()
  208. ctx := context.Background()
  209. svc := jsapi.JsapiApiService{Client: utils.WechatCertClient}
  210. resp, result, err := svc.QueryOrderByOutTradeNo(ctx,
  211. jsapi.QueryOrderByOutTradeNoRequest{
  212. OutTradeNo: core.String(outTradeNo),
  213. Mchid: core.String(utils.Mchid),
  214. },
  215. )
  216. statusCode = result.Response.StatusCode
  217. //订单状态码不存在直接返回
  218. if statusCode == 404 {
  219. err = nil
  220. return
  221. }
  222. tradeState = *resp.TradeState
  223. data, err := json.Marshal(resp)
  224. if err != nil {
  225. return
  226. }
  227. jsonstr := string(data)
  228. //item := new(Transaction)
  229. if err = json.Unmarshal([]byte(jsonstr), &itemResp); err != nil {
  230. return
  231. }
  232. //utils.FileLog.Info(jsonstr)
  233. ////itemResp = item
  234. //fmt.Println(itemResp)
  235. //fmt.Println(tradeState)
  236. //fmt.Println(itemResp.TransactionId)
  237. return
  238. }