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 }