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

317 lines
9.8 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
  1. package pay_service
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. core2 "github.com/chanxuehong/wechat/mch/core"
  6. "github.com/chanxuehong/wechat/mch/pay"
  7. "hudongzhuanjia/logger"
  8. "hudongzhuanjia/models"
  9. "hudongzhuanjia/utils"
  10. "net/http"
  11. "strconv"
  12. "time"
  13. )
  14. const CallbackOrderUrl = "https://api.ouxuanhudong.com/PcClient/common/WeChatOauthCtl/callbackOrder"
  15. func Order(content, ip, openid string, fee, goodType int, userId, activityId int64) (map[string]interface{}, error) {
  16. client, err := Client()
  17. if err != nil {
  18. return nil, err
  19. }
  20. now := time.Now()
  21. timeStart := now.Format("20060101150405")
  22. timeExpire := now.Add(2 * time.Hour).Format("20060101150405")
  23. outTradeNo := utils.RandomStr(32)
  24. nonceStr := utils.RandomStr(32)
  25. resp, err := pay.UnifiedOrder2(client, &pay.UnifiedOrderRequest{
  26. Body: content,
  27. OutTradeNo: outTradeNo,
  28. TotalFee: int64(fee),
  29. SpbillCreateIP: ip,
  30. NotifyURL: CallbackOrderUrl,
  31. TradeType: "JSAPI",
  32. DeviceInfo: "WEB",
  33. NonceStr: nonceStr,
  34. SignType: core2.SignType_MD5,
  35. TimeStart: now,
  36. OpenId: openid,
  37. })
  38. if err != nil {
  39. return nil, err
  40. }
  41. userOrder := new(models.UserOrder)
  42. userOrder.DeviceInfo = "WEB"
  43. userOrder.Desc = content
  44. userOrder.UserId = userId
  45. userOrder.ActivityId = activityId
  46. userOrder.FeeType = "CNY"
  47. userOrder.GoodType = goodType
  48. userOrder.OpenId = openid
  49. userOrder.OutTradeNo = outTradeNo
  50. userOrder.TimeStart = timeStart
  51. userOrder.TimeExpire = timeExpire
  52. userOrder.TotalFee = fee
  53. userOrder.TradeType = "JSAPI"
  54. userOrder.PrepayId = resp.PrepayId
  55. userOrder.Status = 0
  56. userOrder.IsDelete = false
  57. userOrder.CreatedAt = time.Now()
  58. userOrder.UpdatedAt = time.Now()
  59. if _, err = userOrder.AddUserOrder(); err != nil {
  60. return nil, err
  61. }
  62. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  63. //获取H5支付需要的paySign
  64. pac := "prepay_id=" + resp.PrepayId
  65. paySign := core2.JsapiSign(client.AppId(), nonceStr, pac, core2.SignType_MD5, timestamp, ApiKey)
  66. return map[string]interface{}{
  67. "appid": Appid,
  68. "timestamp": timestamp,
  69. "nonce_str": nonceStr,
  70. "package": pac,
  71. "sign_type": core2.SignType_MD5,
  72. "pay_sign": paySign,
  73. "out_trade_no": outTradeNo,
  74. "user_order_id": userOrder.Id,
  75. }, nil
  76. }
  77. func UnifiedOrder(content, ip, openid string, fee int64) (map[string]interface{}, error) {
  78. client, err := Client()
  79. if err != nil {
  80. return nil, err
  81. }
  82. now := time.Now()
  83. outTradeNo := utils.RandomStr(32)
  84. nonceStr := utils.RandomStr(32)
  85. resp, err := pay.UnifiedOrder2(client, &pay.UnifiedOrderRequest{
  86. Body: content,
  87. OutTradeNo: outTradeNo,
  88. TotalFee: int64(fee),
  89. SpbillCreateIP: ip,
  90. NotifyURL: CallbackOrderUrl,
  91. TradeType: "JSAPI",
  92. DeviceInfo: "WEB",
  93. NonceStr: nonceStr,
  94. SignType: core2.SignType_MD5,
  95. TimeStart: now,
  96. OpenId: openid,
  97. })
  98. if err != nil {
  99. return nil, err
  100. }
  101. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  102. //获取H5支付需要的paySign
  103. pac := "prepay_id=" + resp.PrepayId
  104. paySign := core2.JsapiSign(client.AppId(), nonceStr, pac, core2.SignType_MD5, timestamp, ApiKey)
  105. return map[string]interface{}{
  106. "appid": Appid,
  107. "timestamp": timestamp,
  108. "nonce_str": nonceStr,
  109. "package": pac,
  110. "sign_type": core2.SignType_MD5,
  111. "pay_sign": paySign,
  112. "out_trade_no": outTradeNo,
  113. }, nil
  114. }
  115. // Notify
  116. type NotifyRequest struct {
  117. ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
  118. ReturnMsg string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
  119. ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
  120. ErrCode string `xml:"err_code,omitempty" json:"err_code,omitempty"`
  121. ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
  122. Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
  123. MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
  124. DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
  125. NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
  126. Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
  127. SignType string `xml:"sign_type,omitempty" json:"sign_type,omitempty"`
  128. Openid string `xml:"openid,omitempty" json:"openid,omitempty"`
  129. IsSubscribe string `xml:"is_subscribe,omitempty" json:"is_subscribe,omitempty"`
  130. TradeType string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
  131. BankType string `xml:"bank_type,omitempty" json:"bank_type,omitempty"`
  132. TotalFee int `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
  133. SettlementTotalFee int `xml:"settlement_total_fee,omitempty" json:"settlement_total_fee,omitempty"`
  134. FeeType string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
  135. CashFee int `xml:"cash_fee,omitempty" json:"cash_fee,omitempty"`
  136. CashFeeType string `xml:"cash_fee_type,omitempty" json:"cash_fee_type,omitempty"`
  137. CouponFee int `xml:"coupon_fee,omitempty" json:"coupon_fee,omitempty"`
  138. CouponCount int `xml:"coupon_count,omitempty" json:"coupon_count,omitempty"`
  139. CouponType0 string `xml:"coupon_type_0,omitempty" json:"coupon_type_0,omitempty"`
  140. CouponType1 string `xml:"coupon_type_1,omitempty" json:"coupon_type_1,omitempty"`
  141. CouponId0 string `xml:"coupon_id_0,omitempty" json:"coupon_id_0,omitempty"`
  142. CouponId1 string `xml:"coupon_id_1,omitempty" json:"coupon_id_1,omitempty"`
  143. CouponFee0 int `xml:"coupon_fee_0,omitempty" json:"coupon_fee_0,omitempty"`
  144. CouponFee1 int `xml:"coupon_fee_1,omitempty" json:"coupon_fee_1,omitempty"`
  145. TransactionId string `xml:"transaction_id,omitempty" json:"transaction_id,omitempty"`
  146. OutTradeNo string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
  147. Attach string `xml:"attach,omitempty" json:"attach,omitempty"`
  148. TimeEnd string `xml:"time_end,omitempty" json:"time_end,omitempty"`
  149. }
  150. func NotifyOrder(req *http.Request) error {
  151. res := new(NotifyRequest)
  152. if err := xml.NewDecoder(req.Body).Decode(res); err != nil {
  153. return fmt.Errorf("xml.NewDecoder.Decode:%w", err)
  154. }
  155. if res.ReturnCode != CODE_SUCCESS {
  156. return fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
  157. }
  158. if res.ResultCode != CODE_SUCCESS {
  159. return fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
  160. }
  161. userOrder := new(models.UserOrder)
  162. exist, err := userOrder.GetByOutTradeNo(res.OutTradeNo)
  163. if err != nil {
  164. return err
  165. }
  166. if !exist {
  167. return fmt.Errorf("user order not exist")
  168. }
  169. userOrder.TimeEnd = res.TimeEnd
  170. userOrder.TransactionId = res.TransactionId
  171. userOrder.Status = 1
  172. if _, err = userOrder.UpdateStatusById(userOrder.Id); err != nil {
  173. return err
  174. }
  175. // 设置一下
  176. if userOrder.GoodType == 1 { // 霸屏
  177. _, err = new(models.BullyScreenHistory).UpdateStatusByUserOrderId(userOrder.Id, 0)
  178. if err != nil {
  179. return err
  180. }
  181. } else if userOrder.GoodType == 2 {
  182. _, err = new(models.RewardHistory).UpdateStatusByUserOrderId(userOrder.Id, 0)
  183. if err != nil {
  184. return err
  185. }
  186. }
  187. return nil
  188. }
  189. func Query(outTradeNo string) (*models.UserOrder, error) {
  190. client, err := Client()
  191. if err != nil {
  192. return nil, err
  193. }
  194. // 请求订单查询,成功后得到结果
  195. res, err := pay.OrderQuery2(client, &pay.OrderQueryRequest{
  196. OutTradeNo: outTradeNo,
  197. NonceStr: utils.RandomStr(32),
  198. SignType: core2.SignType_MD5,
  199. })
  200. if err != nil {
  201. return nil, err
  202. }
  203. userOrder := new(models.UserOrder)
  204. userOrder.TransactionId = res.TransactionId
  205. userOrder.TimeEnd = core2.FormatTime(res.TimeEnd)
  206. switch res.TradeState {
  207. case CODE_TRADE_CLOSED:
  208. userOrder.Status = -1
  209. case CODE_TRADE_SUCCESS:
  210. userOrder.Status = 1
  211. case CODE_TRADE_REVOKED:
  212. userOrder.Status = 2
  213. case CODE_TRADE_REFUND:
  214. userOrder.Status = 3
  215. case CODE_TRADE_PAYERROR:
  216. userOrder.Status = 4
  217. default:
  218. userOrder.Status = 0
  219. }
  220. if _, err = userOrder.UpdateStatusByOutTradeNo(outTradeNo, userOrder.Status); err != nil {
  221. return nil, err
  222. }
  223. return userOrder, nil
  224. }
  225. func BatchQueryByUserId(userId int64) error {
  226. orders, err := models.GetUserOrdersByStatusAndUserId(userId, 0)
  227. if err != nil {
  228. return err
  229. }
  230. return batchQuery(orders)
  231. }
  232. func BatchQueryByActivityId(activityId int64) error {
  233. orders, err := models.GetUserOrdersByStatusAndActivityId(activityId, 0)
  234. if err != nil {
  235. return nil
  236. }
  237. return batchQuery(orders)
  238. }
  239. func batchQuery(orders []*models.UserOrder) error {
  240. for _, order := range orders {
  241. userOrder, err := Query(order.OutTradeNo)
  242. if err != nil {
  243. return err
  244. }
  245. order.Status = userOrder.Status
  246. order.TransactionId = userOrder.TransactionId
  247. order.TimeEnd = userOrder.TimeEnd
  248. if order.Status == 1 { // 付款成功
  249. if order.GoodType == 1 {
  250. _, err = new(models.BullyScreenHistory).UpdateStatusByUserOrderId(order.Id, 0)
  251. if err != nil {
  252. return err
  253. }
  254. } else if order.GoodType == 2 {
  255. _, err = new(models.RewardHistory).UpdateStatusByUserOrderId(order.Id, 0)
  256. if err != nil {
  257. return err
  258. }
  259. } else {
  260. logger.Sugar.Info("支付测试")
  261. }
  262. } else if order.TimeExpire <= time.Now().Format("20060101150405") {
  263. err = Close(order.OutTradeNo)
  264. if err != nil {
  265. return err
  266. }
  267. order.Status = -1 // 关闭支付
  268. _, err = order.UpdateStatusById(order.Id)
  269. if err != nil {
  270. return err
  271. }
  272. }
  273. }
  274. return nil
  275. }
  276. func Close(outTradeNo string) error {
  277. //client := wechat.NewClient(Appid, Mchid, ApiKey, true)
  278. client, err := Client()
  279. if err != nil {
  280. return err
  281. }
  282. err = pay.CloseOrder2(client, &pay.CloseOrderRequest{
  283. OutTradeNo: outTradeNo,
  284. NonceStr: utils.RandomStr(32),
  285. SignType: core2.SignType_MD5,
  286. })
  287. // 请求关闭订单,成功后得到结果
  288. if err != nil {
  289. return err
  290. }
  291. return nil
  292. }