互动
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.

334 lines
11 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. package pay_service
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. "hudongzhuanjia/logger"
  6. "hudongzhuanjia/models"
  7. "hudongzhuanjia/utils"
  8. "hudongzhuanjia/utils/define"
  9. "strconv"
  10. "time"
  11. pay_core "github.com/chanxuehong/wechat/mch/core"
  12. "github.com/chanxuehong/wechat/mch/pay"
  13. "github.com/syndtr/goleveldb/leveldb/errors"
  14. )
  15. func UnifiedOrder(content, openId string, fee, goodType, userId, activityId int, expireAt int64) (map[string]interface{}, error) {
  16. client, err := Client()
  17. if err != nil {
  18. return nil, err
  19. }
  20. outTradeNo := utils.RandomStr(32)
  21. nonceStr := utils.RandomStr(32)
  22. body := make(map[string]string, 0)
  23. body["body"] = content
  24. body["out_trade_no"] = outTradeNo
  25. body["total_fee"] = fmt.Sprint(fee)
  26. body["notify_url"] = define.CallbackOrderUrl
  27. body["trade_type"] = "JSAPI"
  28. body["nonce_str"] = nonceStr
  29. body["sign_type"] = pay_core.SignType_MD5
  30. body["openid"] = openId
  31. resp, err := pay.UnifiedOrder(client, body)
  32. if err != nil {
  33. return nil, err
  34. }
  35. // 记录这次订单
  36. userOrder := new(models.UserOrder)
  37. userOrder.Body = content
  38. userOrder.UserId = userId
  39. userOrder.ActivityId = activityId
  40. userOrder.FeeType = "CNY"
  41. userOrder.GoodType = goodType
  42. userOrder.OpenId = openId
  43. userOrder.OutTradeNo = outTradeNo
  44. userOrder.ExpireAt = expireAt
  45. userOrder.TotalFee = fee
  46. userOrder.TradeType = "JSAPI"
  47. userOrder.PrepayId = resp["prepay_id"]
  48. userOrder.Status = 0
  49. if _, err = models.Add(userOrder); err != nil {
  50. return nil, err
  51. }
  52. //获取H5支付需要的paySign
  53. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  54. pac := "prepay_id=" + resp["prepay_id"]
  55. paySign := pay_core.JsapiSign(client.AppId(), timestamp, nonceStr, pac, pay_core.SignType_MD5, define.ApiKey)
  56. return map[string]interface{}{
  57. "appid": client.AppId(),
  58. "timestamp": timestamp,
  59. "nonce_str": nonceStr,
  60. "package": pac,
  61. "sign_type": pay_core.SignType_MD5,
  62. "pay_sign": paySign,
  63. "out_trade_no": outTradeNo,
  64. "user_order_id": userOrder.Id,
  65. }, nil
  66. }
  67. func ReOrder(outTradeNo string) (map[string]interface{}, error) {
  68. userOrder := new(models.UserOrder)
  69. exist, err := userOrder.GetByOutTradeNo(outTradeNo)
  70. if err != nil {
  71. return nil, err
  72. }
  73. if !exist {
  74. return nil, fmt.Errorf("订单不存在")
  75. }
  76. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  77. nonceStr := utils.RandomStr(32)
  78. //获取H5支付需要的paySign
  79. pac := "prepay_id=" + userOrder.PrepayId
  80. paySign := pay_core.JsapiSign(define.AppId, timestamp, nonceStr, pac, pay_core.SignType_MD5, define.ApiKey)
  81. //go PutOrderDelayQueue(userOrder)
  82. return map[string]interface{}{
  83. "appid": define.AppId,
  84. "timestamp": timestamp,
  85. "nonce_str": nonceStr,
  86. "package": pac,
  87. "sign_type": pay_core.SignType_MD5,
  88. "pay_sign": paySign,
  89. "out_trade_no": outTradeNo,
  90. "user_order_id": userOrder.Id,
  91. }, nil
  92. }
  93. // Notify
  94. type NotifyOrderParam struct {
  95. XMLName struct{} `xml:"xml" json:"-"`
  96. ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
  97. ReturnMsg string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
  98. ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
  99. ErrCode string `xml:"err_code,omitempty" json:"err_code,omitempty"`
  100. ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
  101. Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
  102. MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
  103. DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
  104. NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
  105. Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
  106. SignType string `xml:"sign_type,omitempty" json:"sign_type,omitempty"`
  107. Openid string `xml:"openid,omitempty" json:"openid,omitempty"`
  108. IsSubscribe string `xml:"is_subscribe,omitempty" json:"is_subscribe,omitempty"`
  109. TradeType string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
  110. BankType string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
  111. TotalFee int `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
  112. SettlementTotalFee int `xml:"settlement_total_fee,omitempty" json:"settlement_total_fee,omitempty"`
  113. FeeType string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
  114. CashFee int `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
  115. CashFeeType string `xml:"cash_fee_type,omitempty" json:"cash_fee_type,omitempty"`
  116. TransactionId string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
  117. OutTradeNo string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
  118. TimeEnd string `xml:"time_end,omitempty" json:"time_end,omitempty"`
  119. }
  120. func NotifyOrder(body string) (*models.UserOrder, error) {
  121. res := NotifyOrderParam{}
  122. err := xml.Unmarshal([]byte(body), &res)
  123. if err != nil {
  124. err = fmt.Errorf("xml unmarsal error:%+v", err)
  125. return nil, err
  126. }
  127. if res.ReturnCode != define.CODE_SUCCESS {
  128. err = fmt.Errorf("network error, retrun_code: %+v and return_msg: %+v", res.ReturnCode, res.ReturnMsg)
  129. return nil, err
  130. }
  131. if res.ResultCode != define.CODE_SUCCESS {
  132. err = fmt.Errorf("trade error, result_code: %+v and err_code: %+v and err_desc: %+v",
  133. res.ResultCode, res.ErrCode, res.ErrCodeDes)
  134. return nil, err
  135. }
  136. order := new(models.UserOrder)
  137. exist, err := order.GetByOutTradeNo(res.OutTradeNo)
  138. if err != nil || !exist {
  139. err = fmt.Errorf("user order get by out_trade_no: %+v, error: %+v, exist: %+v", res.OutTradeNo, err, exist)
  140. return nil, err
  141. }
  142. order.TransactionId = res.TransactionId
  143. order.Status = 1
  144. _, err = models.Update(order.Id, order, "status", "transaction_id")
  145. if err != nil {
  146. return nil, err
  147. }
  148. err = HandleSuccess(order)
  149. if err != nil {
  150. logger.Error(fmt.Sprintf("callback 错误处理: %v", err))
  151. return nil, err
  152. }
  153. return order, nil
  154. }
  155. func OrderQuery(outTradeNo string) (map[string]string, error) {
  156. client, err := Client()
  157. if err != nil {
  158. return nil, err
  159. }
  160. body := make(map[string]string)
  161. body["out_trade_no"] = outTradeNo
  162. body["nonce_str"] = utils.RandomStr(32)
  163. body["sign_type"] = pay_core.SignType_MD5
  164. res, err := pay.OrderQuery(client, body)
  165. if err != nil {
  166. return nil, err
  167. }
  168. return res, nil
  169. }
  170. func Close(outTradeNo string) error {
  171. client, err := Client()
  172. if err != nil {
  173. return err
  174. }
  175. body := make(map[string]string)
  176. body["out_trade_no"] = outTradeNo
  177. body["nonce_str"] = utils.RandomStr(32)
  178. body["sign_type"] = pay_core.SignType_MD5
  179. _, err = pay.CloseOrder(client, body)
  180. // 请求关闭订单,成功后得到结果
  181. if err != nil {
  182. return err
  183. }
  184. return nil
  185. }
  186. const CallbackRefundUrl = "https://api.ouxuanhudong.com/PcClient/common/WeChatOauthCtl/callbackRefund"
  187. func Refund(reason, outTradeNo string) (map[string]string, error) {
  188. userOrder := new(models.UserOrder)
  189. exist, err := userOrder.GetByOutTradeNo(outTradeNo)
  190. if err != nil || !exist {
  191. return nil, errors.New("订单异常")
  192. }
  193. client, err := Client()
  194. if err != nil {
  195. return nil, err
  196. }
  197. outRefundNo := utils.RandomStr(64)
  198. nonceStr := utils.RandomStr(32)
  199. body := make(map[string]string, 0)
  200. body["out_trade_no"] = outTradeNo
  201. body["out_refund_no"] = outRefundNo
  202. body["total_fee"] = fmt.Sprint(userOrder.TotalFee)
  203. body["refund_fee"] = fmt.Sprint(userOrder.TotalFee)
  204. body["nonce_str"] = nonceStr
  205. body["sign_type"] = pay_core.SignType_MD5
  206. body["refund_desc"] = reason
  207. body["notify_url"] = CallbackRefundUrl
  208. res, err := pay.Refund(client, body)
  209. if err != nil {
  210. return nil, err
  211. }
  212. userOrder.Status = 3
  213. _, err = models.Update(userOrder.Id, userOrder, "status")
  214. if err != nil {
  215. return nil, err
  216. }
  217. return res, nil
  218. }
  219. func QueryRefund(outTradeNo string) (*pay.RefundQueryResponse, error) {
  220. client, err := Client()
  221. if err != nil {
  222. return nil, err
  223. }
  224. res, err := pay.RefundQuery2(client, &pay.RefundQueryRequest{
  225. OutTradeNo: outTradeNo,
  226. NonceStr: utils.RandomStr(32),
  227. SignType: pay_core.SignType_MD5,
  228. })
  229. //请求申请退款
  230. if err != nil {
  231. return nil, err
  232. }
  233. return res, nil
  234. }
  235. type NotifyRefundParam struct {
  236. XMLName struct{} `xml:"xml" json:"-"`
  237. ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
  238. ReturnMsg string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
  239. ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
  240. ErrCode string `xml:"err_code,omitempty" json:"err_code,omitempty"`
  241. ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
  242. Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
  243. MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
  244. NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
  245. ReqInfo string `xml:"req_info,omitempty" json:"req_info,omitempty"`
  246. TransactionId string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
  247. OutTradeNo string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
  248. RefundId string `xml:"refund_id,omitempty" json:"refund_id,omitempty"`
  249. OutRefundNo string `xml:"out_refund_no,omitempty" json:"out_refund_no,omitempty"`
  250. TotalFee int `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
  251. SettlementTotalFee int `xml:"settlement_total_fee,omitempty" json:"settlement_total_fee,omitempty"`
  252. RefundFee int `xml:"refund_fee,omitempty" json:"refund_fee,omitempty"`
  253. SettlementRefundFee int `xml:"settlement_refund_fee,omitempty" json:"settlement_refund_fee,omitempty"`
  254. RefundStatus string `xml:"refund_status,omitempty" json:"refund_status,omitempty"`
  255. SuccessTime string `xml:"success_time,omitempty" json:"success_time,omitempty"`
  256. RefundRecvAccout string `xml:"refund_recv_accout,omitempty" json:"refund_recv_accout,omitempty"`
  257. RefundAccount string `xml:"refund_account,omitempty" json:"refund_account,omitempty"`
  258. RefundRequestSource string `xml:"refund_request_source,omitempty" json:"refund_request_source,omitempty"`
  259. }
  260. func NotifyRefund(body string) (*models.UserOrder, error) {
  261. res := NotifyRefundParam{}
  262. err := xml.Unmarshal([]byte(body), &res)
  263. if err != nil {
  264. err = fmt.Errorf("xml unmarsal error: %+v", err)
  265. return nil, err
  266. }
  267. logger.Error("return-->", res.ReturnCode == define.CODE_SUCCESS)
  268. logger.Error("result-->", res.ResultCode == define.CODE_SUCCESS)
  269. logger.Error(res)
  270. if res.ReturnCode != define.CODE_SUCCESS {
  271. err = fmt.Errorf("network error, retrun_code: %+v and return_msg: %+v", res.ReturnCode, res.ReturnMsg)
  272. return nil, err
  273. }
  274. if res.ResultCode != define.CODE_SUCCESS {
  275. err = fmt.Errorf("trade error, result_code: %+v and err_code: %+v and err_desc: %+v",
  276. res.ResultCode, res.ErrCode, res.ErrCodeDes)
  277. return nil, err
  278. }
  279. order := new(models.UserOrder)
  280. exist, err := order.GetByOutTradeNo(res.OutTradeNo)
  281. if err != nil || !exist {
  282. err = fmt.Errorf("user order get by out_trade_no: %+v, error: %+v, exist: %+v", res.OutTradeNo, err, exist)
  283. return nil, err
  284. }
  285. order.RefundRecvAccount = res.RefundRecvAccout
  286. order.RefundAccount = res.RefundAccount
  287. order.TransactionId = res.TransactionId
  288. order.Status = 4
  289. _, err = models.Update(order.Id, order, "status", "transaction_id")
  290. if err != nil {
  291. return nil, err
  292. }
  293. return order, nil
  294. }