pay.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. package shanghu
  2. import (
  3. "duoduo/apis/common"
  4. "duoduo/apis/shanghu/models"
  5. "duoduo/models/shanghu"
  6. "duoduo/tools"
  7. "duoduo/tools/app"
  8. "encoding/xml"
  9. "errors"
  10. "fmt"
  11. "github.com/gin-gonic/gin"
  12. "github.com/go-pay/gopay"
  13. "github.com/go-pay/gopay/wechat"
  14. wechatV3 "github.com/go-pay/gopay/wechat/v3"
  15. "github.com/shopspring/decimal"
  16. "net/http"
  17. "strconv"
  18. "time"
  19. )
  20. type wechatCallbackResp struct {
  21. XMLName xml.Name `xml:"xml"`
  22. ReturnCode Cdata `xml:"return_code"`
  23. ReturnMsg Cdata `xml:"return_msg"`
  24. }
  25. type Cdata struct {
  26. Value string `xml:",cdata"`
  27. }
  28. var (
  29. successResp = &wechatCallbackResp{ReturnCode: Cdata{Value: "SUCCESS"}, ReturnMsg: Cdata{Value: "OK"}}
  30. failResp = &wechatCallbackResp{ReturnCode: Cdata{Value: "FAIL"}, ReturnMsg: Cdata{Value: "数据处理异常"}}
  31. )
  32. func UnifiedOrder(c *gin.Context) {
  33. var inData models.UnifiedOrderRequest
  34. var sqlData shanghu.ClientPayTrans
  35. var outData models.UnifiedOrderReply
  36. err := c.ShouldBindJSON(&inData)
  37. if err != nil {
  38. app.Error(c, 400, err, err.Error())
  39. return
  40. }
  41. //校验 防止同一笔记录存在
  42. sqlData.RequestID = inData.RequestId
  43. if sqlData.GetRequestNum() > 0 {
  44. app.Error(c, 400, errors.New("交易已存在"), "交易已存在")
  45. return
  46. }
  47. //校验金额
  48. // 检查微信相关参数
  49. if !inData.Amount.GreaterThan(decimal.NewFromInt(0)) {
  50. app.Error(c, 400, errors.New("amount:金额必须大于0"), "amount:金额必须大于0")
  51. return
  52. }
  53. if inData.Amount.Round(2).String() != inData.Amount.String() {
  54. app.Error(c, 400, errors.New("total_fee:金额最多只能保留两位小数"), "total_fee:金额最多只能保留两位小数")
  55. return
  56. }
  57. //创建支付记录
  58. sqlData.ClientOpenID = inData.ClientOpenId
  59. sqlData.RequestID = inData.RequestId
  60. sqlData.CreatedAt = time.Now()
  61. sqlData.UpdatedAt = time.Now()
  62. sqlData.Amount = inData.Amount
  63. sqlData.OutTradeNo = strconv.FormatInt(inData.MerchantCardId, 10) + strconv.FormatInt(time.Now().UnixNano(), 10)
  64. sqlData.Status = 1 //未支付
  65. sqlData.MerchantCardID = inData.MerchantCardId
  66. sqlData.InvitationCode = inData.InvitationCode
  67. _, err = sqlData.Create()
  68. if err != nil {
  69. app.Error(c, 400, err, "创建支付失败")
  70. return
  71. }
  72. fmt.Println(sqlData.OutTradeNo)
  73. bm := make(gopay.BodyMap)
  74. bm.Set("nonce_str", common.GetRandomString(32))
  75. bm.Set("body", "商户卡")
  76. bm.Set("out_trade_no", sqlData.OutTradeNo)
  77. bm.Set("total_fee", inData.Amount.Mul(decimal.NewFromInt(100)).IntPart())
  78. bm.Set("spbill_create_ip", "127.0.0.1")
  79. bm.Set("notify_url", "https://shisanmiao.com/v1/client/pay/callback")
  80. bm.Set("device_info", "WEB")
  81. bm.Set("trade_type", "JSAPI")
  82. bm.Set("sign_type", wechat.SignType_MD5)
  83. bm.Set("openid", inData.ClientOpenId)
  84. client := NewWechatService()
  85. //请求支付下单,成功后得到结果
  86. wxResp, err := client.UnifiedOrder(c, bm)
  87. if err != nil {
  88. app.Error(c, 400, err, "下单失败")
  89. return
  90. }
  91. if wxResp.ReturnCode != "SUCCESS" {
  92. app.Error(c, 400, errors.New(wxResp.ReturnMsg), "下单失败")
  93. return
  94. }
  95. if wxResp.ResultCode != "SUCCESS" {
  96. app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "下单失败")
  97. return
  98. }
  99. timestamp := strconv.FormatInt(time.Now().Unix(), 10)
  100. pac := "prepay_id=" + wxResp.PrepayId
  101. paySign := wechat.GetMiniPaySign("wx25357518f710b8ce", wxResp.NonceStr, pac, wechat.SignType_MD5, timestamp, "1RKRJBVH4vaRrF0XPW9GX2M3ZSImukIz")
  102. outData.Timestamp = timestamp
  103. outData.NonceStr = wxResp.NonceStr
  104. outData.Package = pac
  105. outData.PaySign = paySign
  106. outData.SignType = wechat.SignType_MD5
  107. //merchant, count, err := sqlData.GetOpenIdList(pageSize, pageIndex)
  108. //if err != nil {
  109. // app.Error(c, 500, err, err.Error())
  110. // return
  111. //}
  112. app.OK(c, outData, app.Success)
  113. }
  114. func PayCashOut(c *gin.Context) {
  115. var inData models.PayCashOutRequest
  116. //var sqlData
  117. if inData.CashType == "client" {
  118. //先设置账户状态 为提现中,提现中不允许再操作,提现金额默认全部
  119. } else if inData.CashType == "merchant" {
  120. } else {
  121. app.Error(c, 400, errors.New("类型错误"), "类型错误")
  122. return
  123. }
  124. client := NewWechatService()
  125. err := client.AddCertPkcs12FilePath("./apiclient_cert.p12")
  126. if err != nil {
  127. app.Error(c, 400, err, err.Error())
  128. return
  129. }
  130. bm := make(gopay.BodyMap)
  131. partnerTradeNo := common.GetRandomString(32)
  132. bm.Set("nonce_str", common.GetRandomString(32))
  133. bm.Set("partner_trade_no", partnerTradeNo)
  134. bm.Set("openid", inData.OpenId)
  135. bm.Set("check_name", "FORCE_CHECK")
  136. bm.Set("re_user_name", inData.UserName)
  137. bm.Set("amount", 30) // 企业付款金额,单位为分
  138. bm.Set("desc", "测试转账") // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
  139. bm.Set("spbill_create_ip", "127.0.0.1")
  140. wxResp, err := client.Transfer(c, bm)
  141. if err != nil {
  142. app.Error(c, 400, err, "提现失败")
  143. return
  144. }
  145. if wxResp.ReturnCode != "SUCCESS" {
  146. app.Error(c, 400, errors.New(wxResp.ReturnMsg), "提现")
  147. return
  148. }
  149. if wxResp.ResultCode != "SUCCESS" {
  150. app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "提现")
  151. return
  152. }
  153. }
  154. func PayCallBack(c *gin.Context) {
  155. var payLog shanghu.PayCallbackLog
  156. var payTrans shanghu.ClientPayTrans
  157. wxNotify, err := wechat.ParseNotifyToBodyMap(c.Request)
  158. if err != nil {
  159. c.XML(http.StatusOK, failResp)
  160. return
  161. }
  162. //通知回调log
  163. payLog.CallBackLog = wxNotify.JsonBody()
  164. payLog.ThirdTradeNo = wxNotify.Get("transaction_id")
  165. payLog.OutTradeNo = wxNotify.Get("out_trade_no")
  166. payLog.CreatedAt = time.Now()
  167. payLog.UpdatedAt = time.Now()
  168. _, err = payLog.Create()
  169. if err != nil {
  170. c.XML(http.StatusOK, failResp)
  171. return
  172. }
  173. if wxNotify.Get("return_code") != "SUCCESS" || wxNotify.Get("result_code") != "SUCCESS" {
  174. payLog.ErrLog = "微信返回错误:" + wxNotify.Get("return_code") + "--" + wxNotify.Get("result_code")
  175. payLog.UpdateMerchant()
  176. c.XML(http.StatusOK, failResp)
  177. return
  178. }
  179. //校验金额
  180. payTrans.OutTradeNo = wxNotify.Get("out_trade_no")
  181. payTransInfo, err := payTrans.GetPayTransByTradeNo()
  182. if err != nil {
  183. payLog.ErrLog = "查询交易信息错误:" + " err=" + err.Error()
  184. payLog.UpdateMerchant()
  185. c.XML(http.StatusOK, failResp)
  186. return
  187. }
  188. // 判断金额与支付流水是否一致
  189. totalFee, err := decimal.NewFromString(wxNotify.Get("total_fee"))
  190. if err != nil {
  191. payLog.ErrLog = "解析总金额报错:" + "err=" + err.Error()
  192. payLog.UpdateMerchant()
  193. c.XML(http.StatusOK, failResp)
  194. return
  195. }
  196. if !totalFee.Equal(payTransInfo.Amount.Mul(decimal.NewFromInt(100))) {
  197. payLog.ErrLog = "验证金额报错:total_fee=" + wxNotify.Get("total_fee") + " amount=" + payTransInfo.Amount.String()
  198. payLog.UpdateMerchant()
  199. c.XML(http.StatusOK, failResp)
  200. return
  201. }
  202. // 解析支付时间
  203. timeEnd, err := time.ParseInLocation("20060102150405", wxNotify.Get("time_end"), tools.TimeLocation)
  204. if err != nil {
  205. payLog.ErrLog = "付款时间解析出错:err=" + err.Error()
  206. payLog.UpdateMerchant()
  207. c.XML(http.StatusOK, failResp)
  208. return
  209. }
  210. payTrans.ThirdTradeNo = wxNotify.Get("transaction_id")
  211. payTrans.Status = 2 //支付成功
  212. payTrans.PayTime = timeEnd
  213. payTrans.AccountStatus = 1 //未分账
  214. err = payTrans.UpdatePayTransByTradeNo()
  215. if err != nil {
  216. payLog.ErrLog = "更新支付状态失败:err=" + err.Error()
  217. payLog.UpdateMerchant()
  218. c.XML(http.StatusOK, failResp)
  219. return
  220. }
  221. c.XML(http.StatusOK, successResp)
  222. }
  223. func NewWechatService() *wechat.Client {
  224. client := wechat.NewClient("wx25357518f710b8ce", "1501641641", "1RKRJBVH4vaRrF0XPW9GX2M3ZSImukIz", true)
  225. //设置国家
  226. client.SetCountry(wechat.China)
  227. return client
  228. }
  229. func NewWechatServiceV3() (*wechatV3.ClientV3, error) {
  230. key := `MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD/RTrS1Tycrskr
  231. SkuzdLNmOic4UklFtoyKtKDIeklbQFvynJBC1wYaitoOqFkdGWagkcuqRqJOcgEQ
  232. T8DRDD/rnVKTrnntevUSW3vZYwMscomK3dgjRRui5GLY5wYHuKhp02bldLrhPKNy
  233. wT5IYhoDwQLmf5IrURbtT8bKpdC+NyEEfw+d/mHMK56w80YKfzFtSmjoB9SkWDLg
  234. YFBlw91C78E73uqhCKnArN7p2iJe+tsp7EGpDVcdowqcMKjY2YiNPY6ABZaI9YJx
  235. nRQs5Sjm6YSsJujMR5rQVZ3HCfLlzxLpPyHfqffbJ+vviend1PJ/ugJeM2hehn1d
  236. LrpKuWyHAgMBAAECggEAIbow6nhYGM+TLtATLnPF3ETkt7FPkxFqgk0ZTUOy+4aG
  237. X4jGGr60RL+Bzhv6Ijkf8SkyQp4whbLUZyZScIxwyZ2wsmiEHZd4V+OUeoV1fuLn
  238. P1zOWOKhoyUP1l630j9YqRrQZpLEuku7wMa9huzHSSWwT2odkvGU2OgIeO/to6P7
  239. gIE4Q+3pNmTdaXJweUlVoz6sdqsSWAZ729SxzY34zcRyXI+feBQb9n/C1hr9+Ge4
  240. KbBsvrECy0eUNiAT9f5dPwgwjyRpR9gJ8xxaezIYfxdpTTW3EB1Gf+xPX4X7ml2B
  241. zObPN2HEwLHhrwbOXLFP8F/62TK4fIGe2yXPIKIe8QKBgQD/t4Xy9pTFrmNhDLMe
  242. ZMHdj9XMoM/izcquI6rq4pGWLtnyxIcFuXiqvPszbJL+urCc1+HqfPAVScryEg5W
  243. b6AvLENVhC5E3GcZA50ciAr+PUrB1UXH0vbbc7HP/Mofsz61kxEW2SvKaPoKhW8M
  244. IavoVWDJkcLHnjM20Gt7tioEXwKBgQD/jZR7FDSB8VCRp687QcH4s0HyAWaRVhmC
  245. qId2xVbPFVlbm4BWcQVWPdsUei29sPPtcvzREFStKwTmu2FSUfoDv3uM4Nl2+h/Y
  246. pbhfuYfHd79UZa0OtT9njJHZcYPwKRmZQIVBVHSJFSZy2HSGLe9AdI7gAsNMx/Mm
  247. eqZDU79I2QKBgQCBSNoSIpTI9QgNkwwkO7DAQe5IDK3N71mffSz2oCIXGgza7n2N
  248. aV4WhIFEWIpg+yY7xfHUSeJgAPT4OiTBkqIb93b7j16NNhlxzh/qwuU78OUQ5rDm
  249. /EQOY4nsq9PM/ySfTIGBWb8IENcJ5rhkG8n8Jt5OSsF9hwBBoFIXM9w+ZQKBgQD1
  250. rArw43Sy8uTskZKA2e96ggHEgBo1X9s4Y4GO6ZlRjQmRaoVPFGn4BZEGN4qfkGx/
  251. egqXhSaSLwgQNFUUCWDbl4pT3ZjRqxVQdcgwpjBkzratkO10dUOV7WoM6vbWuvwz
  252. +vXf3ywE2MNUpsgmciROB3+O1LkhqBsVg9UwZmM+yQKBgQD6yBvxOaHXBSZncz+m
  253. 3SpdbcRjK82i3IUJ3sl18J7YEPer0FclsUcQOluqBbHTOAr8letWPrKnjZGuyFfg
  254. gAjwa8uLSyfEEcWb9WcObvud2GNxS/LiI0GnW9ittvT29JvOhmUUtnty5/TiWIsi
  255. slm2kO53RSw9brymV8PAX2+SXg==`
  256. client, err := wechatV3.NewClientV3("wx25357518f710b8ce", "219B3AF3B5F17D4C2F145EE318188708318DD7BD", "9x9ydkdk0nzsa4mr2ucq75grlvt9n8l3", key)
  257. if err != nil {
  258. return nil, err
  259. }
  260. // 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
  261. err = client.AutoVerifySign()
  262. if err != nil {
  263. return nil, err
  264. }
  265. // 打开Debug开关,输出日志,默认是关闭的
  266. //client.DebugSwitch = gopay.DebugOn
  267. return client, nil
  268. }