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

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