feat: 收银台
This commit is contained in:
parent
64973f683d
commit
2a21f854e1
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) },
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 // 支付响应失败
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>收银台页面</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
{{if eq .code 200 }}
|
||||
<body>
|
||||
<!-- 页面内容 -->
|
||||
{{/*<h1>收银台页面</h1>*/}}
|
||||
<p>订单号:{{ .id }}</p>
|
||||
<p>订单金额:{{ .amount }} 元</p>
|
||||
<ul id="payment-list"></ul>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
// 从 URL 中提取参数
|
||||
function getQueryParam(param) {
|
||||
const queryString = window.location.search.substring(1);
|
||||
const params = queryString.split('&');
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const [key, value] = params[i].split('=');
|
||||
if (key === param) {
|
||||
return decodeURIComponent(value);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取支付方式列表
|
||||
function fetchPaymentMethods() {
|
||||
const id = getQueryParam('no');
|
||||
console.log('Order no:', id);
|
||||
if (id) {
|
||||
fetch(`/pay/front/api/v1/payPage/list?id=${id}`, {
|
||||
method: 'POST',
|
||||
})
|
||||
.then(async response => {
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
console.log(data)
|
||||
if (data.code !== 200) {
|
||||
throw new Error('无效');
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error('无效');
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Received payment methods:', data);
|
||||
// 处理返回的数据,例如渲染支付方式列表
|
||||
renderPaymentMethods(data.data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('data', data);
|
||||
|
||||
});
|
||||
} else {
|
||||
console.error('Order no not found in URL');
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染支付方式列表
|
||||
function renderPaymentMethods(paymentMethods) {
|
||||
const paymentList = document.getElementById('payment-list');
|
||||
paymentList.innerHTML = '';
|
||||
paymentMethods.forEach(method => {
|
||||
const listItem = document.createElement('li');
|
||||
const radioInput = document.createElement('input');
|
||||
radioInput.type = 'radio';
|
||||
radioInput.name = 'paymentMethod';
|
||||
radioInput.value = method.pay_channel_id;
|
||||
listItem.appendChild(radioInput);
|
||||
listItem.appendChild(document.createTextNode(method.pay_name));
|
||||
paymentList.appendChild(listItem);
|
||||
});
|
||||
|
||||
// 添加提交按钮
|
||||
const submitButton = document.createElement('button');
|
||||
submitButton.type = 'button';
|
||||
submitButton.textContent = '提交';
|
||||
submitButton.onclick = function () {
|
||||
const no = getQueryParam('no');
|
||||
const selectedMethod = document.querySelector('input[name="paymentMethod"]:checked');
|
||||
if (selectedMethod) {
|
||||
window.location.href = `/pay/front/api/v1/payPage/submit?pay_channel_id=${selectedMethod.value}&no=${no}`;
|
||||
} else {
|
||||
alert('请选择支付方式');
|
||||
}
|
||||
};
|
||||
paymentList.appendChild(submitButton);
|
||||
}
|
||||
|
||||
|
||||
// 在页面加载时调用 fetchPaymentMethods 函数
|
||||
window.onload = fetchPaymentMethods;
|
||||
</script>
|
||||
|
||||
{{ else}}
|
||||
<body>
|
||||
<p>{{.message}}</p>
|
||||
</body>
|
||||
|
||||
{{end}}
|
||||
|
||||
|
||||
</html>
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
// 网页默认跳转url
|
||||
window.location.href = "{{.payUrl}}";
|
||||
</script>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue