package com.jeequan.jeepay.pay.ctrl.qr;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jeequan.jeepay.components.mq.model.PushWxMpMsgMQ;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.exception.openapi.ParamException;
import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService;
import com.jeequan.jeepay.core.interfaces.device.IPrinterService;
import com.jeequan.jeepay.core.interfaces.device.ISpeakerService;
import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.AppletResult;
import com.jeequan.jeepay.core.model.DBMarketingConfig;
import com.jeequan.jeepay.core.model.QRCodeParams;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params;
import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg;
import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ;
import com.jeequan.jeepay.core.model.rqrs.payorder.payway.*;
import com.jeequan.jeepay.core.utils.*;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.pay.ctrl.payorder.AbstractPayOrderController;
import com.jeequan.jeepay.pay.service.ChannelOrderReissueService;
import com.jeequan.jeepay.pay.service.PayMchNotifyService;
import com.jeequan.jeepay.pay.service.PayOrderMarketReissueService;
import com.jeequan.jeepay.service.impl.*;
import com.jeequan.jeepay.thirdparty.service.wxmp.WxTgAppletService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* 聚合码支付二维码收银台controller
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/6/8 17:27
*/
@RestController
@RequestMapping("/api/cashier")
public class QrCashierController extends AbstractPayOrderController {

    @Autowired private PayOrderService payOrderService;
    @Autowired private IConfigContextQueryService configContextQueryService;
    @Autowired private SysConfigService sysConfigService;
    @Autowired private PayMchNotifyService payMchNotifyService;
    @Autowired private MchQrcodeCardService mchQrcodeCardService;
    @Autowired private MchStoreDeviceService mchStoreDeviceService;
    @Autowired private MchConfigService mchConfigService;
    @Autowired private MchQrcDeviceRelaService mchQrcDeviceRelaService;
    @Autowired private MchPayPassageService mchPayPassageService;
    @Autowired private MchStoreService mchStoreService;
    @Autowired private SysUserService sysUserService;
    @Autowired private WxTgAppletService wxTgAppletService;
    @Autowired private ChannelOrderReissueService channelOrderReissueService;
    @Autowired private RedPacketAccountService redPacketAccountService;
    @Autowired private RedPacketRuleService redPacketRuleService;
    @Autowired private RedPacketInfoService redPacketInfoService;
    @Autowired private PayOrderMarketReissueService payOrderMarketReissueService;
    @Autowired private CacheTkService cacheTkService;
    @Autowired private MchVideoCacheService mchVideoCacheService;
    @Autowired private RouteService routeService;
    @Autowired private MchAppService mchAppService;
    @Autowired private MchApplymentService mchApplymentService;

    /**
     * 返回 oauth2【获取uerId跳转地址】
     * **/
    @PostMapping("/redirectUrl")
    public ApiRes redirectUrl(){

        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        //码牌
        if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC){

            MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());

            if(mchQrCode == null){
                throw new BizException("当前码牌已被删除，无法使用，请更换新的码牌进行支付");
            }

            if(mchQrCode.getBindState() != CS.YES){
                throw new BizException("当前码牌暂未绑定门店或暂未开启使用状态，请绑定后重试");
            }

            // 空码 跳转到注册页面
            if(mchQrCode.getBindState() != CS.YES){
                String mchRegisterUrl = String.format("%s/register?"+JeepayKit.TOKEN_KEY+"=%s", sysConfigService.getDBApplicationConfig().getMchSiteUrl(), getToken());
                String redirectUrl;
                if (StringUtils.isNotEmpty(mchQrCode.getAgentNo())) {
                    // 如果已划拨到服务商，携带服务商下默认用户的邀请码
                    SysUserEntity sysUserEntity = sysUserService.getBaseMapper().selectOne(SysUserEntity.gw()
                            .eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT)
                            .eq(SysUserEntity::getBelongInfoId, mchQrCode.getAgentNo())
                            .orderByAsc(SysUserEntity::getCreatedAt)
                            .last("limit 1")
                    );
                    redirectUrl = String.format("%s&c=%s", mchRegisterUrl, sysUserEntity.getInviteCode());
                } else {
                    redirectUrl = mchRegisterUrl;
                }
                JSONObject result = JsonKit.newJson("redirectFlag", true);
                result.put("redirectUrl", redirectUrl);
                return ApiRes.ok(result);
            }

            // 支付宝内 && wap支付， 无需获取
            if(QRCodeParams.PAGE_TYPE_ALIPAY_H5.equals(qrCodeParams.getPageType()) && CS.PAY_WAY_CODE.ALI_WAP.equals(mchQrCode.getAlipayWayCode())){
                return ApiRes.ok(JsonKit.newJson("redirectFlag", false));
            }
        }

        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, true);
        //回调地址
        String redirectUrlEncode = sysConfigService.getDBApplicationConfig().genOauth2RedirectUrlEncode(getToken());

        //获取接口并返回数据
        MutablePair<String, IChannelUserService> mutablePair = getServiceByWayCode(qrCodeParams.getPageType(), "ChannelUserService", mchAppConfigContext, IChannelUserService.class);
