互动
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
6.0 KiB

5 years ago
  1. package pay_service
  2. import (
  3. "encoding/xml"
  4. "errors"
  5. "fmt"
  6. "github.com/iGoogle-ink/gopay/v2"
  7. "github.com/iGoogle-ink/gopay/v2/wechat"
  8. "github.com/ouxuanserver/osmanthuswine/src/core"
  9. "hudongzhuanjia/libs/wx"
  10. "hudongzhuanjia/models"
  11. "net/http"
  12. "time"
  13. )
  14. const CALLBACK_REFUND_URL = "https://api.ouxuanhudong.com/PcClient/common/WeChatOauthCtl/callbackRefund"
  15. func RefundExtend(bm gopay.BodyMap) (*wechat.RefundResponse, error) {
  16. err := bm.CheckEmptyError("nonce_str", "out_refund_no", "total_fee", "refund_fee")
  17. if err != nil {
  18. return nil, err
  19. }
  20. if bm.Get("out_trade_no") == gopay.NULL && bm.Get("transaction_id") == gopay.NULL {
  21. return nil, errors.New("out_trade_no and transaction_id are not allowed to be null at the same time")
  22. }
  23. bs, err := ClientExtend(bm, wx.RefundURL)
  24. if err != nil {
  25. return nil, err
  26. }
  27. wxRsp := new(wechat.RefundResponse)
  28. if err = xml.Unmarshal(bs, wxRsp); err != nil {
  29. return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err)
  30. }
  31. return wxRsp, nil
  32. }
  33. func Refund(reason, outTradeNo, openId string, goodType, totalFee, refundFee int, userId, activityId int64) (*wechat.RefundResponse, error) {
  34. //client := wechat.NewClient(wx.Appid, wx.Mchid, wx.ApiKey, true)
  35. outRefundNo := gopay.GetRandomString(64)
  36. // 初始化参数结构体
  37. body := make(gopay.BodyMap)
  38. body.Set("out_trade_no", outTradeNo)
  39. body.Set("nonce_str", gopay.GetRandomString(32))
  40. body.Set("sign_type", wechat.SignType_MD5)
  41. body.Set("out_refund_no", outRefundNo)
  42. body.Set("total_fee", totalFee)
  43. body.Set("refund_fee", refundFee)
  44. body.Set("notify_url", CALLBACK_REFUND_URL)
  45. body.Set("refund_desc", reason)
  46. body.Set("refund_fee_type", "CNY")
  47. body.Set("appid", wx.Appid)
  48. body.Set("mch_id", wx.Mchid)
  49. res, err := RefundExtend(body)
  50. if err != nil {
  51. return nil, err
  52. }
  53. //ok, err := wechat.VerifySign(wx.ApiKey, wechat.SignType_MD5, res)
  54. //if err != nil {
  55. // return nil, err
  56. //}
  57. //
  58. //if !ok {
  59. // return nil, errors.New("签名验证失败")
  60. //}
  61. if res.ReturnCode != wx.CODE_SUCCESS {
  62. return nil, fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
  63. }
  64. if res.ResultCode != wx.CODE_SUCCESS {
  65. return nil, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
  66. }
  67. refund := new(models.UserRefund)
  68. refund.OutTradeNo = outTradeNo
  69. refund.Status = 0
  70. refund.TotalFee = totalFee
  71. refund.GoodType = goodType
  72. refund.RefundDesc = reason
  73. refund.FeeType = "CNY"
  74. refund.OpenId = openId
  75. refund.UserId = userId
  76. refund.ActivityId = activityId
  77. refund.IsDelete = false
  78. refund.CreatedAt = time.Now()
  79. refund.UpdatedAt = time.Now()
  80. if _, err := core.GetXormAuto().InsertOne(refund); err != nil {
  81. return nil, err
  82. }
  83. return res, err
  84. }
  85. func CallbackRefund(req *http.Request) error {
  86. res, err := wechat.ParseRefundNotifyResult(req)
  87. if err != nil {
  88. return err
  89. }
  90. //ok, err := wechat.VerifySign(wx.ApiKey, wechat.SignType_MD5, res)
  91. //if err != nil {
  92. // return err
  93. //}
  94. //if !ok {
  95. // return errors.New("sign verify failed")
  96. //}
  97. if res.ReturnCode != wx.CODE_SUCCESS {
  98. return fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
  99. }
  100. info, err := wechat.DecryptRefundNotifyReqInfo(res.ReqInfo, wx.ApiKey)
  101. if err != nil {
  102. return err
  103. }
  104. userRefund := new(models.UserRefund)
  105. exist, err := userRefund.GetByOutRefundNo(info.OutRefundNo)
  106. if err != nil {
  107. return err
  108. }
  109. if !exist {
  110. return errors.New("user refund not exist")
  111. }
  112. userRefund.Status = 1
  113. userRefund.RefundStatus = info.RefundStatus
  114. userRefund.TransactionId = info.TransactionId
  115. userRefund.OutTradeNo = info.OutTradeNo
  116. userRefund.RefundRecvAccount = info.RefundRecvAccout
  117. userRefund.RefundAccount = info.RefundAccount
  118. userRefund.SuccessTime = info.SuccessTime
  119. if _, err := core.GetXormAuto().Id(userRefund.Id).Update(userRefund); err != nil {
  120. return err
  121. }
  122. return nil
  123. }
  124. func QueryRefund(outTradeNo string) (*wechat.QueryRefundResponse, error) {
  125. client := wechat.NewClient(wx.Appid, wx.Mchid, wx.ApiKey, true)
  126. // 初始化参数结构体
  127. body := make(gopay.BodyMap)
  128. body.Set("out_trade_no", outTradeNo)
  129. body.Set("nonce_str", gopay.GetRandomString(32))
  130. body.Set("sign_type", wechat.SignType_MD5)
  131. //请求申请退款
  132. res, err := client.QueryRefund(body)
  133. if err != nil {
  134. return nil, err
  135. }
  136. ok, err := wechat.VerifySign(wx.ApiKey, wechat.SignType_MD5, res)
  137. if err != nil {
  138. return nil, err
  139. }
  140. if !ok {
  141. return nil, errors.New("签名验证失败")
  142. }
  143. if res.ReturnCode != wx.CODE_SUCCESS {
  144. return nil, fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
  145. }
  146. if res.ResultCode != wx.CODE_SUCCESS {
  147. return nil, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
  148. }
  149. fmt.Println("wxRsp:", *res)
  150. return res, nil
  151. }
  152. func BatchQueryRefundByUserId(userId int64) error {
  153. refunds := make([]*models.UserRefund, 0)
  154. if err := core.GetXormAuto().Where("status = 0 and user_id=?", userId).Find(&refunds); err != nil {
  155. return err
  156. }
  157. if err := batchQueryRefund(refunds); err != nil {
  158. return err
  159. }
  160. return nil
  161. }
  162. func BatchQueryRefundByActivityId(activityId int64) error {
  163. refunds := make([]*models.UserRefund, 0)
  164. if err := core.GetXormAuto().Where("status = 0 and user_id=?", activityId).Find(&refunds); err != nil {
  165. return err
  166. }
  167. if err := batchQueryRefund(refunds); err != nil {
  168. return err
  169. }
  170. return nil
  171. }
  172. func batchQueryRefund(refunds []*models.UserRefund) error {
  173. for _, refund := range refunds {
  174. res, err := QueryRefund(refund.OutTradeNo)
  175. if err != nil {
  176. return err
  177. }
  178. refund.RefundAccount = res.RefundAccount0
  179. refund.RefundRecvAccount = res.RefundRecvAccout0
  180. refund.RefundStatus = res.RefundStatus0
  181. refund.Status = 1
  182. refund.SuccessTime = res.RefundSuccessTime0
  183. refund.WxRefundId = res.RefundId0
  184. refund.TransactionId = res.TransactionId
  185. if _, err = core.GetXormAuto().Id(refund.Id).Cols("refund_account, refund_recv_account, " +
  186. "status, refund_status, success_time, wx_refund_id, transaction_id").Update(refund); err != nil {
  187. return err
  188. }
  189. }
  190. return nil
  191. }