pay.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package paymob
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "bet24.com/log"
  10. "bet24.com/public"
  11. coreClient "bet24.com/servers/coreservice/client"
  12. "bet24.com/servers/payment/config"
  13. "bet24.com/servers/payment/db"
  14. "bet24.com/servers/payment/shop"
  15. "github.com/gin-gonic/gin"
  16. )
  17. // 下单
  18. func PayOrder(c *gin.Context) {
  19. obj := db.NewOrder(db.SP_paymob_ORDER)
  20. if err := c.ShouldBind(&obj.In); err != nil {
  21. log.Debug("%s query params err %v", "payMob.PayOrder", err)
  22. c.String(http.StatusOK, "")
  23. return
  24. }
  25. obj.In.IpAddress = strings.Split(c.Request.RemoteAddr, ":")[0]
  26. //// 币种为空,根据ip获取
  27. //if obj.In.Currency == "" {
  28. // currency := shop.GetCurrencyRateByIp(obj.In.UserID, obj.In.IpAddress)
  29. // obj.In.Currency = currency
  30. //}
  31. // 获取产品信息
  32. item := shop.GetProduct(obj.In.ProductID)
  33. if item == nil {
  34. log.Error("%s query GetProduct productId=%s currency=%s is nil", "paymob.PayOrder", obj.In.ProductID, obj.In.Currency)
  35. c.String(http.StatusOK, "")
  36. return
  37. }
  38. //// 获取当前汇率信息
  39. //info := shop.GetExchangeRate(obj.In.Currency)
  40. //if info == nil {
  41. // log.Error("%s query GetExchangeRate obj.In.Currency=%s is nil", "paymob.PayOrder", obj.In.Currency)
  42. // c.String(http.StatusOK, "")
  43. // return
  44. //}
  45. //
  46. //// 计算价格
  47. //calPrice := info.Rate * item.Price
  48. //
  49. //// 检查价格是否篡改
  50. //if calPrice != obj.In.Price {
  51. // log.Error("%s obj.In.Price=%v info.Rate=%v calPrice=%v is invalid", "paymob.PayOrder", obj.In.Price, info.Rate, calPrice)
  52. // c.String(http.StatusOK, "")
  53. // return
  54. //}
  55. // 检查价格是否篡改
  56. if item.Price != obj.In.Price {
  57. log.Error("%s obj.In.Price=%v calPrice=%v is invalid", "paymob.PayOrder", obj.In.Price, item.Price)
  58. c.String(http.StatusOK, "")
  59. return
  60. }
  61. obj.DoAction(nil)
  62. if obj.Out.OrderID == "" {
  63. log.Debug("%s GenOrder fail obj.In=%+v", "payMob.PayOrder", obj.In)
  64. c.String(http.StatusOK, "")
  65. return
  66. }
  67. price := fmt.Sprintf("%d", int(math.Ceil(obj.In.Price)))
  68. // 第1步:获取身份验证token
  69. authToken := getAuthToken()
  70. // 第2步:订单注册
  71. orderReg := orderRegister(authToken, price, obj.Out.OrderID, obj.In.ProductID, obj.In.ProductID)
  72. orderId := strconv.Itoa(orderReg.Id)
  73. // 第3步:获取支付token
  74. paymentToken := getPaymentToken(authToken, price, orderId, obj.In.Currency)
  75. // 第4步:现金支付请求
  76. resp := cashPay(paymentToken, obj.In.Tel)
  77. // 跳转到支付页面,以便持卡人完成支付过程
  78. c.Redirect(http.StatusMovedPermanently, resp.Redirect_url)
  79. return
  80. }
  81. // 第1步:获取身份验证token
  82. func getAuthToken() string {
  83. info := auth_token_req{Api_Key: config.Server.PayMob.Api_Key}
  84. buf, _ := json.Marshal(info)
  85. data := string(buf)
  86. // POST请求
  87. respBody := public.HttpPostByJson(config.Server.PayMob.Url_Auth_Token, data)
  88. log.Debug("payMob.getAuthToken 第1步,获取身份验证token! req ==> %+v resp ==> %+v", data, respBody)
  89. var resp auth_token_resp
  90. if err := json.Unmarshal([]byte(respBody), &resp); err != nil {
  91. log.Debug("%s query params err %v", "payMob.getAuthToken", err)
  92. return ""
  93. }
  94. return resp.Token
  95. }
  96. // 第2步:订单注册,返回id
  97. func orderRegister(authToken, price, orderId, name, description string) order_register_resp {
  98. var items []order_register_product
  99. items = append(items, order_register_product{
  100. Name: name,
  101. Amount_cents: price,
  102. Description: description,
  103. Quantity: "1",
  104. })
  105. info := order_register_req{
  106. Auth_token: authToken,
  107. Delivery_needed: "false",
  108. Amount_cents: price,
  109. Merchant_order_id: orderId,
  110. Items: items,
  111. }
  112. buf, _ := json.Marshal(info)
  113. data := string(buf)
  114. // POST请求
  115. respBody := public.HttpPostByJson(config.Server.PayMob.Url_Order_Register, data)
  116. log.Debug("payMob.orderRegister 第2步,订单注册,返回id! req ==> %+v resp ==> %+v", data, respBody)
  117. var resp order_register_resp
  118. if err := json.Unmarshal([]byte(respBody), &resp); err != nil {
  119. log.Debug("%s query params err %v", "payMob.orderRegister", err)
  120. return resp
  121. }
  122. return resp
  123. }
  124. // 第3步:获取支付token
  125. func getPaymentToken(authToken, price, orderId, currency string) string {
  126. info := payment_toke_req{
  127. Auth_token: authToken,
  128. Amount_cents: price,
  129. Expiration: 3600,
  130. Order_id: orderId,
  131. Billing_data: payment_token_req_billing_data{
  132. Apartment: "NA",
  133. Email: "test",
  134. Floor: "NA",
  135. First_name: "test",
  136. Street: "NA",
  137. Building: "NA",
  138. Phone_number: "test",
  139. Shipping_method: "NA",
  140. Postal_code: "NA",
  141. City: "NA",
  142. Country: "NA",
  143. Last_name: "test",
  144. State: "NA",
  145. },
  146. Currency: currency,
  147. Integration_id: config.Server.PayMob.Integration_Id,
  148. }
  149. buf, _ := json.Marshal(info)
  150. data := string(buf)
  151. // POST请求
  152. respBody := public.HttpPostByJson(config.Server.PayMob.Url_Payment_Token, data)
  153. log.Debug("payMob.getPaymentToken 第3步,获取支付token! req ==> %+v resp ==> %+v", data, respBody)
  154. var resp payment_token_resp
  155. if err := json.Unmarshal([]byte(respBody), &resp); err != nil {
  156. log.Debug("%s query params err %v", "payMob.getPaymentToken", err)
  157. return ""
  158. }
  159. return resp.Token
  160. }
  161. // 第4步:现金支付请求
  162. func cashPay(paymentToken, tel string) cash_pay_resp {
  163. info := cash_pay_req{
  164. Source: cash_pay_source{
  165. Identifier: tel,
  166. Subtype: "WALLET",
  167. },
  168. Payment_token: paymentToken,
  169. }
  170. buf, _ := json.Marshal(info)
  171. data := string(buf)
  172. // POST请求
  173. respBody := public.HttpPostByJson(config.Server.PayMob.Url_Payment_CashPay, data)
  174. log.Debug("payMob.cashPay 第4步,现金支付请求! req ==> %+v resp ==> %+v", data, respBody)
  175. var resp cash_pay_resp
  176. if err := json.Unmarshal([]byte(respBody), &resp); err != nil {
  177. log.Debug("%s query params err %v", "payMob.cashPay", err)
  178. return resp
  179. }
  180. return resp
  181. }
  182. // 回调通知
  183. func PayNotify(c *gin.Context) {
  184. var resp payNotify_req
  185. if err := c.ShouldBind(&resp); err != nil {
  186. log.Debug("%s query params err %v", "payMob.PayNotify", err)
  187. c.String(http.StatusOK, "")
  188. return
  189. }
  190. log.Debug("payMob.PayNotify resp ==> %+v", resp)
  191. checkContent := fmt.Sprintf("%v%v%v%v%v%v%v%v%v%v%v%v%v%v%v%v%v%v%v%v",
  192. resp.Amount_cents, resp.Created_at, resp.Currency, resp.Error_occured, resp.Has_parent_transaction,
  193. resp.Id, resp.Integration_id, resp.Is_3d_secure, resp.Is_auth, resp.Is_capture,
  194. resp.Is_refunded, resp.Is_standalone_payment, resp.Is_voided, resp.Order, resp.Owner,
  195. resp.Pending, resp.Source_data_pan, resp.Source_data_sub_type, resp.Source_data_type, resp.Success,
  196. )
  197. hmac := public.HmacSHA512(config.Server.PayMob.HMAC, checkContent)
  198. log.Debug("payMob.PayNotify 拼接 hmac ==> %s", hmac)
  199. // 验证签名
  200. if hmac != resp.Hmac {
  201. log.Error("payMob.PayNotify 签名失败 ==> %+v", resp)
  202. return
  203. }
  204. log.Debug("payMob.PayNotify 签名成功")
  205. // 返回码,’APPLY_SUCCESS’代表成功
  206. if !resp.Success {
  207. log.Error("payMob.PayNotify resp ==> %+v 失败", resp)
  208. c.JSON(http.StatusOK, ret{
  209. Code: "SUCCESS",
  210. Msg: "Success",
  211. })
  212. return
  213. }
  214. // 数据库操作
  215. obj := db.NewNotify(db.SP_paymob_NOTIFY)
  216. obj.In.OrderID = resp.Merchant_order_id
  217. obj.In.TradeID = strconv.Itoa(resp.Order)
  218. //obj.In.Price = resp.Amount_cents
  219. obj.DoAction(nil)
  220. // 操作成功,给道具
  221. if obj.Out.RetCode == 1 {
  222. // 充值
  223. resp := coreClient.Recharge(obj.Out.UserID, obj.Out.ProductID)
  224. log.Debug("%s 充值成功 %+v", "payMob.PayNotify", resp)
  225. }
  226. c.JSON(http.StatusOK, ret{
  227. Code: "SUCCESS",
  228. Msg: "Success",
  229. })
  230. return
  231. }
  232. // 支付完成跳转处理
  233. func PayCallback(c *gin.Context) {
  234. c.String(http.StatusOK, "success")
  235. log.Debug("payMob.payCallback")
  236. }