//        String ifCode = mutablePair.getLeft();
        IChannelUserService channelUserService = mutablePair.getRight();

        JSONObject result = JsonKit.newJson("redirectFlag", true);

        ChannelUserInfoMsg channelUserInfoMsg = channelUserService.buildUserRedirectUrl(redirectUrlEncode, mchAppConfigContext);

        result.put("redirectUrl", channelUserInfoMsg.getRedirectUrl());
        result.put("channelAppId", channelUserInfoMsg.getChannelAppId());

        // 用户ID 缓存key， 要求前端做缓存，  不存在说明： 不要求前端做缓存。
        if(StringUtils.isNotEmpty(channelUserInfoMsg.getChannelAppId())){
            // 规则： channelUserId_页面类型_渠道appId  （不再设置jeepay系统的appId， 同一个服务商不同商户也支持查询缓存userId ）
            result.put("channelUserIdCacheKey", String.format("jeepayChannelUserId_%s_%s", qrCodeParams.getPageType(), channelUserInfoMsg.getChannelAppId()));
        }

        return ApiRes.ok(result);
    }




    @RequestMapping(value = "getisvNo")
    public ApiRes getisvNo(){
        String qrcId=getValStringRequired("qrcId");

        MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId);

        // 添加商户、门店、应用名称
        if (dbRecord.getBindState() == CS.YES) {
            if (dbRecord.getStoreId() != null) {
                MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId());
                if (mchStore != null) {
                    dbRecord.addExt("storeName", mchStore.getStoreName());
                }
            }

            if (StringUtils.isNotBlank(dbRecord.getAppId())) {
                MchAppEntity mchAppEntity = mchAppService.getById(dbRecord.getAppId());
                if (mchAppEntity != null) {
                    dbRecord.addExt("appName", mchAppEntity.getAppName());
                }
            }
        }
        MchApplyment mchApplyment = mchApplymentService.getById(dbRecord.getMchApplyId());
        // 封装URL
        dbRecord.addExt("qrUrl", sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, dbRecord.getEntryPage(), qrcId + "", mchApplyment.getIsvNo()));
        return ApiRes.ok(dbRecord);

    }

    /**
     * 获取userId
     * **/
    @PostMapping("/channelUserId")
    public ApiRes channelUserId() throws Exception {

        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        //获取商户配置信息
        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, true);

        JSONObject reqParam = getReqParamJSON();

        // 获取响应结果类型（纯粹为了做小程序兼容（20221011）， 避免后端上线后，线上小程序报错） onlyChannelUserId   channelUserJSON
        String jeepayResType = StringUtils.defaultIfEmpty(reqParam.getString("jeepayResType"), "onlyChannelUserId");

        if (StringUtils.isNotBlank(getAppUpIdentifier())) {
            reqParam.put("appUpIdentifier", getAppUpIdentifier()); // 通过UA获取银联app标志
        }

        reqParam.put("clientIp", getClientIp());

        //获取商户配置信息
        MutablePair<String, IChannelUserService> mutablePair = getServiceByWayCode(qrCodeParams.getPageType(), "ChannelUserService", mchAppConfigContext, IChannelUserService.class);
        String ifCode = mutablePair.getLeft();
        IChannelUserService channelUserService = mutablePair.getRight();

        String channelUserId = channelUserService.getChannelUserId(qrCodeParams.getPageType(), reqParam, mchAppConfigContext, ifCode);

        logger.info("{}获取到channelUserId={}", qrCodeParams, channelUserId);
        // 仅获取userId
        if("onlyChannelUserId".equals(jeepayResType)){
            return ApiRes.ok(channelUserId);

        }else{ // 集合数据， 包含了 channelUserId, channelUserIdCacheKey

            JSONObject result = new JSONObject();
            result.put("channelUserId", channelUserId);

            ChannelUserInfoMsg channelUserInfoMsg = channelUserService.buildUserRedirectUrl("", mchAppConfigContext);

            // 用户ID 缓存key， 要求前端做缓存，  不存在说明： 不要求前端做缓存。
            if(StringUtils.isNotEmpty(channelUserInfoMsg.getChannelAppId())){
                // 规则： channelUserId_页面类型_渠道appId  （不再设置jeepay系统的appId， 同一个服务商不同商户也支持查询缓存userId ）
                result.put("channelUserIdCacheKey", String.format("jeepayChannelUserId_%s_%s", qrCodeParams.getPageType(), channelUserInfoMsg.getChannelAppId()));
            }

            return ApiRes.ok(result);
        }
    }


    /**
     * 获取订单支付信息
     * **/
    @PostMapping("/payOrderInfo")
    public ApiRes payOrderInfo() throws Exception {

        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        //获取商户配置信息
        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, false);

        PayOrder resOrder = new PayOrder();
        //强制备注默认为否
        resOrder.addExt("isForceReamrk",false);
        JSONObject randomOneVo = mchVideoCacheService.getRandomOneVo(mchAppConfigContext.getMchNo());
        if(randomOneVo != null){
            resOrder.addExt("video",randomOneVo);
        }
        // 订单类型 需要查询订单
        if(qrCodeParams.getType() == QRCodeParams.TYPE_PAY_ORDER){

            PayOrder payOrder = getPayOrder(false);
            //门店名称
            resOrder.setStoreName(StringUtils.isNotBlank(payOrder.getStoreName()) ? payOrder.getStoreName() : "");
            resOrder.setMchName(StringUtils.isNotBlank(payOrder.getMchName()) ? payOrder.getMchName() : "");
            resOrder.setAmount(payOrder.getAmount());
            resOrder.setState(payOrder.getState());
            resOrder.setReturnUrl(payMchNotifyService.createReturnUrl(payOrder, configContextQueryService.queryMchInfoAndAppInfoV2(payOrder.getMchNo(), payOrder.getAppId(),payOrder.getMchExtNo()).getMchApp().getAppSecret()));
            resOrder.addExt("autoPay", true); // 自动调起支付
            resOrder.addExt("fixedFlag", true); //固定金额，不可变更。
            // 商户自行创建的二维码
        }else if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC || qrCodeParams.getType() == QRCodeParams.TYPE_QRC_DEVICE || qrCodeParams.getType() == QRCodeParams.TYPE_ROUTE){
            if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC){
                MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
                if(mchQrCode == null){
                    throw new BizException("当前码牌已被删除，无法使用，请更换新的码牌进行支付");
                }
                if(mchQrCode.getQrcState() != CS.YES){
                    throw new BizException("当前码牌暂未绑定门店或暂未开启使用状态，请绑定后重试");
                }

                MchStore mchStore = mchStoreService.getById(mchQrCode.getStoreId());
                if(mchStore != null && StringUtils.isNotBlank(mchStore.getStoreName())) {
                    //门店名称
                    resOrder.setStoreName(mchStore.getStoreName());
                    resOrder.setMchName(mchQrCode.getMchApplyName());
                }else {
                    resOrder.setMchName(mchAppConfigContext.getMchInfo().getMchShortName());
                }

                if(mchQrCode.getFixedFlag() == CS.YES){
                    resOrder.setAmount(mchQrCode.getFixedPayAmount()); // 固定金额
                    resOrder.addExt("fixedFlag", true); //固定金额，不可变更。
                }
                resOrder.addExt("isForceReamrk",CS.YES == mchQrCode.getIsForceReamrk() ? true : false);
            }
            if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC_DEVICE){
                Long amt = qrCodeParams.getAmt();
                MchStoreDevice storeDevice = mchStoreDeviceService.getById(qrCodeParams.getId());
                if(MchStoreDevice.DEVICE_BIND_TYPE_STORE == storeDevice.getBindType()){
                    MchStore store = mchStoreService.getById(storeDevice.getStoreId());
                    //门店名称
                    resOrder.setStoreName(store.getStoreName());
                    resOrder.setMchName(storeDevice.getMchApplyName());
                    resOrder.setStoreId(store.getStoreId());
                    if(amt != null){
                        resOrder.setAmount(amt); // 固定金额
                        resOrder.addExt("fixedFlag", true);
                    }
                }else{
                    List<MchQrcDeviceRela> list = mchQrcDeviceRelaService.list(MchQrcDeviceRela.gw()
                            .eq(MchQrcDeviceRela::getDeviceId, storeDevice.getDeviceId()));
                    if(list.isEmpty()){
                        throw new BizException("设备绑定的码牌信息异常");
                    }
                    MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(list.get(0).getQrcId());
                    MchStore mchStore = mchStoreService.getById(mchQrCode.getStoreId());
                    if(mchStore != null && StringUtils.isNotBlank(mchStore.getStoreName())) {
                        //门店名称
                        resOrder.setStoreName(mchStore.getStoreName());
                        resOrder.setMchName(mchQrCode.getMchApplyName());
                        resOrder.setStoreId(mchStore.getStoreId());
                    }else {
                        resOrder.setMchName(mchAppConfigContext.getMchInfo().getMchShortName());
                    }
                    if(amt != null){
                        resOrder.setAmount(amt); // 固定金额
                        resOrder.addExt("fixedFlag", true);
                    }else{
                        if(mchQrCode.getFixedFlag() == CS.YES){
                            resOrder.setAmount(mchQrCode.getFixedPayAmount()); // 固定金额
                            resOrder.addExt("fixedFlag", true); //固定金额，不可变更。
                        }
                    }
                    resOrder.addExt("isForceReamrk",CS.YES == mchQrCode.getIsForceReamrk() ? true : false);
                }
            }
        }

        return ApiRes.ok(ApiResBodyAdviceKit.procAndConvertJSON(resOrder));
    }


    /** 调起下单接口, 返回支付数据包  **/
    @PostMapping("/pay")
    public ApiRes pay() throws Exception {

        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        //获取商户配置信息
        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, true);
        if(mchAppConfigContext == null){
            throw new BizException("商户或商户应用不存在");
        }
        if(mchAppConfigContext.getMchInfo() == null || mchAppConfigContext.getMchInfo().getState() != CS.YES){
            throw new BizException("商户信息不存在或商户状态不可用");
        }

        // 封装下单参数
        UnifiedOrderRQ rq = packagePayRQ(qrCodeParams);
        rq.setIsMarketRed(Boolean.FALSE);
        PayOrder payOrder = null;

        // 订单类型 需要查询订单
        if(qrCodeParams.getType() == QRCodeParams.TYPE_PAY_ORDER){
            payOrder = getPayOrder(true);
        // 码牌或设备二维码
        }else if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC || qrCodeParams.getType() == QRCodeParams.TYPE_QRC_DEVICE || qrCodeParams.getType() == QRCodeParams.TYPE_ROUTE){
            rq.setMchNo(mchAppConfigContext.getMchNo());
            rq.setAppId(mchAppConfigContext.getAppId());
            rq.setMchOrderNo(SeqKit.genMhoOrderId());
            rq.setAmount(getRequiredAmountL("amount"));
            rq.setCurrency("cny");
            rq.setStoreId(getValString("storeId"));
            JSONObject discount = getVal("discount",JSONObject.class);
            rq.setDiscount(discount);
            if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC){
                MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById(qrCodeParams.getId());
                rq.setSubject(StringUtils.isNotBlank(mchQrcodeCard.getQrcAlias()) ? mchQrcodeCard.getQrcAlias() : "静态码支付");
                rq.setBody(StringUtils.isNotBlank(mchQrcodeCard.getQrcAlias()) ? mchQrcodeCard.getQrcAlias() : "静态码支付");
                rq.setQrcId(mchQrcodeCard.getQrcId());
                rq.setStoreId(mchQrcodeCard.getStoreId());
            }else if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC_DEVICE){
                MchStoreDevice storeDevice = mchStoreDeviceService.getById(qrCodeParams.getId());
                MchStore mchStore = mchStoreService.getById(storeDevice.getStoreId());
                if(MchStoreDevice.DEVICE_BIND_TYPE_QRC == storeDevice.getBindType()){
                    List<MchQrcDeviceRela> list = mchQrcDeviceRelaService.list(MchQrcDeviceRela.gw()
                            .eq(MchQrcDeviceRela::getDeviceId, storeDevice.getDeviceId()));
                    if(list.isEmpty()){
                        throw new BizException("设备绑定的码牌信息异常");
                    }
                    MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(list.get(0).getQrcId());
                    rq.setSubject(StringUtils.isNotBlank(mchQrCode.getQrcAlias()) ? mchQrCode.getQrcAlias() : "静态码支付");
                    rq.setBody(StringUtils.isNotBlank(mchQrCode.getQrcAlias()) ? mchQrCode.getQrcAlias() : "静态码支付");
                    rq.setQrcId(mchQrCode.getQrcId());
                    rq.setStoreId(mchQrCode.getStoreId());
                }else{
                    rq.setSubject(mchStore.getStoreName());
                    rq.setBody(mchStore.getStoreName());
                    rq.setStoreId(mchStore.getStoreId());
                }
                // 设备信息
                UnifiedOrderRQ.DeviceInfo deviceInfo = new UnifiedOrderRQ.DeviceInfo();
                deviceInfo.setDeviceNo(storeDevice.getDeviceNo());
                deviceInfo.setDeviceType(PayOrder.DEVICE_TYPE_QR_BOX_KXP);
                deviceInfo.setProvider(storeDevice.getProvider());
                rq.setDeviceInfo(JSONObject.toJSONString(deviceInfo));
            }else{
                String storeName = getValString("storeName");
                if(StringUtils.isNotBlank(storeName)){
                    rq.setSubject(storeName);
                    rq.setBody(storeName);
                }
            }
            if(StringUtils.isNotBlank(getValString("buyerRemark"))) {
                rq.setBuyerRemark(getValString("buyerRemark"));
            }
            // 会员信息
            if(StringUtils.isNotBlank(getValString("mbrId"))) {
                rq.setMbrId(getValString("mbrId"));
            }
            if(StringUtils.isNotBlank(getValString("mbrTel"))) {
                rq.setMbrTel(getValString("mbrTel"));
            }
            //判断是否开启了红包
            Boolean isRedPacket = sysConfigService.getDbMarketPlatRedPacket();
            if(isRedPacket){
                DBMarketingConfig marketConfig = sysConfigService.getDBMarketingConfig();
                if(StringUtils.isEmpty(marketConfig.getMchNo())){
                    throw new BizException("红包营销功能已开启，未设置红包分账方商户号，请在系统配置-营销配置里面填写");
                }
                rq.setIsMarketRed(Boolean.TRUE);
            }
            boolean checkStoreRedRule = redPacketRuleService.isCheckStoreRedRule(mchAppConfigContext.getMchNo(),rq.getStoreId());
            if(isRedPacket && !checkStoreRedRule){
                throw new BizException("当前门店未配置红包规则,请在运营中心-营销红包-红包规则中开启后再支付");
            }
        }
        rq.setSignType(MchApp.SIGN_TYPE_MD5); // 设置默认签名方式为MD5

        ApiRes apiRes = this.unifiedOrder(rq.getWayCode(), rq, payOrder,null);
        logger.info("收银台下单返回支付数据包apiRes：{}", JSON.toJSONString(apiRes));

        return ApiRes.ok(apiRes);

    }

    /**
     * 订单取消支付  语音播报
     * **/
    @PostMapping("/payCancelBoardCast")
    public ApiRes payCancelBoardCast() {
        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        String payOrderId = getValString("payOrderId");

        payCancel(payOrderId);

        return ApiRes.ok();
    }


    /**
     * 微信小程序、微信公众号、支付宝服务窗、支付宝小程序 --- js调起支付后返回的内容
     */
    @PostMapping("/payEventBoardCast")
    public ApiRes payEventBoardCast() {

        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();

        String payOrderId = getValString("payOrderId");
        String resData = getValString("resData");

        if (StringUtils.isBlank(payOrderId)) {
            logger.error("调起微信、支付宝JSAPI收款上报数据，缺失参数：payOrderId");
            return ApiRes.ok();
        }

        // 异步处理前端支付事件消息
        SpringUtil.getBean(QrCashierController.class).asyncPayEventBoardCast(payOrderId, resData);

        return ApiRes.ok();
    }

    /** 会员配置查询 **/
    @GetMapping("/memberConfig")
    public ApiRes getMemberConfig() {
        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();
        // 获取到当前应用类型
        String currentPageType = qrCodeParams.getPageType();

        JSONObject result = new JSONObject();
        result.put("memberIsOpen", false);
        // 是否有会员模块
        SysConfig memberConfig = sysConfigService.getById(SysConfigService.MEMBER_ENT_CONFIG);
        // 支付宝WAP、自建二维码、动态聚合码不支持功能
        MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());

        if (memberConfig != null && mchQrCode != null && mchQrCode.getQrcBelongType() == MchQrcodeCard.QRC_BELONG_TYPE_ISV_PRE
                && !CS.PAY_WAY_CODE.ALI_WAP.equals(mchQrCode.getAlipayWayCode())) {

            // 是否开启会员模块
            MchConfig memberModelConfig = mchConfigService.getByMchNoAndConfigKey(mchQrCode.getMchNo(), "memberModelState");
            if (memberModelConfig != null && MchConfig.YES.equals(memberModelConfig.getConfigVal())) {

                // 商户是否开启会员支付功能
                MchConfig memberPayConfig = mchConfigService.getByMchNoAndConfigKey(mchQrCode.getMchNo(), "memberPayState");
                if (memberPayConfig != null && MchConfig.YES.equals(memberPayConfig.getConfigVal())) {
                    result.put("memberIsOpen", true);
                    result.put("memberSiteUrl", memberConfig.getConfigVal());
                }
            }
        }
        return ApiRes.ok(result);
    }

    /** 获取配置信息 **/
    @GetMapping("/config")
    public ApiRes getConfig() {
        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();
        JSONObject result = new JSONObject();
        String configKey = getValString("configKey");
        if(QRCodeParams.CONFIG_MARKETING_TYPE.equals(configKey)){
            String channelUserId = getValStringRequired("channelUserId");
            JSONObject redConfig = new JSONObject();
            DBMarketingConfig dbMarketingConfig = sysConfigService.getDBMarketingConfig();
            boolean isOpen = CS.YES == Byte.valueOf(dbMarketingConfig.getPlatRedPacket()) ? true : false;
            redConfig.put("isOpen",isOpen);
            if(isOpen){
                String storeId = getValString("storeId");
                RedPacketAccount account = redPacketAccountService.getByStorePayUserId(channelUserId, storeId);
                redConfig.put("balance",account == null ? 0 : account.getBalance());
            }
            JSONObject config = JSON.parseObject(JSON.toJSONString(dbMarketingConfig));
            config.put("isAdsOpen",CS.YES == Byte.valueOf(dbMarketingConfig.getAdsStatus()) ? true : false);
            redConfig.putAll(config);
            //检查配置
            result.put(configKey,redConfig);
            return ApiRes.ok(result);
        }
        return ApiRes.fail(ApiCodeEnum.PARAMS_ERROR);
    }


    private UnifiedOrderRQ packagePayRQ(QRCodeParams qrCodeParams){

        String channelUserId = getValString("channelUserId");

        if(QRCodeParams.TYPE_ROUTE != qrCodeParams.getType()){
            if(StringUtils.isEmpty(channelUserId)){
                String code = getValString("code");
                if(StringUtils.isNotEmpty(code)){
                    try {
                        ApiRes apiRes = channelUserId();
                        if(apiRes.getData() instanceof String ){
                            channelUserId = apiRes.getData().toString();
                        }else if(apiRes.getData() instanceof JSONObject ){
                            channelUserId = ((JSONObject)apiRes.getData()).getString("channelUserId");
                        }
                    }catch (Exception e){
                        throw new ParamException("用户信息获取异常");
                    }
                }else{
                    throw new ParamException("非法请求");
                }
            }
        }
        // 是否商户自己的小程序调起的
        Byte isUseSubmchAccount = getValByteDefault("isUseSubmchAccount", CS.NO);

        // 获取到当前应用类型
        String currentPageType = qrCodeParams.getPageType();

        // 支付宝内 && 自行创建二维码
        if(QRCodeParams.PAGE_TYPE_ALIPAY_H5.equals(currentPageType) && qrCodeParams.getType() == QRCodeParams.TYPE_QRC){
            MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
            if(CS.PAY_WAY_CODE.ALI_WAP.equals(mchQrCode.getAlipayWayCode())){ //wap支付， 无需获取
                return new AliWapOrderRQ();
            }
        }

        if(currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_H5) ){

            AliJsapiOrderRQ rq = new AliJsapiOrderRQ();
            rq.setBuyerUserId(channelUserId);
            return rq;

        }else if( currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_LITE)) {

            AliLiteOrderRQ rq = new AliLiteOrderRQ();
            rq.setBuyerUserId(channelUserId);
            return rq;

        }else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_H5) ){

            WxJsapiOrderRQ rq = new WxJsapiOrderRQ();
            rq.setOpenid(channelUserId);
            return rq;

        }else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_LITE) ){

            WxLiteOrderRQ rq = new WxLiteOrderRQ();
            rq.setOpenid(channelUserId);
            rq.setIsSubOpenId(isUseSubmchAccount); // 是否 商户自己的小程序调起
            return rq;

        }else if(currentPageType.equals(QRCodeParams.PAGE_TYPE_YSFPAY_H5) ){

            YsfJsapiOrderRQ rq = new YsfJsapiOrderRQ();
            rq.setUserId(channelUserId);
            return rq;

        }
        return null;
    }


    private String getToken(){

        String token = request.getHeader(JeepayKit.TOKEN_KEY);
        if(StringUtils.isEmpty(token)) {
            throw new BizException("获取二维码参数失败");
        }
        return token;
    }

    private String getCurrentPageType(){
        String pageType = request.getHeader("pageType");
        if(StringUtils.isEmpty(pageType)) {
            throw new BizException("不支持的客户端");
        }
        return pageType;
    }


    private PayOrder getPayOrder(boolean checkState){
        CacheTk cache = cacheTkService.getById(getToken());
        PayOrder payOrder = payOrderService.getById(cache.getSourceId());
        if(checkState == false) {
            return payOrder;
        }
        if(payOrder == null) {
            throw new BizException("订单不存");
        }
        if(payOrder.getState() == PayOrder.STATE_SUCCESS) {
            throw new BizException("订单已支付");
        }
        if(payOrder.getState() != PayOrder.STATE_INIT && payOrder.getState() != PayOrder.STATE_ING) {
            throw new BizException("订单状态不正确");
        }
        return payOrder;
    }

    private MchAppConfigContext     getQrParamsMchAppConfigContext(QRCodeParams qrCodeParams, boolean checkState){
        // 订单
        if(qrCodeParams.getType() == QRCodeParams.TYPE_PAY_ORDER){
            PayOrder payOrder = getPayOrder(checkState);
            return configContextQueryService.queryMchInfoAndAppInfoV2(payOrder.getMchNo(), payOrder.getAppId(),payOrder.getMchExtNo());
        // 商户自建二维码
        }else if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC){
            MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(qrCodeParams.getId());
            return configContextQueryService.queryMchInfoAndAppInfoV2(mchQrCode.getMchNo(), mchQrCode.getAppId(),mchQrCode.getMchApplyId());
        // 商户设备二维码
        }else if(qrCodeParams.getType() == QRCodeParams.TYPE_QRC_DEVICE){
            MchStoreDevice storeDevice = mchStoreDeviceService.getById(qrCodeParams.getId());
            if(storeDevice == null){
                throw new BizException("设备信息有误");
            }
            if(storeDevice.getBindState() == MchStoreDevice.NO_BIND){
                throw new BizException("当前设备未绑定或者设备已解绑");
            }
            if(storeDevice.getBindType() == MchStoreDevice.DEVICE_BIND_TYPE_STORE){
                MchStore store = mchStoreService.getById(storeDevice.getStoreId());
                if(store == null){
                    throw new BizException("设备绑定的门店信息异常");
                }
                return configContextQueryService.queryMchInfoAndAppInfoV2(storeDevice.getMchNo(), storeDevice.getAppId(),store.getMchApplyId());
            }else if (storeDevice.getBindType() == MchStoreDevice.DEVICE_BIND_TYPE_QRC){
                List<MchQrcDeviceRela> list = mchQrcDeviceRelaService.list(MchQrcDeviceRela.gw()
                        .eq(MchQrcDeviceRela::getDeviceId, storeDevice.getDeviceId()));
                if(list.isEmpty()){
                    throw new BizException("设备绑定的码牌信息异常");
                }
                MchQrcodeCard mchQrCode = mchQrcodeCardService.getById(list.get(0).getQrcId());
                return configContextQueryService.queryMchInfoAndAppInfoV2(mchQrCode.getMchNo(), mchQrCode.getAppId(),null);
            }
        }
        throw new BizException("二维码参数有误");
    }

    private QRCodeParams tokenConvert(){
        CacheTk cacheTk = cacheTkService.getById(getToken());
        if(cacheTk == null){
            throw new BizException("二维码参数有误");
        }
        QRCodeParams qrCodeParams = new QRCodeParams(cacheTk.getSourceId(),cacheTk.getType(),cacheTk.getAmount());
        qrCodeParams.setPageType(getCurrentPageType());
        qrCodeParams.setTk(cacheTk.getTk());
        return qrCodeParams;
    }

    private <T> MutablePair<String, T> getServiceByWayCode(String currentPageType, String serviceSuffix, MchAppConfigContext mchAppConfigContext, Class<T> cls){

        if( QRCodeParams.PAGE_TYPE_ALIPAY_LITE.equals(currentPageType) ||QRCodeParams.PAGE_TYPE_ALIPAY_H5.equals(currentPageType) ){
            return MutablePair.of(CS.IF_CODE.ALIPAY, SpringBeansUtil.getBean(CS.IF_CODE.ALIPAY + serviceSuffix, cls));

        }else if( QRCodeParams.PAGE_TYPE_WECHAT_LITE.equals(currentPageType) ||QRCodeParams.PAGE_TYPE_WECHAT_H5.equals(currentPageType) ){
            return MutablePair.of(CS.IF_CODE.WXPAY, SpringBeansUtil.getBean(CS.IF_CODE.WXPAY + serviceSuffix, cls));
        }

        // 云闪付JSAPI，根据支付通道配置获取ifcode
        else if( QRCodeParams.PAGE_TYPE_YSFPAY_H5.equals(currentPageType)){

            // 根据支付方式， 查询出 该商户 可用的支付接口
            MchPayPassage mchPayPassage = mchPayPassageService.findMchPayPassage(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.PAY_WAY_CODE.YSF_JSAPI);
            if(mchPayPassage == null){
                throw new BizException("商户应用不支持该支付方式");
            }

            return MutablePair.of(mchPayPassage.getIfCode(), SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(mchPayPassage.getIfCode()) + serviceSuffix, cls));
        }
        return null;
    }

    @Async
    public void asyncPayEventBoardCast(String payOrderId, String resData) {
        PayOrder payOrder = payOrderService.getById(payOrderId);
        if (payOrder == null) {
            logger.error("调起微信、支付宝JSAPI收款上报数据，订单不存在：payOrderId={}", payOrderId);
            return ;
        }
        if (StringUtils.isNotBlank(resData)) {
            JSONObject resJSON = JSONObject.parseObject(resData);

            logger.info("订单payOrderId={}，支付方式：payway={}，调起JSAPI收款后返回：resData={}", payOrderId, payOrder.getWayCode(), resData);

            // 取消支付，异步语音播报
            // 支付宝返回6001    微信H5返回 get_brand_wcpay_request:cancel    微信小程序返回 requestPayment:fail cancel
            if ((resJSON.getInteger("resultCode") != null && resJSON.getInteger("resultCode") == 6001)
                    || "get_brand_wcpay_request:cancel".equalsIgnoreCase(resJSON.getString("err_msg"))
                    || "requestPayment:fail cancel".equalsIgnoreCase(resJSON.getString("errMsg"))
            ) {
                payCancel(payOrderId);
            }else{
                payOrderMarketReissueService.marketReissue(payOrder);
            }
        }

    }

    /**
     * 处理取消支付事件
     * @param payOrderId
     */
    public void payCancel(String payOrderId) {

        String logPrefix = "【订单取消支付防逃单】";
        logger.info("开始处理{}", logPrefix);

        if (StringUtils.isBlank(payOrderId)) {
            logger.error("{}，缺失参数：payOrderId", logPrefix);
            return ;
        }

        PayOrder payOrder = payOrderService.getById(payOrderId);
        if (payOrder == null) {
            logger.error("{}，订单不存在：payOrderId={}", logPrefix, payOrderId);
            return ;
        }
        if (payOrder.getQrcId() == null && StringUtils.isEmpty(payOrder.getDeviceNo())) {
            logger.error("{}，非扫码牌支付：payOrderId={}", logPrefix, payOrderId);
            return ;
        }

//        MchConfig mchConfig = mchConfigService.getByMchNoAndConfigKey(payOrder.getMchNo(), "qrcEscaping");
//        if (mchConfig == null || !mchConfig.getConfigVal().equals(MchConfig.YES)) {
//            logger.error("{}，商户未启用该功能：payOrderId={}", logPrefix, payOrderId);
//            return ;
//        }

        // 消息内容
        PayOrderInfo4Device payOrderInfo = new PayOrderInfo4Device();
        payOrderInfo.setAmount(payOrder.getAmount());
        payOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis()));
        payOrderInfo.setWayCodeType(PayOrderInfo4Device.BOARD_TYPE_CANCEL); // 取消收款播报

        try {
            // 查询云打印设备
            List<JSONObject> printList = mchStoreDeviceService.selectAvailableDeviceList(payOrder.getMchNo(), payOrder.getStoreId(),
                    Arrays.asList( DeviceProvideConfig.DEVICE_TYPE_PRINTER));

            // 查询云喇叭设备
            List<JSONObject> speakList = mchStoreDeviceService.selectAvailableDeviceList(payOrder.getMchNo(), payOrder.getStoreId(),
                    Arrays.asList(DeviceProvideConfig.DEVICE_TYPE_SPEAKER));
            if (CollUtil.isNotEmpty(speakList)) {
                // 绑定类型为 【门店】 或 【已绑定下单码牌】
                speakList = speakList.stream()
                        .filter(item -> {
                            if (item.getByte("bindType") == MchStoreDevice.DEVICE_BIND_TYPE_STORE) {
                                return true;
                            }else if (item.getByte("bindType") == MchStoreDevice.DEVICE_BIND_TYPE_QRC) {
                                MchQrcDeviceRela rela = mchQrcDeviceRelaService.getOne(MchQrcDeviceRela.gw()
                                        .eq(MchQrcDeviceRela::getDeviceId, item.getString("deviceId"))
                                        .eq(MchQrcDeviceRela::getQrcId, payOrder.getQrcId())
                                );
                                if (rela != null) {
                                    return true;
                                }
                            }

                            return false;
                        })
                        .collect(Collectors.toList());
            }


            // 循环调用云喇叭设备播报
            for (JSONObject deviceParams : speakList) {
                logger.info("{}要播报的云喇叭设备ID：{}", logPrefix, deviceParams.getString("deviceId"));

                // 设备类型
                String provider = deviceParams.getString("provider");
                ISpeakerService speakerService = SpringBeansUtil.getBean(provider + "SpeakerService", ISpeakerService.class);
                if (null == speakerService) {
                    continue;
                }

                try {
                    speakerService.sendCustomMsg(deviceParams, payOrderInfo);
                    logger.info("{}云喇叭播报成功，设备厂商provider={}, payOderId={}", logPrefix, provider, payOrder.getPayOrderId());
                }catch (Exception e) {
                    logger.error("{}云喇叭播报失败，设备厂商provider={}, payOderId={}", logPrefix, provider, payOrder.getPayOrderId(), e);
                }
            }

            // 循环调用云打印设备播报
            for (JSONObject deviceParams : printList) {
                logger.info("{}要播报的云打印设备ID：{}", logPrefix, deviceParams.getString("deviceId"));

                // 设备类型
                String provider = deviceParams.getString("provider");
                IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class);
                if (null == printerService) {
                    continue;
                }

                try {
                    printerService.sendCustomMsg(deviceParams, payOrderInfo);
                    logger.info("{}云打印防逃单播报成功，设备厂商provider={}, payOderId={}", logPrefix, provider, payOrder.getPayOrderId());
                }catch (Exception e) {
                    logger.error("{}云打印防逃单播报失败，设备厂商provider={}, payOderId={}", logPrefix, provider, payOrder.getPayOrderId(), e);
                }
            }

        } catch (Exception e) {
            logger.error("error", e);
        }
    }

    /** 通过UA获取银联app标志 **/
    private static final String APPUPIDENTIFIER_REGEX = "UnionPay\\/\\d{1,2}\\.\\d{1,2} [A-Za-z0-9]+";
    private String getAppUpIdentifier(){

        Matcher matcher = Pattern.compile(APPUPIDENTIFIER_REGEX).matcher(request.getHeader("User-Agent"));
        if(matcher.find()){
            return matcher.group();
        }

        return null;
    }

    @RequestMapping(value = "toAppletPayment")
    public ApiRes toAppletPayment(){
        QRCodeParams qrCodeParams = tokenConvert();
        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, true);
        PayOrder payOrder = getPayOrder(true);
        AppletResult result = wxTgAppletService.toAppletPayment(payOrder,mchAppConfigContext,qrCodeParams);
        return ApiRes.ok(result);
    }

    /**
     * 查询订单状态
     * @return
     */
    @RequestMapping(value = "orderStatus")
    public ApiRes getOrderStatus(){
        QRCodeParams qrCodeParams = tokenConvert();
        PayOrder order = payOrderService.getById(qrCodeParams.getId());
        if(order == null){
            return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
        }
        //订单支付中的状态去查询订单实际支付状态
        if(PayOrder.STATE_ING == order.getState()){
            //查询支付接口是否存在
            ChannelRetMsg retMsg = channelOrderReissueService.processPayOrder(order);
            if(retMsg != null){
                if(retMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS){
                    order.setState(PayOrder.STATE_SUCCESS);
                }if(retMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL){
                    order.setState(PayOrder.STATE_FAIL);
                    order.setErrMsg(retMsg.getChannelErrMsg());
                }
            }
        }
        return ApiRes.ok(order);
    }
    /**
     * 输入金额计算优惠
     * @return
     */
    @GetMapping(value = "calcDiscount")
    public ApiRes calcDiscount(){
        QRCodeParams qrCodeParams = tokenConvert();
        MchAppConfigContext mchAppConfigContext = getQrParamsMchAppConfigContext(qrCodeParams, true);
        JSONObject result = new JSONObject();
        String channelUserId = getValString("channelUserId");
        String storeId = getValString("storeId");
        Long amount = getAmountL("amount");
        result.put("findAmt",amount);
        result.put("discountAmt",BigDecimal.ZERO);
        //判断是否开启了红包
        RedPacketRule ruleByMchStrore = redPacketRuleService.getRuleByMchStrore(mchAppConfigContext.getMchNo(), storeId);
        if(ruleByMchStrore != null && amount != null){
            RedPacketAccount account = redPacketAccountService.getByStorePayUserId(channelUserId, storeId);
            if(account != null){
                BigDecimal platScale = ruleByMchStrore.getPlatScale().compareTo(BigDecimal.TEN) >= 0 ? ruleByMchStrore.getPlatScale().divide(BigDecimal.valueOf(100)) : ruleByMchStrore.getPlatScale().divide(BigDecimal.TEN);
                BigDecimal exAmt = new BigDecimal(amount).multiply(platScale).setScale(0, RoundingMode.DOWN);
                BigDecimal discountAmt = new BigDecimal(amount).subtract(exAmt);
                if(account.getBalance() >= discountAmt.longValue()){
                    result.put("discountAmt",discountAmt.longValue());
                    result.put("findAmt",amount - discountAmt.longValue());
                }else{
                    result.put("discountAmt",account.getBalance());
                    result.put("findAmt",amount - account.getBalance());
                }
            }
            result.put("discountScale",ruleByMchStrore.getPlatScale());
        }
        return ApiRes.ok(result);
    }

    /**
     * 获取支付成功后的红包详情
     * @return
     */
    @GetMapping(value = "/getDiscountDetail/{payOrderId}")
    public ApiRes getDiscountDetail(@PathVariable("payOrderId") String payOrderId){
        QRCodeParams qrCodeParams = tokenConvert();
        PayOrder payOrder = payOrderService.getById(payOrderId);
        if(payOrder == null){
            return ApiRes.fail(ApiCodeEnum.PARAMS_ERROR,"订单数据异常");
        }
        JSONObject result = new JSONObject(2);
        result.put("order",payOrder);
        RedPacketInfo redPacketInfo = redPacketInfoService.getById(payOrderId);
        result.put("redPacketInfo",redPacketInfo);
        return ApiRes.ok(result);
    }

    /**
     * 获取路由
     * @return
     */
    @PostMapping("/doRoute")
    public ApiRes doRoute(){
        // token转换对象
        QRCodeParams qrCodeParams = tokenConvert();
        qrCodeParams.setAmt(getRequiredAmountL("amount"));
        String remark = getValString("remark");
        String pageType = qrCodeParams.getPageType().contains("wechat") ? CS.PAY_WAY_CODE_TYPE.WECHAT : qrCodeParams.getPageType().contains("alipay") ? CS.PAY_WAY_CODE_TYPE.ALIPAY : null;
        RouteManage manage = routeService.doRoute(qrCodeParams.getId(),qrCodeParams.getAmt(),pageType);
        //获取商户配置信息
        MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfoV2(manage.getMchNo(), manage.getAppid(),manage.getApplyId());
        if(CS.PAY_WAY_CODE_TYPE.WECHAT.equals(pageType)){
            WxpayOauth2Params oauth2Params = (WxpayOauth2Params)configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY);
            if(oauth2Params == null){
                return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"服务商微信Oauth2授权参数未配置");
            }
            if(CS.NO == manage.getRoute().getPayMethod() && StringUtils.isEmpty(oauth2Params.getAppId())){
                return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"服务商微信Oauth2授权APPID参数未配置");
            }
            if(CS.YES == manage.getRoute().getPayMethod() && StringUtils.isEmpty(oauth2Params.getLiteAppId())){
                return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"服务商微信Oauth2授权小程序APPID参数未配置");
            }
        }else if(CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(pageType)){
            AlipayOauth2Params oauth2Params = (AlipayOauth2Params)configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY);
            if(oauth2Params == null){
                return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"服务商支付宝Oauth2授权参数未配置");
            }
            if(CS.NO == manage.getRoute().getPayMethod() && StringUtils.isEmpty(oauth2Params.getAppId())){
                return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"服务商支付宝Oauth2授权APPID参数未配置");
            }
            if(CS.YES == manage.getRoute().getPayMethod() && StringUtils.isEmpty(oauth2Params.getLiteParams().getAppId())){
                return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"服务商支付宝Oauth2授权小程序APPID参数未配置");
            }
        }else{
            return ApiRes.fail(ApiCodeEnum.CUSTOM_FAIL,"请使用支付宝或微信支付");
        }
        // 封装下单参数
        UnifiedOrderRQ rq = packagePayRQ(qrCodeParams);
        rq.setMchNo(mchAppConfigContext.getMchNo());
        rq.setAppId(mchAppConfigContext.getAppId());
        rq.setMchOrderNo(SeqKit.genMhoOrderId());
        rq.setAmount(qrCodeParams.getAmt());
        rq.setCurrency("cny");
        rq.setStoreId(manage.getStoreId());
        rq.setSubject(mchAppConfigContext.getMchApplyment().getMchShortName());
        rq.setBody(mchAppConfigContext.getMchApplyment().getMchShortName());
        rq.setIsRoute(true);
        rq.setTk(qrCodeParams.getTk());
        rq.setBuyerRemark(remark);
        rq.setSignType(MchApp.SIGN_TYPE_MD5); // 设置默认签名方式为MD5
        ApiRes apiRes = this.unifiedOrder(rq.getWayCode(), rq, null,manage);
        return apiRes;
    }
}
