package services import ( "PaymentCenter/app/constants/common" "PaymentCenter/app/constants/errorcode" "PaymentCenter/app/http/entities" "PaymentCenter/app/http/entities/backend" "PaymentCenter/app/http/entities/front" "PaymentCenter/app/models/ordersmodel" "PaymentCenter/app/models/paychannelmodel" "PaymentCenter/app/utils" "PaymentCenter/config" "fmt" "strconv" "time" "xorm.io/builder" ) // 收银台支付渠道列表 func PayPageChannelList(reqParam front.PayChannelListRequest) (resultPayChannelList []paychannelmodel.PayChannel, code int) { orderId, err := strconv.ParseInt(reqParam.OrderId, 10, 64) if err != nil { code = errorcode.ParamError return } // 订单检查 orderInfo := &ordersmodel.Orders{Id: orderId} orderInfo, code = OrderFindOne(orderInfo, builder.Eq{"id": orderId}) if code != errorcode.Success { return } if !(orderInfo.Status == common.ORDER_STATUS_PAYING || orderInfo.Status == common.ORDER_STATUS_WAITPAY) { code = errorcode.OrderStatusErr return } // 商户拥有的支付渠道检查 req := backend.PayChannelListRequest{ MerchantId: orderInfo.MerchantId, PageRequest: entities.PageRequest{}, } payList := make([]paychannelmodel.PayChannel, 0) payList, _, code = PayChannelList(req) if code != errorcode.Success { return } if len(payList) == 0 { code = errorcode.PayChannelNotFound return } merchantPayChannelMap := make(map[int]paychannelmodel.PayChannel, 0) for _, pay := range payList { merchantPayChannelMap[pay.ChannelType] = pay } // 客户端环境检查 openType := ClientEnvCheck(reqParam.UserAgent) if channels, ok := common.OpenInPayChannelMap[openType]; !ok { code = errorcode.ClientEnvErr return } else { for _, channel := range channels { if _, ok = merchantPayChannelMap[channel]; ok { resultPayChannelList = append(resultPayChannelList, merchantPayChannelMap[channel]) } } } return resultPayChannelList, code } // 客户端环境检查 func ClientEnvCheck(ua string) int { if utils.IsWeChatClient(ua) { return common.OpenInWeChat } else if utils.IsPC(ua) { return common.OpenInWindows } else if utils.IsMobile(ua) { return common.OpenInMobile } 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 (this *payUrl) orderExist() { switch this.result.Order.Status { case common.ORDER_STATUS_CLOSE: this.result.PayCode = errorcode.OrderClosed case common.ORDER_STATUS_PAYED: this.result.PayCode = errorcode.OrderPayed case common.ORDER_STATUS_FAILED: this.result.PayCode = errorcode.OrderFailed case common.ORDER_STATUS_WAITPAY, common.ORDER_STATUS_PAYING: this.result.PayCode = errorcode.Success default: this.result.PayCode = errorcode.OrderStatusErr } } 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.orderExist() } 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 }