PaymentCenter/app/services/thirdpay/do/pay.go

307 lines
8.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package do
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/models/merchantmodel"
"PaymentCenter/app/models/paychannelmodel"
"PaymentCenter/app/services"
"PaymentCenter/app/third/paymentService/payCommon"
"PaymentCenter/app/utils"
"PaymentCenter/config"
"context"
"net/url"
"strconv"
"time"
"xorm.io/builder"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/third/paymentService"
)
type PayParam struct {
Merchant *merchantmodel.Merchant
Channel *paychannelmodel.PayChannel
App_id int64
OutTradeNo string
Amount int
ExtJson string
Desc string
ClientIp string
ReturnUrl string
OpenId string
}
type Pay struct {
ctx *context.Context
PayParam *PayParam
RelationOrder *ordersmodel.Orders
Order *ordersmodel.Orders
PayCode int // 支付状态码
Url string // 支付链接
ThirdMsg string // 第三方错误信息
JsApiInfo *front.WxMiniPayResponse // jsapi支付参数
}
func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
return &Pay{
ctx: paycheck.ctx,
PayParam: &PayParam{
Merchant: paycheck.Merchant,
Channel: paycheck.Channel,
App_id: paycheck.Reqs.AppId,
OutTradeNo: paycheck.Reqs.OutTradeNo,
Amount: paycheck.Reqs.Amount,
ExtJson: paycheck.Reqs.ExtJson,
Desc: paycheck.Reqs.Desc,
ClientIp: paycheck.AppCheck.Ip,
ReturnUrl: paycheck.Reqs.ReturnUrl,
OpenId: paycheck.Reqs.OpenId,
},
RelationOrder: paycheck.OldOrder,
PayCode: errorcode.Success,
}
}
func (w *Pay) CheckRefundOrder() bool {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"app_id": w.PayParam.App_id}, builder.Eq{"order_type": common.ORDER_TYPE_REFUND}, builder.Eq{"out_trade_no": w.PayParam.OutTradeNo})
order, code := services.OrderFindOne(&ordersmodel.Orders{}, cond)
if code != errorcode.Success {
return true
}
if order.Status == common.ORDER_STATUS_FAILED {
return true
}
w.Order = order
return false
}
func (w *Pay) CreateOrder(order_type int) {
if _, ok := common.OrderTypeList[order_type]; !ok { //判断是否是支持的支付渠道
w.PayCode = errorcode.PayChannelNotFound
return
}
order := &ordersmodel.Orders{
MerchantId: w.PayParam.Merchant.Id,
PayChannelId: w.PayParam.Channel.Id,
AppId: w.PayParam.App_id,
OutTradeNo: w.PayParam.OutTradeNo,
OrderType: order_type,
Amount: w.PayParam.Amount,
ExtJson: w.PayParam.ExtJson,
Desc: w.PayParam.Desc,
Status: common.ORDER_STATUS_WAITPAY,
}
if order_type == common.ORDER_TYPE_REFUND {
order.RefundOrderId = w.RelationOrder.Id
}
w.Order, w.PayCode = services.OrderCreate(order)
}
func (w *Pay) PayUrl() (url string) {
var (
payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error
ok bool
res paymentService.PayOrderResponse
)
thirdPay := &paymentService.PayOrderRequest{
PayChannelId: w.PayParam.Channel.Id,
OrderId: w.Order.Id,
ChannelType: w.PayParam.Channel.ChannelType,
Description: w.Order.Desc,
Amount: w.Order.Amount,
PayerClientIp: w.PayParam.ClientIp,
ReturnUrl: w.PayParam.ReturnUrl,
OpenId: w.PayParam.OpenId,
}
// 判断是否是支持的支付渠道,找到对应的配置
if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok {
w.PayCode = errorcode.PayChannelNotBuild
return
}
err := payFunc(thirdPay, w.PayParam.Channel)
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
return
}
// 根据渠道类型,调用对应的支付方式
switch w.PayParam.Channel.ChannelType {
// 微信公众号支付,返回的是用户授权链接
case common.PAY_CHANNEL_WECHAT_JSAPI:
// 获取授权链接
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)
case common.PAY_CHANNEL_WECHAT_H5:
// 微信h5支付
res = paymentService.PaymentService(*w.ctx, *thirdPay)
if res.Result != "" {
res.Result = config.GetConf().PayService.Host + "/pay/front/api/v1/brokerWechatUrl" + "?url=" + res.Result
}
case common.PAY_CHANNEL_WECHAT_MINI:
// 微信小程序支付
// 如果传openid获取支付参数
if w.PayParam.OpenId != "" {
res = paymentService.PaymentService(*w.ctx, *thirdPay)
} else {
// 如果没有传openid获取小程序scheme链接
req := front.GetWxMiniSchemeRequest{
PayChannelId: strconv.Itoa(int(w.PayParam.Channel.Id)),
GenerateSchemeRequest: front.GenerateSchemeRequest{
JumpWxa: front.JumpWxa{Query: "?order_id=" + strconv.Itoa(int(w.Order.Id))},
}}
if config.GetEnv() == config.LocalEnv {
req.GenerateSchemeRequest.JumpWxa.EnvVersion = "develop"
} else if config.GetEnv() == config.DevEnv {
req.GenerateSchemeRequest.JumpWxa.EnvVersion = "trial"
}
// 微信小程序支付返回小程序的scheme
wx := NewWxMini().WithPayChannel(w.PayParam.Channel)
// 拼接订单id参数
req.JumpWxa.Query = "?order_id=" + strconv.Itoa(int(w.Order.Id))
url, err = wx.GetWxMiniScheme(req)
res.Result = url
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
w.ThirdMsg = err.Error()
return
}
}
default:
w.PayCode = errorcode.PayChannelNotBuild
return
}
if res.Code == payCommon.PAY_SUCCESS_CODE {
w.Order.Status = common.ORDER_STATUS_PAYING
code := services.OrderUpdate(w.Order, "status")
if code != errorcode.Success {
w.PayCode = code
}
// 微信小程序
if w.PayParam.Channel.ChannelType == common.PAY_CHANNEL_WECHAT_MINI {
// 组装返回数据
if res.Result != "" {
w.JsApiInfo = &front.WxMiniPayResponse{
AppId: w.PayParam.Channel.AppId,
TimeStamp: strconv.Itoa(int(time.Now().Unix())),
NonceStr: strconv.Itoa(int(time.Now().Unix())),
Package: "prepay_id=" + res.Result,
SignType: "RSA",
ThirdMsg: res.ErrorMsg,
ReturnUrl: w.PayParam.ReturnUrl,
}
// 获取签名
err = w.JsApiInfo.SignPaySign(thirdPay.Wx.PrivateKey)
}
} else {
w.Url = res.Result
}
} else {
w.PayCode = errorcode.PrePayFail
w.ThirdMsg = res.ErrorMsg
}
return
}
func (w *Pay) Refund() {
var (
refundFunc func(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error
ok bool
)
thirdPayRefund := &paymentService.OrderRefundRequest{
OrderId: w.RelationOrder.Id,
RefundOrderId: w.Order.Id,
RefundReason: w.PayParam.Desc,
RefundAmount: int64(w.PayParam.Amount),
}
if refundFunc, ok = RefundWayList[w.PayParam.Channel.ChannelType]; !ok {
w.PayCode = errorcode.PayChannelNotBuild
return
}
err := refundFunc(thirdPayRefund, w.PayParam.Channel)
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
return
}
res := paymentService.OrderRefund(*w.ctx, *thirdPayRefund)
if res.Code == payCommon.PAY_SUCCESS_CODE {
w.Order.Status = common.ORDER_STATUS_PAYING
code := services.OrderUpdate(w.Order, "status")
if code != errorcode.Success {
w.PayCode = code
return
}
} else {
w.PayCode = errorcode.ThirdRefundFail
w.ThirdMsg = res.ErrorMsg
}
}
// 关闭订单
func (w *Pay) CloseOrder() {
var (
payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error
ok bool
)
thirdPay := &paymentService.PayOrderRequest{
PayChannelId: w.PayParam.Channel.Id,
OrderId: w.Order.Id,
ChannelType: w.PayParam.Channel.ChannelType,
Description: w.Order.Desc,
Amount: w.Order.Amount,
PayerClientIp: w.PayParam.ClientIp,
ReturnUrl: w.PayParam.ReturnUrl,
}
if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok {
w.PayCode = errorcode.PayChannelNotBuild
return
}
err := payFunc(thirdPay, w.PayParam.Channel)
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
return
}
closeRequest := paymentService.OrderCloseRequest{
OrderId: thirdPay.OrderId,
PayChannel: utils.PayType(thirdPay.ChannelType),
Wx: thirdPay.Wx,
Ali: thirdPay.Ali,
}
res := paymentService.OrderClose(*w.ctx, closeRequest)
w.ThirdMsg = res.ErrorMsg
w.PayCode = res.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
}