From 2a21f854e12808561ade49e56f6b7c8917b4d184 Mon Sep 17 00:00:00 2001 From: wolter Date: Mon, 23 Dec 2024 15:42:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=B6=E9=93=B6=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/common/common.go | 7 +- app/http/controllers/front/pay_page.go | 42 +++- .../controllers/front/payment_controller.go | 10 +- app/http/entities/front/pay.go | 5 +- app/http/requestmapping/front.go | 5 +- app/http/routes/route.go | 17 +- app/services/pay_page.go | 175 +-------------- app/services/request_log.go | 5 + app/services/thirdpay/do/pay.go | 4 +- app/services/thirdpay/do/pay_way.go | 1 + app/services/thirdpay/pay_page.go | 212 ++++++++++++++++++ app/third/paymentService/ali_service.go | 63 ++++++ app/third/paymentService/payCommon/common.go | 4 +- app/third/paymentService/payment_service.go | 3 + app/utils/useragent.go | 2 +- front/templates/payPage.html | 147 ++++++++++++ front/templates/payTemplate.html | 15 ++ 17 files changed, 522 insertions(+), 195 deletions(-) create mode 100644 app/services/thirdpay/pay_page.go create mode 100644 front/templates/payPage.html create mode 100644 front/templates/payTemplate.html diff --git a/app/constants/common/common.go b/app/constants/common/common.go index 1f9eaeb..fdf9479 100644 --- a/app/constants/common/common.go +++ b/app/constants/common/common.go @@ -7,11 +7,10 @@ const ( FRONT_V1 = "/pay/front/api/v1" FRONT_V2 = "/pay/front/api/v2" - WXCodeRedirectAddress = FRONT_V1 + "/wx/payurl" // 微信支付,授权code后 重定向地址 - PayPageAddress = FRONT_V1 + "/payPage" // 收银台页面地址 - PayPageChannelList = FRONT_V1 + "/payPage/list" // 收银台支付方式列表地址 + WXCodeRedirectAddress = FRONT_V1 + "/wx/payurl" // 微信支付,授权code后 重定向地址 + PayPageAddress = FRONT_V1 + "/payPage" // 收银台页面地址 - // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI,9支付宝电脑网站支付 + // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI,9支付宝电脑网站支付,10支付宝扫码支付 PAY_CHANNEL_UNKNOWN = 0 PAY_CHANNEL_WECHAT_JSAPI = 1 PAY_CHANNEL_WECHAT_H5 = 2 diff --git a/app/http/controllers/front/pay_page.go b/app/http/controllers/front/pay_page.go index 7447c9f..3136e09 100644 --- a/app/http/controllers/front/pay_page.go +++ b/app/http/controllers/front/pay_page.go @@ -1,25 +1,31 @@ package front import ( + "PaymentCenter/app/constants/errorcode" "PaymentCenter/app/http/controllers" "PaymentCenter/app/http/entities/front" + "PaymentCenter/app/models/ordersmodel" "PaymentCenter/app/models/paychannelmodel" "PaymentCenter/app/services" "PaymentCenter/app/services/thirdpay" + "fmt" "github.com/ahmetb/go-linq/v3" "github.com/gin-gonic/gin" "net/http" "strconv" + "xorm.io/builder" ) // 预支付接口V2, 返回收银台页面 func PayUrlV2(c *gin.Context) { var res front.ApiResponse req := controllers.GetRequest(c).(*front.PayReqsV2) + // 更新请求日志需要的参数 + c.Set("OutTradeNo", req.OutTradeNo) appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck) - result, code := services.NewPayUrl(*req). + result, code := thirdpay.NewPayUrl(*req). WithApp(appCheckInfo). WithClientIp(c.ClientIP()). PayUrlV2Service() @@ -32,11 +38,31 @@ func PayUrlV2(c *gin.Context) { return } -// V2 下单接口 // 收银台页面 func PayPage(c *gin.Context) { + var ( + code int + message string + amount string + ) + orderId := c.Query("no") + if orderId != "" { + orderInfo := &ordersmodel.Orders{} + orderInfo, code = services.OrderFindOne(&ordersmodel.Orders{}, builder.Eq{"id": orderId}) + if code == errorcode.Success { + amount = fmt.Sprintf("%.2f", float64(orderInfo.Amount)/100) + } else { + message = errorcode.GetMsg(code, "") + } + } else { + message = "页面不存在" + } + c.HTML(http.StatusOK, "payPage.html", gin.H{ - //"host": config.GetConf().PayService.Host + common.PayPageChannelList, + "code": code, + "message": message, + "id": orderId, + "amount": amount, }) } @@ -62,6 +88,12 @@ func PayChannelList(c *gin.Context) { func GetPayLink(c *gin.Context) { req, _ := controllers.GetRequest(c).(*front.GetPayLinkRequest) - result, code := services.GetPayLinkService(*req) - controllers.HandCodeRes(c, result, code) + result, message, code := thirdpay.GetPayLinkService(*req) + if code == errorcode.Success { + c.HTML(http.StatusOK, "payTemplate.html", gin.H{ + "payUrl": result, + }) + } else { + c.String(http.StatusOK, errorcode.GetMsg(code, "")+message) + } } diff --git a/app/http/controllers/front/payment_controller.go b/app/http/controllers/front/payment_controller.go index 94ae43f..25a4a93 100644 --- a/app/http/controllers/front/payment_controller.go +++ b/app/http/controllers/front/payment_controller.go @@ -102,11 +102,11 @@ func AliCallback(c *gin.Context) { c.String(http.StatusBadRequest, "%s", "fail") return } - if payChannelModel.ChannelType != common.PAY_CHANNEL_ALIPAY_WEB { - logger.Error(c, "AliCallback-回调数据解析支付配置错误,查询的数据不是当前渠道") - c.String(http.StatusBadRequest, "%s", "fail") - return - } + //if payChannelModel.ChannelType != common.PAY_CHANNEL_ALIPAY_WEB { + // logger.Error(c, "AliCallback-回调数据解析支付配置错误,查询的数据不是当前渠道") + // c.String(http.StatusBadRequest, "%s", "fail") + // return + //} var aliConfig paymentService.AliPay err := json.Unmarshal([]byte(payChannelModel.ExtJson), &aliConfig) diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index e371d54..7395e79 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -93,6 +93,7 @@ type PayReqsV2Response struct { } type GetPayLinkRequest struct { - PayChannelId string `json:"pay_channel_id"` - OrderId string `json:"id"` + PayChannelId string `json:"pay_channel_id" form:"pay_channel_id"` + OrderId string `json:"no" form:"no"` + ClientIp string } diff --git a/app/http/requestmapping/front.go b/app/http/requestmapping/front.go index c98fe23..68d9abc 100644 --- a/app/http/requestmapping/front.go +++ b/app/http/requestmapping/front.go @@ -13,6 +13,8 @@ var FrontRequestMap = map[string]func() (validForm interface{}, isSaveLog bool){ common.FRONT_V1 + "/pay/query": func() (interface{}, bool) { return new(front.QueryReqs), false }, common.FRONT_V1 + "/pay/close": func() (interface{}, bool) { return new(front.CloseReqs), true }, common.FRONT_V1 + "/wx/payurl": func() (interface{}, bool) { return new(front.WxJsApiPayRequest), true }, + + common.PayPageAddress: func() (interface{}, bool) { return new(entities.IdRequest), true }, } var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{ @@ -27,7 +29,8 @@ var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{ common.FRONT_V1 + "/wx/getWxAuth": func() interface{} { return new(front.GetWxAuthRequest) }, common.FRONT_V1 + "/wx/getCode": func() interface{} { return new(front.GetWxAuthRequest) }, - common.FRONT_V1 + "/payPage/list": func() interface{} { return new(front.PayChannelListRequest) }, + common.FRONT_V1 + "/payPage/list": func() interface{} { return new(front.PayChannelListRequest) }, + common.FRONT_V1 + "/payPage/submit": func() interface{} { return new(front.GetPayLinkRequest) }, common.WXCodeRedirectAddress: func() interface{} { return new(front.WxJsApiPayRequest) }, } diff --git a/app/http/routes/route.go b/app/http/routes/route.go index 9951313..00259ac 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -82,15 +82,26 @@ func RegisterRoute(router *gin.Engine) { v2 := router.Group(common.FRONT_V2) { pay := v2.Group("/pay", middlewares.ValidatePayRequest()) - pay.POST("/url", front.PayUrlV2) // 下单 + // V2下单,存订单信息,返回收银台地址 + pay.POST("/url", front.PayUrlV2) } //收银台 { // 收银台地址 router.GET(common.PayPageAddress, front.PayPage) - // 收银台支付方式 - router.POST(common.PayPageChannelList, middlewares.ValidateRequest(), front.PayChannelList) + + payPage := router.Group(common.PayPageAddress, middlewares.ValidateRequest()) + // 收银台 支付渠道列表 + payPage.POST("/list", front.PayChannelList) + // 获取付款链接 + payPage.GET("/submit", front.GetPayLink) + + //router.GET(common.PayPageAddress, middlewares.ValidateRequest(), front.PayPage) + //// 收银台 支付渠道列表 + //router.POST(common.FRONT_V1+"/payPage/list", middlewares.ValidateRequest(), front.PayChannelList) + //// 获取付款链接 + //v1.POST("/payPage/link", middlewares.ValidateRequest(), front.GetPayLink) } router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) diff --git a/app/services/pay_page.go b/app/services/pay_page.go index 11b8511..4792f3a 100644 --- a/app/services/pay_page.go +++ b/app/services/pay_page.go @@ -6,14 +6,9 @@ import ( "PaymentCenter/app/http/entities" "PaymentCenter/app/http/entities/backend" "PaymentCenter/app/http/entities/front" - "PaymentCenter/app/models/orderrequestlogmodel" "PaymentCenter/app/models/ordersmodel" "PaymentCenter/app/models/paychannelmodel" "PaymentCenter/app/utils" - "PaymentCenter/config" - "encoding/json" - "fmt" - "net/url" "strconv" "time" "xorm.io/builder" @@ -55,6 +50,9 @@ func PayPageChannelList(reqParam front.PayChannelListRequest) (resultPayChannelL } merchantPayChannelMap := make(map[int]paychannelmodel.PayChannel, 0) for _, pay := range payList { + if !pay.ExpireTime.IsZero() && pay.ExpireTime.Unix() < time.Now().Unix() { + continue + } merchantPayChannelMap[pay.ChannelType] = pay } @@ -87,30 +85,8 @@ func ClientEnvCheck(ua string) int { return common.OpenInUnknown } -// 预支付 -type payUrl struct { - ClientIp string - param front.PayReqsV2 - app *AppCheck - result front.PayReqsV2Response -} - -func NewPayUrl(param front.PayReqsV2) *payUrl { - return &payUrl{ - param: param, - } -} -func (this *payUrl) WithApp(app *AppCheck) *payUrl { - this.app = app - return this -} -func (this *payUrl) WithClientIp(ip string) *payUrl { - this.ClientIp = ip - return this -} - // 订单是否是支付状态 -func orderStatusCheck(order ordersmodel.Orders) (code int) { +func OrderStatusCheck(order ordersmodel.Orders) (code int) { switch order.Status { case common.ORDER_STATUS_CLOSE: code = errorcode.OrderClosed @@ -125,146 +101,3 @@ func orderStatusCheck(order ordersmodel.Orders) (code int) { } return code } - -func (this *payUrl) saveOrder() { - order := &ordersmodel.Orders{ - MerchantId: this.app.App.MerchantId, - //PayChannelId: w.PayParam.Channel.Id, - AppId: this.app.App.Id, - OutTradeNo: this.param.OutTradeNo, - OrderType: common.ORDER_TYPE_PAY, - Amount: this.param.Amount, - ExtJson: this.param.ExtJson, - Desc: this.param.Desc, - Status: common.ORDER_STATUS_WAITPAY, - } - this.result.Order, this.result.PayCode = OrderCreate(order) -} - -func (this *payUrl) PayUrlV2Service() (result front.PayReqsV2Response, code int) { - var ( - channelList []paychannelmodel.PayChannel - order = new(ordersmodel.Orders) - ) - - // redis 分布式锁 订单号幂等 - key := utils.GetRealKey("payUrl:" + this.param.OutTradeNo) - lockValue := fmt.Sprintf("%d", time.Now().UnixNano()) - ok, err := utils.AcquireLock(key, lockValue, time.Second*time.Duration(3)) - if ok { - defer utils.ReleaseLock(key, lockValue) - } else { - if err != nil { - utils.Log(nil, "", "PayUrlV2Service,获取分布式锁失败", fmt.Sprintf("错误原因:%s", err.Error())) - } - return - } - - // 商户是否有配置支付渠道 - channelList, _, code = PayChannelList(backend.PayChannelListRequest{MerchantId: this.app.App.MerchantId}) - if code != errorcode.Success { - return - } - if len(channelList) == 0 { - code = errorcode.PayChannelNotFound - return - } - // 订单是否存在 - conn := builder.NewCond() - conn = conn.And(builder.Eq{"out_trade_no": this.param.OutTradeNo}) - conn = conn.And(builder.Eq{"app_id": this.param.AppId}) - order, code = OrderFindOne(order, conn) - if code == errorcode.Success { - // 订单存在 - this.result.Order = order - this.result.PayCode = orderStatusCheck(*order) - } else if code == errorcode.OrdersNotFound { - // 订单不存在 - this.saveOrder() - } else { - return - } - code = this.result.PayCode - if code == errorcode.Success { - this.result.Url = config.GetConf().PayService.Host + common.PayPageAddress + "?id=" + strconv.FormatInt(this.result.Order.Id, 10) - } - - return this.result, code -} - -// 拼接微信授权链接 appid:微信的公众号appid -func GetWxAuthUrl(appid string, orderId int64) (targetUrl string, code int) { - var ( - // 重定向地址 - redirectUri = config.GetConf().PayService.Host + common.WXCodeRedirectAddress - ) - baseUrl := "https://open.weixin.qq.com/connect/oauth2/authorize" - redirectUri = url.QueryEscape(redirectUri) - responseType := "code" - scope := "snsapi_base" - order := strconv.Itoa(int(orderId)) - - targetUrl = baseUrl + "?appid=" + appid + "&redirect_uri=" + redirectUri + "&response_type=" + responseType + "&scope=" + scope + "&state=" + order + "#wechat_redirect" - code = errorcode.Success - return -} - -// 收银台获取付款链接 -func GetPayLinkService(req front.GetPayLinkRequest) (result string, code int) { - var ( - payChannel = &paychannelmodel.PayChannel{} - order = &ordersmodel.Orders{} - orderPayRequest front.PayReqsV2 - ) - // 支付方式校验 - payChannel, code = PayChannelFindOne(payChannel, builder.Eq{"id": req.PayChannelId}) - if code != errorcode.Success { - return - } - if payChannel.ExpireTime.Unix() < time.Now().Unix() { - code = errorcode.PayChannelExpired - return - } - // 订单校验 - order, code = OrderFindOne(order, builder.Eq{"id": req.OrderId}) - if code != errorcode.Success { - return - } - // 订单状态校验 - code = orderStatusCheck(*order) - if code != errorcode.Success { - return - } - // 获取订单的请求参数 - orderRequestLog := orderrequestlogmodel.OrderRequestLog{ - OutTradeNo: order.OutTradeNo, - AppId: order.AppId, - } - has, err := OrderRequestLogs(&orderRequestLog) - if err != nil { - code = handErr(err) - return - } - if !has { - code = errorcode.OrderPayRequestLogNotExist - return - } - err = json.Unmarshal([]byte(orderRequestLog.MerchantRequest), &orderPayRequest) - if err != nil { - code = handErr(err) - return - } - // 支付方式需要用户授权 - if payChannel.ChannelType == common.PAY_CHANNEL_WECHAT_JSAPI && orderPayRequest.OpenId == "" { - result, code = GetWxAuthUrl(payChannel.AppId, order.Id) - return - } - // 请求第三方支付获取付款链接 - //payParam := paymentService.PayOrderRequest{ - // OrderId: order.Id, - //} - //res := paymentService.PaymentService(context.Background(), payParam) - //result = res.Result - //code = res.Code - return -} diff --git a/app/services/request_log.go b/app/services/request_log.go index f84bdda..e206b61 100644 --- a/app/services/request_log.go +++ b/app/services/request_log.go @@ -4,6 +4,7 @@ import ( "PaymentCenter/app/constants/common" "PaymentCenter/app/data" "PaymentCenter/app/models/orderrequestlogmodel" + "encoding/json" "xorm.io/builder" ) @@ -32,7 +33,11 @@ func RequestLogUpdate(log *orderrequestlogmodel.OrderRequestLog) (logOut *orderr } func AddRequestLog(requestDataByte []byte, ip string, url string) (int64, int) { + tempMap := make(map[string]interface{}) + _ = json.Unmarshal(requestDataByte, &tempMap) + requestLog, checkCode := RequestLogCreate(&orderrequestlogmodel.OrderRequestLog{ + OutTradeNo: tempMap["out_trade_no"].(string), IpAddress: ip, MerchantRequest: string(requestDataByte), URL: url, diff --git a/app/services/thirdpay/do/pay.go b/app/services/thirdpay/do/pay.go index 97b79e1..e908b7b 100644 --- a/app/services/thirdpay/do/pay.go +++ b/app/services/thirdpay/do/pay.go @@ -128,7 +128,7 @@ func (w *Pay) PayUrl() (url string) { // 微信公众号支付,返回的是用户授权链接 case common.PAY_CHANNEL_WECHAT_JSAPI: // 获取授权链接 - res.Result, res.Code = w.GetWxAuthUrl(w.PayParam.Channel.AppId, w.Order.Id) + res.Result, res.Code = GetWxAuthUrl(w.PayParam.Channel.AppId, w.Order.Id) case common.PAY_CHANNEL_ALIPAY_WEB: // 支付宝h5 res = paymentService.PaymentService(*w.ctx, *thirdPay) @@ -233,7 +233,7 @@ func (w *Pay) CloseOrder() { } // appid:微信的公众号appid -func (w *Pay) GetWxAuthUrl(appid string, orderId int64) (targetUrl string, code int) { +func GetWxAuthUrl(appid string, orderId int64) (targetUrl string, code int) { var ( // 重定向地址 redirectUri = config.GetConf().PayService.Host + common.WXCodeRedirectAddress diff --git a/app/services/thirdpay/do/pay_way.go b/app/services/thirdpay/do/pay_way.go index 34d0c56..666c75a 100644 --- a/app/services/thirdpay/do/pay_way.go +++ b/app/services/thirdpay/do/pay_way.go @@ -11,6 +11,7 @@ import ( var PayWayList = map[int]func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error{ common.PAY_CHANNEL_WECHAT_H5: WechatH5, common.PAY_CHANNEL_ALIPAY_WEB: AlipayWeb, + common.PAY_CHANNEL_ALIPAY_PC: AlipayWeb, common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPI, } diff --git a/app/services/thirdpay/pay_page.go b/app/services/thirdpay/pay_page.go new file mode 100644 index 0000000..f2bf37e --- /dev/null +++ b/app/services/thirdpay/pay_page.go @@ -0,0 +1,212 @@ +package thirdpay + +import ( + "PaymentCenter/app/constants/common" + "PaymentCenter/app/constants/errorcode" + "PaymentCenter/app/http/entities/backend" + "PaymentCenter/app/http/entities/front" + "PaymentCenter/app/models/orderrequestlogmodel" + "PaymentCenter/app/models/ordersmodel" + "PaymentCenter/app/models/paychannelmodel" + "PaymentCenter/app/services" + "PaymentCenter/app/services/thirdpay/do" + "PaymentCenter/app/third/paymentService" + "PaymentCenter/app/third/paymentService/payCommon" + "PaymentCenter/app/utils" + "PaymentCenter/config" + "context" + "encoding/json" + "fmt" + "strconv" + "time" + "xorm.io/builder" +) + +// 收银台获取付款链接 +func GetPayLinkService(req front.GetPayLinkRequest) (result, message string, code int) { + var ( + payChannel = &paychannelmodel.PayChannel{} + order = &ordersmodel.Orders{} + orderPayRequest front.PayReqsV2 + ) + // 支付方式校验 + payChannel, code = services.PayChannelFindOne(payChannel, builder.Eq{"id": req.PayChannelId}) + if code != errorcode.Success { + return + } + if !payChannel.ExpireTime.IsZero() && payChannel.ExpireTime.Unix() < time.Now().Unix() { + code = errorcode.PayChannelExpired + return + } + // 订单校验 + order, code = services.OrderFindOne(order, builder.Eq{"id": req.OrderId}) + if code != errorcode.Success { + return + } + // 订单状态校验 + code = services.OrderStatusCheck(*order) + if code != errorcode.Success { + return + } + // todo 订单的支付方式是否一致 + if order.PayChannelId != payChannel.Id { + order.PayChannelId = payChannel.Id + code = services.OrderUpdate(order) + if code != errorcode.Success { + return + } + } + // 获取订单的请求参数 + orderRequestLog := orderrequestlogmodel.OrderRequestLog{ + OutTradeNo: order.OutTradeNo, + AppId: order.AppId, + } + has, err := services.OrderRequestLogs(&orderRequestLog) + if err != nil { + code = handErr(err) + return + } + if !has { + code = errorcode.OrderPayRequestLogNotExist + return + } + err = json.Unmarshal([]byte(orderRequestLog.MerchantRequest), &orderPayRequest) + if err != nil { + code = handErr(err) + return + } + // 支付方式需要用户授权 + if payChannel.ChannelType == common.PAY_CHANNEL_WECHAT_JSAPI && orderPayRequest.OpenId == "" { + result, code = do.GetWxAuthUrl(payChannel.AppId, order.Id) + return + } + // 请求第三方支付获取付款链接 + payParam := paymentService.PayOrderRequest{ + PayChannelId: payChannel.Id, + OrderId: order.Id, + ChannelType: payChannel.ChannelType, + Description: orderPayRequest.Desc, + Amount: orderPayRequest.Amount, + PayerClientIp: req.ClientIp, + ReturnUrl: orderPayRequest.ReturnUrl, + OpenId: orderPayRequest.OpenId, + } + // 判断是否是支持的支付渠道,找到对应的配置 + var payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error + var ok bool + if payFunc, ok = do.PayWayList[payChannel.ChannelType]; !ok { + code = errorcode.PayChannelNotBuild + return + } + err = payFunc(&payParam, payChannel) + if err != nil { + code = errorcode.PayChannelExtJsonError + return + } + + res := paymentService.PaymentService(context.Background(), payParam) + // 下单失败 + if res.Code != payCommon.PAY_SUCCESS_CODE { + code = errorcode.PrePayFail + message = res.ErrorMsg + return + } + // 更新订单状态 + order.Status = common.ORDER_STATUS_PAYING + code = services.OrderUpdate(order, "status") + if code != errorcode.Success { + utils.Log(nil, "成功下单,更新订单状态失败", order) + } + + result = res.Result + code = res.Code + return +} + +// 预支付 +type payUrl struct { + ClientIp string + param front.PayReqsV2 + app *services.AppCheck + result front.PayReqsV2Response +} + +func NewPayUrl(param front.PayReqsV2) *payUrl { + return &payUrl{ + param: param, + } +} +func (this *payUrl) WithApp(app *services.AppCheck) *payUrl { + this.app = app + return this +} +func (this *payUrl) WithClientIp(ip string) *payUrl { + this.ClientIp = ip + return this +} + +func (this *payUrl) saveOrder() { + order := &ordersmodel.Orders{ + MerchantId: this.app.App.MerchantId, + //PayChannelId: w.PayParam.Channel.Id, + AppId: this.app.App.Id, + OutTradeNo: this.param.OutTradeNo, + OrderType: common.ORDER_TYPE_PAY, + Amount: this.param.Amount, + ExtJson: this.param.ExtJson, + Desc: this.param.Desc, + Status: common.ORDER_STATUS_WAITPAY, + } + this.result.Order, this.result.PayCode = services.OrderCreate(order) +} + +func (this *payUrl) PayUrlV2Service() (result front.PayReqsV2Response, code int) { + var ( + channelList []paychannelmodel.PayChannel + order = new(ordersmodel.Orders) + ) + + // redis 分布式锁 订单号幂等 + key := utils.GetRealKey("payUrl:" + this.param.OutTradeNo) + lockValue := fmt.Sprintf("%d", time.Now().UnixNano()) + ok, err := utils.AcquireLock(key, lockValue, time.Second*time.Duration(3)) + if ok { + defer utils.ReleaseLock(key, lockValue) + } else { + if err != nil { + utils.Log(nil, "", "PayUrlV2Service,获取分布式锁失败", fmt.Sprintf("错误原因:%s", err.Error())) + } + return + } + + // 商户是否有配置支付渠道 + channelList, _, code = services.PayChannelList(backend.PayChannelListRequest{MerchantId: this.app.App.MerchantId}) + if code != errorcode.Success { + return + } + if len(channelList) == 0 { + code = errorcode.PayChannelNotFound + return + } + // 订单是否存在 + conn := builder.NewCond() + conn = conn.And(builder.Eq{"out_trade_no": this.param.OutTradeNo}) + conn = conn.And(builder.Eq{"app_id": this.param.AppId}) + order, code = services.OrderFindOne(order, conn) + if code == errorcode.Success { + // 订单存在 + this.result.Order = order + this.result.PayCode = services.OrderStatusCheck(*order) + } else if code == errorcode.OrdersNotFound { + // 订单不存在 + this.saveOrder() + } else { + return + } + code = this.result.PayCode + if code == errorcode.Success { + this.result.Url = config.GetConf().PayService.Host + common.PayPageAddress + "?no=" + strconv.FormatInt(this.result.Order.Id, 10) + } + + return this.result, code +} diff --git a/app/third/paymentService/ali_service.go b/app/third/paymentService/ali_service.go index fb7034e..47075b0 100644 --- a/app/third/paymentService/ali_service.go +++ b/app/third/paymentService/ali_service.go @@ -82,6 +82,69 @@ func ALiH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, e return aliRsp, nil } +// ALiPCPayInfo 支付宝 支付宝PC网站支付 +func ALiPCPayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) { + // 初始化支付宝客户端 + aliClient, err := AliInitClient(payOrderRequest.Ali) + if err != nil { + return "", err + } + // 初始化 BodyMap + amount := float64(payOrderRequest.Amount) / 100.0 + + envConfig := config.GetConf() + bm := make(gopay.BodyMap) + bm.Set("out_trade_no", payOrderRequest.OrderId). + Set("total_amount", amount). + Set("subject", payOrderRequest.Description). + Set("qr_pay_mode", 1). + Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.ALI_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)) + if payOrderRequest.ReturnUrl != "" { + bm.Set("return_url", payOrderRequest.ReturnUrl) + } + + aliRsp, err := aliClient.TradePagePay(c, bm) + if err != nil { + logger.Error(c, "ALiH5PayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error())) + if bizErr, ok := alipay.IsBizError(err); ok { + return "", bizErr + } + return "", err + } + return aliRsp, nil +} + +// ALiQrCodeTradePrecreate 支付宝 订单码支付 +func ALiQrCodeTradePrecreate(c context.Context, payOrderRequest PayOrderRequest) (string, error) { + // 初始化支付宝客户端 + aliClient, err := AliInitClient(payOrderRequest.Ali) + if err != nil { + return "", err + } + // 初始化 BodyMap + amount := float64(payOrderRequest.Amount) / 100.0 + + envConfig := config.GetConf() + bm := make(gopay.BodyMap) + bm.Set("out_trade_no", payOrderRequest.OrderId). + Set("total_amount", amount). + Set("subject", payOrderRequest.Description). + Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.ALI_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)) + if payOrderRequest.ReturnUrl != "" { + bm.Set("return_url", payOrderRequest.ReturnUrl) + } + + aliRsp, err := aliClient.TradePrecreate(c, bm) + if err != nil { + logger.Error(c, "ALiH5PayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error())) + if bizErr, ok := alipay.IsBizError(err); ok { + return "", bizErr + } + return "", err + } + return aliRsp.Response.QrCode, nil +} + // ALiCallBack 支付宝支付回调 func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error { var orderStatus int diff --git a/app/third/paymentService/payCommon/common.go b/app/third/paymentService/payCommon/common.go index cc6d229..9baefd5 100644 --- a/app/third/paymentService/payCommon/common.go +++ b/app/third/paymentService/payCommon/common.go @@ -4,7 +4,7 @@ import "PaymentCenter/app/constants/common" const ( - // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI + // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI,9支付宝电脑网页,10支付宝订单码扫码支付 PAY_CHANNEL_UNKNOWN = 0 PAY_CHANNEL_WECHAT_JSAPI = 1 PAY_CHANNEL_WECHAT_H5 = 2 @@ -14,6 +14,8 @@ const ( PAY_CHANNEL_ALIPAY_WEB = 6 PAY_CHANNEL_ALIPAY_MINI = 7 PAY_CHANNEL_ALIPAY_JSAPI = 8 + PAY_CHANNEL_ALIPAY_PC = 9 + PAY_CHANNEL_ALIPAY_QrCode = 10 PAY_SUCCESS_CODE = 200 // 支付响应成功 PAY_ERROR_CODE = 500 // 支付响应失败 diff --git a/app/third/paymentService/payment_service.go b/app/third/paymentService/payment_service.go index 31c3978..82fafb0 100644 --- a/app/third/paymentService/payment_service.go +++ b/app/third/paymentService/payment_service.go @@ -63,6 +63,9 @@ func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrder case payCommon.PAY_CHANNEL_WECHAT_JSAPI: // 微信JSAPI支付 info, err = WxJsApiPayInfo(c, payOrderRequest) + case payCommon.PAY_CHANNEL_ALIPAY_PC: + // 支付宝PC支付 + info, err = ALiPCPayInfo(c, payOrderRequest) default: payOrderResponse = PayOrderResponse{ diff --git a/app/utils/useragent.go b/app/utils/useragent.go index 916cec2..8b5fd98 100644 --- a/app/utils/useragent.go +++ b/app/utils/useragent.go @@ -24,6 +24,6 @@ func IsMobile(ua string) bool { func IsPC(userAgent string) bool { // 检查 User-Agent 中是否包含 PC 浏览器的标识 - t := strings.Contains(userAgent, "Windows NT") || strings.Contains(userAgent, "Macintosh") || strings.Contains(userAgent, "Linux") + t := strings.Contains(userAgent, "Windows NT") || strings.Contains(userAgent, "Macintosh") return t } diff --git a/front/templates/payPage.html b/front/templates/payPage.html new file mode 100644 index 0000000..52ebbcf --- /dev/null +++ b/front/templates/payPage.html @@ -0,0 +1,147 @@ + + + + + + 收银台页面 + + + + +{{if eq .code 200 }} + + +{{/*

收银台页面

*/}} +

订单号:{{ .id }}

+

订单金额:{{ .amount }} 元

+ + + + + +{{ else}} + +

{{.message}}

+ + +{{end}} + + + diff --git a/front/templates/payTemplate.html b/front/templates/payTemplate.html new file mode 100644 index 0000000..9c24437 --- /dev/null +++ b/front/templates/payTemplate.html @@ -0,0 +1,15 @@ + + + + + Title + + + + + + + \ No newline at end of file