|
@@ -0,0 +1,201 @@
|
|
|
+package shanghu
|
|
|
+
|
|
|
+import (
|
|
|
+ "duoduo/apis/common"
|
|
|
+ "duoduo/apis/shanghu/models"
|
|
|
+ "duoduo/models/shanghu"
|
|
|
+ "duoduo/tools"
|
|
|
+ "duoduo/tools/app"
|
|
|
+ "encoding/xml"
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
+ "github.com/go-pay/gopay"
|
|
|
+ "github.com/go-pay/gopay/wechat"
|
|
|
+ "github.com/shopspring/decimal"
|
|
|
+ "net/http"
|
|
|
+ "strconv"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type wechatCallbackResp struct {
|
|
|
+ XMLName xml.Name `xml:"xml"`
|
|
|
+ ReturnCode Cdata `xml:"return_code"`
|
|
|
+ ReturnMsg Cdata `xml:"return_msg"`
|
|
|
+}
|
|
|
+
|
|
|
+type Cdata struct {
|
|
|
+ Value string `xml:",cdata"`
|
|
|
+}
|
|
|
+
|
|
|
+var (
|
|
|
+ successResp = &wechatCallbackResp{ReturnCode: Cdata{Value: "SUCCESS"}, ReturnMsg: Cdata{Value: "OK"}}
|
|
|
+ failResp = &wechatCallbackResp{ReturnCode: Cdata{Value: "FAIL"}, ReturnMsg: Cdata{Value: "数据处理异常"}}
|
|
|
+)
|
|
|
+
|
|
|
+func UnifiedOrder(c *gin.Context) {
|
|
|
+ var inData models.UnifiedOrderRequest
|
|
|
+ var sqlData shanghu.ClientPayTrans
|
|
|
+
|
|
|
+ err := c.ShouldBindJSON(&inData)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //校验 防止同一笔记录存在
|
|
|
+ sqlData.RequestID = inData.RequestId
|
|
|
+ if sqlData.GetRequestNum() > 0 {
|
|
|
+ app.Error(c, 400, errors.New("交易已存在"), "交易已存在")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //校验金额
|
|
|
+ // 检查微信相关参数
|
|
|
+ if !inData.Amount.GreaterThan(decimal.NewFromInt(0)) {
|
|
|
+ app.Error(c, 400, errors.New("amount:金额必须大于0"), "amount:金额必须大于0")
|
|
|
+ return
|
|
|
+
|
|
|
+ }
|
|
|
+ if inData.Amount.Round(2).String() != inData.Amount.String() {
|
|
|
+ app.Error(c, 400, errors.New("total_fee:金额最多只能保留两位小数"), "total_fee:金额最多只能保留两位小数")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //创建支付记录
|
|
|
+ sqlData.ClientOpenID = inData.ClientOpenId
|
|
|
+ sqlData.RequestID = inData.RequestId
|
|
|
+ sqlData.CreatedAt = time.Now()
|
|
|
+ sqlData.UpdatedAt = time.Now()
|
|
|
+ sqlData.Amount = inData.Amount
|
|
|
+ sqlData.OutTradeNo = strconv.FormatInt(inData.MerchantCardId, 10) + strconv.FormatInt(time.Now().UnixNano(), 10)
|
|
|
+ sqlData.Status = 1 //未支付
|
|
|
+ sqlData.MerchantCardID = inData.MerchantCardId
|
|
|
+ _, err = sqlData.Create()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, "创建支付失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ fmt.Println(sqlData.OutTradeNo)
|
|
|
+ bm := make(gopay.BodyMap)
|
|
|
+ bm.Set("nonce_str", common.GetRandomString(32))
|
|
|
+ bm.Set("body", "商户卡")
|
|
|
+ bm.Set("out_trade_no", sqlData.OutTradeNo)
|
|
|
+ bm.Set("total_fee", inData.Amount.Mul(decimal.NewFromInt(100)).IntPart())
|
|
|
+ bm.Set("spbill_create_ip", "127.0.0.1")
|
|
|
+ bm.Set("notify_url", "https://shisanmiao.com/v1/client/pay/callback")
|
|
|
+ bm.Set("device_info", "WEB")
|
|
|
+ bm.Set("trade_type", "JSAPI")
|
|
|
+ bm.Set("sign_type", wechat.SignType_MD5)
|
|
|
+ bm.Set("openid", inData.ClientOpenId)
|
|
|
+
|
|
|
+ client := NewWechatService()
|
|
|
+ //请求支付下单,成功后得到结果
|
|
|
+ wxResp, err := client.UnifiedOrder(c, bm)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, "下单失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if wxResp.ReturnCode != "SUCCESS" {
|
|
|
+ app.Error(c, 400, errors.New(wxResp.ReturnMsg), "下单失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if wxResp.ResultCode != "SUCCESS" {
|
|
|
+ app.Error(c, 400, errors.New(wxResp.ErrCode+"--"+wxResp.ErrCodeDes), "下单失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //merchant, count, err := sqlData.GetOpenIdList(pageSize, pageIndex)
|
|
|
+ //if err != nil {
|
|
|
+ // app.Error(c, 500, err, err.Error())
|
|
|
+ // return
|
|
|
+ //}
|
|
|
+ app.OK(c, wxResp, app.Success)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func PayCallBack(c *gin.Context) {
|
|
|
+ var payLog shanghu.PayCallbackLog
|
|
|
+ var payTrans shanghu.ClientPayTrans
|
|
|
+ wxNotify, err := wechat.ParseNotifyToBodyMap(c.Request)
|
|
|
+ if err != nil {
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //通知回调log
|
|
|
+ payLog.CallBackLog = wxNotify.JsonBody()
|
|
|
+ payLog.ThirdTradeNo = wxNotify.Get("transaction_id")
|
|
|
+ payLog.OutTradeNo = wxNotify.Get("out_trade_no")
|
|
|
+ payLog.CreatedAt = time.Now()
|
|
|
+ payLog.UpdatedAt = time.Now()
|
|
|
+
|
|
|
+ _, err = payLog.Create()
|
|
|
+ if err != nil {
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if wxNotify.Get("return_code") != "SUCCESS" || wxNotify.Get("result_code") != "SUCCESS" {
|
|
|
+ payLog.ErrLog = "微信返回错误:" + wxNotify.Get("return_code") + "--" + wxNotify.Get("result_code")
|
|
|
+ payLog.UpdateMerchant()
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //校验金额
|
|
|
+ payTrans.OutTradeNo = wxNotify.Get("out_trade_no")
|
|
|
+ payTransInfo, err := payTrans.GetPayTransByTradeNo()
|
|
|
+ if err != nil {
|
|
|
+ payLog.ErrLog = "查询交易信息错误:" + " err=" + err.Error()
|
|
|
+ payLog.UpdateMerchant()
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 判断金额与支付流水是否一致
|
|
|
+ totalFee, err := decimal.NewFromString(wxNotify.Get("total_fee"))
|
|
|
+ if err != nil {
|
|
|
+ payLog.ErrLog = "解析总金额报错:" + "err=" + err.Error()
|
|
|
+ payLog.UpdateMerchant()
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if !totalFee.Equal(payTransInfo.Amount.Mul(decimal.NewFromInt(100))) {
|
|
|
+ payLog.ErrLog = "验证金额报错:total_fee=" + wxNotify.Get("total_fee") + " amount=" + payTransInfo.Amount.String()
|
|
|
+ payLog.UpdateMerchant()
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 解析支付时间
|
|
|
+ timeEnd, err := time.ParseInLocation("20060102150405", wxNotify.Get("time_end"), tools.TimeLocation)
|
|
|
+ if err != nil {
|
|
|
+ payLog.ErrLog = "付款时间解析出错:err=" + err.Error()
|
|
|
+ payLog.UpdateMerchant()
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ payTrans.ThirdTradeNo = wxNotify.Get("transaction_id")
|
|
|
+ payTrans.Status = 2 //支付成功
|
|
|
+ payTrans.PayTime = timeEnd
|
|
|
+
|
|
|
+ err = payTrans.UpdatePayTransByTradeNo()
|
|
|
+ if err != nil {
|
|
|
+ payLog.ErrLog = "更新支付状态失败:err=" + err.Error()
|
|
|
+ payLog.UpdateMerchant()
|
|
|
+ c.XML(http.StatusOK, failResp)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ c.XML(http.StatusOK, successResp)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func NewWechatService() *wechat.Client {
|
|
|
+
|
|
|
+ client := wechat.NewClient("wx25357518f710b8ce", "1501641641", "1RKRJBVH4vaRrF0XPW9GX2M3ZSImukIz", true)
|
|
|
+ //设置国家
|
|
|
+ client.SetCountry(wechat.China)
|
|
|
+
|
|
|
+ return client
|
|
|
+}
|