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

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