- 将校验错误的错误信息改为固定提示“校验错误” - 在解析金额失败时添加ServeJSON调用,保证响应返回 - 在金额有误时添加ServeJSON调用,保证响应返回 - 统一错误处理流程,避免遗漏响应返回导致前端异常
568 lines
14 KiB
Go
568 lines
14 KiB
Go
package controllers
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/beego/beego/v2/core/logs"
|
||
"github.com/duke-git/lancet/v2/convertor"
|
||
"net/url"
|
||
"shop/internal/config"
|
||
"shop/internal/models"
|
||
"shop/internal/schema/request"
|
||
"shop/internal/schema/response"
|
||
"shop/internal/service"
|
||
"shop/internal/traceRouter"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/beego/beego/v2/core/validation"
|
||
"github.com/beego/beego/v2/server/web"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
type PayController struct {
|
||
web.Controller
|
||
}
|
||
|
||
// Pay /* 支付接口 */
|
||
func (c *PayController) Pay() {
|
||
ctx, span := traceRouter.CreateSpan(c.Ctx.Request.Context(), "span", "首页")
|
||
defer span.End()
|
||
|
||
flash := web.NewFlash()
|
||
returnUrl := strings.TrimSpace(c.GetString("returnUrl"))
|
||
orderNo := strings.TrimSpace(c.GetString("orderId"))
|
||
productCode := strings.TrimSpace(c.GetString("productCode"))
|
||
recoveryType := strings.TrimSpace(c.GetString("recoveryType"))
|
||
chard := strings.TrimSpace(c.GetString("chard"))
|
||
cardNo := strings.TrimSpace(c.GetString("cardNo"))
|
||
sign := strings.TrimSpace(c.GetString("sign"))
|
||
deviceId := strings.TrimSpace(c.GetString("deviceId"))
|
||
|
||
if orderNo == "" {
|
||
flash.Error("订单号为空")
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + "0" +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "订单号为空!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
faceMM := strings.TrimSpace(c.GetString("factMMValue"))
|
||
if !c.judgeAmount(faceMM) {
|
||
flash.Error("金额有误")
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "金额有误!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
m := models.OrderParams{}
|
||
m.Decrypt(ctx, sign)
|
||
if time.Since(time.Unix(m.GeneratedTime, 0)).Hours() > float64(m.Duration) {
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "订单超时!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
if m.PayKey == "" {
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "支付秘钥错误!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
if m.NotifyUrl == "" {
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "通知地址为空!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
if m.OrderNo == "" {
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "订单号为空!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
pp := map[string]string{
|
||
"recoveryType": recoveryType,
|
||
"data": chard,
|
||
"cardNo": cardNo,
|
||
}
|
||
marshal, err := json.Marshal(&pp)
|
||
if err != nil {
|
||
flash.Store(&c.Controller)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + "卡密数据解析错误!"
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
scanShop := new(service.ScanShopController)
|
||
scanShop.Params = map[string]string{
|
||
"orderPeriod": "24",
|
||
"notifyUrl": m.NotifyUrl,
|
||
"orderPrice": faceMM,
|
||
"orderNo": orderNo,
|
||
"productCode": productCode,
|
||
"exValue": string(marshal),
|
||
"ip": c.Ctx.Input.IP(),
|
||
"deviceId": deviceId,
|
||
}
|
||
|
||
res := scanShop.Shop(ctx, m.PayKey)
|
||
if res.Code == 200 {
|
||
str := "/order-confirm.html" + "?orderId=" + orderNo + "&returnUrl=" + returnUrl +
|
||
"&payKey=" + m.PayKey + "&amount=" + faceMM
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
return
|
||
}
|
||
|
||
flash.Store(&c.Controller)
|
||
errMsg := res.Msg
|
||
if errMsg == "" {
|
||
errMsg = "不存在这样的支付类型!"
|
||
}
|
||
errMsg = url.PathEscape(errMsg)
|
||
str := "/error.html" + "?orderId=" + orderNo + "&amount=" + faceMM +
|
||
"&returnUrl=" + returnUrl + "&errorMsg=" + errMsg
|
||
c.Ctx.Output.Header("Location", str)
|
||
c.Redirect(str, 302)
|
||
}
|
||
|
||
// PayWithJson 后端接口支付
|
||
func (c *PayController) PayWithJson() {
|
||
ctx, span := traceRouter.CreateSpan(c.Ctx.Request.Context(), "span", "首页")
|
||
defer span.End()
|
||
|
||
orderNo := strings.TrimSpace(c.GetString("orderId"))
|
||
|
||
if orderNo == "" {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "订单号为空",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
faceMM := strings.TrimSpace(c.GetString("factMMValue"))
|
||
if !c.judgeAmount(faceMM) {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "金额有误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
productCode := strings.TrimSpace(c.GetString("productCode"))
|
||
recoveryType := strings.TrimSpace(c.GetString("recoveryType"))
|
||
chard := strings.TrimSpace(c.GetString("chard"))
|
||
cardNo := strings.TrimSpace(c.GetString("cardNo"))
|
||
sign := strings.TrimSpace(c.GetString("sign"))
|
||
deviceId := strings.TrimSpace(c.GetString("deviceId"))
|
||
|
||
m, err := service.VerifyPaySign(ctx, sign)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: err.Error(),
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
if m == nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "支付秘钥错误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
ok2, _ := service.Pay(ctx, &models.OriginalJdParams{
|
||
OrderId: orderNo,
|
||
FactMMValue: faceMM,
|
||
ProductCode: productCode,
|
||
RecoveryType: recoveryType,
|
||
Chard: chard,
|
||
CardNo: cardNo,
|
||
DeviceId: deviceId,
|
||
NotifyUrl: m.NotifyUrl,
|
||
}, m, c.Ctx.Input.IP())
|
||
if ok2 {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: 0,
|
||
Msg: "成功!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "内部错误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
func (c *PayController) judgeAmount(amount string) bool {
|
||
_, err := strconv.ParseFloat(amount, 64)
|
||
if err != nil {
|
||
traceRouter.Logger.WithContext(c.Ctx.Request.Context()).Info("输入金额有误", zap.String("amount", amount))
|
||
//logs.Error("输入金额有误")
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// PayOriginalJD /* 支付接口 */
|
||
func (c *PayController) PayOriginalJD() {
|
||
ctx, span := traceRouter.CreateSpan(c.Ctx.Request.Context(), "PayController", "PayController.ayOriginalJD")
|
||
defer span.End()
|
||
|
||
input := models.OriginalJdReq{}
|
||
err := c.BindJSON(&input)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "JSON解析失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
valid := validation.Validation{}
|
||
ok, err := valid.Valid(input)
|
||
if err != nil || !ok {
|
||
traceRouter.Logger.WithContext(ctx).Error("解析失败", zap.Error(err))
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "解析失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 校验sign
|
||
m, err := service.VerifyPaySign(ctx, input.Sign)
|
||
if err != nil || m == nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: err.Error(),
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
faceMMValue, err := strconv.ParseFloat(input.MMValue, 64)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "金额有误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
wxPay, err := service.PayWithJd(ctx, input.OrderId, "cTrip", faceMMValue)
|
||
if err != nil {
|
||
traceRouter.Logger.WithContext(ctx).Error("微信支付拉单错误!", zap.String("orderNo", m.OrderNo),
|
||
zap.String("error", err.Error()),
|
||
)
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "微信支付拉单错误!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
//去掉域名
|
||
wxPay = strings.ReplaceAll(wxPay, "https://wx.tenpay.com", "")
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: 0,
|
||
Msg: "成功!",
|
||
Data: map[string]string{"wxPay": wxPay},
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// PayOriginalAliPay /* 支付接口 */
|
||
func (c *PayController) PayOriginalAliPay() {
|
||
ctx, span := traceRouter.CreateSpan(c.Ctx.Request.Context(), "PayController", "PayController.PayOriginalAliPay")
|
||
defer span.End()
|
||
|
||
input := models.OriginalJdReq{}
|
||
err := c.BindJSON(&input)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "JSON解析失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
valid := validation.Validation{}
|
||
ok, err := valid.Valid(input)
|
||
if err != nil || !ok {
|
||
traceRouter.Logger.WithContext(ctx).Error("解析失败", zap.Error(err))
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "解析失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 校验sign
|
||
m, err := service.VerifyPaySign(ctx, input.Sign)
|
||
if err != nil || m == nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: err.Error(),
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
faceMMValue, err := strconv.ParseFloat(input.MMValue, 64)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "金额有误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
_, err = service.PayWithAliPay(ctx, input.OrderId, faceMMValue)
|
||
if err != nil {
|
||
traceRouter.Logger.WithContext(ctx).Error("支付宝支付拉单错误!", zap.String("orderNo", m.OrderNo),
|
||
zap.String("error", err.Error()),
|
||
)
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "支付宝支付拉单错误!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
jumpAddr := config.GetShopUrl() + "/alipay/pay?orderId=" + input.OrderId + "&amount=" + convertor.ToString(faceMMValue)
|
||
//url编码
|
||
logs.Info("alipayUrl", jumpAddr)
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: 0,
|
||
Msg: "成功!",
|
||
Data: map[string]string{"alipayUrl": fmt.Sprintf("alipays://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=%s", url.QueryEscape(jumpAddr))},
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// PayV2 新版本JSON支付接口,支持JSON请求和响应
|
||
func (c *PayController) PayV2() {
|
||
ctx, span := traceRouter.CreateSpan(c.Ctx.Request.Context(), "span", "JSON支付接口")
|
||
defer span.End()
|
||
|
||
var req request.PayRequest
|
||
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "JSON解析失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 验证必填字段
|
||
if req.OrderId == "" {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "订单号为空",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
if !c.judgeAmount(req.FactMMValue) {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "金额有误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
m, err := service.VerifyPaySign(ctx, req.Sign)
|
||
if err != nil || m == nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "校验错误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
//req.FactMMValue
|
||
factValue, err := convertor.ToFloat(req.FactMMValue)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "解析金额失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
if m.ShowMMValue != factValue {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "金额有误",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
if m.OrderNo != req.OrderId {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "校验失败",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
// 验证订单超时
|
||
if time.Since(time.Unix(m.GeneratedTime, 0)).Hours() > float64(m.Duration) {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "订单超时!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 验证支付密钥
|
||
if m.PayKey == "" {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "支付秘钥错误!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 验证通知地址
|
||
if m.NotifyUrl == "" {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "通知地址为空!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 验证订单号
|
||
if m.OrderNo == "" {
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: -1,
|
||
Msg: "订单号为空!",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 构建卡密数据
|
||
pp := map[string]string{
|
||
"recoveryType": req.RecoveryType,
|
||
"data": req.Chard,
|
||
"cardNo": req.CardNo,
|
||
}
|
||
marshal, err := json.Marshal(&pp)
|
||
if err != nil {
|
||
errHtml := "/error.html" + "?orderId=" + req.OrderId + "&amount=" + req.FactMMValue +
|
||
"&returnUrl=" + req.ReturnUrl + "&errorMsg=" + url.PathEscape("卡密数据解析错误!")
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: 0,
|
||
Msg: "支付成功",
|
||
Data: map[string]string{
|
||
"orderId": req.OrderId,
|
||
"returnUrl": req.ReturnUrl,
|
||
"payKey": m.PayKey,
|
||
"amount": req.FactMMValue,
|
||
"redirectUrl": errHtml,
|
||
},
|
||
}
|
||
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 调用支付服务
|
||
scanShop := new(service.ScanShopController)
|
||
scanShop.Params = map[string]string{
|
||
"orderPeriod": "24",
|
||
"notifyUrl": m.NotifyUrl,
|
||
"orderPrice": req.FactMMValue,
|
||
"orderNo": req.OrderId,
|
||
"productCode": req.ProductCode,
|
||
"exValue": string(marshal),
|
||
"ip": c.Ctx.Input.IP(),
|
||
"deviceId": req.DeviceId,
|
||
}
|
||
|
||
res := scanShop.Shop(ctx, m.PayKey)
|
||
if res.Code == 200 {
|
||
// 返回成功响应,包含订单确认页面URL
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: 0,
|
||
Msg: "支付成功",
|
||
Data: map[string]string{
|
||
"orderId": req.OrderId,
|
||
"returnUrl": req.ReturnUrl,
|
||
"payKey": m.PayKey,
|
||
"amount": req.FactMMValue,
|
||
"redirectUrl": "/order-confirm.html?orderId=" + req.OrderId + "&returnUrl=" + req.ReturnUrl + "&payKey=" + m.PayKey + "&amount=" + req.FactMMValue,
|
||
},
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 处理错误情况
|
||
errMsg := res.Msg
|
||
if errMsg == "" {
|
||
errMsg = "不存在这样的支付类型!"
|
||
}
|
||
|
||
errHtml := "/error.html" + "?orderId=" + req.OrderId + "&amount=" + req.FactMMValue +
|
||
"&returnUrl=" + req.ReturnUrl + "&errorMsg=" + url.PathEscape(errMsg)
|
||
|
||
c.Data["json"] = response.CommonResponse{
|
||
Code: 0,
|
||
Msg: "支付成功",
|
||
Data: map[string]string{
|
||
"orderId": req.OrderId,
|
||
"returnUrl": req.ReturnUrl,
|
||
"payKey": m.PayKey,
|
||
"amount": req.FactMMValue,
|
||
"redirectUrl": errHtml,
|
||
},
|
||
}
|
||
_ = c.ServeJSON()
|
||
}
|