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 }